package mifare.info; import com.google.appinventor.components.runtime.*; import android.app.Activity; import android.content.Intent; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.util.Log; import android.nfc.tech.MifareClassic; import android.nfc.tech.MifareUltralight; 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.SimpleFunction; 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.UsesActivityMetadata; 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; import java.io.IOException; /** * Non-visible component to provide MIFARE Info. The component provides the Tag UID and other info * Added possibility to read and write block using AuthenticationKeyA *(if supported by the device). * **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 MIFARE Info. " + "The component provides the Tag UID and other info" + "Added possibility to read and write block using AuthenticationKeyA" + "(if supported by the device)

" + "

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") /* @UsesActivities( activities = { @ActivityElement( intentFilters = { @IntentFilterElement( actionElements = { @ActionElement( name = "android.nfc.action.NDEF_DISCOVERED,android.nfc.action.TECH_DISCOVERED,android.nfc.action.TAG_DISCOVERED" ) }, categoryElements = { @CategoryElement( name = "android.intent.category.DEFAULT" ) } ) } ,launchMode="singleTask" ,name=".Screen1" ) } ) /* @UsesActivityMetadata( metaDataElements = { @MetaDataElement( name = "android.nfc.action.TECH_DISCOVERED", resource = "@xml/nfc_tech_list" ) } ) */ @UsesActivities( activities = { @ActivityElement( intentFilters = { @IntentFilterElement( actionElements = { @ActionElement( name = "android.nfc.action.TAG_DISCOVERED" ) }, categoryElements = { @CategoryElement( name = "android.intent.category.DEFAULT" ) } ) } ,launchMode="singleTask" ,name=".Screen1" ) } ) public class MifareInfo extends AndroidNonvisibleComponent implements OnStopListener, OnResumeListener, OnPauseListener, OnNewIntentListener, Deleteable { private static final String TAG = "nearfield"; private Activity activity; private NfcAdapter nfcAdapter; private boolean readMode = true; private int writeType; private String LastUid = ""; private String LastType = ""; private int LastSize = 0; private int LastBlocks = 0; private int LastSectors = 0; private String textToWrite = ""; private String AuthKeyA = ""; private Tag tag; /* 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 MifareInfo(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"); } // Events /** * The UID of the Mifare Tag read */ @SimpleEvent public void GetUid(String TagUid) { Log.d(TAG, "Uid: got message " + TagUid); LastUid = TagUid; EventDispatcher.dispatchEvent(this, "GetUid", TagUid); } /** * The Type of the Mifare Tag read */ @SimpleEvent public void GetType(String TagType) { Log.d(TAG, "Type: got message " + TagType); LastType = TagType; EventDispatcher.dispatchEvent(this, "GetType", TagType); } /** * The Size of the Mifare Tag read */ @SimpleEvent public void GetSize(int TagSize) { Log.d(TAG, "Size: got message " + TagSize); LastSize = TagSize; EventDispatcher.dispatchEvent(this, "GetSize", TagSize); } /** * The number of Sectors of the Mifare Tag read */ @SimpleEvent public void GetSectors(int TagSectors) { Log.d(TAG, "Sectors: got message " + TagSectors); LastSectors = TagSectors; EventDispatcher.dispatchEvent(this, "GetSectors", TagSectors); } /** * The number of Blocks of the Mifare Tag read */ @SimpleEvent public void GetBlocks(int TagBlocks) { Log.d(TAG, "Blocks: got message " + TagBlocks); LastBlocks = TagBlocks; EventDispatcher.dispatchEvent(this, "GetBlocks", TagBlocks); } /** * The Mifare Classic Block read */ @SimpleEvent public void GetMifareClassicBlock(String BlockRead) { Log.d(TAG, "BlockRead: got message " + BlockRead); EventDispatcher.dispatchEvent(this, "GetMifareClassicBlock", BlockRead); } // Properties /** * Returns the UID of the last Mifare Tag Read. */ @SimpleProperty(category = PropertyCategory.BEHAVIOR) public String LastReadUid() { Log.d(TAG, "String message method stared"); return LastUid; } /** * Returns the Type of the last Mifare Tag Read. */ @SimpleProperty(category = PropertyCategory.BEHAVIOR) public String LastReadType() { Log.d(TAG, "String message method stared"); return LastType; } /** * Returns the Size of the last Mifare Tag Read. */ @SimpleProperty(category = PropertyCategory.BEHAVIOR) public int LastReadSize() { Log.d(TAG, "String message method stared"); return LastSize; } /** * Returns the number of Sectors of the last Mifare Tag Read. */ @SimpleProperty(category = PropertyCategory.BEHAVIOR) public int LastReadSectors() { Log.d(TAG, "String message method stared"); return LastSectors; } /** * Returns the number of Blocks of the last Mifare Tag Read. */ @SimpleProperty(category = PropertyCategory.BEHAVIOR) public int LastReadBlocks() { Log.d(TAG, "String message method stared"); return LastBlocks; } /** * 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"); 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); } } /** * Specifies the content of the AuthenticationKey A * */ @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Specifies the content of the AuthenticationKey A.") public void AuthenticationKeyA(String keyA) { Log.d(TAG, "AuthenticationKeyA " + keyA); AuthKeyA = keyA; } /** * Read the Block specified after the authenticationA * */ @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Read the Block specified after the authentication.") public void readMifareClassicBlock(int Block) { Log.d(TAG, "Mifare Classic Block to read" + Block); if(readMode == true){ if(SdkLevel.getLevel() >= SdkLevel.LEVEL_GINGERBREAD){ rMCB(Block); } } } /** * Write the Block specified after the authenticationA * */ @SimpleFunction(description = "Write the Block specified after the authentication.") public void writeMifareClassicBlock(int Block, String DataToWrite) { Log.d(TAG, "Mifare Classic Block to read" + Block); if(readMode == false){ if(SdkLevel.getLevel() >= SdkLevel.LEVEL_GINGERBREAD){ wMCB(Block,DataToWrite); } } } @Override public void onNewIntent(Intent intent) { Log.d(TAG, "Nearfield on onNewIntent. Intent is: " + intent); resolveIntent(intent); } // TODO: Re-enable NFC communication if it had been disabled @Override public void onResume() { Intent intent = activity.getIntent(); Log.d(TAG, "Nearfield on onResume. Intent is: " + intent); } void resolveIntent(Intent intent) { Log.d(TAG, "resolve intent. Intent is: " + intent); String action = intent.getAction(); //if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); GetUid(ByteArrayToHexString(tag.getId())); assert tag != null; detectTagData(tag); } } void detectTagData(Tag tag) { for (String tech : tag.getTechList()) { if (tech.equals(MifareClassic.class.getName())) { MifareClassic mifareTag = MifareClassic.get(tag); String type = "Unknown"; switch (mifareTag.getType()) { case MifareClassic.TYPE_CLASSIC: type = "Classic"; break; case MifareClassic.TYPE_PLUS: type = "Plus"; break; case MifareClassic.TYPE_PRO: type = "Pro"; break; } GetType(type); GetSize(mifareTag.getSize()); GetSectors(mifareTag.getSectorCount()); GetBlocks(mifareTag.getBlockCount()); } if (tech.equals(MifareUltralight.class.getName())) { MifareUltralight mifareUlTag = MifareUltralight.get(tag); String type = "Unknown"; switch (mifareUlTag.getType()) { case MifareUltralight.TYPE_ULTRALIGHT: type = "Ultralight"; break; case MifareUltralight.TYPE_ULTRALIGHT_C: type = "Ultralight C"; break; } GetType(type); } } } void rMCB(int BTR) { for (String tech : tag.getTechList()) { if (tech.equals(MifareClassic.class.getName())) { MifareClassic mifareTag = MifareClassic.get(tag); int Sector = FindSector(BTR); try { mifareTag.connect(); if(mifareTag.authenticateSectorWithKeyA(Sector, hexStringToByteArray(AuthKeyA))) { GetMifareClassicBlock(ByteArrayToHexString(mifareTag.readBlock(BTR))); } mifareTag.close(); } catch (IOException e) { e.printStackTrace(); } finally{ if(mifareTag!=null){ try { mifareTag.close(); } catch (IOException e) { e.printStackTrace(); } } } } } } void wMCB(int BTR, String DTW) { for (String tech : tag.getTechList()) { if (tech.equals(MifareClassic.class.getName())) { MifareClassic mifareTag = MifareClassic.get(tag); int Sector = FindSector(BTR); try { mifareTag.connect(); if(mifareTag.authenticateSectorWithKeyA(Sector, hexStringToByteArray(AuthKeyA))) { while (DTW.length() < 32) { DTW = DTW + "0"; } mifareTag.writeBlock(BTR,hexStringToByteArray(DTW)); } mifareTag.close(); } catch (IOException e) { e.printStackTrace(); } finally{ if(mifareTag!=null){ try { mifareTag.close(); } catch (IOException e) { e.printStackTrace(); } } } } } } public int FindSector(int BTR) { int Sect = 0; if (BTR <= 127) //because Mifare 4K memory is like 1K and 2K until block 127 every sector 4 blocks than each sector 15 blocks { Sect = (BTR / 4); } else { if (BTR >= 128 && BTR <= 143) Sect = 32; if (BTR >= 144 && BTR <= 159) Sect = 33; if (BTR >= 160 && BTR <= 176) Sect = 34; if (BTR >= 176 && BTR <= 191) Sect = 35; if (BTR >= 192 && BTR <= 207) Sect = 36; if (BTR >= 208 && BTR <= 223) Sect = 37; if (BTR >= 224 && BTR <= 239) Sect = 38; if (BTR >= 240 && BTR <= 255) Sect = 39; } return Sect; } public void onPause() { Log.d(TAG, "OnPause method started."); if (nfcAdapter != null) { GingerbreadUtil.disableNFCAdapter(activity, nfcAdapter); } } @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; } private byte[] hexStringToByteArray(String instring) { int len = instring.length(); byte[] out = new byte[len / 2]; for (int i = 0; i < len; i += 2) { out[i / 2] = (byte) ((Character.digit(instring.charAt(i), 16) << 4) + Character.digit(instring.charAt(i+1), 16)); } 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(); } } */ }