I have an application where I am supposed to scan NFC tags and Call different functions depending on the tag result, but every time I scan an NFC on my phone the default Android reader pops up and the app doesnt recognize it, is there a way I can override the default reader and let the application scan the NFC instead?
ValueNotifier<dynamic> result = ValueNotifier(null);
void _tagRead() {
NfcManager.instance.startSession(
onDiscovered: (NfcTag tag) async {
result.value = tag.data;
if(result.value.toString().toLowerCase()=="main " || result.value.toString().toLowerCase()=="it" || result.value.toString().toLowerCase()=="eng"){
addRecord(result.value.toString());
}
else{
registerAttendance(result.value.toString());
}
NfcManager.instance.stopSession();
});
}
Related
In my app for Zebra MC330M I use EMDK: Zebra Technologies Corp:EMDK APIs:26
I have a activity that implements listener and I override onOpened function:
#Override
public void onOpened(EMDKManager emdkManager) {
this.emdkManager = emdkManager;
try {
initializeScanner();
} catch (ScannerException e) {
Log.e("ON_OPENED", e.getMessage());
e.printStackTrace();
}
}
And as documentation said in Link: Basic Scanning Tutorial using Barcode API - Zebra Technologies Techdocs
I put in the initializeScanner function:
if (scanner == null) {
// Get the Barcode Manager object
barcodeManager = (BarcodeManager) emdkManager.getInstance(FEATURE_TYPE.BARCODE);
// Add connection listener
if (barcodeManager != null) {
barcodeManager.addConnectionListener(this);
}
// Get default scanner defined on the device
scanner = barcodeManager.getDevice(BarcodeManager.DeviceIdentifier.DEFAULT);
// Add data and status listeners
scanner.addDataListener(this);
scanner.addStatusListener(this);
// Hard trigger. When this mode is set, the user has to manually
// press the trigger on the device after issuing the read call.
scanner.triggerType = TriggerType.HARD;
// Enable the scanner
scanner.enable();
startRead = true;
}
But when call scanner.enable() it throws
ScannerException
exception with message:
"Failure"
But seems that error is shown only in debug mode when I try to compile my app and launch when device is standby mode or when the device is in standby for many time.
Someone else has this problem?
This is how usually an NFC tag is detected in my app:
protected void onNewIntent(Intent intent) {
if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
Tag nfcTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
...
}
}
Now I need to also listen if an NFC tag is held close to the reader for a long time (about 3 seconds). In that case I want to do something else (similar to distinguishing between a normal press and a longpress on a view). Is this possible?
The method
isConnected()
tells you whether the connection to the tag ist still alive. If you check the connection periodically, you can detect a long connection.
The concept behind NFC is to quickly exchange small amounts of data between a tag and an NFC device (or two NFC devices) and not to detect the duration of an interaction. Consequently, there is no dedicated event that lets you distinguish between short and slightly longer interactions.
As corvairjo wrote, you could connect to the tag and check if the tag is still connected after a certain amount of time (e.g. 3 seconds). However, you can only measure the time from the point where your app is notified about the tag (i.e. after onNewIntent() was invoked). You can't measure the time that Android needed to notify your app after the user actually scanned the tag.
Note that isConnected() on its own is not reliable for all device/tag combinations. The most reliable way to test if a tag is still present would be to send a valid command to the tag and check if you get a response:
new AsyncTask<Tag, Void, Boolean>() {
protected Boolean doInBackground(Tag... tags) {
try {
Thread.sleep(3000);
// test if tag is still connected
Ndef ndef = Ndef.get(tags[0]);
if (ndef != null) {
try {
ndef.connect();
ndef.getNdefMessage();
} finally {
ndef.close();
}
return Boolean.TRUE;
}
} catch (Exception e) {
}
return Boolean.FALSE;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
// "long press" event
}
}
}.execute(tag);
If your tag supports NDEF (the Ndef tag technology) you could simply query the tag for its NDEF message using Ndef.getNdefMessage() (see above). If your tag does not support NDEF, you would first need to find out what commands your tag supports and then send such a command using the proper tag technology.
E.g. if your tag is an MIFARE Ultralight or NTAG tag (or any NFC Forum Type 2 tag), you could use:
// test if tag is still connected
NfcA nfca = NfcA.get(tags[0]);
if (nfca != null) {
try {
nfca.connect();
byte[] response = nfca.transceive(new byte[] { (byte)0x30, (byte)0x00 });
if ((response != null) && (response.length > 0))
return Boolean.TRUE;
}
} finally {
ndef.close();
}
}
I am using the phonegap-nfc plugin to read NFC tags in my cordova app. I also included the uses-permission tags in the AndroidManifest.xml.
My Typescript-Code is:
module myapp.nfcRead {
export class NfcCtrl {
private status:string;
constructor(private $cordovaNfc:any, private $cordovaNfcUtil:any) {
this.status = "nfc";
}
public readNFC() {
console.log("trying to find nfc");
this.$cordovaNfc.then((nfcInstance:any) => {
nfcInstance.addNdefListener((nfcEvent:any) => {
this.status = "NFC Detected";
})
.then(
//Success callback
(event:any) => {
this.status = "Reading NFC";
console.log("Reading NFC");
},
//Fail callback
(err:any) => {
this.status = "error";
console.log("error");
});
});
this.$cordovaNfcUtil.then((nfcUtil:any) => {
this.status = nfcUtil.bytesToString("some bytes");
});
}
}
NfcCtrl.$inject = ['$cordovaNfc', '$cordovaNfcUtil'];
angular.module('myapp.nfcRead', ['ngCordova.plugins.nfc']).controller('NfcCtrl', NfcCtrl);}
If i start the App in the browser and i call the method "readNFC()" the status remains "nfc". If i deploy the app on my android phone and i call the "readNFC()"-function and NFC is disabled, the status is "error". After activating NFC and calling the function again, it says "Reading NFC". Now i want to read NFC tags, but the status doesn't change. (no event is raised)
I downloaded an app from the Google Play Store to see if tags are discovered:
(app: NFC Tools)
NFC Tools output
Do you have any tip for me?
Thank you
Your code is using nfc.addNdefListener which will only find tags that contain NDEF messages.
The screenshot from NFC Tools says your tag is NDEF Formatable, so I don't think it contains an NDEF message.
You can change your code to use nfc.addTagDiscoveredListener or nfc.addNdefFormatableListener. It's fine to have multiple listeners. Android will call the most specific listener for the tag that is scanned.
Alternately, you can use NFCTools to write an NDEF message onto the tag. Then try reading it with your exiting code.
Is there a way to check at run time whether a device has an NFC reader? My app uses NFC to perform a task, but if no reader is present, it can perform the same task by using a button.
Hope This works for you
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter = manager.getDefaultAdapter();
if (adapter != null && adapter.isEnabled()) {
//Yes NFC available
}else if(adapter != null && !adapter.isEnabled()){
//NFC is not enabled.Need to enable by the user.
}else{
//NFC is not supported
}
The simplest way to check if an Android device has NFC functionality is to check for the system feature PackageManager.FEATURE_NFC ("android.hardware.nfc"):
PackageManager pm = context.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
// device has NFC functionality
}
However, there exist devices (at least one of Sony's first Android NFC smartphones has this issue) that do not properly report the FEATURE_NFC. (That's those devices that do not allow you to install apps that require NFC functionality through Play Store does such a check for apps that require NFC.)
Therefore, the more reliable solution is the one described by Sainath Patwary karnate. To check if a device has NFC functionality (or rather if a device has a running NFC service), you can use:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
if (nfcAdapter != null) {
// device has NFC functionality
}
If you also want to check if the user enabled NFC on their device, you may use the NfcAdapter's isEnabled() method. But be warned that it's not always as easy as described by Sainath Patwary karnate. Particularly on Android 4.0.*, the isEnabled() method sometimes throws undocumented exceptions when the NFC service had crashed before, so you might want to catch those exceptions. Moreover, on Android >= 2.3.4 and < 4.1 (I could not reproduce the problem on later versions but that does not mean it is not there!), the first call to isEnabled() after the NFC service had been stopped or crashed always returned false, so it is advisable to always ignore the result of the first call of isEnabled().
if (nfcAdapter != null) {
try {
nfcAdapter.isEnabled();
} catch (Exception e) {}
bool isEnabled = false;
try {
isEnabled = nfcAdapter.isEnabled();
} catch (Exception e) {}
if (isEnabled) {
// NFC functionality is available and enabled
}
}
Here's my function that I use for detecting NFC presence.
public static boolean deviceHasNfc() {
// Is NFC adapter present (whether enabled or not)
NfcManager nfcMgr = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
if (manager != null) {
NfcAdapter adapter = manager.getDefaultAdapter();
return adapter != null;
}
return false;
}
As stated in #Sainath's answer you can also detect if the NFC is enabled using adapter.isEnabled()
For those of you doing Kotlin here is a quick enabled check extension following the rules posted above
fun Context.isNfcEnabled(): Boolean {
val nfcAdapter = NfcAdapter.getDefaultAdapter(this)
if (nfcAdapter != null) {
return try {
nfcAdapter.isEnabled
} catch (exp: Exception) {
// Double try this as there are times it will fail first time
try {
nfcAdapter.isEnabled
} catch (exp: Exception) {
false
}
}
}
return false
}
I am wondering when exactly the NFC Service is started and stopped.
The source code for android 4.0.3 seems to state that the polling is dependent on a single constant (located in NfcService.java)
/** minimum screen state that enables NFC polling (discovery) */
static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
I would interpret this as "the screen light is on, therefore the nfc service is active".
BUT when the screen is locked, a NFC Tag wont be recognized, altough the screen is lit.
So I am curious: Is the NFC Service already deactivated when the lock screen appears, or is it still running but not processing the Tags?
Actually, I do not think that NFC Service is deactivated. When the screen has lower value then SCREEN_STATE_ON_UNLOCKED a device stops to ask NFC tags around. You can see this from this code:
// configure NFC-C polling
if (mScreenState >= POLLING_MODE) {
if (force || !mNfcPollingEnabled) {
Log.d(TAG, "NFC-C ON");
mNfcPollingEnabled = true;
mDeviceHost.enableDiscovery();
}
} else {
if (force || mNfcPollingEnabled) {
Log.d(TAG, "NFC-C OFF");
mNfcPollingEnabled = false;
mDeviceHost.disableDiscovery();
}
}
But NFC-EE routing is enabled util screen state is higher then SCREEN_STATE_ON_LOCKED:
// configure NFC-EE routing
if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
if (force || !mNfceeRouteEnabled) {
Log.d(TAG, "NFC-EE ON");
mNfceeRouteEnabled = true;
mDeviceHost.doSelectSecureElement();
}
} else {
if (force || mNfceeRouteEnabled) {
Log.d(TAG, "NFC-EE OFF");
mNfceeRouteEnabled = false;
mDeviceHost.doDeselectSecureElement();
}
}
The service itself is started and stopped in other parts of this class.
See related http://forum.xda-developers.com/showthread.php?t=1712024&page=14