12fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands/* 22fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * Copyright (C) 2010 The Android Open Source Project 32fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * 42fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * Licensed under the Apache License, Version 2.0 (the "License"); 52fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * you may not use this file except in compliance with the License. 62fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * You may obtain a copy of the License at 72fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * 82fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * http://www.apache.org/licenses/LICENSE-2.0 92fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * 102fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * Unless required by applicable law or agreed to in writing, software 112fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * distributed under the License is distributed on an "AS IS" BASIS, 122fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * See the License for the specific language governing permissions and 142fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * limitations under the License. 152fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands */ 162fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 174e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamiltonpackage android.nfc.tech; 182fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 19112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenenimport android.nfc.ErrorCodes; 202fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brandsimport android.nfc.Tag; 2174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pellyimport android.nfc.TagLostException; 22fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenenimport android.os.Bundle; 232fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brandsimport android.os.RemoteException; 24112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenenimport android.util.Log; 252fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 26ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamiltonimport java.io.IOException; 27ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton 284a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly//TOOD: Ultralight C 3-DES authentication, one-way counter 294a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly 302fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands/** 3174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Provides access to MIFARE Ultralight properties and I/O operations on a {@link Tag}. 322fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * 3374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Acquire a {@link MifareUltralight} object using {@link #get}. 342fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands * 3574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>MIFARE Ultralight compatible tags have 4 byte pages {@link #PAGE_SIZE}. 3674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * The primary operations on an Ultralight tag are {@link #readPages} and 3774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link #writePage}. 384a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * 394a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * <p>The original MIFARE Ultralight consists of a 64 byte EEPROM. The first 404a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * 4 pages are for the OTP area, manufacturer data, and locking bits. They are 414a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * readable and some bits are writable. The final 12 pages are the user 424a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * read/write area. For more information see the NXP data sheet MF0ICU1. 434a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * 444a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * <p>The MIFARE Ultralight C consists of a 192 byte EEPROM. The first 4 pages 454a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * are for OTP, manufacturer data, and locking bits. The next 36 pages are the 464a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * user read/write area. The next 4 pages are additional locking bits, counters 474a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * and authentication configuration and are readable. The final 4 pages are for 484a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * the authentication key and are not readable. For more information see the 494a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * NXP data sheet MF0ICU2. 5074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 5174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Implementation of this class on a Android NFC device is optional. 5274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * If it is not implemented, then 5374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link MifareUltralight} will never be enumerated in {@link Tag#getTechList}. 5474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * If it is enumerated, then all {@link MifareUltralight} I/O operations will be supported. 5574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * In either case, {@link NfcA} will also be enumerated on the tag, 5674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * because all MIFARE Ultralight tags are also {@link NfcA} tags. 5739cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 5839cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note"><strong>Note:</strong> Methods that perform I/O operations 5939cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * require the {@link android.Manifest.permission#NFC} permission. 602fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands */ 612fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brandspublic final class MifareUltralight extends BasicTagTechnology { 62112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen private static final String TAG = "NFC"; 63112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen 644a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly /** A MIFARE Ultralight compatible tag of unknown type */ 654a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly public static final int TYPE_UNKNOWN = -1; 66ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton /** A MIFARE Ultralight tag */ 672fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands public static final int TYPE_ULTRALIGHT = 1; 68ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton /** A MIFARE Ultralight C tag */ 692fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands public static final int TYPE_ULTRALIGHT_C = 2; 704a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly 714a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly /** Size of a MIFARE Ultralight page in bytes */ 724a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly public static final int PAGE_SIZE = 4; 732fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 7450b4d8f643f31b37e9872f562fb869059cf79c8aNick Pelly private static final int NXP_MANUFACTURER_ID = 0x04; 754a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly private static final int MAX_PAGE_COUNT = 256; 762fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 77fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen /** @hide */ 78fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen public static final String EXTRA_IS_UL_C = "isulc"; 79fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen 802fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands private int mType; 812fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 824e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton /** 8374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Get an instance of {@link MifareUltralight} for the given tag. 8474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Returns null if {@link MifareUltralight} was not enumerated in 8574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link Tag#getTechList} - this indicates the tag is not MIFARE 8674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Ultralight compatible, or that this Android 8774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * device does not implement MIFARE Ultralight. 8874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Does not cause any RF activity and does not block. 894e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton * 9074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @param tag an MIFARE Ultralight compatible tag 9174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @return MIFARE Ultralight object 924e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton */ 934e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton public static MifareUltralight get(Tag tag) { 944e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null; 954e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton try { 964e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton return new MifareUltralight(tag); 974e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } catch (RemoteException e) { 984e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton return null; 994e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } 1004e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } 1014e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton 102ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton /** @hide */ 1034e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton public MifareUltralight(Tag tag) throws RemoteException { 1044e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton super(tag, TagTechnology.MIFARE_ULTRALIGHT); 1052fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 106734e9b0c73483fdaa582c21dedc24107b1fe8838Jeff Hamilton // Check if this could actually be a MIFARE 1074e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton NfcA a = NfcA.get(tag); 1082fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 1092fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands mType = TYPE_UNKNOWN; 1102fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 1114e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton if (a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID) { 112fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen Bundle extras = tag.getTechExtras(TagTechnology.MIFARE_ULTRALIGHT); 113fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen if (extras.getBoolean(EXTRA_IS_UL_C)) { 114fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen mType = TYPE_ULTRALIGHT_C; 115fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen } else { 116fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen mType = TYPE_ULTRALIGHT; 117fe6dfd504bfa31d95382d80cc7acc5b1add01b34Martijn Coenen } 1182fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands } 1192fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands } 1202fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 12174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly /** 12274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Return the MIFARE Ultralight type of the tag. 12374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>One of {@link #TYPE_ULTRALIGHT} or {@link #TYPE_ULTRALIGHT_C} or 12474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link #TYPE_UNKNOWN}. 12574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Depending on how the tag has been formatted, it can be impossible 12674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * to accurately classify between original MIFARE Ultralight and 12774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Ultralight C. So treat this method as a hint. 12874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Does not cause any RF activity and does not block. 12974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 13074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @return the type 13174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly */ 1322fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands public int getType() { 1332fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands return mType; 1342fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands } 1352fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 1362fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands /** 1374a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * Read 4 pages (16 bytes). 13874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 13974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>The MIFARE Ultralight protocol always reads 4 pages at a time, to 14074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * reduce the number of commands required to read an entire tag. 14174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>If a read spans past the last readable block, then the tag will 1424a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * return pages that have been wrapped back to the first blocks. MIFARE 1434a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * Ultralight tags have readable blocks 0x00 through 0x0F. So a read to 1444a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE 1454a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to 1464a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * block 0x2A would return blocks 0x2A, 0x2B, 0x00, 0x01. 147ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton * 14874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is an I/O operation and will block until complete. It must 14974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * not be called from the main application thread. A blocked call will be canceled with 15074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link IOException} if {@link #close} is called from another thread. 15174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 15239cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 15339cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 15446797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly * @param pageOffset index of first page to read, starting from 0 1554a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * @return 4 pages (16 bytes) 15674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws TagLostException if the tag leaves the field 15774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws IOException if there is an I/O failure, or the operation is canceled 1582fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands */ 15946797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly public byte[] readPages(int pageOffset) throws IOException { 16046797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly validatePageIndex(pageOffset); 1614049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen checkConnected(); 1624049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen 16346797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly byte[] cmd = { 0x30, (byte) pageOffset}; 1644a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly return transceive(cmd, false); 1652fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands } 1662fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands 1672fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands /** 1684a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly * Write 1 page (4 bytes). 169ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton * 17074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>The MIFARE Ultralight protocol always writes 1 page at a time, to 17174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * minimize EEPROM write cycles. 17274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 17374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is an I/O operation and will block until complete. It must 17474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * not be called from the main application thread. A blocked call will be canceled with 17574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link IOException} if {@link #close} is called from another thread. 17674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 17739cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 17839cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 17946797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly * @param pageOffset index of page to write, starting from 0 18074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @param data 4 bytes to write 18174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws TagLostException if the tag leaves the field 18274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws IOException if there is an I/O failure, or the operation is canceled 183c58c3f1ae27c0c7f560bd381180397d7f6a2ebedMartijn Coenen */ 18446797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly public void writePage(int pageOffset, byte[] data) throws IOException { 18546797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly validatePageIndex(pageOffset); 186c58c3f1ae27c0c7f560bd381180397d7f6a2ebedMartijn Coenen checkConnected(); 187c58c3f1ae27c0c7f560bd381180397d7f6a2ebedMartijn Coenen 1884a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly byte[] cmd = new byte[data.length + 2]; 1894a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly cmd[0] = (byte) 0xA2; 19046797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly cmd[1] = (byte) pageOffset; 1914a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly System.arraycopy(data, 0, cmd, 2, data.length); 192c58c3f1ae27c0c7f560bd381180397d7f6a2ebedMartijn Coenen 1934a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly transceive(cmd, false); 194c58c3f1ae27c0c7f560bd381180397d7f6a2ebedMartijn Coenen } 195c58c3f1ae27c0c7f560bd381180397d7f6a2ebedMartijn Coenen 196ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton /** 197ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton * Send raw NfcA data to a tag and receive the response. 198ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton * 19974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is equivalent to connecting to this tag via {@link NfcA} 20074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * and calling {@link NfcA#transceive}. Note that all MIFARE Classic 20174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * tags are based on {@link NfcA} technology. 20274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 203faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes 204faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen * that can be sent with {@link #transceive}. 205faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen * 20674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is an I/O operation and will block until complete. It must 20774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * not be called from the main application thread. A blocked call will be canceled with 20874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link IOException} if {@link #close} is called from another thread. 20974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 21039cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 21139cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 21274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @see NfcA#transceive 213ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton */ 214ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton public byte[] transceive(byte[] data) throws IOException { 215ce3224cda51f946871daa1e11e3976e25c59e6faJeff Hamilton return transceive(data, true); 216c58c3f1ae27c0c7f560bd381180397d7f6a2ebedMartijn Coenen } 2174a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly 218112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen /** 219faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen * Return the maximum number of bytes that can be sent with {@link #transceive}. 220faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen * @return the maximum number of bytes that can be sent with {@link #transceive}. 221faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen */ 222faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen public int getMaxTransceiveLength() { 223faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen return getMaxTransceiveLengthInternal(); 224faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen } 225faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen 226faca12adc62d148505fadfd286e6a2752c197fa0Martijn Coenen /** 22782328bfd40008d85917cc01a1b2eb8eed1f23ec4Nick Pelly * Set the {@link #transceive} timeout in milliseconds. 22882328bfd40008d85917cc01a1b2eb8eed1f23ec4Nick Pelly * 22982328bfd40008d85917cc01a1b2eb8eed1f23ec4Nick Pelly * <p>The timeout only applies to {@link #transceive} on this object, 230112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * and is reset to a default value when {@link #close} is called. 23182328bfd40008d85917cc01a1b2eb8eed1f23ec4Nick Pelly * 232112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * <p>Setting a longer timeout may be useful when performing 233112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * transactions that require a long processing time on the tag 234112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * such as key generation. 235112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * 236112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 237112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * 238112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen * @param timeout timeout value in milliseconds 239112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen */ 240112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen public void setTimeout(int timeout) { 241112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen try { 242112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen int err = mTag.getTagService().setTimeout( 243112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen TagTechnology.MIFARE_ULTRALIGHT, timeout); 244112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen if (err != ErrorCodes.SUCCESS) { 245112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen throw new IllegalArgumentException("The supplied timeout is not valid"); 246112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen } 247112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen } catch (RemoteException e) { 248112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen Log.e(TAG, "NFC service dead", e); 249112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen } 250112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen } 251112fdf612db71a552fce063136bf2796df3b71ecMartijn Coenen 25220e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen /** 25382328bfd40008d85917cc01a1b2eb8eed1f23ec4Nick Pelly * Get the current {@link #transceive} timeout in milliseconds. 25420e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen * 25520e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 25620e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen * 25720e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen * @return timeout value in milliseconds 25820e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen */ 25920e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen public int getTimeout() { 26020e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen try { 26120e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen return mTag.getTagService().getTimeout(TagTechnology.MIFARE_ULTRALIGHT); 26220e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen } catch (RemoteException e) { 26320e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen Log.e(TAG, "NFC service dead", e); 26420e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen return 0; 26520e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen } 26620e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen } 26720e62c9f1466ace5771e244f03a995dc0939b11bMartijn Coenen 26874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly private static void validatePageIndex(int pageIndex) { 2694a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly // Do not be too strict on upper bounds checking, since some cards 2704a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly // may have more addressable memory than they report. 2714a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly // Note that issuing a command to an out-of-bounds block is safe - the 2724a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly // tag will wrap the read to an addressable area. This validation is a 2734a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly // helper to guard against obvious programming mistakes. 27474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly if (pageIndex < 0 || pageIndex >= MAX_PAGE_COUNT) { 27574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly throw new IndexOutOfBoundsException("page out of bounds: " + pageIndex); 2764a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly } 2774a5e2532205252e0b8616ebc07ca089fd3721681Nick Pelly } 2782fe24e3e14cce791e89c93ddc23e28af5c2c90ccJan Brands} 279