This question already has answers here:
How to use NFC ACTIONS
(5 answers)
Closed 3 years ago.
I made app that detects nfc tag. All work fine, when my app is closed and i scan the nfc tag with my phone it shows me an activity have onCreate() method , when i scan again for the 2nd time it works , i dont know if im wrong in the lifecycle of the app or that i missed something in my code?
when i open app , scanning is working : 1st photo
when app is closed 2nd photo : from 2nd photo but in the 2nd scan it works
this is my code
public class NfcActivity extends AppCompatActivity {
private static final String TAG = "NfcActivity";
private NfcAdapter mNfcAdapter;
private TextView mTextView;
PendingIntent pendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nfc);
mTextView = findViewById(R.id.tv_nfc_detail);
mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
if (mNfcAdapter == null) {
Toast.makeText(this, "Cet appareil ne supporte pas nfc", Toast.LENGTH_SHORT).show();
finish();
return;
}
if (!mNfcAdapter.isEnabled()) {
startActivity(new Intent("android.settings.NFC_SETTINGS"));
Toast.makeText(this, "Activer nfc", Toast.LENGTH_SHORT).show();
}
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
}
#Override
protected void onPause() {
super.onPause();
mNfcAdapter.disableForegroundDispatch(this);
}
#Override
protected void onResume() {
super.onResume();
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter[] intentFilters = new IntentFilter[]{};
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null);
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Tag iTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
mTextView.setText(TagReader.readTag(iTag, intent));
}
// }
}
}
<activity android:name=".Activities.NfcActivity" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
</activity>
Edit: see full solution in related:
How to use NFC ACTIONS
You are only processing the intent the 2nd time round.
Add a new method based on your current onNewIntent() method like this:
private void onNewNfcTag(Intent intent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Tag iTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
mTextView.setText(TagReader.readTag(iTag, intent));
}
}
Change your onNewIntent() to call this new method:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
onNewNfcTag(intent);
}
Call this same method from onCreate() with the intent from getIntent():
#Override
protected void onCreate(Bundle savedInstanceState) {
// .... your code already here
onNewNfcTag(getIntent());
}
Related
I am working on notification and I have a problem. I have an activity already open when I click on notification I don't want to open it again just update the current activity.
if (!NotificationUtils.isAppIsInBackground(getApplicationContext())) {
Intent pushNotification = null;
if (NotificationType != 0 && NotificationType != 2 && NotificationType != 5 && NotificationType != 26) {
pushNotification = new Intent(getApplication(), SplashScreen.class);
pushNotification.putExtra("NotificationType", NotificationType);
pushNotification.putExtra("ReferenceID", ReferenceID);
pushNotification.putExtra("NotificationID", ReferenceID);
pushNotification.putExtra("isread", ReferenceID);
showNotificationMessage(getApplicationContext(), title, message, time, pushNotification);
} else if (NotificationType == 0 || NotificationType == 2 || NotificationType == 5 || NotificationType == 26) {
showNotificationMessageWithNoAction(getApplicationContext(), title, message, title, null);
}
}
can Anyone tell me how I update the activity when I click on notification?
You just need to declare the launchMode to the singleTask to make ensure that multiple same screens not will open.
There are four launch modes for activity. They are:
1. Standard
2. SingleTop
3. SingleTask
4. SingleInstance
Please refer this link Click here
<activity android:name="YOUR_SPLASH_ACTIVITY"
android:launchMode="singleTask"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
And in the Java code , you just override the onNewIntent method , to refresh activity,
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
/**
* HERE YOU JUST REFRESH , YOUR ACTIVITY
*/
}
I don't know if this is what you need but you can do this
finish();
startActivity(getIntent());
Let me know what you really need.
EDIT:
If you need to keep your activity state intact, you can do this
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("MyString", "Welcome back to Android");
}
This will save your activity state
And then you retrieve UI state like this
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String myString = savedInstanceState.getString("MyString");
}
Best way is to make use of the onNewIntent(Intent) method of your Activity.
You can use the Intent parameter of this method to get your Intent Extras, because getIntent() will give the Intent that started the Activity in the first place.
public class MainActivity extends Activity {
public void onCreate(Bundle SavedInstanceState) {
//Initial loading
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if(intent.getStringExtra("methodName").equals("myMethod")) {
//Update the existing screen
}
}
}
I'm trying to make an app that monitors the users phone usage by tracking time of screen lock and unlock. I tried to setup a BroadcastReceiver which works fine when the app is running the background. But won't work when I close the app. Is there a solution for this.
The code I'm using now is as follows :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, ScreenListenerService.class);
startService(intent);
}
}
ScreenListenerService class is as follows..
public class ScreenListenerService extends Service {
private BroadcastReceiver mScreenStateBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// Save something to the server
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// Save something to the server
}
}
};
#Override
public void onCreate() {
super.onCreate();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStateBroadcastReceiver, intentFilter);
}
#Override
public void onDestroy() {
unregisterReceiver(mScreenStateBroadcastReceiver);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
My AndroidManifest file is as follows :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.abbinvarghese.calculu">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<service android:name=".ScreenListenerService" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
To overcome the imposed limitations of 8.0 you could run a foreground service. Just like a service but a notification is posted to the foreground.
Then the service code would be like this (remember to unregister the receiver onDestory):
BroadcastReceiver screenReceiver;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startRunningInForeground();
detectingDeterminateOfServiceCall(intent.getExtras());
registerBroadcastReceivers();
return START_STICKY;
}
private void startRunningInForeground() {
//if more than or equal to 26
if (Build.VERSION.SDK_INT >= 26) {
//if more than 26
if(Build.VERSION.SDK_INT > 26){
String CHANNEL_ONE_ID = "sensor.example. geyerk1.inspect.screenservice";
String CHANNEL_ONE_NAME = "Screen service";
NotificationChannel notificationChannel = null;
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null) {
manager.createNotificationChannel(notificationChannel);
}
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.background_running);
Notification notification = new Notification.Builder(getApplicationContext())
.setChannelId(CHANNEL_ONE_ID)
.setContentTitle("Recording data")
.setContentText("ActivityLog is logging data")
.setSmallIcon(R.drawable.background_running)
.setLargeIcon(icon)
.build();
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
startForeground(101, notification);
}
//if version 26
else{
startForeground(101, updateNotification());
}
}
//if less than version 26
else{
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Activity logger")
.setContentText("data recording on going")
.setSmallIcon(R.drawable.background_running)
.setOngoing(true).build();
startForeground(101, notification);
}
}
private Notification updateNotification() {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
return new NotificationCompat.Builder(this)
.setContentTitle("Activity log")
.setTicker("Ticker")
.setContentText("recording of data is on going")
.setSmallIcon(R.drawable.activity_log_icon)
.setContentIntent(pendingIntent)
.setOngoing(true).build();
}
private void detectingDeterminateOfServiceCall(Bundle b) {
if(b != null){
Log.i("screenService", "bundle not null");
if(b.getBoolean("phone restarted")){
storeInternally("Phone restarted");
}
}else{
Log.i("screenService", " bundle equals null");
}
documentServiceStart();
}
private void documentServiceStart() {
Log.i("screenService", "started running");
}
private void registerBroadcastReceivers() {
screenReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch (Objects.requireNonNull(intent.getAction())){
case Intent.ACTION_SCREEN_ON:
//or do something else
storeInternally("Screen on");
break;
case Intent.ACTION_SCREEN_OFF:
//or do something else
storeInternally("Screen off");
break;
}
}
};
IntentFilter screenFilter = new IntentFilter();
screenFilter.addAction(Intent.ACTION_SCREEN_ON);
screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(screenReceiver, screenFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(screenReceiver);
}
and call it from the main activity:
private void startServiceRunning() {
if(!isMyServiceRunning(Background.class)){
if(Build.VERSION.SDK_INT >25){
startForegroundService(new Intent(this, Background.class));
}else{
startService(new Intent(this, Background.class));
}
}
}
As Background Execution Limit imposes on Android 8.0 (API level 26) so now it's not possible to listen SCREEN_OFF and SCREEN_ON action in background by running the service.
I have found a work around for same with the help of JobScheduler which works fine for listen broadcast in background without running any service.
Please check on this: Screen OFF/ON broadcast listener without service on Android Oreo
Instead of creating a new service for broadcast receiver, you can directly create a broadcast receiver class that will listen to system broadcasts even when the app is not running.
Create a new class which extends BroadcastReceiver.
public class YourReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Do your stuff
}
}
And register it in manifest.
<receiver
android:name=".YourReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_SCREEN_ON" />
<action android:name="android.intent.action. ACTION_SCREEN_OFF" />
<category android:name="android.intent.category.DEFAUL" />
</intent-filter>
</receiver>
Read about Manifest-declared receivers here.
Above solution won't work, here is the reason why. Problem is that your service is getting killed when the app is killed, so your receiver instance is removed from memory. Here is a little trick to re-start the service in background. Add the following code to your service.
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
Although this is not the right way to do it. Also in Android 26+ you won't be able to do this and you'd go for foreground service. https://developer.android.com/about/versions/oreo/background
I have a working NFC reader/writer code. Using the same code, I added the reader function in another app which is following MVP architecture.
The activity is named NFCReaderActivity. A separate NFC class is created (NFCReader), which implements Sensor interface.
The app is supposed to work both in the foreground and launch showing the NFC tag info. The launch part is working fine and app launches and reads the tag and shows its content.
However, in the foreground, on scanning, it does nothing. I only hear the scan beep but no onNewIntent is firing.
Below are the log entries captured for foreground and launch actions. There is a difference in the class names:
When not launching
I/ActivityManager: START u0 {act=android.nfc.action.NDEF_DISCOVERED typ=application/com.abc.vi flg=0x14008000 cmp=com.abc.vi/.ui.reader.NFCReader (has extras)} from uid 10038 on display 0
When launching
I/ActivityManager: START u0 {act=android.nfc.action.NDEF_DISCOVERED typ=application/com.abc.vi cmp=com.abc.vi/.ui.reader.NFCReaderActivity (has extras)} from uid 1027 on display 0
Activity
onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "__onCreate__ " );
setContentView(R.layout.activity_nfc_reader);
VI.setNFCReaderActivityContext(this); //VI is the Application class
ButterKnife.bind(this);
presenter = new ReaderPresenter(this);
}
onNewIntent
#Override
public void onNewIntent(Intent intent) {
Log.i(TAG, "__onNewIntent__ " );
// onResume gets called after this to handle the intent
// setIntent(intent);
presenter.onNewIntent(intent);
}
onResume, onPause
#Override
protected void onResume() {
super.onResume();
Log.i(TAG, "__onResume__ " );
presenter.onResume();
}
#Override
protected void onPause() {
super.onPause();
Log.i(TAG, "__onPause__ " );
presenter.onPause();
}
Presenter
ReaderPresenter(ReaderContract.View view) {
this.view = view;
initSensor();
}
#Override
public void initSensor() {
nfcReader = new NFCReader(VI.getNFCReaderActivityContext(), this); //VI is the Application class
}
#Override
public void onNewIntent(Intent intent) {
nfcReader.resolveIntent(intent);
}
#Override
public void onResume() {
nfcReader.onResume();
}
#Override
public void onPause() {
nfcReader.onPause();
}
#Override
public void onDestroy() {
speech.onDestroy();
}
NFCReader
public class NFCReader implements Sensors {
private static final String TAG = NFCReader.class.getSimpleName();
private NfcAdapter nfcAdapter;
private PendingIntent nfcPendingIntent;
private NFCReaderActivity activity;
private ReaderPresenter presenter;
NFCReader(NFCReaderActivity nfcReaderActivity, ReaderPresenter readerPresenter) {
this.activity = nfcReaderActivity;
this.presenter = readerPresenter;
init();
}
#Override
public void init() {
//Initialize NFC adapter
nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
nfcPendingIntent = PendingIntent.getActivity(activity, 0, new Intent(activity,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP), 0);
}
public void onResume() {
if (nfcAdapter != null) {
nfcAdapter.enableForegroundDispatch(activity, nfcPendingIntent, null, null);
// if NFC not enabled
if (!nfcAdapter.isEnabled()) {
new AlertDialog.Builder(activity)
.setPositiveButton(activity.getString(R.string.update_setting_btn),
(dialog, which) -> {
Intent setNfc = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
activity.startActivity(setNfc);
})
.setOnCancelListener(
dialog -> activity.finish()
)
.create().show();
}
resolveIntent(activity.getIntent());
} else {
Toast.makeText(VI.getAppContext(),
activity.getString(R.string.error_no_nfc_found), Toast.LENGTH_LONG).show();
}
}
public void onPause() {
if (nfcAdapter != null) {
nfcAdapter.disableForegroundDispatch(activity);
}
}
public void resolveIntent(Intent intent){
Log.i(TAG, "__resolveIntent__");
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
NdefMessage[] messages = null;
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
messages = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
messages[i] = (NdefMessage) rawMsgs[i];
}
}
if ((messages != null ? messages[0] : null) != null) {
StringBuilder result = new StringBuilder();
byte[] payload = messages[0].getRecords()[0].getPayload();
for (byte aPayload : payload) {
result.append((char) aPayload);
}
Log.i(TAG,"Decoded --> "+result.toString());
presenter.getData(result.toString());
}
}
}
}
Manifest
<activity android:name=".ui.reader.NFCReaderActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="#string/mime_type" />
</intent-filter>
</activity>
UPDATE
I moved all the code from NFCReader class to NFCReaderActivity and both foreground and launch modes are working. The issue is with MVP architecture. How to convert it back to MVP?
You seem to register the pending intent for the wrong (actually an invalid) component (not your activity class). The reason is that when you create the PendingIntent that you assign to nfcPendingIntent, you use getClass() to obtain the class of the NFCReader instance. Instead you would need to use activity.getClass() to obtain the class of your activity component.
I have running service (previously successfuly binded, started and unbinded with main activity):
Intent startingIntent = new Intent(this, SturkoPlayerService.class);
startingIntent.setAction(SturkoPlayerService.PLAYER_START);
bindService(startingIntent, connection, Context.BIND_AUTO_CREATE);
When I successfuly close mainactivity (service is unbinded and keeps running) and want to reopen mainactivity with notification intent:
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.putExtra("Service", 1);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); //tried also another flags
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
and then try to bind my running service
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
if (getIntent() != null && getIntent().hasExtra("Service")) {
if (!bound) {
bindService(new Intent(this, SturkoPlayerService.class), connection, 0);
}
}
}
the onServiceConnected function of my Connection variable is not called
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
SturkoPlayerService.LocalBinder mBinder = (SturkoPlayerService.LocalBinder) service;
sturkoService = mBinder.getService();
bound = true;
sturkoService.registerClient(MainActivity.this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
bound = false;
}
};
Manifest:
...
<activity android:name=".MainActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask"> //tried other modes too
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".Service.SturkoPlayerService"
android:enabled="true"
android:exported="true"
android:singleUser="true">
</service>
...
P.S.: Catlog did not show somthing
A service will only be running if:
There are 1+ clients bound to it, or
You called startService() on it and nothing has stopped it (e.g., stopSelf(), stopService())
Otherwise, once the last bound connection is unbound, the service stops.
I am trying to get NFC foreground dispatch to work in my app using the tutorials
here and here. From what I can deduce all other functions seem to be working a it is just the NFC forground dispatch system that isn't working.
In my onCreate, I check NFC exists and initialise pending Intents and filters and get the NFC adapter:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Set some stuff
mTV = (TextView) findViewById(R.id.textView);
mButt = (Button) findViewById(R.id.button);
//mNfcAd = NfcAdapter.getDefaultAdapter(this);
//Init elsewhere
getAdapter();
//Hide button until its needed
mButt.setVisibility(View.INVISIBLE);
//Make sure NFC actually exists.....
if (mNfcAd == null) {
//Not going to work without NFC
Toast.makeText(this, "This device does not support NFC\nGet used to the pen and paper for now :/", Toast.LENGTH_LONG).show();
finish();
return;
}
Intent nfcIntent = new Intent(this, getClass());
nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
nfcPendingIntent =
PendingIntent.getActivity(this, 0, nfcIntent, 0);
IntentFilter tagIntentFilter =
new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
tagIntentFilter.addDataType("text/plain");
intentFiltersArray = new IntentFilter[]{tagIntentFilter};
}
catch (Throwable t) {
t.printStackTrace();
}
//Init the prefs
initPrefs();
}
public void initPrefs() {
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
}
private NfcAdapter getAdapter(){
if(mNfcAd ==null){
NfcManager manager = (NfcManager) getSystemService(NFC_SERVICE);
mNfcAd = manager.getDefaultAdapter();
}
return mNfcAd;
}
I then go on to check NFC is enabled (if not display a button that shows NFC settings) as well as checking if the app is in its first run. At the end of onResume(), I (attempt to) enable Foreground Dispatch for the adapter.
protected void onResume() {
super.onResume();
//Define the mButt action
mButt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent dialogIntent = new Intent(Settings.ACTION_NFC_SETTINGS);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
}
});
//If NFC exists, check if its turned on
if (!mNfcAd.isEnabled()) {
Toast.makeText(this, "You have NFC, but you haven't enabled it...", Toast.LENGTH_LONG).show();
mTV.setText("NFC not enabled");
mButt.setVisibility(View.VISIBLE);
}
//Check if first run
if (prefs.getInt("firstTime", 1) == 1 ||
prefs.getString("fullName", null) == null ||
prefs.getString("house", null) == null) {
Intent intent = new Intent(this, First_Run.class);
startActivity(intent);
prefs.edit().putInt("firstTime", 0);
prefs.edit().putString("fullName", getIntent().getExtras().getString("fullName"));
prefs.edit().putString("house", getIntent().getExtras().getString("house"));
prefs.edit().apply();
}
getAdapter().enableForegroundDispatch(this, nfcPendingIntent, intentFiltersArray, null);
handleIntent(getIntent());
}
The error is:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.nfc.NfcAdapter.enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][])' on a null object reference
However, all the arguments seem to be initialised;
It is being called in onResume, so the activity context is created;
nfcPendingIntent and intentFiltersArray are initialised in onCreate;
I do not have a techlist so I use null as the final argument;
The adapter itself is initialised in getAdapter.
I am currently combing through other tutorials to see the different methods that can be used, however I would really like to get this fixed.
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<uses-permission android:name="android.permission.NFC" />
<application
android:fullBackupContent="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name=".First_Run"
android:label="#string/title_activity_first__run">
</activity>
</application>
Try creating your NfcAdapter object like below.
NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this);