Skip to content

Commit

Permalink
support for NFC (#383)
Browse files Browse the repository at this point in the history
NFC module was added for reading / writing data from NFC Ndef tags.
  • Loading branch information
Svyatoslav2 authored Dec 6, 2020
1 parent 76f7ece commit 88183af
Show file tree
Hide file tree
Showing 3 changed files with 315 additions and 0 deletions.
10 changes: 10 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.NFC"/>

<!-- permissions to install/uninstall apps -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
Expand Down Expand Up @@ -57,6 +58,15 @@
tools:ignore="GoogleAppIndexingWarning">
<receiver android:name="com.termux.api.TermuxApiReceiver"/>
<activity android:name="com.termux.api.DialogActivity" android:theme="@style/DialogTheme" android:noHistory="true" android:excludeFromRecents="true" android:exported="false"/>
<activity android:name="com.termux.api.NfcActivity" android:theme="@style/DialogTheme" android:noHistory="true" android:excludeFromRecents="true" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".FingerprintAPI$FingerprintActivity" android:theme="@style/TransparentTheme"
android:noHistory="true"
android:excludeFromRecents="true"
Expand Down
301 changes: 301 additions & 0 deletions app/src/main/java/com/termux/api/NfcActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
package com.termux.api;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.Layout;
import android.util.JsonWriter;
import android.util.Log;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.termux.api.util.ResultReturner;


public class NfcActivity extends AppCompatActivity{
private NfcAdapter adapter;
static String socket_input;
static String socket_output;
String mode;
String param;
String value;
//Check for NFC
protected void errorNfc(final Context context, Intent intent, String error) {
ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() {
@Override
public void writeJson(JsonWriter out) throws Exception {
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context);
out.beginObject();
if (error.length() > 0)
out.name("error").value(error);
out.name("nfcPresent").value(null != adapter);
if(null!=adapter)
out.name("nfcActive").value(adapter.isEnabled());
out.endObject();
}
});
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = this.getIntent();
if (intent != null) {
mode = intent.getStringExtra("mode");
if (null == mode)
mode = "noData";
param =intent.getStringExtra("param");
if (null == param)
param = "noData";
value=intent.getStringExtra("value");
if (null == socket_input) socket_input = intent.getStringExtra("socket_input");
if (null == socket_output) socket_output = intent.getStringExtra("socket_output");
if (mode == "noData") {
errorNfc(this, intent,"");
finish();
}
}

NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
if((null==adapter)||(!adapter.isEnabled())){
errorNfc(this,intent,"");
finish();
}
}

@Override
protected void onResume() {
super.onResume();
adapter = NfcAdapter.getDefaultAdapter(this);
Intent intentNew = new Intent(this, NfcActivity.class).addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intentNew, 0);
IntentFilter[] intentFilter = new IntentFilter[]{
new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED),
new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED),
new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)};
adapter.enableForegroundDispatch(this, pendingIntent, intentFilter, null);
}

@Override
protected void onNewIntent(Intent intent) {
intent.putExtra("socket_input", socket_input);
intent.putExtra("socket_output", socket_output);

if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
try {
postResult(this, intent);
}
catch (Exception e)
{
Log.e("Termix-api.NfcAction",e.getMessage());
}
finish();
}
super.onNewIntent(intent);
}

@Override
protected void onPause() {
adapter.disableForegroundDispatch(this);
super.onPause();
}

@Override
protected void onDestroy() {
socket_input = null;
socket_output = null;
super.onDestroy();
}

protected void postResult(final Context context, Intent intent) {
ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() {
@Override
public void writeJson(JsonWriter out) throws Exception {
Log.e("NFC","postResult");
try
{
switch (mode) {
case "write":
switch (param) {
case "text":
Log.e("NFC","-->write");
onReceiveNfcWrite(context, intent);
Log.e("NFC","<--write");
break;
default:
onUnexpectedAction(out, "Wrong Params", "Should be text for TAG");
break;
}
break;
case "read":
switch (param){
case "short":
readNDEFTag(intent,out);
break;
case "full":
readFullNDEFTag(intent,out);
break;
case "noData":
readNDEFTag(intent,out);
break;
default:
onUnexpectedAction(out, "Wrong Params", "Should be correct param value");
break;
}
break;
default:
onUnexpectedAction(out, "Wrong Params", "Should be correct mode value ");
break;
}
}
catch (Exception e){
onUnexpectedAction(out, "exception", e.getMessage());
}
}
});
}
public void onReceiveNfcWrite( final Context context, Intent intent) throws Exception {
{
Log.e("NFC","---->onReceiveNfcWrite");
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
NdefRecord record = NdefRecord.createTextRecord("en", value);
NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
Ndef ndef = Ndef.get(tag);
ndef.connect();
ndef.writeNdefMessage(msg);
ndef.close();
}
}


public void readNDEFTag(Intent intent, JsonWriter out) throws Exception {
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
Parcelable[] msgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndefTag = Ndef.get(tag);
boolean bNdefPresent = false;
String strs[] = tag.getTechList();
for (String s: strs){
if (s.equals("android.nfc.tech.Ndef"))
bNdefPresent = true;
}
if (!bNdefPresent){
onUnexpectedAction(out, "Wrong Technology","termux API support only NFEF Tag");
return;
}
NdefMessage[] nmsgs = new NdefMessage[msgs.length];
if (msgs.length == 1) {
nmsgs[0] = (NdefMessage) msgs[0];
NdefRecord records[] = nmsgs[0].getRecords();
out.beginObject();
if (records.length >0 ) {
{
out.name("Record");
if (records.length > 1)
out.beginArray();
for (NdefRecord record: records){
out.beginObject();
int pos = 1 + record.getPayload()[0];
pos = (NdefRecord.TNF_WELL_KNOWN==record.getTnf())?(int)record.getPayload()[0]+1:0;
int len = record.getPayload().length - pos;
byte msg[] = new byte[len];
System.arraycopy(record.getPayload(), pos, msg, 0, len);
out.name("Payload").value(new String(msg));
out.endObject();
}
if (records.length > 1)
out.endArray();
}
}
out.endObject();
}
}

public void readFullNDEFTag(Intent intent, JsonWriter out) throws Exception {
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndefTag = Ndef.get(tag);
Parcelable[] msgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

String strs[] = tag.getTechList();
boolean bNdefPresent = false;
for (String s: strs){
if (s.equals("android.nfc.tech.Ndef"))
bNdefPresent = true;
}
if (!bNdefPresent){
onUnexpectedAction(out, "Wrong Technology","termux API support only NFEF Tag");
return;
}
NdefMessage[] nmsgs = new NdefMessage[msgs.length];
out.beginObject();
{
byte[] tagID = tag.getId();
StringBuilder sp = new StringBuilder();
for (byte tagIDpart : tagID) { sp.append(String.format("%02x", tagIDpart)); }
out.name("id").value(sp.toString());
out.name("typeTag").value(ndefTag.getType());
out.name("maxSize").value(ndefTag.getMaxSize());
out.name("techList");
{
out.beginArray();
String[] tlist = tag.getTechList();
for (String str : tlist) {
out.value(str);
}
out.endArray();
}
if (msgs.length == 1) {
Log.e("NFC", "-->> readFullNDEFTag - 06");
nmsgs[0] = (NdefMessage) msgs[0];
NdefRecord records[] = nmsgs[0].getRecords();
{
out.name("record");
if (records.length > 1)
out.beginArray();
for (NdefRecord record : records) {
out.beginObject();
out.name("type").value(new String(record.getType()));
out.name("tnf").value(record.getTnf());
if (records[0].toUri() != null) out.name("URI").value(record.toUri().toString());
out.name("mime").value(record.toMimeType());
int pos = 1 + record.getPayload()[0];
pos = (NdefRecord.TNF_WELL_KNOWN==record.getTnf())?(int)record.getPayload()[0]+1:0;
int len = record.getPayload().length - pos;
byte msg[] = new byte[len];
System.arraycopy(record.getPayload(), pos, msg, 0, len);
out.name("payload").value(new String(msg));
out.endObject();
}
if (records.length > 1) out.endArray();
}
}

}
out.endObject();
}

protected void onUnexpectedAction(JsonWriter out,String error, String description) throws Exception {
out.beginObject();
out.name("error").value(error);
out.name("description").value(description);
out.endObject();
out.flush();
}
}
4 changes: 4 additions & 0 deletions app/src/main/java/com/termux/api/TermuxApiReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.os.Build;
import android.provider.Settings;
import android.widget.Toast;
Expand Down Expand Up @@ -115,6 +116,9 @@ private void doWork(Context context, Intent intent) {
MicRecorderAPI.onReceive(context, intent);
}
break;
case "Nfc":
context.startActivity(new Intent(context, NfcActivity.class).putExtras(intent.getExtras()).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
break;
case "NotificationList":
ComponentName cn = new ComponentName(context, NotificationService.class);
String flat = Settings.Secure.getString(context.getContentResolver(), "enabled_notification_listeners");
Expand Down

0 comments on commit 88183af

Please sign in to comment.