/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.nfc;
import android.content.Intent;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.os.Parcelable;
import android.util.Log;
import org.catrobat.catroid.ProjectManager;
import org.catrobat.catroid.common.BrickValues;
import org.catrobat.catroid.content.Sprite;
import org.catrobat.catroid.formulaeditor.InterpretationException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
public final class NfcHandler {
private static final String TAG = NfcHandler.class.getSimpleName();
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
private static String nfcTagId = "0x0";
private static String nfcTagMessage = "";
private NfcHandler() {
}
public static void processIntent(Intent intent) {
if (intent == null) {
return;
}
String uid = getTagIdFromIntent(intent);
setLastNfcTagId(uid);
setLastNfcTagMessage(getMessageFromIntent(intent));
List<Sprite> spriteList = ProjectManager.getInstance().getCurrentProject().getSpriteListWithClones();
for (Sprite sprite : spriteList) {
sprite.createWhenNfcScriptAction(uid);
}
}
public static String getTagIdFromIntent(Intent intent) {
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
byte[] tagId = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
String uidHex = String.valueOf(byteArrayToHex(tagId));
setLastNfcTagId(uidHex);
Log.d(TAG, "read successful. uid = int: " + uidHex);
return uidHex;
}
return null;
}
public static String getMessageFromIntent(Intent intent) {
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
NdefMessage[] messages = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
messages[i] = (NdefMessage) rawMsgs[i];
}
if (messages[0] != null) {
String result = "";
byte[] payload = messages[0].getRecords()[0].getPayload();
if (payload.length > 0) {
int i = payloadStartContainsText(payload[0]) ? 0 : 1;
for (; i < payload.length; i++) {
result += (char) payload[i];
}
}
return result;
}
}
}
return null;
}
private static boolean payloadStartContainsText(byte payloadStart) {
return payloadStart != 1;
}
public static Object getLastNfcTagMessage() {
return nfcTagMessage;
}
public static String getLastNfcTagId() {
return nfcTagId;
}
public static void setLastNfcTagId(String tagID) {
nfcTagId = tagID;
}
public static void setLastNfcTagMessage(String message) {
nfcTagMessage = message;
}
public static String byteArrayToHex(byte[] a) {
if (a == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (byte b : a) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
public static void writeTag(Tag tag, NdefMessage message) {
if (tag != null) {
try {
Ndef ndefTag = Ndef.get(tag);
if (ndefTag == null) {
NdefFormatable nForm = NdefFormatable.get(tag);
if (nForm != null) {
nForm.connect();
nForm.format(message);
nForm.close();
}
} else {
ndefTag.connect();
ndefTag.writeNdefMessage(message);
ndefTag.close();
}
} catch (IOException | FormatException e) {
Log.d(TAG, "Couldn't create message", e);
}
}
}
public static NdefMessage createMessage(String message, int spinnerSelection) throws InterpretationException {
NdefRecord ndefRecord;
short tnf = 0;
byte[] type;
byte[] id;
byte[] payload;
byte[] uriField;
switch (spinnerSelection) {
case BrickValues.TNF_EMPTY:
tnf = NdefRecord.TNF_EMPTY;
type = new byte[] {};
id = new byte[] {};
payload = new byte[] {};
ndefRecord = new NdefRecord(tnf, type, id, payload);
break;
case BrickValues.TNF_MIME_MEDIA:
tnf = NdefRecord.TNF_MIME_MEDIA;
String mimeType = "text/plain";
type = mimeType.getBytes(UTF8_CHARSET);
id = new byte[] {};
payload = message.getBytes(UTF8_CHARSET);
ndefRecord = new NdefRecord(tnf, type, id, payload);
break;
case BrickValues.TNF_WELL_KNOWN_HTTP:
tnf = NdefRecord.TNF_WELL_KNOWN;
type = NdefRecord.RTD_URI;
id = new byte[] {};
uriField = deleteProtocolPrefixIfExist(message).getBytes(UTF8_CHARSET);
payload = new byte[uriField.length + 1];
payload[0] = BrickValues.NDEF_PREFIX_HTTP;
System.arraycopy(uriField, 0, payload, 1, uriField.length);
ndefRecord = new NdefRecord(tnf, type, id, payload);
break;
case BrickValues.TNF_WELL_KNOWN_HTTPS:
tnf = NdefRecord.TNF_WELL_KNOWN;
type = NdefRecord.RTD_URI;
id = new byte[] {};
uriField = deleteProtocolPrefixIfExist(message).getBytes(UTF8_CHARSET);
payload = new byte[uriField.length + 1];
payload[0] = BrickValues.NDEF_PREFIX_HTTPS;
System.arraycopy(uriField, 0, payload, 1, uriField.length);
ndefRecord = new NdefRecord(tnf, type, id, payload);
break;
case BrickValues.TNF_WELL_KNOWN_MAILTO:
tnf = NdefRecord.TNF_WELL_KNOWN;
type = NdefRecord.RTD_URI;
id = new byte[] {};
uriField = message.getBytes(UTF8_CHARSET);
payload = new byte[uriField.length + 1];
payload[0] = BrickValues.NDEF_PREFIX_MAILTO;
System.arraycopy(uriField, 0, payload, 1, uriField.length);
ndefRecord = new NdefRecord(tnf, type, id, payload);
break;
case BrickValues.TNF_WELL_KNOWN_TEL:
tnf = NdefRecord.TNF_WELL_KNOWN;
type = NdefRecord.RTD_URI;
id = new byte[] {};
uriField = message.getBytes(UTF8_CHARSET);
payload = new byte[uriField.length + 1];
payload[0] = BrickValues.NDEF_PREFIX_TEL;
System.arraycopy(uriField, 0, payload, 1, uriField.length);
ndefRecord = new NdefRecord(tnf, type, id, payload);
break;
case BrickValues.TNF_WELL_KNOWN_SMS:
tnf = NdefRecord.TNF_EXTERNAL_TYPE;
type = "nfclab.com:smsService".getBytes(UTF8_CHARSET);
id = new byte[] {};
String textMessage = "SMS from Catrobat";
String smsMessage = "sms:" + message + "?body=" + textMessage;
payload = smsMessage.getBytes(UTF8_CHARSET);
ndefRecord = new NdefRecord(tnf, type, id, payload);
break;
case BrickValues.TNF_EXTERNAL_TYPE:
String domain = "catrobat.com";
String externalType = "catroid";
byte[] data = message.getBytes(UTF8_CHARSET);
ndefRecord = NdefRecord.createExternal(domain, externalType, data);
break;
default:
ndefRecord = NdefRecord.createUri(message);
}
return new NdefMessage(new NdefRecord[] { ndefRecord });
}
public static String deleteProtocolPrefixIfExist(String url) {
return url.replaceFirst("^\\w+://", "");
}
}