// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2012-2014 MIT, All rights reserved // Released under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 //package com.google.appinventor.components.runtime; package mifare.uid; import com.google.appinventor.components.runtime.*; import android.app.Activity; import android.content.Intent; //import android.app.PendingIntent; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.util.Log; import android.nfc.tech.MifareClassic; //added these to have a log file to undestand what is executed and what no import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.BufferedWriter; import java.io.FileWriter; // import com.google.appinventor.components.annotations.DesignerComponent; import com.google.appinventor.components.annotations.DesignerProperty; import com.google.appinventor.components.annotations.PropertyCategory; import com.google.appinventor.components.annotations.SimpleEvent; import com.google.appinventor.components.annotations.SimpleObject; import com.google.appinventor.components.annotations.SimpleProperty; import com.google.appinventor.components.annotations.UsesPermissions; import com.google.appinventor.components.annotations.UsesActivities; import com.google.appinventor.components.annotations.androidmanifest.*; import com.google.appinventor.components.common.ComponentCategory; import com.google.appinventor.components.common.PropertyTypeConstants; import com.google.appinventor.components.common.YaVersion; import com.google.appinventor.components.runtime.util.GingerbreadUtil; import com.google.appinventor.components.runtime.util.SdkLevel; /** * Non-visible component to provide NFC capabilities. For now this component supports the reading * and writing of text tags only (if supported by the device). * * In order to read and write text tags, the component must have its {@link #ReadMode(boolean)} * property set to `true`{:.logic.block} or `false`{:.logic.block} respectively. * * **Note:** This component will only work on Screen1 of any App Inventor app. */ @DesignerComponent(version = YaVersion.NEARFIELD_COMPONENT_VERSION, description = "

Non-visible component to provide NFC capabilities. " + "For now this component supports the reading and writing of text tags only " + "(if supported by the device)

" + "

In order to read and write text tags, the component must have its " + "ReadMode property set to True or False respectively.

" + "

Note: This component will only work on Screen1 of" + " any App Inventor app.

", category = ComponentCategory.EXTENSION, nonVisible = true, iconName = "images/nearfield.png") @SimpleObject(external=true) @UsesPermissions(permissionNames = "android.permission.NFC,android.permission.WRITE_EXTERNAL_STORAGE") /* @UsesActivities( activities = { @ActivityElement( intentFilters = { @IntentFilterElement( actionElements = { @ActionElement( name = "android.nfc.action.TAG_DISCOVERED" ) }, categoryElements = { @CategoryElement( name = "android.intent.category.DEFAULT" ) } ) } ,name=".Screen1" ) } ) */ //after create the apk i edit the manifest adding manually this lines because i didn't find the right way to add this directly from the extension, //this enable the app to receive the tag discovered // // // // //this should resolve the problem of the onNewIntent but.... //android:launchMode="singleTop" public class MifareUid extends AndroidNonvisibleComponent implements OnStopListener, OnResumeListener, OnPauseListener, OnNewIntentListener, Deleteable { private static final String TAG = "nearfield"; private Activity activity; private NfcAdapter nfcAdapter; //private PendingIntent pendingIntent; private boolean readMode = true; private int writeType; private String tagContent = ""; private String textToWrite = ""; /* Used to identify the call to startActivityForResult. Will be passed back into the resultReturned() callback method. */ protected int requestCode; /** * Creates a new NearField component * @param container ignored (because this is a non-visible component) */ public MifareUid(ComponentContainer container) { super(container.$form()); activity = container.$context(); writeType = 1; nfcAdapter = (SdkLevel.getLevel() >= SdkLevel.LEVEL_GINGERBREAD) ? GingerbreadUtil.newNfcAdapter(activity) : null; // register with the forms to that OnResume and OnNewIntent // messages get sent to this component form.registerForOnResume(this); form.registerForOnNewIntent(this); form.registerForOnPause(this); Log.d(TAG, "Nearfield component created"); appendLog("Nearfield component created"); //Add PendingIntent as advised on but they add the pendingintent in the onStart, that I don't have, so how to use it? //pendingIntent = PendingIntent.getActivity(this,0,new Intent(this,this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),0); } // Events /** * Indicates that a new tag has been detected. * Currently this is only a plain text tag, as specified in the * manifest. * @internaldoc * See Compiler.java. */ @SimpleEvent public void TagRead(String message) { Log.d(TAG, "Tag read: got message " + message); appendLog("Tag read: got message " + message); tagContent = message; EventDispatcher.dispatchEvent(this, "TagRead", message); } // Properties /** * Returns the content of the most recently received tag. */ @SimpleProperty(category = PropertyCategory.BEHAVIOR)//what does this mean? public String LastMessage() { Log.d(TAG, "String message method stared"); appendLog("String message method stared"); return tagContent; } /** * Returns true if in read mode, false if in write mode. */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "True") @SimpleProperty(category = PropertyCategory.BEHAVIOR) public boolean ReadMode() { Log.d(TAG, "boolean method stared"); appendLog("boolean method stared"); return readMode; } /** * Specifies whether the NFC hardware should operate in read mode (`true`{:.logic.block}) or * write mode (`false`{:.logic.block}). */ @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Specifies whether the NFC hardware should operate in read or write mode.") public void ReadMode(boolean newMode) { Log.d(TAG, "Read mode set to" + newMode); readMode = newMode; if(!readMode && SdkLevel.getLevel() >= SdkLevel.LEVEL_GINGERBREAD){ GingerbreadUtil.enableNFCWriteMode(activity, nfcAdapter, textToWrite); } } @Override public void onNewIntent(Intent intent) { Log.d(TAG, "Nearfield on onNewIntent. Intent is: " + intent); appendLog("Nearfield on onNewIntent. Intent is: " + intent); //added as advised but commented because I have cannot find symbol when compile wit ant //super.onNewIntent(intent); //setIntent(intent); resolveIntent(intent); } // TODO: Re-enable NFC communication if it had been disabled @Override public void onResume() { //added as advised but commented because I have cannot find symbol when compile wit ant //super.onResume(); //assert nfcAdapter != null; //nfcAdapter.enableForegroundDispatch(this,pendingIntent,null,null); Intent intent = activity.getIntent(); Log.d(TAG, "Nearfield on onResume. Intent is: " + intent); appendLog("Nearfield on on onResume. Intent is: " + intent); } void resolveIntent(Intent intent) { Log.d(TAG, "resolve intent. Intent is: " + intent); appendLog("resolve intent. Intent is: " + intent); // Parse the intent // if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED)) { // tagContent = ByteArrayToHexString(intent.getByteArrayExtra(NfcAdapter.EXTRA_ID)); // } String action = intent.getAction(); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); appendLog("TAG: " + tag.getId()); appendLog("TAG: " + ByteArrayToHexString(tag.getId())); assert tag != null; byte[] payload = detectTagData(tag).getBytes(); } else { appendLog("NO!!!!!!! ACTION_NDEF_DISCOVERED_DISCOVERED"); } } private String detectTagData(Tag tag) { String sb = ""; byte[] id = tag.getId(); sb = ByteArrayToHexString(id); String prefix = "android.nfc.tech."; for (String tech : tag.getTechList()) { sb = sb +" "+ (tech.substring(prefix.length())); sb = sb +", "; } for (String tech : tag.getTechList()) { if (tech.equals(MifareClassic.class.getName())) { String type = "Unknown"; try { MifareClassic mifareTag = MifareClassic.get(tag); switch (mifareTag.getType()) { case MifareClassic.TYPE_CLASSIC: type = "Classic"; break; case MifareClassic.TYPE_PLUS: type = "Plus"; break; case MifareClassic.TYPE_PRO: type = "Pro"; break; } sb = sb + "Mifare Classic type: "; sb = sb + type; } catch (Exception e) { sb = "Mifare classic error: " + e.getMessage(); } } } TagRead(sb); return sb; } public void onPause() { Log.d(TAG, "OnPause method started."); /* if (nfcAdapter != null) { GingerbreadUtil.disableNFCAdapter(activity, nfcAdapter); } */ //super.onPause(); //Onpause stop listening if (nfcAdapter != null) { nfcAdapter.disableForegroundDispatch(activity); } //nfcAdapter.disableForegroundDispatch(activity); } @Override public void onDelete() { // TODO Auto-generated method stub // need to delete the nearfieldActivity } @Override public void onStop() { // TODO Auto-generated method stub } private String ByteArrayToHexString(byte [] inarray) { int i, j, in; String [] hex = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; String out= ""; for(j = 0 ; j < inarray.length ; ++j) { in = (int) inarray[j] & 0xff; i = (in >> 4) & 0x0f; out += hex[i]; i = in & 0x0f; out += hex[i]; } return out; } public void appendLog(String text) { File logFile = new File("sdcard/MyNFCLog.txt"); if (!logFile.exists()) { try { logFile.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { //BufferedWriter for performance, true to set append to file flag BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); buf.append(text); buf.newLine(); buf.flush(); buf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }