/***************************************************************************
*
* This file is part of the 'NDEF Tools for Android' project at
* http://code.google.com/p/ndef-tools-for-android/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
****************************************************************************/
package org.ndeftools;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
/**
*
* Abstract {@link Activity} for detecting incoming NFC messages.<br/><br/>
*
* - detects whether NFC is available (if device has NFC chip).<br/>
* - detect whether NFC setting is on or off, and whether it changes from off to on or on to off.<br/>
* - detect incoming data tags or beams.<br/>
*
* @author Thomas Rorvik Skjolberg
*
*/
public abstract class NfcDetectorActivity extends FragmentActivity {
private static final String TAG = NfcDetectorActivity.class.getName();
protected NfcAdapter nfcAdapter;
protected IntentFilter[] writeTagFilters;
protected PendingIntent nfcPendingIntent;
protected boolean foreground = false;
protected boolean intentProcessed = false;
protected boolean nfcEnabled = false;
protected boolean detecting = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
// Check for available NFC Adapter
PackageManager pm = getPackageManager();
if(pm != null && !pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
Log.d(TAG, "NFC feature not found");
onNfcFeatureNotFound();
} else {
Log.d(TAG, "NFC feature found");
onNfcFeatureFound();
}
}
/**
* Notify that NFC is available
*/
protected void onNfcFeatureFound() {
initializeNfc();
detectInitialNfcState();
}
/**
*
* Initialize Nfc fields
*
*/
protected void initializeNfc() {
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
IntentFilter techDetected = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
writeTagFilters = new IntentFilter[] {ndefDetected, tagDetected, techDetected};
}
/**
*
* Detect initial NFC state.
*
*/
protected void detectInitialNfcState() {
nfcEnabled = nfcAdapter.isEnabled();
if(nfcEnabled) {
Log.d(TAG, "NFC is enabled");
onNfcStateEnabled();
} else {
Log.d(TAG, "NFC is disabled"); // change state in wireless settings
onNfcStateDisabled();
}
}
/**
*
* NFC feature was found and is currently enabled
*
*/
protected abstract void onNfcStateEnabled();
/**
*
* NFC feature was found but is currently disabled
*
*/
protected abstract void onNfcStateDisabled();
@Override
protected void onResume() {
super.onResume();
if(nfcAdapter != null) {
// enable foreground mode if nfc is on and we have started detecting
boolean enabled = nfcAdapter.isEnabled();
if(enabled && detecting) {
enableForeground();
}
detectNfcStateChanges();
}
if(!intentProcessed) {
intentProcessed = true;
processIntent();
}
}
/**
*
* NFC setting changed since last check. For example, the user enabled NFC in the wireless settings.
*
*/
protected abstract void onNfcStateChange(boolean enabled);
/**
*
* Detect changes in NFC settings - enabled/disabled
*
*/
protected void detectNfcStateChanges() {
boolean enabled = nfcAdapter.isEnabled();
if(nfcEnabled != enabled) {
onNfcStateChange(enabled);
nfcEnabled = enabled;
}
}
@Override
protected void onPause() {
super.onPause();
if(nfcAdapter != null) {
disableForeground();
}
}
@Override
public void onNewIntent(Intent intent) {
Log.d(TAG, "onNewIntent");
// onResume gets called after this to handle the intent
intentProcessed = false;
setIntent(intent);
}
protected void enableForeground() {
if(!foreground) {
Log.d(TAG, "Enable nfc forground mode");
nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
foreground = true;
}
}
/**
*
* Start detecting NDEF messages
*
*/
protected void startDetecting() {
if(!detecting) {
enableForeground();
detecting = true;
}
}
/**
*
* Stop detecting NDEF messages
*
*/
protected void stopDetecting() {
if(detecting) {
disableForeground();
detecting = false;
}
}
protected void disableForeground() {
if(foreground) {
Log.d(TAG, "Disable nfc forground mode");
nfcAdapter.disableForegroundDispatch(this);
foreground = false;
}
}
/**
*
* Process the current intent, looking for NFC-related actions
*
*/
public void processIntent() {
Intent intent = getIntent();
// Check to see that the Activity started due to an Android Beam
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
Log.d(TAG, "Process NDEF discovered action");
nfcIntentDetected(intent, NfcAdapter.ACTION_NDEF_DISCOVERED);
} else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Log.d(TAG, "Process APP_TAG discovered action");
nfcIntentDetected(intent, NfcAdapter.ACTION_TAG_DISCOVERED);
} else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
Log.d(TAG, "Process TECH discovered action");
nfcIntentDetected(intent, NfcAdapter.ACTION_TECH_DISCOVERED);
} else {
Log.d(TAG, "Ignore action " + intent.getAction());
}
}
/**
*
* Launch an activity for nfc (or wireless) settings, so that the user might enable or disable nfc
*
*/
protected void startNfcSettingsActivity() {
if (android.os.Build.VERSION.SDK_INT >= 16) {
startActivity(new Intent(android.provider.Settings.ACTION_NFC_SETTINGS));
} else {
startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS));
}
}
/**
*
* Incoming NFC communication (in form of tag or beam) detected
*
*/
protected abstract void nfcIntentDetected(Intent intent, String action);
/**
*
* This device does not have NFC hardware
*
*/
protected abstract void onNfcFeatureNotFound();
public boolean isDetecting() {
return detecting;
}
public void setDetecting(boolean detecting) {
this.detecting = detecting;
}
}