diff options
author | Nick Pelly <npelly@google.com> | 2010-12-06 11:50:47 -0800 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2010-12-06 11:50:47 -0800 |
commit | 089c3c7c0bea4610a5dcb9653e8ddfe06c101318 (patch) | |
tree | 358387e43ec6af760a5bce75dc86e444ee7c2210 | |
parent | 38dab454d151423faa9eb8c17f9cb8579f5e79c8 (diff) | |
parent | 28e8c66d4bb0c6e13b65d48767851dd02d554ebb (diff) | |
download | frameworks_base-089c3c7c0bea4610a5dcb9653e8ddfe06c101318.zip frameworks_base-089c3c7c0bea4610a5dcb9653e8ddfe06c101318.tar.gz frameworks_base-089c3c7c0bea4610a5dcb9653e8ddfe06c101318.tar.bz2 |
resolved conflicts for merge of 28e8c66d to master
Change-Id: I9746fd7478d3954b491179ffbd241f481cc2fb6c
20 files changed, 1148 insertions, 565 deletions
@@ -121,11 +121,11 @@ LOCAL_SRC_FILES += \ core/java/android/nfc/ILlcpConnectionlessSocket.aidl \ core/java/android/nfc/ILlcpServiceSocket.aidl \ core/java/android/nfc/ILlcpSocket.aidl \ - core/java/android/nfc/INdefTag.aidl \ core/java/android/nfc/INfcAdapter.aidl \ core/java/android/nfc/INfcTag.aidl \ core/java/android/nfc/IP2pInitiator.aidl \ core/java/android/nfc/IP2pTarget.aidl \ + core/java/android/nfc/INfcSecureElement.aidl \ core/java/android/os/IHardwareService.aidl \ core/java/android/os/IMessenger.aidl \ core/java/android/os/INetworkManagementService.aidl \ @@ -254,7 +254,6 @@ aidl_files := \ frameworks/base/core/java/android/nfc/NdefMessage.aidl \ frameworks/base/core/java/android/nfc/NdefRecord.aidl \ frameworks/base/core/java/android/nfc/Tag.aidl \ - frameworks/base/core/java/android/nfc/NdefTag.aidl \ frameworks/base/core/java/android/os/Bundle.aidl \ frameworks/base/core/java/android/os/DropBoxManager.aidl \ frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index c7bd9fd..15e073e 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -86,6 +86,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/androi $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/trustedlogic) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/com/trustedlogic) $(call add-clean-step, rm -rf $(OUT_DIR)/target/target/common/obj/APPS/Music2_intermediates) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/INdefTag.java) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index cd08e33..a663fb8 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -24,6 +24,7 @@ import android.nfc.ILlcpConnectionlessSocket; import android.nfc.INfcTag; import android.nfc.IP2pTarget; import android.nfc.IP2pInitiator; +import android.nfc.INfcSecureElement; /** * @hide @@ -36,9 +37,12 @@ interface INfcAdapter INfcTag getNfcTagInterface(); IP2pTarget getP2pTargetInterface(); IP2pInitiator getP2pInitiatorInterface(); + INfcSecureElement getNfcSecureElementInterface(); // NfcAdapter-class related methods boolean isEnabled(); + NdefMessage localGet(); + void localSet(in NdefMessage message); void openTagConnection(in Tag tag); // Non-public methods diff --git a/core/java/android/nfc/INdefTag.aidl b/core/java/android/nfc/INfcSecureElement.aidl index d131ebe..aa98dd2 100644..100755 --- a/core/java/android/nfc/INdefTag.aidl +++ b/core/java/android/nfc/INfcSecureElement.aidl @@ -16,13 +16,13 @@ package android.nfc; -import android.nfc.NdefMessage; - /** - * @hide + * {@hide} */ -interface INdefTag -{ - NdefMessage read(int nativeHandle); - boolean write(int nativeHandle, in NdefMessage msg); +interface INfcSecureElement { + int openSecureElementConnection(); + int closeSecureElementConnection(int nativeHandle); + byte[] exchangeAPDU(int nativeHandle, in byte[] data); + int[] getSecureElementTechList(int nativeHandle); + byte[] getSecureElementUid(int nativeHandle); }
\ No newline at end of file diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl index 13b97d6..ad3c1bb 100644 --- a/core/java/android/nfc/INfcTag.aidl +++ b/core/java/android/nfc/INfcTag.aidl @@ -25,7 +25,7 @@ interface INfcTag { int close(int nativeHandle); int connect(int nativeHandle); - String getType(int nativeHandle); + int[] getTechList(int nativeHandle); byte[] getUid(int nativeHandle); boolean isNdef(int nativeHandle); boolean isPresent(int nativeHandle); diff --git a/core/java/android/nfc/NdefTag.aidl b/core/java/android/nfc/NdefTag.aidl deleted file mode 100644 index 288f667..0000000 --- a/core/java/android/nfc/NdefTag.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 android.nfc; - -parcelable NdefTag;
\ No newline at end of file diff --git a/core/java/android/nfc/NdefTag.java b/core/java/android/nfc/NdefTag.java deleted file mode 100644 index eb9d0dc..0000000 --- a/core/java/android/nfc/NdefTag.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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 android.nfc; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Represents a discovered tag that contains {@link NdefMessage}s (or a tag that can store them). - * In practice, a tag is a thing that an NFC-enabled device can communicate with. This - * class is a representation of such a tag and can contain the NDEF messages shared by the tag. - * <p>An NDEF tag can contain zero or more NDEF messages (represented by {@link NdefMessage} - * objects) in addition to the basic tag properties of UID and Type. - * <p> - * {@link NdefTag}s that have been initialized will usually contain a single {@link NdefMessage} - * (and that Message can contain multiple {@link NdefRecord}s). However it - * is possible for {@link NdefTag}s to contain multiple {@link NdefMessage}s. - * <p>{@link NfcAdapter#createNdefTagConnection createNdefTagConnection()} can be used to modify the - * contents of some tags. - * <p>This is an immutable data class. All properties are set at Tag discovery - * time and calls on this class will retrieve those read-only properties, and - * not cause any further RF activity or block. Note however that arrays passed to and - * returned by this class are *not* cloned, so be careful not to modify them. - * @hide - */ -public class NdefTag extends Tag implements Parcelable { - /** - * Target for NFC Forum Type 1 compliant tag. - * <p>This is based on Jewel/Topaz technology - */ - public static final String TARGET_TYPE_1 = "type_1"; - - /** - * Target for NFC Forum Type 2 compliant tag. - * <p>This is based on Mifare Ultralight technology. - */ - public static final String TARGET_TYPE_2 = "type_2"; - - /** - * Target for NFC Forum Type 3 compliant tag. - * <p>This is based on Felica technology. - */ - public static final String TARGET_TYPE_3 = "type_3"; - - /** - * Target for NFC Forum Type 4 compliant tag. - * <p>This is based on Mifare Desfire technology. - */ - public static final String TARGET_TYPE_4 = "type_4"; - - /** - * Target for NFC Forum Enabled: Mifare Classic tag. - * <p>This is not strictly a NFC Forum tag type, but is a common - * NDEF message container. - */ - public static final String TARGET_MIFARE_CLASSIC = "type_mifare_classic"; - - /** - * Any other target. - */ - public static final String TARGET_OTHER = "other"; - - private final String[] mNdefTargets; - private final NdefMessage[][] mMessages; // one NdefMessage[] per NDEF target - private NdefMessage[] mFlatMessages; // collapsed mMessages, built lazily, protected by (this) - - /** - * Hidden constructor to be used by NFC service only. - * @hide - */ - public NdefTag(byte[] id, String[] rawTargets, byte[] pollBytes, byte[] activationBytes, - int serviceHandle, String[] ndefTargets, NdefMessage[][] messages) { - super(id, true, rawTargets, pollBytes, activationBytes, serviceHandle); - if (ndefTargets == null || messages == null) { - throw new IllegalArgumentException("ndefTargets or messages cannot be null"); - } - if (ndefTargets.length != messages.length){ - throw new IllegalArgumentException("ndefTargets and messages arrays must match"); - } - for (NdefMessage[] ms : messages) { - if (ms == null) { - throw new IllegalArgumentException("messages elements cannot be null"); - } - } - mNdefTargets = ndefTargets; - mMessages = messages; - } - - /** - * Construct a mock NdefTag. - * <p>This is an application constructed tag, so NfcAdapter methods on this - * Tag such as {@link NfcAdapter#createRawTagConnection} will fail with - * {@link IllegalArgumentException} since it does not represent a physical Tag. - * <p>This constructor might be useful for mock testing. - * @param id The tag identifier, can be null - * @param rawTargets must not be null - * @param pollBytes can be null - * @param activationBytes can be null - * @param ndefTargets NDEF target array, such as {TARGET_TYPE_2}, cannot be null - * @param messages messages, one array per NDEF target, cannot be null - * @return freshly constructed NdefTag - */ - public static NdefTag createMockNdefTag(byte[] id, String[] rawTargets, byte[] pollBytes, - byte[] activationBytes, String[] ndefTargets, NdefMessage[][] messages) { - // set serviceHandle to 0 to indicate mock tag - return new NdefTag(id, rawTargets, pollBytes, activationBytes, 0, ndefTargets, messages); - } - - /** - * Get all NDEF Messages. - * <p> - * This retrieves the NDEF Messages that were found on the Tag at discovery - * time. It does not cause any further RF activity, and does not block. - * <p> - * Most tags only contain a single NDEF message. - * - * @return NDEF Messages found at Tag discovery - */ - public NdefMessage[] getNdefMessages() { - // common-case optimization - if (mMessages.length == 1) { - return mMessages[0]; - } - - // return cached flat array - synchronized(this) { - if (mFlatMessages != null) { - return mFlatMessages; - } - // not cached - build a flat array - int sz = 0; - for (NdefMessage[] ms : mMessages) { - sz += ms.length; - } - mFlatMessages = new NdefMessage[sz]; - int i = 0; - for (NdefMessage[] ms : mMessages) { - System.arraycopy(ms, 0, mFlatMessages, i, ms.length); - i += ms.length; - } - return mFlatMessages; - } - } - - /** - * Get only the NDEF Messages from a single NDEF target on a tag. - * <p> - * This retrieves the NDEF Messages that were found on the Tag at discovery - * time. It does not cause any further RF activity, and does not block. - * <p> - * Most tags only contain a single NDEF message. - * - * @param target one of targets strings provided by getNdefTargets() - * @return NDEF Messages found at Tag discovery - */ - public NdefMessage[] getNdefMessages(String target) { - for (int i=0; i<mNdefTargets.length; i++) { - if (target.equals(mNdefTargets[i])) { - return mMessages[i]; - } - } - throw new IllegalArgumentException("target (" + target + ") not found"); - } - - /** - * Return the NDEF targets on this Tag that support NDEF messages. - * - * @return - */ - public String[] getNdefTargets() { - return mNdefTargets; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - // Tag fields - dest.writeInt(mIsNdef ? 1 : 0); - writeBytesWithNull(dest, mId); - dest.writeInt(mRawTargets.length); - dest.writeStringArray(mRawTargets); - writeBytesWithNull(dest, mPollBytes); - writeBytesWithNull(dest, mActivationBytes); - dest.writeInt(mServiceHandle); - - // NdefTag fields - dest.writeInt(mNdefTargets.length); - dest.writeStringArray(mNdefTargets); - dest.writeInt(mMessages.length); - for (NdefMessage[] ms : mMessages) { - dest.writeInt(ms.length); - dest.writeTypedArray(ms, flags); - } - } - - public static final Parcelable.Creator<NdefTag> CREATOR = - new Parcelable.Creator<NdefTag>() { - public NdefTag createFromParcel(Parcel in) { - boolean isNdef = (in.readInt() == 1); - if (!isNdef) { - throw new IllegalArgumentException("Creating NdefTag from Tag parcel"); - } - - // Tag fields - byte[] id = readBytesWithNull(in); - String[] rawTargets = new String[in.readInt()]; - in.readStringArray(rawTargets); - byte[] pollBytes = readBytesWithNull(in); - byte[] activationBytes = readBytesWithNull(in); - int serviceHandle = in.readInt(); - - // NdefTag fields - String[] ndefTargets = new String[in.readInt()]; - in.readStringArray(ndefTargets); - NdefMessage[][] messages = new NdefMessage[in.readInt()][]; - for (int i=0; i<messages.length; i++) { - messages[i] = new NdefMessage[in.readInt()]; - in.readTypedArray(messages[i], NdefMessage.CREATOR); - } - return new NdefTag(id, rawTargets, pollBytes, activationBytes, serviceHandle, - ndefTargets, messages); - } - public NdefTag[] newArray(int size) { - return new NdefTag[size]; - } - }; -}
\ No newline at end of file diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 88b6ea4..a1c22bf 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -1,25 +1,26 @@ /* - * 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. + * 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 android.nfc; -import java.lang.UnsupportedOperationException; - import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.ActivityThread; -import android.content.Context; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; -import android.nfc.INfcAdapter; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -40,6 +41,12 @@ public final class NfcAdapter { public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; /** + * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED + * @hide + */ + public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST"; + + /** * Mandatory Tag extra for the ACTION_TAG intents. * @hide */ @@ -170,6 +177,14 @@ public final class NfcAdapter { } /** + * Returns the binder interface to the service. + * @hide + */ + public INfcAdapter getService() { + return mService; + } + + /** * Helper to check if this device has FEATURE_NFC, but without using * a context. * Equivalent to @@ -230,8 +245,11 @@ public final class NfcAdapter { } } - /** NFC service dead - attempt best effort recovery */ - /*package*/ void attemptDeadServiceRecovery(Exception e) { + /** + * NFC service dead - attempt best effort recovery + * @hide + */ + public void attemptDeadServiceRecovery(Exception e) { Log.e(TAG, "NFC service dead - attempting to recover", e); INfcAdapter service = getServiceInterface(); if (service == null) { @@ -301,50 +319,41 @@ public final class NfcAdapter { } /** - * Create a raw tag connection to the default Target - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * @hide - */ - public RawTagConnection createRawTagConnection(Tag tag) { - if (tag.mServiceHandle == 0) { - throw new IllegalArgumentException("mock tag cannot be used for connections"); - } - try { - return new RawTagConnection(this, tag); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return null; - } - } - - /** - * Create a raw tag connection to the specified Target + * Set the NDEF Message that this NFC adapter should appear as to Tag + * readers. + * <p> + * Any Tag reader can read the contents of the local tag when it is in + * proximity, without any further user confirmation. + * <p> + * The implementation of this method must either + * <ul> + * <li>act as a passive tag containing this NDEF message + * <li>provide the NDEF message on over LLCP to peer NFC adapters + * </ul> + * The NDEF message is preserved across reboot. * <p>Requires {@link android.Manifest.permission#NFC} permission. + * + * @param message NDEF message to make public * @hide */ - public RawTagConnection createRawTagConnection(Tag tag, String target) { - if (tag.mServiceHandle == 0) { - throw new IllegalArgumentException("mock tag cannot be used for connections"); - } + public void setLocalNdefMessage(NdefMessage message) { try { - return new RawTagConnection(this, tag, target); + mService.localSet(message); } catch (RemoteException e) { attemptDeadServiceRecovery(e); - return null; } } /** - * Create an NDEF tag connection to the default Target + * Get the NDEF Message that this adapter appears as to Tag readers. * <p>Requires {@link android.Manifest.permission#NFC} permission. + * + * @return NDEF Message that is publicly readable * @hide */ - public NdefTagConnection createNdefTagConnection(NdefTag tag) { - if (tag.mServiceHandle == 0) { - throw new IllegalArgumentException("mock tag cannot be used for connections"); - } + public NdefMessage getLocalNdefMessage() { try { - return new NdefTagConnection(this, tag); + return mService.localGet(); } catch (RemoteException e) { attemptDeadServiceRecovery(e); return null; @@ -352,18 +361,14 @@ public final class NfcAdapter { } /** - * Create an NDEF tag connection to the specified Target - * <p>Requires {@link android.Manifest.permission#NFC} permission. + * Create an Nfc Secure Element Connection * @hide */ - public NdefTagConnection createNdefTagConnection(NdefTag tag, String target) { - if (tag.mServiceHandle == 0) { - throw new IllegalArgumentException("mock tag cannot be used for connections"); - } + public NfcSecureElement createNfcSecureElementConnection() { try { - return new NdefTagConnection(this, tag, target); + return new NfcSecureElement(mService.getNfcSecureElementInterface()); } catch (RemoteException e) { - attemptDeadServiceRecovery(e); + Log.e(TAG, "createNfcSecureElementConnection failed", e); return null; } } diff --git a/core/java/android/nfc/NfcSecureElement.java b/core/java/android/nfc/NfcSecureElement.java new file mode 100755 index 0000000..5f4c066 --- /dev/null +++ b/core/java/android/nfc/NfcSecureElement.java @@ -0,0 +1,138 @@ +/* + * 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 android.nfc; + +import android.nfc.technology.TagTechnology; +import android.os.RemoteException; +import android.util.Log; + +import java.io.IOException; + +//import android.util.Log; + +/** + * This class provides the primary API for managing all aspects Secure Element. + * Get an instance of this class by calling + * Context.getSystemService(Context.NFC_SERVICE). + * @hide + */ +public final class NfcSecureElement { + + private static final String TAG = "NfcSecureElement"; + + private INfcSecureElement mService; + + + /** + * @hide + */ + public NfcSecureElement(INfcSecureElement mSecureElementService) { + mService = mSecureElementService; + } + + public int openSecureElementConnection(String seType) throws IOException { + if (seType.equals("SmartMX")) { + try { + int handle = mService.openSecureElementConnection(); + // Handle potential errors + if (handle != 0) { + return handle; + } else { + throw new IOException("SmartMX connection not allowed"); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in openSecureElementConnection(): ", e); + return 0; + } + + } else if (seType.equals("UICC")) { + return 0; + } else { + throw new IOException("Wrong Secure Element type"); + } + } + + + public byte [] exchangeAPDU(int handle,byte [] data) throws IOException { + + + // Perform exchange APDU + try { + byte[] response = mService.exchangeAPDU(handle, data); + // Handle potential errors + if (response == null) { + throw new IOException("Exchange APDU failed"); + } + return response; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in exchangeAPDU(): ", e); + return null; + } + } + + public void closeSecureElementConnection(int handle) throws IOException { + + try { + int status = mService.closeSecureElementConnection(handle); + // Handle potential errors + if (ErrorCodes.isError(status)) { + throw new IOException("Error during the conection close"); + }; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in closeSecureElement(): ", e); + } + } + + + /** + * Returns target type. constants. + * + * @return Secure Element technology type. The possible values are defined in + * {@link TagTechnology} + * + */ + public int[] getSecureElementTechList(int handle) throws IOException { + try { + return mService.getSecureElementTechList(handle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getType(): ", e); + return null; + } + } + + /** + * Returns Secure Element UID. + * + * @return Secure Element UID. + */ + public byte[] getSecureElementUid(int handle) throws IOException { + + byte[] uid = null; + try { + uid = mService.getSecureElementUid(handle); + // Handle potential errors + if (uid == null) { + throw new IOException("Get Secure Element UID failed"); + } + return uid; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getType(): ", e); + return null; + } + } + +} diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index 5d0b04c..938e6a7 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -16,8 +16,20 @@ package android.nfc; +import android.nfc.technology.IsoDep; +import android.nfc.technology.MifareClassic; +import android.nfc.technology.NfcV; +import android.nfc.technology.Ndef; +import android.nfc.technology.NfcA; +import android.nfc.technology.NfcB; +import android.nfc.technology.NfcF; +import android.nfc.technology.TagTechnology; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; + +import java.util.Arrays; /** * Represents a (generic) discovered tag. @@ -30,13 +42,13 @@ import android.os.Parcelable; * {@link Tag} objects are passed to applications via the {@link NfcAdapter#EXTRA_TAG} extra * in {@link NfcAdapter#ACTION_TAG_DISCOVERED} intents. A {@link Tag} object is immutable * and represents the state of the tag at the time of discovery. It can be - * directly queried for its UID and Type, or used to create a {@link RawTagConnection} - * (with {@link NfcAdapter#createRawTagConnection createRawTagConnection()}). + * directly queried for its UID and Type, or used to create a {@link TagTechnology} + * (with {@link Tag#getTechnology(int)}). * <p> - * A {@link Tag} can be used to create a {@link RawTagConnection} only while the tag is in + * A {@link Tag} can be used to create a {@link TagTechnology} only while the tag is in * range. If it is removed and then returned to range, then the most recent * {@link Tag} object (in {@link NfcAdapter#ACTION_TAG_DISCOVERED}) should be used to create a - * {@link RawTagConnection}. + * {@link TagTechnology}. * <p>This is an immutable data class. All properties are set at Tag discovery * time and calls on this class will retrieve those read-only properties, and * not cause any further RF activity or block. Note however that arrays passed to and @@ -44,78 +56,39 @@ import android.os.Parcelable; * @hide */ public class Tag implements Parcelable { - /** - * ISO 14443-3A technology. - * <p> - * Includes Topaz (which is -3A compatible) - */ - public static final String TARGET_ISO_14443_3A = "iso14443_3a"; - - /** - * ISO 14443-3B technology. - */ - public static final String TARGET_ISO_14443_3B = "iso14443_3b"; - - /** - * ISO 14443-4 technology. - */ - public static final String TARGET_ISO_14443_4 = "iso14443_4"; - - /** - * ISO 15693 technology, commonly known as RFID. - */ - public static final String TARGET_ISO_15693 = "iso15693"; - - /** - * JIS X-6319-4 technology, commonly known as Felica. - */ - public static final String TARGET_JIS_X_6319_4 = "jis_x_6319_4"; - - /** - * Any other technology. - */ - public static final String TARGET_OTHER = "other"; - - /*package*/ final boolean mIsNdef; /*package*/ final byte[] mId; - /*package*/ final String[] mRawTargets; - /*package*/ final byte[] mPollBytes; - /*package*/ final byte[] mActivationBytes; + /*package*/ final int[] mTechList; + /*package*/ final Bundle[] mTechExtras; /*package*/ final int mServiceHandle; // for use by NFC service, 0 indicates a mock /** * Hidden constructor to be used by NFC service and internal classes. * @hide */ - public Tag(byte[] id, boolean isNdef, String[] rawTargets, byte[] pollBytes, - byte[] activationBytes, int serviceHandle) { - if (rawTargets == null) { + public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle) { + if (techList == null) { throw new IllegalArgumentException("rawTargets cannot be null"); } - mIsNdef = isNdef; mId = id; - mRawTargets = rawTargets; - mPollBytes = pollBytes; - mActivationBytes = activationBytes; + mTechList = Arrays.copyOf(techList, techList.length); + // Ensure mTechExtras is as long as mTechList + mTechExtras = Arrays.copyOf(techListExtras, techList.length); mServiceHandle = serviceHandle; } /** * Construct a mock Tag. * <p>This is an application constructed tag, so NfcAdapter methods on this - * Tag such as {@link NfcAdapter#createRawTagConnection} will fail with + * Tag such as {@link #getTechnology} may fail with * {@link IllegalArgumentException} since it does not represent a physical Tag. * <p>This constructor might be useful for mock testing. * @param id The tag identifier, can be null - * @param rawTargets must not be null - * @param pollBytes can be null - * @param activationBytes can be null + * @param techList must not be null * @return freshly constructed tag */ - public static Tag createMockTag(byte[] id, String[] rawTargets, byte[] pollBytes, - byte[] activationBytes) { + public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) { // set serviceHandle to 0 to indicate mock tag - return new Tag(id, false, rawTargets, pollBytes, activationBytes, 0); + return new Tag(id, techList, techListExtras, 0); } /** @@ -127,16 +100,6 @@ public class Tag implements Parcelable { } /** - * Return the available targets that this NFC adapter can use to create - * a RawTagConnection. - * - * @return raw targets, will not be null - */ - public String[] getRawTargets() { - return mRawTargets; - } - - /** * Get the Tag Identifier (if it has one). * <p>Tag ID is usually a serial number for the tag. * @@ -147,37 +110,64 @@ public class Tag implements Parcelable { } /** - * Get the low-level bytes returned by this Tag at poll-time. - * <p>These can be used to help with advanced identification of a Tag. - * <p>The meaning of these bytes depends on the Tag technology. - * <p>ISO14443-3A: ATQA/SENS_RES - * <p>ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES - * <p>JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) - * <p>ISO15693: response flags (1 byte), DSFID (1 byte) - * from SENSF_RES - * - * @return poll bytes, or null if they do not exist for this Tag technology - * @hide + * Returns technologies present in the tag that this implementation understands, + * or a zero length array if there are no supported technologies on this tag. */ - public byte[] getPollBytes() { - return mPollBytes; + public int[] getTechnologyList() { + return Arrays.copyOf(mTechList, mTechList.length); } /** - * Get the low-level bytes returned by this Tag at activation-time. - * <p>These can be used to help with advanced identification of a Tag. - * <p>The meaning of these bytes depends on the Tag technology. - * <p>ISO14443-3A: SAK/SEL_RES - * <p>ISO14443-3B: null - * <p>ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS <TODO: confirm> - * <p>ISO14443-3B & ISO14443-4: ATTRIB response - * <p>JIS_X_6319_4: null - * <p>ISO15693: response flags (1 byte), DSFID (1 byte): null - * @return activation bytes, or null if they do not exist for this Tag technology - * @hide + * Returns the technology, or null if not present */ - public byte[] getActivationBytes() { - return mActivationBytes; + public TagTechnology getTechnology(int tech) { + int pos = -1; + for (int idx = 0; idx < mTechList.length; idx++) { + if (mTechList[idx] == tech) { + pos = idx; + break; + } + } + if (pos < 0) { + return null; + } + + Bundle extras = mTechExtras[pos]; + NfcAdapter adapter = NfcAdapter.getDefaultAdapter(); + try { + switch (tech) { + case TagTechnology.NFC_A: { + return new NfcA(adapter, this, extras); + } + case TagTechnology.NFC_B: { + return new NfcB(adapter, this, extras); + } + case TagTechnology.ISO_DEP: { + return new IsoDep(adapter, this, extras); + } + case TagTechnology.NFC_V: { + return new NfcV(adapter, this, extras); + } + case TagTechnology.TYPE_1: + case TagTechnology.TYPE_2: + case TagTechnology.TYPE_3: + case TagTechnology.TYPE_4: { + return new Ndef(adapter, this, tech, extras); + } + case TagTechnology.NFC_F: { + return new NfcF(adapter, this, extras); + } + case TagTechnology.MIFARE_CLASSIC: { + return new MifareClassic(adapter, this, extras); + } + + default: { + throw new UnsupportedOperationException("Tech " + tech + " not supported"); + } + } + } catch (RemoteException e) { + return null; + } } @Override @@ -185,13 +175,9 @@ public class Tag implements Parcelable { StringBuilder sb = new StringBuilder("TAG ") .append("uid = ") .append(mId) - .append(" poll ") - .append(mPollBytes) - .append(" activation ") - .append(mActivationBytes) - .append(" Raw ["); - for (String s : mRawTargets) { - sb.append(s) + .append(" Tech ["); + for (int i : mTechList) { + sb.append(i) .append(", "); } return sb.toString(); @@ -221,37 +207,32 @@ public class Tag implements Parcelable { return 0; } - @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mIsNdef ? 1 : 0); writeBytesWithNull(dest, mId); - dest.writeInt(mRawTargets.length); - dest.writeStringArray(mRawTargets); - writeBytesWithNull(dest, mPollBytes); - writeBytesWithNull(dest, mActivationBytes); + dest.writeInt(mTechList.length); + dest.writeIntArray(mTechList); + dest.writeTypedArray(mTechExtras, 0); dest.writeInt(mServiceHandle); } public static final Parcelable.Creator<Tag> CREATOR = new Parcelable.Creator<Tag>() { + @Override public Tag createFromParcel(Parcel in) { - boolean isNdef = (in.readInt() == 1); - if (isNdef) { - throw new IllegalArgumentException("Creating Tag from NdefTag parcel"); - } // Tag fields byte[] id = Tag.readBytesWithNull(in); - String[] rawTargets = new String[in.readInt()]; - in.readStringArray(rawTargets); - byte[] pollBytes = Tag.readBytesWithNull(in); - byte[] activationBytes = Tag.readBytesWithNull(in); + int[] techList = new int[in.readInt()]; + in.readIntArray(techList); + Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR); int serviceHandle = in.readInt(); - return new Tag(id, isNdef, rawTargets, pollBytes, activationBytes, serviceHandle); + return new Tag(id, techList, techExtras, serviceHandle); } + + @Override public Tag[] newArray(int size) { return new Tag[size]; } }; -}
\ No newline at end of file +} diff --git a/core/java/android/nfc/RawTagConnection.java b/core/java/android/nfc/technology/BasicTagTechnology.java index bfdaa77..6b281b9 100644 --- a/core/java/android/nfc/RawTagConnection.java +++ b/core/java/android/nfc/technology/BasicTagTechnology.java @@ -14,31 +14,25 @@ * limitations under the License. */ -package android.nfc; +package android.nfc.technology; import java.io.IOException; +import android.nfc.INfcAdapter; +import android.nfc.INfcTag; +import android.nfc.NfcAdapter; +import android.nfc.Tag; import android.os.RemoteException; import android.util.Log; /** - * A low-level connection to a {@link Tag} target. - * <p>You can acquire this kind of connection with {@link NfcAdapter#createRawTagConnection - * createRawTagConnection()}. Use the connection to send and receive data with {@link #transceive - * transceive()}. - * <p> - * Applications must implement their own protocol stack on top of {@link #transceive transceive()}. - * - * <p class="note"><strong>Note:</strong> - * Use of this class requires the {@link android.Manifest.permission#NFC} - * permission. - * @hide + * A base class for tag technologies that are built on top of transceive(). */ -public class RawTagConnection { +/* package */ abstract class BasicTagTechnology implements TagTechnology { /*package*/ final Tag mTag; /*package*/ boolean mIsConnected; - /*package*/ String mSelectedTarget; + /*package*/ int mSelectedTechnology; private final NfcAdapter mAdapter; // Following fields are final after construction, except for @@ -49,30 +43,40 @@ public class RawTagConnection { private static final String TAG = "NFC"; - /*package*/ RawTagConnection(NfcAdapter adapter, Tag tag, String target) throws RemoteException { - String[] targets = tag.getRawTargets(); + /** + * @hide + */ + public BasicTagTechnology(NfcAdapter adapter, Tag tag, int tech) throws RemoteException { + int[] techList = tag.getTechnologyList(); int i; // Check target validity - for (i=0;i<targets.length;i++) { - if (target.equals(targets[i])) { + for (i = 0; i < techList.length; i++) { + if (tech == techList[i]) { break; } } - if (i >= targets.length) { - // Target not found - throw new IllegalArgumentException(); + if (i >= techList.length) { + // Technology not found + throw new IllegalArgumentException("Technology " + tech + " not present on tag " + tag); } mAdapter = adapter; - mService = mAdapter.mService; - mTagService = mService.getNfcTagInterface(); + mService = mAdapter.getService(); + try { + mTagService = mService.getNfcTagInterface(); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + } mTag = tag; - mSelectedTarget = target; + mSelectedTechnology = tech; } - /*package*/ RawTagConnection(NfcAdapter adapter, Tag tag) throws RemoteException { - this(adapter, tag, tag.getRawTargets()[0]); + /** + * @hide + */ + public BasicTagTechnology(NfcAdapter adapter, Tag tag) throws RemoteException { + this(adapter, tag, tag.getTechnologyList()[0]); } /** NFC service dead - attempt best effort recovery */ @@ -80,7 +84,7 @@ public class RawTagConnection { mAdapter.attemptDeadServiceRecovery(e); /* assigning to mService is not thread-safe, but this is best-effort code * and on a well-behaved system should never happen */ - mService = mAdapter.mService; + mService = mAdapter.getService(); try { mTagService = mService.getNfcTagInterface(); } catch (RemoteException e2) { @@ -92,6 +96,7 @@ public class RawTagConnection { * Get the {@link Tag} this connection is associated with. * <p>Requires {@link android.Manifest.permission#NFC} permission. */ + @Override public Tag getTag() { return mTag; } @@ -99,8 +104,9 @@ public class RawTagConnection { /** * <p>Requires {@link android.Manifest.permission#NFC} permission. */ - public String getTagTarget() { - return mSelectedTarget; + @Override + public int getTechnologyId() { + return mSelectedTechnology; } /** @@ -119,7 +125,7 @@ public class RawTagConnection { } try { - return mTagService.isPresent(mTag.mServiceHandle); + return mTagService.isPresent(mTag.getServiceHandle()); } catch (RemoteException e) { attemptDeadServiceRecovery(e); return false; @@ -136,6 +142,7 @@ public class RawTagConnection { * <p>Requires {@link android.Manifest.permission#NFC} permission. * @throws IOException if the target is lost, or connect canceled */ + @Override public void connect() throws IOException { //TODO(nxp): enforce exclusivity mIsConnected = true; @@ -151,10 +158,11 @@ public class RawTagConnection { * calls to {@link #transceive transceive()} or {@link #connect} will fail. * <p>Requires {@link android.Manifest.permission#NFC} permission. */ + @Override public void close() { mIsConnected = false; try { - mTagService.close(mTag.mServiceHandle); + mTagService.close(mTag.getServiceHandle()); } catch (RemoteException e) { attemptDeadServiceRecovery(e); } @@ -173,7 +181,7 @@ public class RawTagConnection { */ public byte[] transceive(byte[] data) throws IOException { try { - byte[] response = mTagService.transceive(mTag.mServiceHandle, data); + byte[] response = mTagService.transceive(mTag.getServiceHandle(), data); if (response == null) { throw new IOException("transcieve failed"); } diff --git a/core/java/android/nfc/technology/IsoDep.java b/core/java/android/nfc/technology/IsoDep.java new file mode 100644 index 0000000..5346c67 --- /dev/null +++ b/core/java/android/nfc/technology/IsoDep.java @@ -0,0 +1,80 @@ +/* + * 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 android.nfc.technology; + +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; + +import java.io.IOException; + +/** + * A low-level connection to a {@link Tag} using the ISO-DEP technology, also known as + * ISO1443-4. + * + * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}. + * Use this class to send and receive data with {@link #transceive transceive()}. + * + * <p>Applications must implement their own protocol stack on top of + * {@link #transceive transceive()}. + * + * <p class="note"><strong>Note:</strong> + * Use of this class requires the {@link android.Manifest.permission#NFC} + * permission. + */ +public final class IsoDep extends BasicTagTechnology { + /** @hide */ + public static final String EXTRA_ATTRIB = "attrib"; + /** @hide */ + public static final String EXTRA_HIST_BYTES = "histbytes"; + + private byte[] mAttrib = null; + private byte[] mHistBytes = null; + + public IsoDep(NfcAdapter adapter, Tag tag, Bundle extras) + throws RemoteException { + super(adapter, tag, TagTechnology.ISO_DEP); + if (extras != null) { + mAttrib = extras.getByteArray(EXTRA_ATTRIB); + mHistBytes = extras.getByteArray(EXTRA_HIST_BYTES); + } + } + + /** + * 3A only + */ + public byte[] getHistoricalBytes() { return mHistBytes; } + + /** + * 3B only + */ + public byte[] getAttrib() { return mAttrib; } + + /** + * Attempts to select the given application on the tag. Note that this only works + * if the tag supports ISO7816-4, which not all IsoDep tags support. If the tag doesn't + * support ISO7816-4 this will throw {@link UnsupportedOperationException}. + * + * This method requires that you call {@link #connect} before calling it. + * + * @throws IOException, UnsupportedOperationException + */ + public void selectAid(byte[] aid) throws IOException, UnsupportedOperationException { + throw new UnsupportedOperationException(); + } +} diff --git a/core/java/android/nfc/technology/MifareClassic.java b/core/java/android/nfc/technology/MifareClassic.java new file mode 100644 index 0000000..c25b71f --- /dev/null +++ b/core/java/android/nfc/technology/MifareClassic.java @@ -0,0 +1,291 @@ +/* + * 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 android.nfc.technology; + +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; + +import java.io.IOException; + +/** + * Concrete class for TagTechnology.MIFARE_CLASSIC + * + * Mifare classic has n sectors, with varying sizes, although + * they are at least the same pattern for any one mifare classic + * product. Each sector has two keys. Authentication with the correct + * key is needed before access to any sector. + * + * Each sector has k blocks. + * Block size is constant across the whole mifare classic family. + */ +public final class MifareClassic extends BasicTagTechnology { + /** + * The well-known, default factory MIFARE read key. + * Use this key to effectively make the payload in this sector + * public. + */ + public static final byte[] DEFAULT_KEY_FACTORY = + {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; + public static final byte[] DEFAULT_KEY_ZERO = + {(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00}; + /** + * The well-known, default Mifare Application Directory read key. + */ + public static final byte[] DEFAULT_KEY_MAD = + {(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5}; + /** + * The well-known, default read key for NDEF data on a Mifare Classic + */ + public static final byte[] DEFAULT_KEY_NFC_FORUM = + {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7}; + + public static final int TYPE_CLASSIC = 0; + public static final int TYPE_PLUS = 1; + public static final int TYPE_PRO = 2; + public static final int TYPE_DESFIRE = 3; + public static final int TYPE_ULTRALIGHT = 4; + public static final int TYPE_UNKNOWN = 5; + + public static final int SIZE_1K = 1024; + public static final int SIZE_2K = 2048; + public static final int SIZE_4K = 4096; + public static final int SIZE_MINI = 320; + public static final int SIZE_UNKNOWN = 0; + + private boolean mIsEmulated; + private int mType; + private int mSize; + + public MifareClassic(NfcAdapter adapter, Tag tag, Bundle extras) throws RemoteException { + super(adapter, tag, TagTechnology.MIFARE_CLASSIC); + + // Check if this could actually be a Mifare + NfcA a = (NfcA) tag.getTechnology(TagTechnology.NFC_A); + //short[] ATQA = getATQA(tag); + + mIsEmulated = false; + mType = TYPE_UNKNOWN; + mSize = SIZE_UNKNOWN; + + switch (a.getSak()) { + case 0x00: + // could be UL or UL-C + mType = TYPE_ULTRALIGHT; + break; + case 0x08: + // Type == classic + // Size = 1K + mType = TYPE_CLASSIC; + mSize = SIZE_1K; + break; + case 0x09: + // Type == classic mini + // Size == ? + mType = TYPE_CLASSIC; + mSize = SIZE_MINI; + break; + case 0x10: + // Type == MF+ + // Size == 2K + // SecLevel = SL2 + mType = TYPE_PLUS; + mSize = SIZE_2K; + break; + case 0x11: + // Type == MF+ + // Size == 4K + // Seclevel = SL2 + mType = TYPE_PLUS; + mSize = SIZE_4K; + break; + case 0x18: + // Type == classic + // Size == 4k + mType = TYPE_CLASSIC; + mSize = SIZE_4K; + break; + case 0x20: + // TODO this really should be a short, not byte + if (a.getAtqa()[0] == 0x03) { + // Type == DESFIRE + mType = TYPE_DESFIRE; + } else { + // Type == MF+ + // SL = SL3 + mType = TYPE_PLUS; + mSize = SIZE_UNKNOWN; + } + break; + case 0x28: + // Type == MF Classic + // Size == 1K + // Emulated == true + mType = TYPE_CLASSIC; + mSize = SIZE_1K; + mIsEmulated = true; + break; + case 0x38: + // Type == MF Classic + // Size == 4K + // Emulated == true + mType = TYPE_CLASSIC; + mSize = SIZE_4K; + mIsEmulated = true; + break; + case 0x88: + // Type == MF Classic + // Size == 1K + // NXP-tag: false + mType = TYPE_CLASSIC; + mSize = SIZE_1K; + break; + case 0x98: + case 0xB8: + // Type == MF Pro + // Size == 4K + mType = TYPE_PRO; + mSize = SIZE_4K; + break; + default: + // Unknown, not MIFARE + break; + } + } + + // Immutable data known at discovery time + public int getSize() { + return mSize; + } + + public int getType() { + return mType; + } + + public boolean isEmulated() { + return mIsEmulated; + } + + public int getSectorCount() { + switch (mSize) { + case SIZE_1K: { + return 16; + } + case SIZE_2K: { + return 32; + } + case SIZE_4K: { + return 40; + } + case SIZE_MINI: { + return 5; + } + default: { + return 0; + } + } + } + + public int getSectorSize(int sector) { + return getBlockCount(sector) * 16; + } + + public int getBlockCount(int sector) { + if (sector >= getSectorCount()) { + throw new IllegalArgumentException("this card only has " + getSectorCount() + + " sectors"); + } + + if (sector <= 32) { + return 4; + } else { + return 16; + } + } + + private byte firstBlockInSector(int sector) { + if (sector < 32) { + return (byte) ((sector * 4) & 0xff); + } else { + return (byte) ((32 * 4 + ((sector - 32) * 16)) & 0xff); + } + } + + // Methods that require connect() + /** + * Authenticate for a given sector. + */ + public boolean authenticateSector(int sector, byte[] key, boolean keyA) { + byte[] cmd = new byte[12]; + + // First byte is the command + if (keyA) { + cmd[0] = 0x60; // phHal_eMifareAuthentA + } else { + cmd[0] = 0x61; // phHal_eMifareAuthentB + } + + // Second byte is block address + cmd[1] = firstBlockInSector(sector); + + // Next 4 bytes are last 4 bytes of UID + byte[] uid = getTag().getId(); + System.arraycopy(uid, uid.length - 4, cmd, 2, 4); + + // Next 6 bytes are key + System.arraycopy(key, 0, cmd, 6, 6); + + try { + if ((transceive(cmd) != null)) { + return true; + } + } catch (IOException e) { + // No need to deal with, will return false anyway + } + return false; + } + + /** + * Sector indexing starts at 0. + * Block indexing starts at 0, and resets in each sector. + * @throws IOException + */ + public byte[] readBlock(int sector, int block) throws IOException { + byte addr = (byte) ((firstBlockInSector(sector) + block) & 0xff); + byte[] blockread_cmd = { 0x30, addr }; // phHal_eMifareRead + + // TODO deal with authentication problems + return transceive(blockread_cmd); + } + +// public byte[] readSector(int sector); + //TODO: define an enumeration for access control settings +// public int readSectorAccessControl(int sector); + + /** + * @throws IOException + * @throws NotAuthenticatedException + */ +/* + public void writeBlock(int block, byte[] data); + public void writeSector(int block, byte[] sector); + public void writeSectorAccessControl(int sector, int access); + public void increment(int block); + public void decrement(int block); +*/ +} diff --git a/core/java/android/nfc/NdefTagConnection.java b/core/java/android/nfc/technology/Ndef.java index aafdbfd..22460cf 100644 --- a/core/java/android/nfc/NdefTagConnection.java +++ b/core/java/android/nfc/technology/Ndef.java @@ -14,115 +14,122 @@ * limitations under the License. */ -package android.nfc; - -import java.io.IOException; +package android.nfc.technology; +import android.nfc.ErrorCodes; +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; import android.os.RemoteException; -import android.util.Log; + +import java.io.IOException; /** - * A connection to an NDEF target on an {@link NdefTag}. - * <p>You can acquire this kind of connection with {@link NfcAdapter#createNdefTagConnection - * createNdefTagConnection()}. Use the connection to read or write {@link NdefMessage}s. + * A high-level connection to a {@link Tag} using one of the NFC type 1, 2, 3, or 4 technologies + * to interact with NDEF data. MiFare Classic cards that present NDEF data may also be used + * via this class. To determine the exact technology being used call {@link #getTechnologyId()} + * + * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}. + * * <p class="note"><strong>Note:</strong> * Use of this class requires the {@link android.Manifest.permission#NFC} * permission. - * @hide */ -public class NdefTagConnection extends RawTagConnection { +public final class Ndef extends BasicTagTechnology { public static final int NDEF_MODE_READ_ONCE = 1; public static final int NDEF_MODE_READ_ONLY = 2; public static final int NDEF_MODE_WRITE_ONCE = 3; public static final int NDEF_MODE_WRITE_MANY = 4; public static final int NDEF_MODE_UNKNOWN = 5; - private static final String TAG = "NFC"; - /** * Internal constructor, to be used by NfcAdapter * @hide */ - /* package private */ NdefTagConnection(NfcAdapter adapter, NdefTag tag, String target) throws RemoteException { - super(adapter, tag); - String[] targets = tag.getNdefTargets(); - int i; + public Ndef(NfcAdapter adapter, Tag tag, int tech, Bundle extras) throws RemoteException { + super(adapter, tag, tech); + } - // Check target validity - for (i=0; i<targets.length; i++) { - if (target.equals(targets[i])) { - break; + /** + * Get the primary NDEF message on this tag. This data is read at discovery time + * and does not require a connection. + */ + public NdefMessage getNdefMessage() throws IOException, FormatException { + try { + int serviceHandle = mTag.getServiceHandle(); + NdefMessage msg = mTagService.read(serviceHandle); + if (msg == null) { + int errorCode = mTagService.getLastError(serviceHandle); + switch (errorCode) { + case ErrorCodes.ERROR_IO: + throw new IOException(); + case ErrorCodes.ERROR_INVALID_PARAM: + throw new FormatException(); + default: + // Should not happen + throw new IOException(); + } } - } - if (i >= targets.length) { - // Target not found - throw new IllegalArgumentException(); + return msg; + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + return null; } } /** - * Internal constructor, to be used by NfcAdapter - * @hide + * Get optional extra NDEF messages. + * Some tags may contain extra NDEF messages, but not all + * implementations will be able to read them. */ - /* package private */ NdefTagConnection(NfcAdapter adapter, NdefTag tag) throws RemoteException { - this(adapter, tag, tag.getNdefTargets()[0]); + public NdefMessage[] getExtraNdefMessage() throws IOException, FormatException { + throw new UnsupportedOperationException(); } /** - * Read NDEF message(s). - * This will always return the most up to date payload, and can block. - * It can be canceled with {@link RawTagConnection#close}. - * Most NDEF tags will contain just one NDEF message. + * Get maximum NDEF message size in bytes + */ + public int getSize() { + throw new UnsupportedOperationException(); + } + + /** + * Read/Write mode hint. + * Provides a hint if further reads or writes are likely to succeed. * <p>Requires {@link android.Manifest.permission#NFC} permission. - * @throws FormatException if the tag is not NDEF formatted + * @return one of NDEF_MODE * @throws IOException if the target is lost or connection closed - * @throws FormatException */ - public NdefMessage[] readNdefMessages() throws IOException, FormatException { - //TODO(nxp): do not use getLastError(), it is racy + public int getModeHint() throws IOException { try { - NdefMessage[] msgArray = new NdefMessage[1]; - NdefMessage msg = mTagService.read(mTag.mServiceHandle); - if (msg == null) { - int errorCode = mTagService.getLastError(mTag.mServiceHandle); - switch (errorCode) { + int result = mTagService.getModeHint(mTag.getServiceHandle()); + if (ErrorCodes.isError(result)) { + switch (result) { case ErrorCodes.ERROR_IO: throw new IOException(); - case ErrorCodes.ERROR_INVALID_PARAM: - throw new FormatException(); default: // Should not happen throw new IOException(); } } - msgArray[0] = msg; - return msgArray; + return result; + } catch (RemoteException e) { attemptDeadServiceRecovery(e); - return null; + return NDEF_MODE_UNKNOWN; } } + // Methods that require connect() /** - * Attempt to write an NDEF message to a tag. - * This method will block until the data is written. It can be canceled - * with {@link RawTagConnection#close}. - * Many tags are write-once, so use this method carefully. - * Specification allows for multiple NDEF messages per NDEF tag, but it is - * encourage to only write one message, this so API only takes a single - * message. Use {@link NdefRecord} to write several records to a single tag. - * For write-many tags, use {@link #makeReadOnly} after this method to attempt - * to prevent further modification. For write-once tags this is not - * necessary. - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * - * @throws FormatException if the tag is not suitable for NDEF messages - * @throws IOException if the target is lost or connection closed or the - * write failed + * Overwrite the primary NDEF message + * @throws IOException */ - public void writeNdefMessage(NdefMessage message) throws IOException, FormatException { + public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException { try { - int errorCode = mTagService.write(mTag.mServiceHandle, message); + int errorCode = mTagService.write(mTag.getServiceHandle(), msg); switch (errorCode) { case ErrorCodes.SUCCESS: break; @@ -140,16 +147,26 @@ public class NdefTagConnection extends RawTagConnection { } /** - * Attempts to make the NDEF data in this tag read-only. - * This method will block until the action is complete. It can be canceled - * with {@link RawTagConnection#close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * @return true if the tag is now read-only - * @throws IOException if the target is lost, or connection closed + * Attempt to write extra NDEF messages. + * Implementations may be able to write extra NDEF + * message after the first primary message, but it is not + * guaranteed. Even if it can be written, other implementations + * may not be able to read NDEF messages after the primary message. + * It is recommended to use additional NDEF records instead. + * + * @throws IOException + */ + public void writeExtraNdefMessage(int i, NdefMessage msg) throws IOException, FormatException { + throw new UnsupportedOperationException(); + } + + /** + * Set the CC field to indicate this tag is read-only + * @throws IOException */ - public boolean makeReadOnly() throws IOException { + public boolean makeReadonly() throws IOException { try { - int errorCode = mTagService.makeReadOnly(mTag.mServiceHandle); + int errorCode = mTagService.makeReadOnly(mTag.getServiceHandle()); switch (errorCode) { case ErrorCodes.SUCCESS: return true; @@ -168,29 +185,11 @@ public class NdefTagConnection extends RawTagConnection { } /** - * Read/Write mode hint. - * Provides a hint if further reads or writes are likely to succeed. - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * @return one of NDEF_MODE - * @throws IOException if the target is lost or connection closed + * Attempt to use tag specific technology to really make + * the tag read-only + * For NFC Forum Type 1 and 2 only. */ - public int getModeHint() throws IOException { - try { - int result = mTagService.getModeHint(mTag.mServiceHandle); - if (ErrorCodes.isError(result)) { - switch (result) { - case ErrorCodes.ERROR_IO: - throw new IOException(); - default: - // Should not happen - throw new IOException(); - } - } - return result; - - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return NDEF_MODE_UNKNOWN; - } + public void makeLowLevelReadonly() { + throw new UnsupportedOperationException(); } -}
\ No newline at end of file +} diff --git a/core/java/android/nfc/technology/NfcA.java b/core/java/android/nfc/technology/NfcA.java new file mode 100644 index 0000000..ef46762 --- /dev/null +++ b/core/java/android/nfc/technology/NfcA.java @@ -0,0 +1,66 @@ +/* + * 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 android.nfc.technology; + +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; + +/** + * A low-level connection to a {@link Tag} using the NFC-A technology, also known as + * ISO1443-3A. + * + * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}. + * Use this class to send and receive data with {@link #transceive transceive()}. + * + * <p>Applications must implement their own protocol stack on top of + * {@link #transceive transceive()}. + * + * <p class="note"><strong>Note:</strong> + * Use of this class requires the {@link android.Manifest.permission#NFC} + * permission. + */ +public final class NfcA extends BasicTagTechnology { + /** @hide */ + public static final String EXTRA_SAK = "sak"; + /** @hide */ + public static final String EXTRA_ATQA = "atqa"; + + private short mSak; + private byte[] mAtqa; + + public NfcA(NfcAdapter adapter, Tag tag, Bundle extras) throws RemoteException { + super(adapter, tag, TagTechnology.NFC_A); + mSak = extras.getShort(EXTRA_SAK); + mAtqa = extras.getByteArray(EXTRA_ATQA); + } + + /** + * Returns the ATQA/SENS_RES bytes discovered at tag discovery. + */ + public byte[] getAtqa() { + return mAtqa; + } + + /** + * Returns the SAK/SEL_RES discovered at tag discovery. + */ + public short getSak() { + return mSak; + } +} diff --git a/core/java/android/nfc/technology/NfcB.java b/core/java/android/nfc/technology/NfcB.java new file mode 100644 index 0000000..64cb08a --- /dev/null +++ b/core/java/android/nfc/technology/NfcB.java @@ -0,0 +1,55 @@ +/* + * 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 android.nfc.technology; + +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; + +/** + * A low-level connection to a {@link Tag} using the NFC-B technology, also known as + * ISO1443-3B. + * + * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}. + * Use this class to send and receive data with {@link #transceive transceive()}. + * + * <p>Applications must implement their own protocol stack on top of + * {@link #transceive transceive()}. + * + * <p class="note"><strong>Note:</strong> + * Use of this class requires the {@link android.Manifest.permission#NFC} + * permission. + */ +public final class NfcB extends BasicTagTechnology { + /** @hide */ + public static final String EXTRA_ATQB = "atqb"; + + private byte[] mAtqb; + + public NfcB(NfcAdapter adapter, Tag tag, Bundle extras) + throws RemoteException { + super(adapter, tag, TagTechnology.NFC_B); + } + + /** + * Returns the ATQB/SENSB_RES bytes discovered at tag discovery. + */ + public byte[] getAtqb() { + return mAtqb; + } +} diff --git a/core/java/android/nfc/technology/NfcF.java b/core/java/android/nfc/technology/NfcF.java new file mode 100644 index 0000000..6741ac8 --- /dev/null +++ b/core/java/android/nfc/technology/NfcF.java @@ -0,0 +1,63 @@ +/* + * 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 android.nfc.technology; + +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; + +/** + * A low-level connection to a {@link Tag} using the NFC-F technology, also known as + * JIS6319-4. + * + * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}. + * Use this class to send and receive data with {@link #transceive transceive()}. + * + * <p>Applications must implement their own protocol stack on top of + * {@link #transceive transceive()}. + * + * <p class="note"><strong>Note:</strong> + * Use of this class requires the {@link android.Manifest.permission#NFC} + * permission. + */ +public final class NfcF extends BasicTagTechnology { + /** @hide */ + public static final String EXTRA_SC = "systemcode"; + /** @hide */ + public static final String EXTRA_PMM = "pmm"; + + private byte[] mSystemCode = null; + private byte[] mManufacturer = null; + + public NfcF(NfcAdapter adapter, Tag tag, Bundle extras) + throws RemoteException { + super(adapter, tag, TagTechnology.NFC_F); + if (extras != null) { + mSystemCode = extras.getByteArray(EXTRA_SC); + mManufacturer = extras.getByteArray(EXTRA_PMM); + } + } + + public byte[] getSystemCode() { + return mSystemCode; + } + + public byte[] getManufacturer() { + return mManufacturer; + } +} diff --git a/core/java/android/nfc/technology/NfcV.java b/core/java/android/nfc/technology/NfcV.java new file mode 100644 index 0000000..9b6a16a --- /dev/null +++ b/core/java/android/nfc/technology/NfcV.java @@ -0,0 +1,43 @@ +/* + * 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 android.nfc.technology; + +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; + +/** + * A low-level connection to a {@link Tag} using the NFC-V technology, also known as + * ISO15693. + * + * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}. + * Use this class to send and receive data with {@link #transceive transceive()}. + * + * <p>Applications must implement their own protocol stack on top of + * {@link #transceive transceive()}. + * + * <p class="note"><strong>Note:</strong> + * Use of this class requires the {@link android.Manifest.permission#NFC} + * permission. + */ +public final class NfcV extends BasicTagTechnology { + public NfcV(NfcAdapter adapter, Tag tag, Bundle extras) + throws RemoteException { + super(adapter, tag, TagTechnology.NFC_V); + } +} diff --git a/core/java/android/nfc/technology/TagTechnology.java b/core/java/android/nfc/technology/TagTechnology.java new file mode 100644 index 0000000..c6c65e8 --- /dev/null +++ b/core/java/android/nfc/technology/TagTechnology.java @@ -0,0 +1,109 @@ +/* + * 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 android.nfc.technology; + +import android.nfc.Tag; + +import java.io.IOException; + +public interface TagTechnology { + /** + * This object is an instance of {@link NfcA} + */ + public static final int NFC_A = 1; + + /** + * This object is an instance of {@link NfcB} + */ + public static final int NFC_B = 2; + + /** + * This object is an instance of {@link IsoDep} + */ + public static final int ISO_DEP = 3; + + /** + * This object is an instance of {@link NfcF} + */ + public static final int NFC_F = 11; + + /** + * This object is an instance of {@link NfcV} + */ + public static final int NFC_V = 21; + + /** + * This object is an instance of {@link Ndef} + */ + public static final int TYPE_1 = 101; + + /** + * This object is an instance of {@link Ndef} + */ + public static final int TYPE_2 = 102; + + /** + * This object is an instance of {@link Ndef} + */ + public static final int TYPE_3 = 103; + + /** + * This object is an instance of {@link Ndef} + */ + public static final int TYPE_4 = 104; + + /** + * This object is an instance of {@link MifareClassic} + */ + public static final int MIFARE_CLASSIC = 200; + + /** + * A Mifare Classic tag with NDEF data + */ + public static final int MIFARE_CLASSIC_NDEF = 201; + + /** + * A Mifare Ultralight tag + */ + public static final int MIFARE_ULTRALIGHT = 202; + + /** + * A Mifare DESFire tag + */ + public static final int MIFARE_DESFIRE = 203; + + /** + * Returns the technology type for this tag connection. + */ + public int getTechnologyId(); + + /** + * Get the backing tag object. + */ + public Tag getTag(); + + /** + * @throws IOException + */ + public void connect() throws IOException; + + /** + * Non-blocking. Immediately causes all blocking calls + * to throw IOException. + */ + public void close(); +} diff --git a/core/java/android/nfc/technology/package.html b/core/java/android/nfc/technology/package.html new file mode 100644 index 0000000..26b8a32 --- /dev/null +++ b/core/java/android/nfc/technology/package.html @@ -0,0 +1,5 @@ +<HTML> +<BODY> +{@hide} +</BODY> +</HTML>
\ No newline at end of file |