Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eab0e97b authored by Nick Pelly's avatar Nick Pelly Committed by Android (Google) Code Review
Browse files

Merge "Clean up MifareUltralight API." into gingerbread

parents 89a54408 4a5e2532
Loading
Loading
Loading
Loading
+21 −10
Original line number Diff line number Diff line
@@ -101577,33 +101577,33 @@
 visibility="public"
>
</field>
<field name="TYPE_OTHER"
<field name="TYPE_PLUS"
 type="int"
 transient="false"
 volatile="false"
 value="-1"
 value="1"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="TYPE_PLUS"
<field name="TYPE_PRO"
 type="int"
 transient="false"
 volatile="false"
 value="1"
 value="2"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="TYPE_PRO"
<field name="TYPE_UNKNOWN"
 type="int"
 transient="false"
 volatile="false"
 value="2"
 value="-1"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -101643,7 +101643,7 @@
 visibility="public"
>
</method>
<method name="readBlock"
<method name="readPages"
 return="byte[]"
 abstract="false"
 native="false"
@@ -101653,7 +101653,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="page" type="int">
<parameter name="pageOffset" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -101683,13 +101683,24 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="page" type="int">
<parameter name="pageOffset" type="int">
</parameter>
<parameter name="data" type="byte[]">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<field name="PAGE_SIZE"
 type="int"
 transient="false"
 volatile="false"
 value="4"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="TYPE_ULTRALIGHT"
 type="int"
 transient="false"
@@ -101716,7 +101727,7 @@
 type="int"
 transient="false"
 volatile="false"
 value="10"
 value="-1"
 static="true"
 final="true"
 deprecated="not deprecated"
+10 −10
Original line number Diff line number Diff line
@@ -55,14 +55,14 @@ public final class MifareClassic extends BasicTagTechnology {
    public static final byte[] KEY_NFC_FORUM =
            {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7};

    /** A Mifare Classic compatible card of unknown type */
    public static final int TYPE_UNKNOWN = -1;
    /** 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;
    /** A Mifare Classic compatible card that does not match the other types */
    public static final int TYPE_OTHER = -1;

    /** The tag contains 16 sectors, each holding 4 blocks. */
    public static final int SIZE_1K = 1024;
@@ -360,12 +360,6 @@ public final class MifareClassic extends BasicTagTechnology {
        transceive(cmd.array(), false);
    }

    private void validateValueOperand(int value) {
        if (value < 0) {
            throw new IllegalArgumentException("value operand negative");
        }
    }

    /**
     * Copy from temporary memory to value block.
     * @param blockIndex
@@ -410,7 +404,7 @@ public final class MifareClassic extends BasicTagTechnology {
        return transceive(data, true);
    }

    private void validateSector(int sector) {
    private static void validateSector(int sector) {
        // Do not be too strict on upper bounds checking, since some cards
        // have more addressable memory than they report. For example,
        // Mifare Plus 2k cards will appear as Mifare Classic 1k cards when in
@@ -423,10 +417,16 @@ public final class MifareClassic extends BasicTagTechnology {
        }
    }

    private void validateBlock(int block) {
    private static void validateBlock(int block) {
        // Just looking for obvious out of bounds...
        if (block < 0 || block >= MAX_BLOCK_COUNT) {
            throw new IndexOutOfBoundsException("block out of bounds: " + block);
        }
    }

    private static void validateValueOperand(int value) {
        if (value < 0) {
            throw new IllegalArgumentException("value operand negative");
        }
    }
}
+64 −20
Original line number Diff line number Diff line
@@ -21,24 +21,43 @@ import android.os.RemoteException;

import java.io.IOException;

//TOOD: Ultralight C 3-DES authentication, one-way counter

/**
 * 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.
 * <p>MIFARE Ultralight compatible tags have 4 byte pages. The read command
 * returns 4 pages (16 bytes) at a time, for speed. The write command operates
 * on a single page (4 bytes) to minimize EEPROM write cycles.
 *
 * <p>The original MIFARE Ultralight consists of a 64 byte EEPROM. The first
 * 4 pages are for the OTP area, manufacturer data, and locking bits. They are
 * readable and some bits are writable. The final 12 pages are the user
 * read/write area. For more information see the NXP data sheet MF0ICU1.
 *
 * <p>The MIFARE Ultralight C consists of a 192 byte EEPROM. The first 4 pages
 * are for OTP, manufacturer data, and locking bits. The next 36 pages are the
 * user read/write area. The next 4 pages are additional locking bits, counters
 * and authentication configuration and are readable. The final 4 pages are for
 * the authentication key and are not readable. For more information see the
 * NXP data sheet MF0ICU2.
 */
public final class MifareUltralight extends BasicTagTechnology {
    /** A MIFARE Ultralight compatible tag of unknown type */
    public static final int TYPE_UNKNOWN = -1;
    /** 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;

    /** Size of a MIFARE Ultralight page in bytes */
    public static final int PAGE_SIZE = 4;

    private static final int NXP_MANUFACTURER_ID = 0x04;
    private static final int MAX_PAGE_COUNT = 256;

    private int mType;

@@ -68,48 +87,62 @@ public final class MifareUltralight extends BasicTagTechnology {

        if (a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID) {
            // could be UL or UL-C
            //TODO: stack should use NXP AN1303 procedure to make a best guess
            // attempt at classifying Ultralight vs Ultralight C.
            mType = TYPE_ULTRALIGHT;
        }
    }

    /** Returns the type of the tag */
    /** Returns the type of the tag.
     * <p>It is very hard to always accurately classify a MIFARE Ultralight
     * compatible tag as Ultralight original or Ultralight C. So consider
     * {@link #getType} a hint. */
    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.
     * Read 4 pages (16 bytes).
     * <p>The MIFARE Ultralight protocol always reads 4 pages at a time.
     * <p>If the read spans past the last readable block, then the tag will
     * return pages that have been wrapped back to the first blocks. MIFARE
     * Ultralight tags have readable blocks 0x00 through 0x0F. So a read to
     * block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE
     * Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to
     * block 0x2A would return blocks 0x2A, 0x2B, 0x00, 0x01.
     * <p>This requires that the tag be connected.
     *
     * @return 4 pages (16 bytes)
     * @throws IOException
     */
    public byte[] readBlock(int page) throws IOException {
    public byte[] readPages(int pageOffset) throws IOException {
        validatePageOffset(pageOffset);
        checkConnected();

        byte[] blockread_cmd = { 0x30, (byte) page}; // phHal_eMifareRead
        return transceive(blockread_cmd, false);
        byte[] cmd = { 0x30, (byte) pageOffset};
        return transceive(cmd, false);
    }

    /**
     * Writes a 4 byte page to the tag.
     *
     * <p>This requires a that the tag be connected.
     * Write 1 page (4 bytes).
     * <p>The MIFARE Ultralight protocol always writes 1 page at a time.
     * <p>This requires 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 {
    public void writePage(int pageOffset, byte[] data) throws IOException {
        validatePageOffset(pageOffset);
        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);
        byte[] cmd = new byte[data.length + 2];
        cmd[0] = (byte) 0xA2;
        cmd[1] = (byte) pageOffset;
        System.arraycopy(data, 0, cmd, 2, data.length);

        transceive(pagewrite_cmd, false);
        transceive(cmd, false);
    }

    /**
@@ -127,4 +160,15 @@ public final class MifareUltralight extends BasicTagTechnology {
    public byte[] transceive(byte[] data) throws IOException {
        return transceive(data, true);
    }

    private static void validatePageOffset(int pageOffset) {
        // Do not be too strict on upper bounds checking, since some cards
        // may have more addressable memory than they report.
        // Note that issuing a command to an out-of-bounds block is safe - the
        // tag will wrap the read to an addressable area. This validation is a
        // helper to guard against obvious programming mistakes.
        if (pageOffset < 0 || pageOffset >= MAX_PAGE_COUNT) {
            throw new IndexOutOfBoundsException("page out of bounds: " + pageOffset);
        }
    }
}