[go: nahoru, domu]

blob: 4aef8b2352bbf6c9687e58ee5b56741655fac666 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.device.nfc;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.nfc.tech.TagTechnology;
import java.io.IOException;
/**
* Utility class that provides I/O operations for NFC tags.
*/
public class NfcTagHandler {
private final TagTechnology mTech;
private final TagTechnologyHandler mTechHandler;
private boolean mWasConnected;
private final String mSerialNumber;
/**
* Factory method that creates NfcTagHandler for a given NFC Tag.
*
* @param tag @see android.nfc.Tag
* @return NfcTagHandler or null when unsupported Tag is provided.
*/
public static NfcTagHandler create(Tag tag) {
if (tag == null) return null;
if (NfcBlocklist.getInstance().isTagBlocked(tag)) return null;
Ndef ndef = Ndef.get(tag);
if (ndef != null) {
String type = ndef.getType();
return new NfcTagHandler(ndef, new NdefHandler(ndef), tag.getId());
}
NdefFormatable formattable = NdefFormatable.get(tag);
if (formattable != null) {
return new NfcTagHandler(
formattable, new NdefFormattableHandler(formattable), tag.getId());
}
return null;
}
/**
* NdefFormatable and Ndef interfaces have different signatures for operating with NFC tags.
* This interface provides generic methods.
*/
private interface TagTechnologyHandler {
public void write(NdefMessage message)
throws IOException, TagLostException, FormatException, IllegalStateException;
public boolean makeReadOnly() throws IOException, TagLostException;
public NdefMessage read()
throws IOException, TagLostException, FormatException, IllegalStateException;
public boolean canAlwaysOverwrite()
throws IOException, TagLostException, FormatException, IllegalStateException;
}
/**
* Implementation of TagTechnologyHandler that uses Ndef tag technology.
* @see android.nfc.tech.Ndef
*/
private static class NdefHandler implements TagTechnologyHandler {
private final Ndef mNdef;
NdefHandler(Ndef ndef) {
mNdef = ndef;
}
@Override
public void write(NdefMessage message)
throws IOException, TagLostException, FormatException, IllegalStateException {
mNdef.writeNdefMessage(message);
}
@Override
public boolean makeReadOnly() throws IOException, TagLostException {
return mNdef.makeReadOnly();
}
@Override
public NdefMessage read()
throws IOException, TagLostException, FormatException, IllegalStateException {
return mNdef.getNdefMessage();
}
@Override
public boolean canAlwaysOverwrite()
throws IOException, TagLostException, FormatException, IllegalStateException {
// Getting null means the tag is empty, overwrite is safe.
return mNdef.getNdefMessage() == null;
}
}
/**
* Implementation of TagTechnologyHandler that uses NdefFormatable tag technology.
* @see android.nfc.tech.NdefFormatable
*/
private static class NdefFormattableHandler implements TagTechnologyHandler {
private final NdefFormatable mNdefFormattable;
NdefFormattableHandler(NdefFormatable ndefFormattable) {
mNdefFormattable = ndefFormattable;
}
@Override
public void write(NdefMessage message)
throws IOException, TagLostException, FormatException, IllegalStateException {
mNdefFormattable.format(message);
}
@Override
public boolean makeReadOnly() throws IOException, TagLostException {
try {
mNdefFormattable.formatReadOnly(NdefMessageUtils.emptyNdefMessage());
} catch (FormatException e) {
return false;
}
return true;
}
@Override
public NdefMessage read() throws FormatException {
return NdefMessageUtils.emptyNdefMessage();
}
@Override
public boolean canAlwaysOverwrite() {
return true;
}
}
protected NfcTagHandler(TagTechnology tech, TagTechnologyHandler handler, byte[] id) {
mTech = tech;
mTechHandler = handler;
mSerialNumber = bytesToSerialNumber(id);
}
/**
* Convert byte array to serial number string (4-7 ASCII hex digits concatenated by ":").
*/
private static String bytesToSerialNumber(byte[] octets) {
if (octets.length < 0) return null;
StringBuilder sb = new StringBuilder(octets.length * 3);
for (byte b : octets) {
if (sb.length() > 0) {
sb.append(":");
}
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
/**
* Get the serial number of this NFC tag.
*/
public String serialNumber() {
return mSerialNumber;
}
/**
* Connects to NFC tag.
*/
public void connect() throws IOException, TagLostException {
if (!mTech.isConnected()) {
mTech.connect();
mWasConnected = true;
}
}
/**
* Checks if NFC tag is connected.
*/
public boolean isConnected() {
return mTech.isConnected();
}
/**
* Closes connection.
*/
public void close() throws IOException {
mTech.close();
}
/**
* Writes NdefMessage to NFC tag.
*/
public void write(NdefMessage message)
throws IOException, TagLostException, FormatException, IllegalStateException {
mTechHandler.write(message);
}
/**
* Make NFC tag read-only.
*/
public boolean makeReadOnly() throws IOException, TagLostException {
return mTechHandler.makeReadOnly();
}
public NdefMessage read()
throws IOException, TagLostException, FormatException, IllegalStateException {
return mTechHandler.read();
}
/**
* If tag was previously connected and subsequent connection to the same tag fails, consider
* tag to be out of range.
*/
public boolean isTagOutOfRange() {
try {
connect();
} catch (IOException e) {
return mWasConnected;
}
return false;
}
/**
* Returns false only if the tag is already NDEF formatted and contains some records. Otherwise
* true.
*/
public boolean canAlwaysOverwrite()
throws IOException, TagLostException, FormatException, IllegalStateException {
return mTechHandler.canAlwaysOverwrite();
}
}