Intent makes my app crash - android

At the moment I'm writing an App which Scans NFC Tags and tells you what's written on the Tag.
But now I have a problem. I wrote a Intent into the Menu, so that from the Menu you can get to that Scan-Page. But when I pasted the code that Scans the NFC Tags, the Intent suddenly Stoped working.
I can install the App without a Problem and there is no Error, but When I click onto the Button in The Menu that should bring me to the Page on which I scan NFC Tags, the App just crashes.
I really do not Know where the error is, and I would be very glad if you could help me.
I will provide the code I have so far below:
Menu with Intents:
package com.example.kristian.nfcproject;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class nfc_menu extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nfc_menu);
getSupportActionBar().hide();
Button buttonLogout = (Button) findViewById(R.id.buttonLogout);
Button buttonProfil = (Button) findViewById(R.id.buttonProfil);
Button buttonAssets = (Button) findViewById(R.id.buttonAssets);
Button buttonNfcid = (Button) findViewById(R.id.buttonNfcid);
Button buttonNfcscan = (Button) findViewById(R.id.buttonNfcscan);
buttonLogout.setOnClickListener(
new Button.OnClickListener()
{
public void onClick(View v)
{
Intent logoutI = new Intent(v.getContext(), MainActivity.class);
startActivity(logoutI);
}
}
);
buttonProfil.setOnClickListener(
new Button.OnClickListener()
{
public void onClick(View v)
{
Intent meinprofilI = new Intent(v.getContext(), meinprofil.class);
startActivity(meinprofilI);
}
}
);
buttonAssets.setOnClickListener(
new Button.OnClickListener()
{
public void onClick(View v)
{
Intent assetsI = new Intent(v.getContext(), meineassets.class);
startActivity(assetsI);
}
}
);
buttonNfcid.setOnClickListener(
new Button.OnClickListener()
{
public void onClick(View v)
{
Intent nfcidI = new Intent(v.getContext(), nfcidhinzu.class);
startActivity(nfcidI);
}
}
);
buttonNfcscan.setOnClickListener(
new Button.OnClickListener()
{
public void onClick(View v)
{
Intent nfcscannI = new Intent(v.getContext(), nfctagscann.class);
startActivity(nfcscannI);
}
}
);
}
}
The NFC Scan Activity:
package com.example.kristian.nfcproject;
import android.app.Activity;
import android.app.PendingIntent;
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.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.view.View;
import android.widget.Button;
import com.example.kristian.nfcproject.R;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class nfctagscann extends AppCompatActivity {
TextView text;
NfcAdapter nfcAdapter;
public static final String MIME_TEXT_PLAIN = "text/plain";
public static final String TAG = "NfcDemo";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nfcidhinzu);
getSupportActionBar().hide();
text = (TextView) findViewById(R.id.textView);
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Toast.makeText(this, "This Device doesn't support NFC", Toast.LENGTH_LONG).show();
finish();
}
if (!nfcAdapter.isEnabled()) {
text.setText("Please enable NFC in your settings.");
} else {
text.setText(R.string.explanation);
}
handleIntent(getIntent());
}
#Override
protected void onResume() {
super.onResume();
/**
* It's important, that the activity is in the foreground (resumed). Otherwise
* an IllegalStateException is thrown.
*/
setupForegroundDispatch(this, nfcAdapter);
}
#Override
protected void onPause() {
/**
* Call this before onPause, otherwise an IllegalArgumentException is thrown as well.
*/
stopForegroundDispatch(this, nfcAdapter);
super.onPause();
}
#Override
protected void onNewIntent(Intent intent) {
/**
* This method gets called, when a new Intent gets associated with the current activity instance.
* Instead of creating a new activity, onNewIntent will be called. For more information have a look
* at the documentation.
*
* In our case this method gets called, when the user attaches a Tag to the device.
*/
handleIntent(intent);
}
public static void setupForegroundDispatch(final Activity activity, NfcAdapter adapter) {
final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0);
IntentFilter[] filters = new IntentFilter[1];
String[][] techList = new String[][]{};
// Notice that this is the same filter as in our manifest.
filters[0] = new IntentFilter();
filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
filters[0].addCategory(Intent.CATEGORY_DEFAULT);
try {
filters[0].addDataType(MIME_TEXT_PLAIN);
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("Check your mime type.");
}
adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
}
public static void stopForegroundDispatch(final Activity activity, NfcAdapter adapter) {
adapter.disableForegroundDispatch(activity);
}
private void handleIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
String type = intent.getType();
if (MIME_TEXT_PLAIN.equals(type)) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
new NdefReaderTask().execute(tag);
} else {
Log.d(TAG, "Wrong mime type: " + type);
}
} else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
// In case we would still use the Tech Discovered Intent
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = tag.getTechList();
String searchedTech = Ndef.class.getName();
for (String tech : techList) {
if (searchedTech.equals(tech)) {
new NdefReaderTask().execute(tag);
break;
}
}
}
}
private class NdefReaderTask extends AsyncTask<Tag, Void, String> {
#Override
protected String doInBackground(Tag... params) {
Tag tag = params[0];
Ndef ndef = Ndef.get(tag);
if (ndef == null) {
// NDEF is not supported by this Tag.
return null;
}
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
NdefRecord[] records = ndefMessage.getRecords();
for (NdefRecord ndefRecord : records) {
if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
try {
return readText(ndefRecord);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unsupported Encoding", e);
}
}
}
return null;
}
private String readText(NdefRecord record) throws UnsupportedEncodingException {
/*
* See NFC forum specification for "Text Record Type Definition" at 3.2.1
*
* http://www.nfc-forum.org/specs/
*
* bit_7 defines encoding
* bit_6 reserved for future use, must be 0
* bit_5..0 length of IANA language code
*/
byte[] payload = record.getPayload();
// Get the Text Encoding
String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16";
// Get the Language Code
int languageCodeLength = payload[0] & 0063;
// String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
// e.g. "en"
// Get the Text
return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
}
#Override
protected void onPostExecute(String result) {
if (result != null) {
text.setText("NFC INHALT" + result);
}
}
}
}
Before Pasting this pre written code into the App the Intent worked fine, now when I click the button to get to the Scan Activity the app just crashes.
I appreciate every kind of help :)
Log:
03-19 18:34:27.669 22810-22810/com.example.kristian.nfcproject E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.kristian.nfcproject, PID: 22810
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.kristian.nfcproject/com.example.kristian.nfcproject.nfctagscann}: java.lang.IllegalStateException: Already attached
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2924)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2985)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.IllegalStateException: Already attached
at android.support.v4.app.FragmentManagerImpl.attachController(FragmentManager.java:3146)
at android.support.v4.app.FragmentController.attachHost(FragmentController.java:95)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:283)
at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:84)
at com.example.kristian.nfcproject.nfctagscann.onCreate(nfctagscann.java:42)
at android.app.Activity.performCreate(Activity.java:6912)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2877)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2985) 
at android.app.ActivityThread.-wrap14(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6692) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358) 

Related

Error Receiving broadcast Intent ACTION_POWER_DISCONNECTED

I am new to android .I am getting a runtime exception says "Error receiving broadcast Intent ACTION_POWER_DISCONNECTED ".I instantiate my receiver in onCreate() of my activity then I register my receiver in onResume() and unregistered it in onPause() methods.
Actually i want to set text Charging and Not Charging according to the charging mode of my app
package com.example.mrfrag.firebattery;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class HomeActivity extends AppCompatActivity{
TextView batteryplus,temp,setting,plug,charging,battery;
private BroadcastReceiver mReceiver;
IntentFilter ifilter =new IntentFilter();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
batteryplus= findViewById(R.id.batteryplus);
temp = findViewById(R.id.temp);
setting= findViewById(R.id.setting);
plug= findViewById(R.id.plug);
charging= findViewById(R.id.charging);
battery= findViewById(R.id.battery);
mReceiver=new PowerConnectionReceiver();
ifilter.addAction(Intent.ACTION_POWER_CONNECTED);
ifilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
ifilter.addAction(Intent.ACTION_BATTERY_CHANGED);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, ifilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
public class PowerConnectionReceiver extends BroadcastReceiver {
public PowerConnectionReceiver(){
}
#Override
public void onReceive(Context context, Intent batteryStatus) {
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS,
-1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
||
status == BatteryManager.BATTERY_STATUS_FULL;
if (isCharging) {
plug.setText("CHARGING");
} else {
plug.setText("NOT CHARGING");
}
int health =
batteryStatus.getIntExtra(BatteryManager.EXTRA_HEALTH,0);
batteryplus.setText(ConvoHealth(health));
String technology =
batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY);
setting.setText(technology);
float tpr = ((float)
batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE,0)) / 10.0f;
temp.setText( String.valueOf(tpr) + "°C / " +
String.valueOf(tpr*1.8+32)+"F"+"\n");
int voltage =
batteryStatus.getIntExtra(BatteryManager.EXTRA_VOLTAGE,0);
charging.setText(voltage+ " mV");
int mah = batteryStatus.getIntExtra(String.valueOf
(BatteryManager.BATTERY_PROPERTY_CAPACITY),0);
battery.setText(mah+ " Mah");
}
}
private String ConvoHealth(int health){
String result;
switch(health){
case BatteryManager.BATTERY_HEALTH_COLD:
result = "COLD";
break;
case BatteryManager.BATTERY_HEALTH_DEAD:
result = "DEAD";
break;
case BatteryManager.BATTERY_HEALTH_GOOD:
result = "GOOD";
break;
case BatteryManager.BATTERY_HEALTH_OVERHEAT:
result = "OVERHEAT";
break;
case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
result = "OVER VOLTAGE";
break;
case BatteryManager.BATTERY_HEALTH_UNKNOWN:
result = "UNKNOWN";
break;
case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
result = "UNSPECIFIED_FAILURE";
break;
default:
result = "Unknown";
}
return result;
}
}
This is my AndroidManifest.xml file
This is Runtime exception
The reason you are getting this exception is because of following line:
String technology =
batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY);
setting.setText(technology);
The above line is throwing null pointer. This extra is only available for Intent.ACTION_BATTERY_CHANGED. So either remove it or add condition
if(intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)){
String technology =
batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY);
setting.setText(technology);
setting.setText(technology);
}

how to know if tag is present?

Good morning, I would like to use the write method I found on the page: https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc.html, to write on an ultralight mifare. I have not yet succeeded.
public void writeTag(Tag tag, String tagText) {
MifareUltralight ultralight = MifareUltralight.get(tag);
try {
ultralight.connect();
ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII")));
ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII")));
ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII")));
ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII")));
} catch (IOException e) {
Log.e(TAG, "IOException while closing MifareUltralight...", e);
} finally {
try {
ultralight.close();
} catch (IOException e) {
Log.e(TAG, "IOException while closing MifareUltralight...", e);
}
}
}
How do I call it from the main?
I think it would be necessary to insert a button to check if the tag is present.
I added the "foreground dispatch system" to my activity (not the main activity) but I still do not understand how to make a message appear if the tag is present or not, what to check before using read and write methods?
package com.example.administrator.myapplication3;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareUltralight;
import android.nfc.tech.Ndef;
import android.nfc.tech.NfcA;
import android.nfc.tech.NfcB;
import android.nfc.tech.NfcF;
import android.nfc.tech.NfcV;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.IOException;
import java.nio.charset.Charset;
public class DisplayMessageActivity extends AppCompatActivity {
private NfcAdapter mAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
// Get the Intent that started this activity and extract the string
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Capture the layout's TextView and set the string as its text
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(message);
pendingIntent = PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
mAdapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// Setup an intent filter for all MIME based dispatches
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
IntentFilter td = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
mFilters = new IntentFilter[] {
ndef, td
};
// Setup a tech list for all NfcF tags
mTechLists = new String[][] { new String[] { MifareUltralight.class.getName(), Ndef.class.getName(), NfcA.class.getName()}};
Button b = (Button) findViewById(R.id.button2);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TextView tv = (TextView) findViewById(R.id.textView);
Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
tv.setText("Click!");
//byte[] x=tag.getId();
writeTag(tag,"x");
Log.e(TAG,"cc");
}
});
}
#Override
public void onResume()
{
super.onResume();
mAdapter.enableForegroundDispatch(this, pendingIntent, mFilters, mTechLists);
}
#Override
public void onPause()
{
super.onPause();
mAdapter.disableForegroundDispatch(this);
}
#Override
public void onNewIntent(Intent intent){
// fetch the tag from the intent
Tag t = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
// String tlist = getTechList(t);
// android.util.Log.v("NFC", "Discovered tag ["+tlist+"]["+t+"] with intent: " + intent);
// android.util.Log.v("NFC", "{"+t+"}");
}
public void writeTag(Tag tag, String tagText) {
MifareUltralight ultralight = MifareUltralight.get(tag);
try {
ultralight.connect();
ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII")));
ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII")));
ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII")));
ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII")));
} catch (IOException e) {
Log.e(TAG, "IOException while closing MifareUltralight...", e);
} finally {
try {
ultralight.close();
} catch (IOException e) {
Log.e(TAG, "IOException while closing MifareUltralight...", e);
}
}
}
public String readTag(Tag tag) {
MifareUltralight mifare = MifareUltralight.get(tag);
try {
mifare.connect();
byte[] payload = mifare.readPages(4);
return new String(payload, Charset.forName("US-ASCII"));
} catch (IOException e) {
Log.e(TAG, "IOException while writing MifareUltralight message...", e);
} finally {
if (mifare != null) {
try {
mifare.close();
}
catch (IOException e) {
Log.e(TAG, "Error closing tag...", e);
}
}
}
return null;
}
}
Thanks!
onNewIntent(Intent intent) gets called as soon as a new NFC tag is scanned. So for example, if you wanted to write onto every scanned tag, your onNewIntent() method would look like this:
//This method is called whenever a new tag is scanned while the activity is running
//Whatever you want to do with scanned tags, do it in here
#Override
public void onNewIntent(Intent intent){
// fetch the tag from the intent
Tag tag = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//Write a String onto the tag
writeTag(tag, "Put any string here");
}
Your writeTag method of course is still not using the String its been given, but you probably know that.
If you want to instead keep a boolean up to date that you can check for available tags, do the following:
#Override
public void onNewIntent(Intent intent){
(new Thread(new Runnable() {
#Override
public void run() {
// fetch the tag from the intent
Tag tag = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareUltralight myTag = MifareUltralight.get(tag);
/* Alternative to MifareUltralight:
NfcA myTag = NfcA.get(tag);
*/
myTag.connect();
while(true){
//someBoolean is just a Boolean that you can use in other threads to ask if tag is still there
someBoolean = true;
//Keep reading the tag until it ends in an exception
//when the exception occurs, you know the tag is gone
try{
myTag.transceive(new byte[] {
(byte) 0xXX, // READ command for your tag here
(byte) 0xXX, // Address of serial or UID field of your tag here
});
}catch(IOException e){
myTag.disconnect();
break;
}
}
//When loop breaks, the tag is gone, so we set the variable back to false
someBoolean = false;
}
})).start();
}
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.NfcA</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.Ndef</tech>
</tech-list>
</resources>
This is what my xml file looks like. MifareUltralight and NfcA are pretty much interchangable. Just use NfcA and it should work.

Android: how do you disable that your app reopens when scanning a NFC tag?

I'm writing an android application that reads data from a Mifare Classic card (4k). I have edited my AndroidManifest.xml file so that the app gets started (or I can choose another app that uses NFC). But when my app is openend and I hold my card next to my phone, it gives the popup again where I can choose which app to open. After some research I have found that I need to edit the function: onNewIntent, because this is the function that gets called when you scan a tag when your app is running.
This is my code: (When I scan my card, the toast on the second line of the handleIntent function reads: ACTION_TECH_DISCOVERED.)
package be.khleuven.aanwezigheidssysteem;
import android.app.Activity;
import android.app.PendingIntent;
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.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import android.content.IntentFilter.MalformedMimeTypeException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Login extends Activity {
public static final String MIME_TEXT_PLAIN = "text/plain";
public static final String TAG = "NfcDemo";
private TextView mTextView;
private NfcAdapter mNfcAdapter;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mTextView = (TextView) findViewById(R.id.textView_explanation);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
// Stop here, we definitely need NFC
Toast.makeText(this, "This device doesn't support NFC.", Toast.LENGTH_LONG).show();
//finish();
return;
}
if (!mNfcAdapter.isEnabled()) {
mTextView.setText("NFC is disabled.");
} else {
mTextView.setText(R.string.explanation);
}
handleIntent(getIntent());
}
#Override
protected void onResume() {
super.onResume();
/**
* It's important, that the activity is in the foreground (resumed). Otherwise
* an IllegalStateException is thrown.
*/
setupForegroundDispatch(this, mNfcAdapter);
}
#Override
protected void onPause() {
/**
* Call this before onPause, otherwise an IllegalArgumentException is thrown as well.
*/
stopForegroundDispatch(this, mNfcAdapter);
super.onPause();
}
#Override
public void onNewIntent(Intent intent) {
/**
* This method gets called, when a new Intent gets associated with the current activity instance.
* Instead of creating a new activity, onNewIntent will be called. For more information have a look
* at the documentation.
*
* In our case this method gets called, when the user attaches a Tag to the device.
*/
handleIntent(intent);
}
private void handleIntent(Intent intent) {
String action = intent.getAction();
Toast.makeText(this, action, Toast.LENGTH_LONG).show();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
String type = intent.getType();
if (MIME_TEXT_PLAIN.equals(type)) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
new NdefReaderTask().execute(tag);
} else {
Log.d(TAG, "Wrong mime type: " + type);
}
} else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
Toast.makeText(this, "Ze zijn gelijk", Toast.LENGTH_LONG).show();
// In case we would still use the Tech Discovered Intent
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = tag.getTechList();
String searchedTech = Ndef.class.getName();
for (String tech : techList) {
if (searchedTech.equals(tech)) {
new NdefReaderTask().execute(tag);
break;
}
}
TextView t = (TextView) findViewById(R.id.textView_explanation);
t.setText("Mooi kaartje heb je daar");
}
else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) {
// In case we would still use the Tech Discovered Intent
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = tag.getTechList();
String searchedTech = Ndef.class.getName();
for (String tech : techList) {
if (searchedTech.equals(tech)) {
new NdefReaderTask().execute(tag);
break;
}
}
}
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
TextView textView = (TextView) findViewById(R.id.textView_explanation);
textView.setText("Hello NFC tag!");
} else {
// ignore
}
}
public static void setupForegroundDispatch(final Activity activity, NfcAdapter adapter) {
final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0);
IntentFilter[] filters = new IntentFilter[1];
String[][] techList = new String[][]{};
// Notice that this is the same filter as in our manifest.
filters[0] = new IntentFilter();
filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
filters[0].addCategory(Intent.CATEGORY_DEFAULT);
try {
filters[0].addDataType(MIME_TEXT_PLAIN);
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("Check your mime type.");
}
adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
}
public static void stopForegroundDispatch(final Activity activity, NfcAdapter adapter) {
adapter.disableForegroundDispatch(activity);
}
private class NdefReaderTask extends AsyncTask<Tag, Void, String> {
#Override
protected String doInBackground(Tag... params) {
Tag tag = params[0];
Ndef ndef = Ndef.get(tag);
if (ndef == null) {
// NDEF is not supported by this Tag.
return null;
}
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
NdefRecord[] records = ndefMessage.getRecords();
for (NdefRecord ndefRecord : records) {
if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
try {
return readText(ndefRecord);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unsupported Encoding", e);
}
}
}
return null;
}
}
}
You already registered for the foreground dispatch system. This is how you would typically give your app precedence over other registered apps while it is the foreground application. However, you only registered the foreground dispatch for tags that contain an NDEF message that starts with a Text record (or a MIME type record of type text/plain), which seems not to apply to your tag:
filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
filters[0].addCategory(Intent.CATEGORY_DEFAULT);
filters[0].addDataType(MIME_TEXT_PLAIN);
Instead, you could register to catch just any tag with the foreground dispatch system (you can later silently drop tags that you are not interested in):
public static void setupForegroundDispatch(final Activity activity, NfcAdapter adapter) {
final Intent intent = new Intent(activity, activity.getClass());
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
final PendingIntent pendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
adapter.enableForegroundDispatch(activity, pendingIntent, null, null);
}
Alternatively, you could register for a more specific type using the last two parameters of the NfcAdapter.enableForegroundDispatch() method.

Read tag NFC ID from foreground dispatch

I am trying to read an NFC tag ID. I know I wont be able to read the data as it is a secure tag (MBTA Fare card). I would like to read the tags unique ID and toast that value. I have successfully gotten the NFC intent to work, so that when a tag is scanned my app attempts to handle it. However app does not show the toast with the tag id.
package com.example.nfctest;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.NfcF;
import android.os.Bundle;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
private NfcAdapter mAdapter;
private PendingIntent mPendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
private int mCount = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = NfcAdapter.getDefaultAdapter(this);
// Create a generic PendingIntent that will be deliver to this activity. The NFC stack
// will fill in the intent with the details of the discovered tag before delivering to
// this activity.
mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// Setup an intent filter for all MIME based dispatches
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
mFilters = new IntentFilter[] {
};
// Setup a tech list for all NfcF tags
mTechLists = new String[][] { new String[] { NfcF.class.getName() } };
}
public void onResume() {
super.onResume();
mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists);
}
#Override
public void onNewIntent(Intent intent) {
Log.i("Foreground dispatch", "Discovered tag with intent: " + intent);
CharSequence text = ("Discovered tag " + ++mCount + " with intent: " + intent);
int duration = Toast.LENGTH_SHORT;
Tag myTag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Toast toast = Toast.makeText(MainActivity.this,myTag.getId().toString() , duration);
toast.show();
}
#Override
public void onPause() {
super.onPause();
//mAdapter.disableForegroundDispatch(this);
throw new RuntimeException("onPause not implemented to fix build");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
It no longer crashes, just doesn't do the toast with the ID.
I strongly recommend this this sample application in this link. Don't give yourself pain by trying everything to succeed easy operations, as I did.
You probably doing something wrong in placements of operations in onResume and onNewIntent. However, in the example I linked you, it has controls for new tag and ndef in both onResume and onNewIntent. If you really want to go on your own project, try this.

connection to a NFC-tag in an android app

I'm trying to write an android app for may Nexus S that is able to write a simple Text Record on a NFC-Tag. My problem is the connection-establishment to the NFC-Tag.
I've implemented two activities called "TagWriter" & "TagWriterStartPage".
Here ist the "TagWriter"-activity:
package nfc.example.writer;
import java.util.Locale;
import com.google.common.base.Charsets;
import com.google.common.primitives.Bytes;
import android.app.Activity;
import android.content.Intent;
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.Bundle;
import android.view.View;
import android.widget.Button;
public class TagWriter extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.tagwriter);
Intent intent = this.getIntent();
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
writeTag(tag);
}
private void writeTag(Tag t)
{
Ndef tag = Ndef.get(t);
Locale locale = Locale.US;
final byte[] langBytes = locale.getLanguage().getBytes(Charsets.US_ASCII);
String text = "Tag, you're it!";
final byte[] textBytes = text.getBytes(Charsets.UTF_8);
final int utfBit = 0;
final char status = (char) (utfBit + langBytes.length);
final byte[] data = Bytes.concat(new byte[] {(byte) status}, langBytes, textBytes);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data);
try
{
NdefRecord[] records = {record};
NdefMessage message = new NdefMessage(records);
tag.connect();
boolean connected = tag.isConnected();
boolean writeable = tag.isWritable();
if( connected && writeable)
{
tag.writeNdefMessage(message);
}
tag.close();
}
catch (Exception e)
{
//do error handling
}
}
}
The activity "TagWriter" is called when I put my device on the NFC-tag. Everytime the method "tag.connect()" is called, there occures an exception.
Can anyone help me to solve the problem???
Thanks,
Dennis
this might work better:
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(tag);
if (ndef != null) {
ndef.connect();
ndef.writeNdefMessage(message);
} else {
NdefFormatable format = NdefFormatable.get(tag);
if (format != null) {
format.connect();
format.format(message);
}
}
need other checks in there for real use (capacity, writable etc) - but that is bare bones..

Categories

Resources