i'm completely new to android development and have to write a simple app for reading an nfc tag (with nexus s) for university.
my problem is that when the nexus discoveres a tag, my app is not listed in the "select an action"-popup. the aim is to read tags using the foreground-dispatch method as described in http://developer.android.com/guide/topics/nfc/index.html and http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/nfc/ForegroundDispatch.html
i think there's something missing in the manifest, but i don't know what. here's the manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.iforge.android.nfc"
>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
>
<activity android:name=".simulator.FakeTagsActivity"
android:theme="@android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="TagViewer"
android:theme="@android:style/Theme.NoTitleBar"
>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<data android:mimeType="mime/type" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="10" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
here's the code of the activity that should be called when a tag is discovered (which is build out of the android NFCDemo as well as the ForegroundDispatch-example):
public class TagViewer extends Activity
{
WebView webView;
private NfcAdapter mAdapter;
private PendingIntent mPendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mAdapter = NfcAdapter.getDefaultAdapter(this);
mPendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* Handles all MIME based dispatches.
You should specify only the ones that you need. */
}
catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
mFilters = new IntentFilter[] {
ndef,
};
mTechLists = new String[][] { new String[] { NfcF.class.getName() } };
setContentView(R.layout.tag_viewer);
webView = (WebView) findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
webView.getSettings().setPluginsEnabled(false);
webView.getSettings().setSupportMultipleWindows(false);
webView.getSettings().setSupportZoom(false);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
resolveIntent(getIntent());
}
@Override
public void onResume() {
super.onResume();
mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists);
}
@Override
public void onPause() {
super.onPause();
mAdapter.disableForegroundDispatch(this);
}
void resolveIntent(Intent intent)
{
// Parse the intent
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action))
{
// When a tag is discovered we send it to the service to be save. We
// include a PendingIntent for the service to call back onto. This
// will cause this activity to be restarted with onNewIntent(). At
// that time we read it from the database and view it.
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs;
if (rawMsgs != null)
{
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++)
{
msgs[i] = (NdefMessage) rawMsgs[i];
}
}
else
{
// Unknown tag type
byte[] empty = new byte[] {};
NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty, empty, empty);
NdefMessage msg = new NdefMessage(new NdefRecord[] {record});
msgs = new NdefMessage[] {msg};
}
// Setup the web-view
setUpWebView(msgs);
}
else
{
Log.e("ViewTag", "Unknown intent " + intent);
finish();
return;
}
}
void setUpWebView(NdefMessage[] msgs)
{
if (msgs == null || msgs.length == 0) return;
String urlToLoad = MessageParser.parseMessage(msgs[0]);
if(!urlToLoad.matches("")) webView.loadUrl(urlToLoad);
}
@Override
public void onNewIntent(Intent intent)
{
setIntent(intent);
resolveIntent(intent);
Log.i("Foreground dispatch", "Discovered tag with intent: " + intent);
}
}
i tried a lot, but nothing works. it would be great if anyone can tell me what i'm missing. i'm running out of time :-(
please
thanks
Foreground dispatch explicitly requires the use of an Activity that's properly configured: it doesn't look like you can use IntentFilter
s set up in the AndroidManifest.xml for foreground dispatch (your app must actually be in the foreground, i.e. running). The code below appears to work correctly (I just tested it) in case you're still interested (ACTION_TAG_DISCOVERED
was what I was watching for):
private NfcAdapter mAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.main);
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 (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[] {
NfcV.class.getName(),
NfcF.class.getName(),
NfcA.class.getName(),
NfcB.class.getName()
} };
}
@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+"}");
}