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
}
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();
}
}
Is it possible to force android to check if an NFC tag is near? I'm only able to read the tag when android detects it, I would like to force it to check if a tag is near at a specific moment
What you want to do is in general not possible. However if you can live with a dirty hack the following will work (thanks to unspecified behaviour):
First disable the reader-mode of all supported tag types. This brings the NFC subsystem into a clean state, e.g. it makes sure that the NFC controller will have no connection to the tag.
Once done restore the reader-mode again. If a tag is present at that moment you will get the usual discovery action as an intent. It may take a second or two though.
Control of the reader-mode is possible using NfcAdapter.enableReaderMode and NfcAdapter.disableReaderMode
I figured out a bit of a hack for this that works (for me, at least!)
First, when you initially detect the tag via the android.nfc.action.NDEF_DISCOVERED, get the tag as a field in your class and start a timer (this is in C#/Xamarin but the same should apply for Java):
_tag = Intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
ReaderTimer = new Timer(2000);
ReaderTimer.Elapsed += TimerElapsed;
ReaderTimer.Start();
Now, every 2 seconds this will fire. It will attempt to reconnect to the tag. If it can't the tag is gone.:
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
if (_tag == null)
{
return;
}
Ndef ndef = Ndef.Get(_tag);
if (ndef == null)
{
// NDEF is not supported by this Tag.
return;
}
if (!ndef.IsConnected)
{
try
{
ndef.Close();
ndef.Connect();
}
catch (Exception ex)
{
// could not reconnect
// implies tag is not in proximity
//do whatever needs to be done when NFC is disconnected
ReaderTimer.Stop();
}
}
}
I've tested this with API 14.
Unfortunately when the screen is turned off ndef.Connect() fails, so that is registered as a disconnect.
Try this code and it works ! It will continuously check if the NFC tag is near to the phone or not.
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
readFromIntent(intent);
if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())){
myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
checkNFCStatus();
handler.postDelayed(this,1000);
}
}, 1000);
}
}
public void checkNFCStatus(){
try {
if(myTag != null) {
Ndef ndefTag = Ndef.get(myTag);
ndefTag.connect();
if (ndefTag.isConnected()) {
Log.d("network", "NFC connected");
} else {
Log.d("network", "NFC disconnected");
}
ndefTag.close();
}
} catch (IOException e) {
e.printStackTrace();
Log.d("network", "NFC disconnected");
}
}
//If the connection is not closed, an exception will be thrown
My friend and I are developing an app that streams synchronized music between android devices using wifi-direct. Our issue is that while the app works fairly well once phones are connected, it takes some doing to get phones to connect because on all AOSP devices it appears that wifi direct is only turned on upon entering the wifi direct menu (and immediately closed upon exiting). This makes in-application connection rather difficult. We were wondering if there is any way to turn on wifi direct from the code and keep it on (if anyone could refer us to a detailed description of how to do this using Reflection that would be fantastic).
Thanks! Here is our current code:
public class Reflector {
static Method turnOnICS;
static Method turnOnJB;
static Method turnOffICS;
public static void turnOnP2P(WifiP2pManager m, Channel c) {
//Log.v("button", "turnOnP2P");
if (android.os.Build.VERSION.SDK_INT == 14 || android.os.Build.VERSION.SDK_INT == 15) {
//Log.v("version", "Version is ICS");
try {
turnOnICS = WifiP2pManager.class.getDeclaredMethod("enableP2p",WifiP2pManager.Channel.class);
turnOnICS.setAccessible(true);
turnOnICS.invoke(m, c);
} catch (NoSuchMethodException e) {
Log.v("ics_error", "ICS enableP2p() not found");
} catch (Exception e) {
Log.v("ics_error", "turnOnICS invocation failure");
}
} else if (android.os.Build.VERSION.SDK_INT == 16 || android.os.Build.VERSION.SDK_INT == 17) {
//Log.v("version", "Version is JB");
try {
turnOnJB = NsdManager.class.getDeclaredMethod("setEnabled", boolean.class);
turnOnJB.setAccessible(true);
turnOnJB.invoke(NsdManager.class, true);
//must feed it an nsdmanager, but none exists in wifidirectactivity
Log.v("nsd", "problem");
} catch (NoSuchMethodException e) {
Log.v("jb_error", "JB setEnabled() not found");
} catch (Exception e) {
Log.v("jb_error", "turnOnJB invocation failure");
e.printStackTrace();
}
}
}
public static void turnOffP2P(WifiP2pManager m, Channel c) {
//Log.v("button", "turnOffP2P");
if (android.os.Build.VERSION.SDK_INT == 14 || android.os.Build.VERSION.SDK_INT == 15) {
//Log.v("version", "Version is ICS");
try {
turnOffICS = WifiP2pManager.class.getDeclaredMethod("disableP2p", WifiP2pManager.Channel.class);
turnOffICS.setAccessible(true);
turnOffICS.invoke(m, c);
} catch (NoSuchMethodException e) {
Log.v("ics_error", "ICS disableP2P() not found");
} catch (Exception e) {
Log.v("ics_error", "turnOffICS invocation failure");
}
}
}
public static void printAll(){
Method[] list = WifiP2pManager.class.getDeclaredMethods();
for(Method m : list){
Log.v("tag",m.getName());
}
}
}
Thank you for asking this question... it's been a question we've been wrestling with as we add WiFi Direct features to our app.
After looking through the settings on several phones from different manufacturers, and reading pages like this and this (which admittedly are not very precise in the details, but it's the best we could find), we've come to the conclusion that there's no need to separately turn on WiFi Direct per se: it's enabled whenever WiFi is enabled. So, at most, your app would need to turn on WiFi.
However, WiFi Direct scanning (and visibility to being scanned) is what you initiate by going to the WiFi Direct settings page.
Leaving that page may stop the scanning (though 3rd-party apps can and do initiate their own scanning), but should not disable WiFi Direct. That would make no sense at all... as you say, that would make it difficult (impossible) for apps to use WiFi Direct, but apps do use it successfully. What did you see that made it seem like WiFi Direct was being disabled when you left that settings page?
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