diff options
author | Jeff Hamilton <jham@android.com> | 2011-01-21 01:13:06 -0600 |
---|---|---|
committer | Jeff Hamilton <jham@android.com> | 2011-01-21 13:32:58 -0600 |
commit | 4e21e1d21a877cce4db5ec8c5786604cc10f2d7e (patch) | |
tree | 25cadcf38afab0b0874f35a029e8ee5604a153bc /core/java/android/nfc/tech | |
parent | 11576102a9794ef964a08bc372dc09803f58997a (diff) | |
download | frameworks_base-4e21e1d21a877cce4db5ec8c5786604cc10f2d7e.zip frameworks_base-4e21e1d21a877cce4db5ec8c5786604cc10f2d7e.tar.gz frameworks_base-4e21e1d21a877cce4db5ec8c5786604cc10f2d7e.tar.bz2 |
API changes for NFC.
Bug: 3366009
Change-Id: Ia28e03e1501421906b640b78d4c9a59a20e9c668
Diffstat (limited to 'core/java/android/nfc/tech')
-rw-r--r-- | core/java/android/nfc/tech/BasicTagTechnology.java | 181 | ||||
-rw-r--r-- | core/java/android/nfc/tech/IsoDep.java | 132 | ||||
-rw-r--r-- | core/java/android/nfc/tech/MifareClassic.java | 417 | ||||
-rw-r--r-- | core/java/android/nfc/tech/MifareUltralight.java | 130 | ||||
-rw-r--r-- | core/java/android/nfc/tech/Ndef.java | 264 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NdefFormatable.java | 108 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcA.java | 99 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcB.java | 101 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcF.java | 95 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcV.java | 94 | ||||
-rw-r--r-- | core/java/android/nfc/tech/TagTechnology.java | 145 |
11 files changed, 1766 insertions, 0 deletions
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/core/java/android/nfc/tech/BasicTagTechnology.java new file mode 100644 index 0000000..a909631 --- /dev/null +++ b/core/java/android/nfc/tech/BasicTagTechnology.java @@ -0,0 +1,181 @@ +/* + * 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.tech; + +import android.nfc.ErrorCodes; +import android.nfc.Tag; +import android.nfc.TagLostException; +import android.nfc.TransceiveResult; +import android.os.RemoteException; +import android.util.Log; + +import java.io.IOException; + +/** + * A base class for tag technologies that are built on top of transceive(). + */ +/* package */ abstract class BasicTagTechnology implements TagTechnology { + private static final String TAG = "NFC"; + + /*package*/ final Tag mTag; + /*package*/ boolean mIsConnected; + /*package*/ int mSelectedTechnology; + + BasicTagTechnology(Tag tag, int tech) throws RemoteException { + int[] techList = tag.getTechnologyList(); + int i; + + // Check target validity + for (i = 0; i < techList.length; i++) { + if (tech == techList[i]) { + break; + } + } + if (i >= techList.length) { + // Technology not found + throw new IllegalArgumentException("Technology " + tech + " not present on tag " + tag); + } + + mTag = tag; + mSelectedTechnology = tech; + } + + BasicTagTechnology(Tag tag) throws RemoteException { + this(tag, tag.getTechnologyList()[0]); + } + + @Override + public Tag getTag() { + return mTag; + } + + /** Internal helper to throw IllegalStateException if the technology isn't connected */ + void checkConnected() { + if ((mTag.getConnectedTechnology() != getTechnologyId()) || + (mTag.getConnectedTechnology() == -1)) { + throw new IllegalStateException("Call connect() first!"); + } + } + + @Override + public int getTechnologyId() { + return mSelectedTechnology; + } + + /** + * Helper to indicate if {@link #connect} has succeeded. + * <p> + * Does not cause RF activity, and does not block. + * @return true if {@link #connect} has completed successfully and the {@link Tag} is believed + * to be within range. Applications must still handle {@link java.io.IOException} + * while using methods that require a connection in case the connection is lost after this + * method returns. + */ + public boolean isConnected() { + if (!mIsConnected) { + return false; + } + + try { + return mTag.getTagService().isPresent(mTag.getServiceHandle()); + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + return false; + } + } + + @Override + public void connect() throws IOException { + try { + int errorCode = mTag.getTagService().connect(mTag.getServiceHandle(), getTechnologyId()); + + if (errorCode == ErrorCodes.SUCCESS) { + // Store this in the tag object + mTag.setConnectedTechnology(getTechnologyId()); + mIsConnected = true; + } else { + throw new IOException(); + } + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + throw new IOException("NFC service died"); + } + } + + @Override + public void reconnect() throws IOException { + if (!mIsConnected) { + throw new IllegalStateException("Technology not connected yet"); + } + + try { + int errorCode = mTag.getTagService().reconnect(mTag.getServiceHandle()); + + if (errorCode != ErrorCodes.SUCCESS) { + mIsConnected = false; + mTag.setTechnologyDisconnected(); + throw new IOException(); + } + } catch (RemoteException e) { + mIsConnected = false; + mTag.setTechnologyDisconnected(); + Log.e(TAG, "NFC service dead", e); + throw new IOException("NFC service died"); + } + } + + @Override + public void close() { + try { + /* Note that we don't want to physically disconnect the tag, + * but just reconnect to it to reset its state + */ + mTag.getTagService().reconnect(mTag.getServiceHandle()); + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + } finally { + mIsConnected = false; + mTag.setTechnologyDisconnected(); + } + } + + /** Internal transceive */ + /*package*/ byte[] transceive(byte[] data, boolean raw) throws IOException { + checkConnected(); + + try { + TransceiveResult result = mTag.getTagService().transceive(mTag.getServiceHandle(), data, raw); + if (result == null) { + throw new IOException("transceive failed"); + } else { + if (result.isSuccessful()) { + return result.getResponseData(); + } else { + if (result.isTagLost()) { + throw new TagLostException("Tag was lost."); + } + else { + throw new IOException("transceive failed"); + } + } + } + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + throw new IOException("NFC service died"); + } + } +} diff --git a/core/java/android/nfc/tech/IsoDep.java b/core/java/android/nfc/tech/IsoDep.java new file mode 100644 index 0000000..f6d141a --- /dev/null +++ b/core/java/android/nfc/tech/IsoDep.java @@ -0,0 +1,132 @@ +/* + * 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.tech; + +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; + +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 #get}. + * 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 { + private static final String TAG = "NFC"; + + /** @hide */ + public static final String EXTRA_HI_LAYER_RESP = "hiresp"; + /** @hide */ + public static final String EXTRA_HIST_BYTES = "histbytes"; + + private byte[] mHiLayerResponse = null; + private byte[] mHistBytes = null; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static IsoDep get(Tag tag) { + if (!tag.hasTech(TagTechnology.ISO_DEP)) return null; + try { + return new IsoDep(tag); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public IsoDep(Tag tag) + throws RemoteException { + super(tag, TagTechnology.ISO_DEP); + Bundle extras = tag.getTechExtras(TagTechnology.ISO_DEP); + if (extras != null) { + mHiLayerResponse = extras.getByteArray(EXTRA_HI_LAYER_RESP); + mHistBytes = extras.getByteArray(EXTRA_HIST_BYTES); + } + } + + /** + * Sets the timeout of an IsoDep transceive transaction in milliseconds. + * If the transaction has not completed before the timeout, + * any ongoing {@link #transceive} operation will be + * aborted and the connection to the tag is lost. This setting is applied + * only to the {@link Tag} object linked to this technology and will be + * reset when {@link IsoDep#close} is called. + * The default transaction timeout is 300 milliseconds. + */ + public void setTimeout(int timeout) { + try { + mTag.getTagService().setIsoDepTimeout(timeout); + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + } + } + + @Override + public void close() { + try { + mTag.getTagService().resetIsoDepTimeout(); + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + } + super.close(); + } + + /** + * Return the historical bytes if the tag is using {@link NfcA}, null otherwise. + */ + public byte[] getHistoricalBytes() { + return mHistBytes; + } + + /** + * Return the hi layer response bytes if the tag is using {@link NfcB}, null otherwise. + */ + public byte[] getHiLayerResponse() { + return mHiLayerResponse; + } + + /** + * Send data to a tag and receive the response. + * <p> + * This method will block until the response is received. It can be canceled + * with {@link #close}. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * + * @param data bytes to send + * @return bytes received in response + * @throws IOException if the target is lost or connection closed + */ + public byte[] transceive(byte[] data) throws IOException { + return transceive(data, true); + } +} diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java new file mode 100644 index 0000000..1c52322 --- /dev/null +++ b/core/java/android/nfc/tech/MifareClassic.java @@ -0,0 +1,417 @@ +/* + * 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.tech; + +import android.nfc.Tag; +import android.nfc.TagLostException; +import android.os.RemoteException; + +import java.io.IOException; + +/** + * Technology class representing MIFARE Classic tags (also known as MIFARE Standard). + * + * <p>Support for this technology type is optional. If the NFC stack doesn't support this technology + * MIFARE Classic tags will still be scanned, but will only show the NfcA technology. + * + * <p>MIFARE Classic tags have sectors that each contain blocks. The block size is constant at + * 16 bytes, but the number of sectors and the sector size varies by product. MIFARE has encryption + * built in and each sector has two keys associated with it, as well as ACLs to determine what + * level acess each key grants. Before operating on a sector you must call either + * {@link #authenticateSector(int, byte[], boolean)} or + * {@link #authenticateBlock(int, byte[], boolean)} to gain authorize your request. + */ +public final class MifareClassic extends BasicTagTechnology { + /** + * The well-known default MIFARE read key. All keys are set to this at the factory. + * Using this key will effectively make the payload in the sector public. + */ + public static final byte[] KEY_DEFAULT = + {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; + /** + * The well-known, default MIFARE Application Directory read key. + */ + public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY = + {(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[] KEY_NFC_FORUM = + {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7}; + + /** A MIFARE Classic tag */ + public static final int TYPE_CLASSIC = 0; + /** A MIFARE Plus tag */ + public static final int TYPE_PLUS = 1; + /** A MIFARE Pro tag */ + public static final int TYPE_PRO = 2; + /** The tag type is unknown */ + public static final int TYPE_UNKNOWN = 5; + + /** The tag contains 16 sectors, each holding 4 blocks. */ + public static final int SIZE_1K = 1024; + /** The tag contains 32 sectors, each holding 4 blocks. */ + public static final int SIZE_2K = 2048; + /** + * The tag contains 40 sectors. The first 32 sectors contain 4 blocks and the last 8 sectors + * contain 16 blocks. + */ + public static final int SIZE_4K = 4096; + /** The tag contains 5 sectors, each holding 4 blocks. */ + public static final int SIZE_MINI = 320; + /** The capacity is unknown */ + public static final int SIZE_UNKNOWN = 0; + + private boolean mIsEmulated; + private int mType; + private int mSize; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static MifareClassic get(Tag tag) { + if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null; + try { + return new MifareClassic(tag); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public MifareClassic(Tag tag) throws RemoteException { + super(tag, TagTechnology.MIFARE_CLASSIC); + + // Check if this could actually be a MIFARE Classic + NfcA a = NfcA.get(tag); + + mIsEmulated = false; + mType = TYPE_UNKNOWN; + mSize = SIZE_UNKNOWN; + + switch (a.getSak()) { + 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 + break; + } 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; + } + } + + /** Returns the size of the tag, determined at discovery time */ + public int getSize() { + return mSize; + } + + /** Returns the size of the tag, determined at discovery time */ + public int getType() { + return mType; + } + + /** Returns true if the tag is emulated, determined at discovery time */ + public boolean isEmulated() { + return mIsEmulated; + } + + /** Returns the number of sectors on this tag, determined at discovery time */ + 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; + } + } + } + + /** Returns the sector size, determined at discovery time */ + public int getSectorSize(int sector) { + return getBlockCount(sector) * 16; + } + + /** Returns the total block count, determined at discovery time */ + public int getTotalBlockCount() { + int totalBlocks = 0; + for (int sec = 0; sec < getSectorCount(); sec++) { + totalBlocks += getSectorSize(sec); + } + + return totalBlocks; + } + + /** Returns the block count for the given sector, determined at discovery time */ + 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 the entire sector that the given block resides in. + * <p>This requires a that the tag be connected. + */ + public boolean authenticateBlock(int block, byte[] key, boolean keyA) throws IOException { + checkConnected(); + + 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] = (byte) block; + + // 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, false) != null)) { + return true; + } + } catch (TagLostException e) { + throw e; + } catch (IOException e) { + // No need to deal with, will return false anyway + } + return false; + } + + /** + * Authenticate for a given sector. + * <p>This requires a that the tag be connected. + */ + public boolean authenticateSector(int sector, byte[] key, boolean keyA) throws IOException { + checkConnected(); + + byte addr = (byte) ((firstBlockInSector(sector)) & 0xff); + + // Note that authenticating a block of a sector, will authenticate + // the entire sector. + return authenticateBlock(addr, key, keyA); + } + + /** + * Sector indexing starts at 0. + * Block indexing starts at 0, and resets in each sector. + * <p>This requires a that the tag be connected. + * @throws IOException + */ + public byte[] readBlock(int sector, int block) throws IOException { + checkConnected(); + + byte addr = (byte) ((firstBlockInSector(sector) + block) & 0xff); + return readBlock(addr); + } + + /** + * Reads absolute block index. + * <p>This requires a that the tag be connected. + * @throws IOException + */ + public byte[] readBlock(int block) throws IOException { + checkConnected(); + + byte addr = (byte) block; + byte[] blockread_cmd = { 0x30, addr }; + + return transceive(blockread_cmd, false); + } + + /** + * Writes absolute block index. + * <p>This requires a that the tag be connected. + * @throws IOException + */ + public void writeBlock(int block, byte[] data) throws IOException { + checkConnected(); + + byte addr = (byte) block; + byte[] blockwrite_cmd = new byte[data.length + 2]; + blockwrite_cmd[0] = (byte) 0xA0; // MF write command + blockwrite_cmd[1] = addr; + System.arraycopy(data, 0, blockwrite_cmd, 2, data.length); + + transceive(blockwrite_cmd, false); + } + + /** + * Writes relative block in sector. + * <p>This requires a that the tag be connected. + * @throws IOException + */ + public void writeBlock(int sector, int block, byte[] data) throws IOException { + checkConnected(); + + byte addr = (byte) ((firstBlockInSector(sector) + block) & 0xff); + + writeBlock(addr, data); + } + + public void increment(int block) throws IOException { + checkConnected(); + + byte[] incr_cmd = { (byte) 0xC1, (byte) block }; + + transceive(incr_cmd, false); + } + + public void decrement(int block) throws IOException { + checkConnected(); + + byte[] decr_cmd = { (byte) 0xC0, (byte) block }; + + transceive(decr_cmd, false); + } + + public void transfer(int block) throws IOException { + checkConnected(); + + byte[] trans_cmd = { (byte) 0xB0, (byte) block }; + + transceive(trans_cmd, false); + } + + public void restore(int block) throws IOException { + checkConnected(); + + byte[] rest_cmd = { (byte) 0xC2, (byte) block }; + + transceive(rest_cmd, false); + } + + /** + * Send raw NfcA data to a tag and receive the response. + * <p> + * This method will block until the response is received. It can be canceled + * with {@link #close}. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * <p>This requires a that the tag be connected. + * + * @param data bytes to send + * @return bytes received in response + * @throws IOException if the target is lost or connection closed + */ + public byte[] transceive(byte[] data) throws IOException { + return transceive(data, true); + } +} diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java new file mode 100644 index 0000000..f096298 --- /dev/null +++ b/core/java/android/nfc/tech/MifareUltralight.java @@ -0,0 +1,130 @@ +/* + * 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.tech; + +import android.nfc.Tag; +import android.os.RemoteException; + +import java.io.IOException; + +/** + * Technology class representing MIFARE Ultralight and MIFARE Ultralight C tags. + * + * <p>Support for this technology type is optional. If the NFC stack doesn't support this technology + * MIFARE Ultralight class tags will still be scanned, but will only show the NfcA technology. + * + * <p>MIFARE Ultralight class tags have a series of 4 bytes pages that can be individually written + * and read in chunks of 4 for a total read of 16 bytes. + */ +public final class MifareUltralight extends BasicTagTechnology { + /** A MIFARE Ultralight tag */ + public static final int TYPE_ULTRALIGHT = 1; + /** A MIFARE Ultralight C tag */ + public static final int TYPE_ULTRALIGHT_C = 2; + /** The tag type is unknown */ + public static final int TYPE_UNKNOWN = 10; + + private static final int NXP_MANUFACTURER_ID = 0x04; + + private int mType; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static MifareUltralight get(Tag tag) { + if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null; + try { + return new MifareUltralight(tag); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public MifareUltralight(Tag tag) throws RemoteException { + super(tag, TagTechnology.MIFARE_ULTRALIGHT); + + // Check if this could actually be a Mifare + NfcA a = NfcA.get(tag); + + mType = TYPE_UNKNOWN; + + if (a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID) { + // could be UL or UL-C + mType = TYPE_ULTRALIGHT; + } + } + + /** Returns the type of the tag */ + public int getType() { + return mType; + } + + // Methods that require connect() + /** + * Reads a single 16 byte block from the given page offset. + * + * <p>This requires a that the tag be connected. + * + * @throws IOException + */ + public byte[] readBlock(int page) throws IOException { + checkConnected(); + + byte[] blockread_cmd = { 0x30, (byte) page}; // phHal_eMifareRead + return transceive(blockread_cmd, false); + } + + /** + * Writes a 4 byte page to the tag. + * + * <p>This requires a that the tag be connected. + * + * @param page The offset of the page to write + * @param data The data to write + * @throws IOException + */ + public void writePage(int page, byte[] data) throws IOException { + checkConnected(); + + byte[] pagewrite_cmd = new byte[data.length + 2]; + pagewrite_cmd[0] = (byte) 0xA2; + pagewrite_cmd[1] = (byte) page; + System.arraycopy(data, 0, pagewrite_cmd, 2, data.length); + + transceive(pagewrite_cmd, false); + } + + /** + * Send raw NfcA data to a tag and receive the response. + * <p> + * This method will block until the response is received. It can be canceled + * with {@link #close}. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * <p>This requires a that the tag be connected. + * + * @param data bytes to send + * @return bytes received in response + * @throws IOException if the target is lost or connection closed + */ + public byte[] transceive(byte[] data) throws IOException { + return transceive(data, true); + } +} diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java new file mode 100644 index 0000000..03f2184 --- /dev/null +++ b/core/java/android/nfc/tech/Ndef.java @@ -0,0 +1,264 @@ +/* + * 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.tech; + +import android.nfc.ErrorCodes; +import android.nfc.FormatException; +import android.nfc.INfcTag; +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 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 #get}. + * + * <p class="note"><strong>Note:</strong> + * Use of this class requires the {@link android.Manifest.permission#NFC} + * permission. + */ +public final class Ndef extends BasicTagTechnology { + private static final String TAG = "NFC"; + + /** @hide */ + public static final int NDEF_MODE_READ_ONLY = 1; + /** @hide */ + public static final int NDEF_MODE_READ_WRITE = 2; + /** @hide */ + public static final int NDEF_MODE_UNKNOWN = 3; + + /** @hide */ + public static final String EXTRA_NDEF_MSG = "ndefmsg"; + + /** @hide */ + public static final String EXTRA_NDEF_MAXLENGTH = "ndefmaxlength"; + + /** @hide */ + public static final String EXTRA_NDEF_CARDSTATE = "ndefcardstate"; + + /** @hide */ + public static final String EXTRA_NDEF_TYPE = "ndeftype"; + + public static final int OTHER = -1; + public static final int NFC_FORUM_TYPE_1 = 1; + public static final int NFC_FORUM_TYPE_2 = 2; + public static final int NFC_FORUM_TYPE_3 = 3; + public static final int NFC_FORUM_TYPE_4 = 4; + public static final int MIFARE_CLASSIC = 101; + + private final int mMaxNdefSize; + private final int mCardState; + private final NdefMessage mNdefMsg; + private final int mNdefType; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static Ndef get(Tag tag) { + if (!tag.hasTech(TagTechnology.NDEF)) return null; + try { + return new Ndef(tag); + } catch (RemoteException e) { + return null; + } + } + + /** + * Internal constructor, to be used by NfcAdapter + * @hide + */ + public Ndef(Tag tag) throws RemoteException { + super(tag, TagTechnology.NDEF); + Bundle extras = tag.getTechExtras(TagTechnology.NDEF); + if (extras != null) { + mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH); + mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE); + mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG); + mNdefType = extras.getInt(EXTRA_NDEF_TYPE); + } else { + throw new NullPointerException("NDEF tech extras are null."); + } + + } + + /** + * Get the primary NDEF message on this tag. This data is read at discovery time + * and does not require a connection. + */ + public NdefMessage getCachedNdefMessage() { + return mNdefMsg; + } + + /** + * Get NDEF tag type. + * <p>Returns one of {@link #NFC_FORUM_TYPE_1}, {@link #NFC_FORUM_TYPE_2}, + * {@link #NFC_FORUM_TYPE_3}, {@link #NFC_FORUM_TYPE_4}, + * {@link #MIFARE_CLASSIC} or {@link #OTHER}. + * <p>Platforms of this API revision will always return one of the above + * values. Platforms at future API revisions may return other values, which + * can be treated as {@link #OTHER} by applications targeting this API. + * <p>Android devices with NFC support must always correctly enumerate + * NFC Forum tag types, and may optionally enumerate + * {@link #MIFARE_CLASSIC} since it requires proprietary technology. + * Devices that cannot enumerate {@link #MIFARE_CLASSIC} will use + * {@link #OTHER} instead. + */ + public int getType() { + return mNdefType; + } + + /** + * Get maximum NDEF message size in bytes + */ + public int getMaxSize() { + return mMaxNdefSize; + } + + /** + * Provides a hint on whether writes are likely to succeed. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * @return true if write is likely to succeed + */ + public boolean isWritable() { + return (mCardState == NDEF_MODE_READ_WRITE); + } + + // Methods that require connect() + /** + * Get the primary NDEF message on this tag. This data is read actively + * and requires a connection. + */ + public NdefMessage getNdefMessage() throws IOException, FormatException { + checkConnected(); + + try { + INfcTag tagService = mTag.getTagService(); + int serviceHandle = mTag.getServiceHandle(); + if (tagService.isNdef(serviceHandle)) { + NdefMessage msg = tagService.ndefRead(serviceHandle); + if (msg == null) { + int errorCode = tagService.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(); + } + } + return msg; + } else { + return null; + } + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + return null; + } + } + + /** + * Overwrite the primary NDEF message + * @throws IOException + */ + public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException { + checkConnected(); + + try { + INfcTag tagService = mTag.getTagService(); + int serviceHandle = mTag.getServiceHandle(); + if (tagService.isNdef(serviceHandle)) { + int errorCode = tagService.ndefWrite(serviceHandle, msg); + switch (errorCode) { + case ErrorCodes.SUCCESS: + break; + case ErrorCodes.ERROR_IO: + throw new IOException(); + case ErrorCodes.ERROR_INVALID_PARAM: + throw new FormatException(); + default: + // Should not happen + throw new IOException(); + } + } + else { + throw new IOException("Tag is not ndef"); + } + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + } + } + + /** + * Indicates whether a tag can be made read-only with + * {@link #makeReadonly()} + */ + public boolean canMakeReadonly() { + if (mNdefType == NFC_FORUM_TYPE_1 || mNdefType == NFC_FORUM_TYPE_2) { + return true; + } else { + return false; + } + } + + /** + * Sets the CC field to indicate this tag is read-only + * and permanently sets the lock bits to prevent any further NDEF + * modifications. + * This is a one-way process and can not be reverted! + * @throws IOException + */ + public boolean makeReadonly() throws IOException { + checkConnected(); + + try { + INfcTag tagService = mTag.getTagService(); + if (tagService.isNdef(mTag.getServiceHandle())) { + int errorCode = tagService.ndefMakeReadOnly(mTag.getServiceHandle()); + switch (errorCode) { + case ErrorCodes.SUCCESS: + return true; + case ErrorCodes.ERROR_IO: + throw new IOException(); + case ErrorCodes.ERROR_INVALID_PARAM: + return false; + default: + // Should not happen + throw new IOException(); + } + } + else { + throw new IOException("Tag is not ndef"); + } + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + return false; + } + } +} diff --git a/core/java/android/nfc/tech/NdefFormatable.java b/core/java/android/nfc/tech/NdefFormatable.java new file mode 100644 index 0000000..2919c43 --- /dev/null +++ b/core/java/android/nfc/tech/NdefFormatable.java @@ -0,0 +1,108 @@ +/* + * 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.tech; + +import android.nfc.ErrorCodes; +import android.nfc.FormatException; +import android.nfc.INfcTag; +import android.nfc.NdefMessage; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.RemoteException; +import android.util.Log; + +import java.io.IOException; + +/** + * An interface to a {@link Tag} allowing to format the tag as NDEF. + * + * <p>You can acquire this kind of connection with {@link #get}. + * + * <p class="note"><strong>Note:</strong> + * Use of this class requires the {@link android.Manifest.permission#NFC} + * permission. + */ +public final class NdefFormatable extends BasicTagTechnology { + private static final String TAG = "NFC"; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static NdefFormatable get(Tag tag) { + if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null; + try { + return new NdefFormatable(tag); + } catch (RemoteException e) { + return null; + } + } + + /** + * Internal constructor, to be used by NfcAdapter + * @hide + */ + public NdefFormatable(Tag tag) throws RemoteException { + super(tag, TagTechnology.NDEF_FORMATABLE); + } + + /** + * Formats a tag as NDEF, if possible. You may supply a first + * NdefMessage to be written on the tag. + */ + public void format(NdefMessage firstMessage) throws IOException, FormatException { + checkConnected(); + + try { + int serviceHandle = mTag.getServiceHandle(); + INfcTag tagService = mTag.getTagService(); + int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT); + switch (errorCode) { + case ErrorCodes.SUCCESS: + break; + case ErrorCodes.ERROR_IO: + throw new IOException(); + case ErrorCodes.ERROR_INVALID_PARAM: + throw new FormatException(); + default: + // Should not happen + throw new IOException(); + } + // Now check and see if the format worked + if (tagService.isNdef(serviceHandle)) { + errorCode = tagService.ndefWrite(serviceHandle, firstMessage); + switch (errorCode) { + case ErrorCodes.SUCCESS: + break; + case ErrorCodes.ERROR_IO: + throw new IOException(); + case ErrorCodes.ERROR_INVALID_PARAM: + throw new FormatException(); + default: + // Should not happen + throw new IOException(); + } + } else { + throw new IOException(); + } + } catch (RemoteException e) { + Log.e(TAG, "NFC service dead", e); + } + } +} diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java new file mode 100644 index 0000000..24badc4 --- /dev/null +++ b/core/java/android/nfc/tech/NfcA.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc.tech; + +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 NFC-A technology, also known as + * ISO1443-3A. + * + * <p>You can acquire this kind of connection with {@link #get}. + * 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; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static NfcA get(Tag tag) { + if (!tag.hasTech(TagTechnology.NFC_A)) return null; + try { + return new NfcA(tag); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public NfcA(Tag tag) throws RemoteException { + super(tag, TagTechnology.NFC_A); + Bundle extras = tag.getTechExtras(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; + } + + /** + * Send data to a tag and receive the response. + * <p> + * This method will block until the response is received. It can be canceled + * with {@link #close}. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * + * @param data bytes to send + * @return bytes received in response + * @throws IOException if the target is lost or connection closed + */ + public byte[] transceive(byte[] data) throws IOException { + return transceive(data, true); + } +} diff --git a/core/java/android/nfc/tech/NfcB.java b/core/java/android/nfc/tech/NfcB.java new file mode 100644 index 0000000..abeef32 --- /dev/null +++ b/core/java/android/nfc/tech/NfcB.java @@ -0,0 +1,101 @@ +/* + * 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.tech; + +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 NFC-B technology, also known as + * ISO1443-3B. + * + * <p>You can acquire this kind of connection with {@link #get}. + * 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_APPDATA = "appdata"; + /** @hide */ + public static final String EXTRA_PROTINFO = "protinfo"; + + private byte[] mAppData; + private byte[] mProtInfo; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static NfcB get(Tag tag) { + if (!tag.hasTech(TagTechnology.NFC_B)) return null; + try { + return new NfcB(tag); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public NfcB(Tag tag) throws RemoteException { + super(tag, TagTechnology.NFC_B); + Bundle extras = tag.getTechExtras(TagTechnology.NFC_B); + mAppData = extras.getByteArray(EXTRA_APPDATA); + mProtInfo = extras.getByteArray(EXTRA_PROTINFO); + } + + /** + * Returns the Application Data bytes from the ATQB/SENSB_RES + * bytes discovered at tag discovery. + */ + public byte[] getApplicationData() { + return mAppData; + } + + /** + * Returns the Protocol Info bytes from the ATQB/SENSB_RES + * bytes discovered at tag discovery. + */ + public byte[] getProtocolInfo() { + return mProtInfo; + } + + /** + * Send data to a tag and receive the response. + * <p> + * This method will block until the response is received. It can be canceled + * with {@link #close}. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * + * @param data bytes to send + * @return bytes received in response + * @throws IOException if the target is lost or connection closed + */ + public byte[] transceive(byte[] data) throws IOException { + return transceive(data, true); + } +} diff --git a/core/java/android/nfc/tech/NfcF.java b/core/java/android/nfc/tech/NfcF.java new file mode 100644 index 0000000..f617739 --- /dev/null +++ b/core/java/android/nfc/tech/NfcF.java @@ -0,0 +1,95 @@ +/* + * 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.tech; + +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 NFC-F technology, also known as + * JIS6319-4. + * + * <p>You can acquire this kind of connection with {@link #get}. + * 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; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static NfcF get(Tag tag) { + if (!tag.hasTech(TagTechnology.NFC_F)) return null; + try { + return new NfcF(tag); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public NfcF(Tag tag) throws RemoteException { + super(tag, TagTechnology.NFC_F); + Bundle extras = tag.getTechExtras(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; + } + + /** + * Send data to a tag and receive the response. + * <p> + * This method will block until the response is received. It can be canceled + * with {@link #close}. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * + * @param data bytes to send + * @return bytes received in response + * @throws IOException if the target is lost or connection closed + */ + public byte[] transceive(byte[] data) throws IOException { + return transceive(data, true); + } +} diff --git a/core/java/android/nfc/tech/NfcV.java b/core/java/android/nfc/tech/NfcV.java new file mode 100644 index 0000000..8e1f066 --- /dev/null +++ b/core/java/android/nfc/tech/NfcV.java @@ -0,0 +1,94 @@ +/* + * 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.tech; + +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 NFC vicinity technology, also known as + * ISO15693. + * + * <p>You can acquire this kind of connection with {@link #get}. + * 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 { + /** @hide */ + public static final String EXTRA_RESP_FLAGS = "respflags"; + + /** @hide */ + public static final String EXTRA_DSFID = "dsfid"; + + private byte mRespFlags; + private byte mDsfId; + + /** + * Returns an instance of this tech for the given tag. If the tag doesn't support + * this tech type null is returned. + * + * @param tag The tag to get the tech from + */ + public static NfcV get(Tag tag) { + if (!tag.hasTech(TagTechnology.NFC_V)) return null; + try { + return new NfcV(tag); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public NfcV(Tag tag) throws RemoteException { + super(tag, TagTechnology.NFC_V); + Bundle extras = tag.getTechExtras(TagTechnology.NFC_V); + mRespFlags = extras.getByte(EXTRA_RESP_FLAGS); + mDsfId = extras.getByte(EXTRA_DSFID); + } + + public byte getResponseFlags() { + return mRespFlags; + } + + public byte getDsfId() { + return mDsfId; + } + + /** + * Send data to a tag and receive the response. + * <p> + * This method will block until the response is received. It can be canceled + * with {@link #close}. + * <p>Requires {@link android.Manifest.permission#NFC} permission. + * + * @param data bytes to send + * @return bytes received in response + * @throws IOException if the target is lost or connection closed + */ + public byte[] transceive(byte[] data) throws IOException { + return transceive(data, true); + } +} diff --git a/core/java/android/nfc/tech/TagTechnology.java b/core/java/android/nfc/tech/TagTechnology.java new file mode 100644 index 0000000..1331bae --- /dev/null +++ b/core/java/android/nfc/tech/TagTechnology.java @@ -0,0 +1,145 @@ +/* + * 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.tech; + +import android.nfc.Tag; + +import java.io.IOException; + +public interface TagTechnology { + /** + * This technology is an instance of {@link NfcA}. + * <p>Support for this technology type is mandatory. + * @hide + */ + public static final int NFC_A = 1; + + /** + * This technology is an instance of {@link NfcB}. + * <p>Support for this technology type is mandatory. + * @hide + */ + public static final int NFC_B = 2; + + /** + * This technology is an instance of {@link IsoDep}. + * <p>Support for this technology type is mandatory. + * @hide + */ + public static final int ISO_DEP = 3; + + /** + * This technology is an instance of {@link NfcF}. + * <p>Support for this technology type is mandatory. + * @hide + */ + public static final int NFC_F = 4; + + /** + * This technology is an instance of {@link NfcV}. + * <p>Support for this technology type is mandatory. + * @hide + */ + public static final int NFC_V = 5; + + /** + * This technology is an instance of {@link Ndef}. + * <p>Support for this technology type is mandatory. + * @hide + */ + public static final int NDEF = 6; + + /** + * This technology is an instance of {@link NdefFormatable}. + * <p>Support for this technology type is mandatory. + * @hide + */ + public static final int NDEF_FORMATABLE = 7; + + /** + * This technology is an instance of {@link MifareClassic}. + * <p>Support for this technology type is optional. If a stack doesn't support this technology + * type tags using it must still be discovered and present the lower level radio interface + * technologies in use. + * @hide + */ + public static final int MIFARE_CLASSIC = 8; + + /** + * This technology is an instance of {@link MifareUltralight}. + * <p>Support for this technology type is optional. If a stack doesn't support this technology + * type tags using it must still be discovered and present the lower level radio interface + * technologies in use. + * @hide + */ + public static final int MIFARE_ULTRALIGHT = 9; + + /** + * Returns the technology type for this tag connection. + * @hide + */ + public int getTechnologyId(); + + /** + * Get the {@link Tag} object this technology came from. + */ + public Tag getTag(); + + /** + * Opens a connection to the {@link Tag} enabling interactive commands. The command set + * varies by the technology type. + * + * <p>This method blocks until the connection has been established. + * + * <p>A call to {@link #close} from another thread will cancel a blocked call and cause an + * IOException to be thrown on the thread that is blocked. + * + * @see #reconnect() + * @see #close() + * @throws IOException if the target is lost, or connect canceled + */ + public void connect() throws IOException; + + /** + * Re-connect to the {@link Tag} associated with this connection. Reconnecting to a tag can be + * used to reset the state of the tag itself. + * + * <p>This method blocks until the connection is re-established. + * + * <p>A call to {@link #close} from another thread will cancel a blocked call and cause an + * IOException to be thrown on the thread that is blocked. + * + * @see #connect() + * @see #close() + * @throws IOException + */ + public void reconnect() throws IOException; + + /** + * Closes the connection to the {@link Tag}. This call is non-blocking and causes all blocking + * operations such as {@link #connect} to be canceled and immediately throw + * {@link java.io.IOException} on the thread that is blocked. + * + * <p> + * Once this method is called, this object cannot be re-used and should be discarded. Further + * calls to {@link #connect} will fail. + * + * @see #connect() + * @see #reconnect() + */ + public void close(); +} |