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