FCM Data messages are not working properly - java

I am using data messages where we can send messages even when the app is killed or in background or in foreground. I am using FCM .
But in my case sometimes my app does not get those messages . I am sending messages from app to app. Sometimes the app get messages even when it is killed or removed from background but again , sometimes it wont.
When i open the app , then suddenly the message appears. I am opening activities when a particular message is received . I know that data messages are used for sending messages even when the app is killed or in background or in foreground , but i am having problem like this . please help !..
I want it to be absolute .
I just want my app to be connected to FirebaseMessagingServices always , even when it is killed. I don't know about services and some says that i need to create a foreground services . How to create it and implement to FirebaseMessagingServices .?
MYFirebaseMessaging.java
package com.example.praful.ubercoustomer.Service;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;
import com.example.praful.ubercoustomer.AcceptedWindow;
import com.example.praful.ubercoustomer.Common.Common;
import com.example.praful.ubercoustomer.CompanycancelledtheBooking;
import com.example.praful.ubercoustomer.DeclinedWindow;
import com.example.praful.ubercoustomer.Helper.NotificationHelper;
import com.example.praful.ubercoustomer.Onthewayandimreached;
import com.example.praful.ubercoustomer.R;
import com.example.praful.ubercoustomer.RateActivity;
import com.example.praful.ubercoustomer.VerifyingCompletedBooking;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Map;
public class MyFirebaseMessaging extends FirebaseMessagingService {
#Override
public void onMessageReceived(final RemoteMessage remoteMessage) {
if (remoteMessage.getData() != null) {
Map<String, String> data = remoteMessage.getData();
String title = data.get("title");
final String companyName = data.get("CompanyName");
final String BookingIdC = data.get("BookingIdC");
final String BookingIdT = data.get("BookingIdT");
final String companyPhone = data.get("CompanyPhone");
final String companyRates = data.get("CompanyRates");
final String companyId = data.get("CompanyId");
final String Date = data.get("Date");
final String companyIdC = data.get("companyIdC");
final String Time = data.get("Time");
final String Id = data.get("Id");
final String Address = data.get("Address");
final String Bookingid = data.get("Bookingid");
final String TimeCB = data.get("TimeCB");
final String DateCB = data.get("DateCB");
final String EventType = data.get("EventType");
final String messageCB = data.get("messageCB");
final String AddressCB = data.get("AddressCB");
final String companythatcancelledthebooking = data.get("CompanyNamethatcancelledthebooking");
final String message = data.get("message");
// remoteMessage.getNotification().getTitle() = title and remoteMessage.getNotification().getBody() = message
if (title != null && title.equals("Cancel")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(MyFirebaseMessaging.this, DeclinedWindow.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Common.isCompanyFound = false;
Common.companyId = "";
Toast.makeText(MyFirebaseMessaging.this, "" + message, Toast.LENGTH_SHORT).show();
}
});
} else if (title != null && title.equals("cancelAdvanceBooking")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(getBaseContext(), CompanycancelledtheBooking.class);
intent.putExtra("DateCB", DateCB);
intent.putExtra("TimeCB", TimeCB);
intent.putExtra("messageCB", messageCB);
intent.putExtra("AddressCB", AddressCB);
intent.putExtra("EventType", EventType);
intent.putExtra("Id", Id);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Common.isCompanyFound = false;
Common.companyId = "";
Toast.makeText(MyFirebaseMessaging.this, "" + messageCB, Toast.LENGTH_SHORT).show();
}
});
} else if (title != null && title.equals("Accept")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(MyFirebaseMessaging.this, AcceptedWindow.class);
intent.putExtra("Date", Date);
intent.putExtra("Time", Time);
intent.putExtra("Address", Address);
intent.putExtra("companyName", companyName);
intent.putExtra("companyPhone", companyPhone);
intent.putExtra("companyRates", companyRates);
intent.putExtra("companyId", companyId);
intent.putExtra("Bookingid", Bookingid);
intent.putExtra("EventType", EventType);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Common.isCompanyFound = false;
Common.companyId = "";
Toast.makeText(MyFirebaseMessaging.this, "" + message, Toast.LENGTH_SHORT).show();
}
});
} else if (title != null && title.equals("Arrived")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
showArrivedNotifAPI26(message);
else
showArrivedNotif(message);
}
});
} else if (title != null && title.equals("Completed")) {
openRateactivity(message);
} else if (title != null && title.equals("completedAdvancebooking")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(MyFirebaseMessaging.this, VerifyingCompletedBooking.class);
intent.putExtra("BookingIdC", BookingIdC);
intent.putExtra("message", message);
intent.putExtra("companyid", companyIdC);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
} else if (title != null && title.equals("Ontheway")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(MyFirebaseMessaging.this, Onthewayandimreached.class);
intent.putExtra("message", message);
intent.putExtra("BookingIdT", BookingIdT);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
} else if (title != null && title.equals("Reached")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(MyFirebaseMessaging.this, Onthewayandimreached.class);
intent.putExtra("message", message);
intent.putExtra("BookingIdT", BookingIdT);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
}
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void showArrivedNotifAPI26(String body) {
PendingIntent contentIntent = PendingIntent.getActivity(getBaseContext(), 0,
new Intent(), PendingIntent.FLAG_ONE_SHOT);
Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationHelper notificationHelper = new NotificationHelper(getBaseContext());
Notification.Builder builder = notificationHelper.getUberNotification("Arrived", body, contentIntent, defaultSound);
notificationHelper.getManager().notify(1, builder.build());
}
private void openRateactivity(String body) {
Intent intent = new Intent(this, RateActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
private void showArrivedNotif(String body) {
PendingIntent contentIntent = PendingIntent.getActivity(getBaseContext(), 0,
new Intent(), PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(getBaseContext());
builder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND)
.setWhen(System.currentTimeMillis()).
setSmallIcon(R.drawable.ic_menu_camera)
.setContentTitle("Arrived")
.setContentText(body)
.setContentIntent(contentIntent);
NotificationManager manager = (NotificationManager) getBaseContext().getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(1, builder.build());
}
}
MyFirebaseIdService
package com.example.praful.ubercoustomer.Service;
import com.example.praful.ubercoustomer.Common.Common;
import com.example.praful.ubercoustomer.Model.Token;
import com.example.praful.ubercoustomer.Common.Common;
import com.example.praful.ubercoustomer.Model.Token;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;
public class MyFirebaseIdService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
super.onTokenRefresh();
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
updateTokenToServer(refreshedToken);
}
private void updateTokenToServer(String refreshedToken) {
FirebaseDatabase db =FirebaseDatabase.getInstance();
DatabaseReference tokens = db.getReference(Common.token_table);
Token token = new Token(refreshedToken);
if(FirebaseAuth.getInstance().getCurrentUser() != null)
tokens.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).setValue(token);
}
}

First check this remote message contains payload, May be payload get corrupt for any reason.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "REMOTE_MSG";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage == null)
return;
// check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.e(TAG, "Notification body: " + remoteMessage.getNotification().getBody());
createNotification(remoteMessage.getNotification());
}
// check if message contains a data payload
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
}
DON'T forgent to update your FCM device token on your DB.
public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {
private static final String TAG = "FCM_ID";
#Override
public void onTokenRefresh() {
// get hold of the registration token
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
// lg the token
Log.d(TAG, "Refreshed token: " + refreshedToken);
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
// implement this method if you want to store the token on your server
}
}
Update 1
As mentioned Firebase repo issue expected that issue to be related to device, Please try another device aspect.
Update 2 Quote from firebase repo contributor kroikie
FCM does not process messages if an app is "killed" or force stopped.
When a user kills an app it is an indication that the user does not
want the app running so that app should not run till the user
explicitly starts it again.
Note that swiping an app from recents list should NOT "kill" or force
stop it. If messages are not being received after swiping from recents
list then please identify these devices and we will work with the
manufactures to correct this behaviour.
Only being able to handle messages when the app is in the foreground
or background is working as intended.
Update 3
Try hacks mentioned on this issue.
Inserting this lines in Manifest.xml
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
It is because of DOZE mode and battery optimization,you just have to turn off battery optimization for all apps or particular app. Go to Settings>> apps >> select your app>> battery>>
battery optimization> select your app>> select don't optimise.
Problem solved.
Now (for APP IS CLOSED case) I write Notification text to file and read this text if extras == null and notificationText.txt is exists... its stupid solution but it works. How can I catch this extras when app is closed in other way.
Update 4
Try to Setting the priority of a message,
Disable Battery Optimization
Users can manually configure the whitelist in Settings > Battery >
Battery Optimization. Alternatively, the system provides ways for apps
to ask users to whitelist them.
An app can fire the ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent
to take the user directly to the Battery Optimization, where they can
add the app. An app holding the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
permission can trigger a system dialog to let the user add the app to
the whitelist directly, without going to settings. The app fires a
ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Intent to trigger the
dialog. The user can manually remove apps from the whitelist as
needed.
Programmatically open Battery Optimization, check this answer.
TAKE CARE ABOUT THIS
Before asking the user to add your app to the whitelist, make sure the
app matches the acceptable use cases for whitelisting.
Note:
Google Play policies prohibit apps from requesting direct exemption from
Power Management features in Android 6.0+ (Doze and App Standby)
unless the core function of the app is adversely affected.
Update 5
Check PowerManager.isIgnoringBatteryOptimizations() from this answer.
When disable battery optimization, Consider to check first if it's already disabled then no need to show dialog, else you can show dialog.
/**
* return false if in settings "Not optimized" and true if "Optimizing battery use"
*/
private boolean checkBatteryOptimized() {
final PowerManager pwrm = (PowerManager) getSystemService(Context.POWER_SERVICE);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return !pwrm.isIgnoringBatteryOptimizations(getBaseContext().getPackageName());
}
}catch (Exception ignored){}
return false;
}
private void startBatteryOptimizeDialog(){
try {
Intent intent = new Intent(android.provider.Settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:PUT_YOUR_PACKAGE_NAME_HERE"));
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}

Related

How to navigate to specific activity/fragment after tapping on one signal push notification?

can someone provide me the proper documentation or code to navigate to specific activity by tapping on one signal push notification, i want to open the specific fragment
here is my code where i extened application class and initialize one signal :
package com.example.nasapp;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Parcelable;
import android.util.Log;
import com.example.nasapp.ui.home.HomeFragment;
import com.example.nasapp.ui.information.InformationFragment;
import com.onesignal.OSMutableNotification;
import com.onesignal.OSNotification;
import com.onesignal.OSNotificationAction;
import com.onesignal.OSNotificationOpenedResult;
import com.onesignal.OSNotificationReceivedEvent;
import com.onesignal.OneSignal;
import org.json.JSONException;
import org.json.JSONObject;
public class OneSignalApplication extends Application {
private static final String ONESIGNAL_APP_ID = "e855e254-9b4e-4e6f-a64a-e48db6f35d07";
#Override
public void onCreate() {
super.onCreate();
// Enable verbose OneSignal logging to debug issues if needed.
//OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE);
// OneSignal Initialization
OneSignal.initWithContext(this);
OneSignal.setAppId(ONESIGNAL_APP_ID);
// promptForPushNotifications will show the native Android notification permission prompt.
// We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 7)
OneSignal.promptForPushNotifications();
OneSignal.setNotificationOpenedHandler(new OneSignal.OSNotificationOpenedHandler() {
#Override
public void notificationOpened(OSNotificationOpenedResult result) {
JSONObject data = result.getNotification().getAdditionalData();
Log.i("OneSignalExample", "Notification Data: " + data);
String notification_topic;
if (data != null) {
try {
System.out.println(data.getString("job_id"));
} catch (JSONException e) {
e.printStackTrace();
}
notification_topic = data.optString("notification_topic", "hii");
if (notification_topic != null) {
OneSignal.addTrigger("level", notification_topic);
}
}
}
});
}
}
here is my NotificationServiceExtensionClass:
public class NotificationServiceExtension extends Service implements OneSignal.OSRemoteNotificationReceivedHandler {
#Override
public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent notificationReceivedEvent) {
OSNotification notification = notificationReceivedEvent.getNotification();
// Example of modifying the notification's accent color
OSMutableNotification mutableNotification = notification.mutableCopy();
mutableNotification.setExtender(builder -> {
//... do stuff
builder.setTimeoutAfter(30000);
Intent intent = new Intent();
JSONObject data = notification.getAdditionalData();
// check the data and create intent
intent = new Intent(context, InformationFragment.class);
// or any other depends on data value
intent.putExtra("data", (Parcelable) data);
PendingIntent pendIntent = PendingIntent.getActivity(context,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
builder = builder.setContentIntent(pendIntent);
return builder;
});
JSONObject data = notification.getAdditionalData();
Log.i("OneSignalExample", "Received Notification Data: " + data);
// If complete isn't call within a time period of 25 seconds, OneSignal internal logic will show the original notification
// To omit displaying a notification, pass `null` to complete()
notificationReceivedEvent.complete(mutableNotification);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
In manifest i declare this service class:
<service
android:name=".service.NotificationServiceExtension"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false">
am i missing some code or what am i doing wrong in code ,can please someone help?

How to start a method from MainActivity in a foreground service

I have got a MainActivity which gets the current location on click of a button. In the activity, and the location is stored with three different methods in
SharedPreferences
An online SQL Database
In a text file on the device
I have another class to start a foreground service (ForegroundService.java) which starts with the click of another button in the MainAcivity and stops with a third button.
My plan is to have regular (1 hour interval) location updates using the ForegroundService and a JobService. So if we click on the StartService-button in the MainActivity the foreground service should start and regularly call the methods from the MainActivity: getCurrentGPSPosition (to get the location), and the three methods to store the information.
The MainActivity works fine. The ForegroundService can be started and stopped bud I do not know how to make it call the methods from the MainActivity.
Here is the code -
ForegroundService.java:
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import static com.example.currentlocation.App.CHANNEL_ID;
public class ForegroundService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//String input = intent.getStringExtra("inputExtra");
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("GPS position tracker")
//.setContentText(input)
.setSmallIcon(R.drawable.ic_baseline_gps_fixed_24)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
App.java
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
public class App extends Application {
public static final String CHANNEL_ID = "CurrentLocationServiceChannel";
#Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
}
private void createNotificationChannel(){
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Current Location Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
In the MainActivity the following parts:
public class MainActivity extends AppCompatActivity {
........
//Backgroundservice
public void startService(View v){
// String input = editTextInput.getText().toString();
Intent serviceIntent = new Intent(this, ForegroundService.class);
// serviceIntent.putExtra("inputExtra", input);
startService(serviceIntent);
}
public void stopService(View v){
Intent serviceIntent = new Intent(this, ForegroundService.class);
stopService(serviceIntent);
}
//Method to store in SQL online
public void OnReg() {.......code....}
//Method to save data in SharedPreferences
public void saveData() {.......code....}
//Method to save data in Internal File
public void saveToFile() {.......code....}
//method for GPS request
getCurrentGPSLocation() {.......code....}
}
Has anybody got an idea how to work that out? Or do you need more details? Thanks for your help!
Don't put those functions in MainActivity. If you need them to be called from both the Activity and a Service, put them in a separate class that can be instantiated as needed. If you can't do that because there's data in MainActivity that both need, rethink your architecture- that data won't be available when the job service fires anyway.
OK, first solution is to make a new class (Functions.java) and using an intent to call this class form the MainActivity and then do the location request there and then give the data back to the MainActivity.
Second step would then be to do the same from the foreground service.
The Problem is, the functions class does not get the data from the method. If I put hard-coded strings into the intent, they are transmitted to the MainActivity, so the intent works. So this is only part of the full solution.
Here's the code:
public class Functions extends AppCompatActivity {
//initialize variable
FusedLocationProviderClient fusedLocationProviderClient;
private double ser_Latitude;
private double ser_Longitude;
private String ser_Accuracy;
private String ser_Altitude;
private String currentDateandTime;
private String ser_Location;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Boolean precision = getIntent().getBooleanExtra("precision", true);
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(
Functions.this);
getCurrentGPSLocation();
Intent intent = new Intent();
intent.putExtra("latitude", ser_Latitude);
intent.putExtra("longitude", ser_Longitude);
intent.putExtra("accuracy", ser_Accuracy);
intent.putExtra("altitude", ser_Altitude);
intent.putExtra("location", ser_Location);
intent.putExtra("currentDateandTime", currentDateandTime);
setResult(RESULT_OK, intent);
Functions.this.finish();
}
//Force new GPS Location Request
private void getCurrentGPSLocation() {
// get the new location from the fused client
// update the UI - i.e. set all properties in their associated text view items
//Initialize new location request
LocationRequest locationRequest = new LocationRequest()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(3000)
.setFastestInterval(2000)
.setNumUpdates(1)
;
//Initialize location call back
LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
//Initialize location1
Location location1 = locationResult.getLastLocation();
//Set latitude
ser_Latitude = location1.getLatitude();
//Set longitude
ser_Longitude = location1.getLongitude();
//Set Accuracy
double ser_accura1 = location1.getAccuracy();
ser_Accuracy = new DecimalFormat("##.##").format(ser_accura1) + " m";
//Set Altitude
double ser_altit1 = location1.getAltitude();
ser_Altitude = new DecimalFormat("##.##").format(ser_altit1) + " m";
//Get Adress
/* Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
try {
List<Address> listAddresses = geocoder.getFromLocation(ser_Latitude, ser_Longitude, 1);
if (null != listAddresses && listAddresses.size() > 0) {
String _Location1 = listAddresses.get(0).getAddressLine(0);
//Set Location
//ser_Location = String.valueOf(_Location1);
}
} catch (IOException e) {
e.printStackTrace();
}*/
//Set location as hard-coded string for testing
ser_Location = "London";
//Set Update Time
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy 'um ' HH:mm:ss z");
currentDateandTime = sdf.format(new Date());
}
};
//Request location updates
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
fusedLocationProviderClient.requestLocationUpdates(locationRequest
, locationCallback, Looper.myLooper());
}
}
The new GPS request is triggered as I can see running the app, but no information is delivered from the method getCurrentGPSLocation() to the intent, which I can see because even the hard-coded location string is not delivered.
This needs revision please.

Foreground Service doesnt work in Android 9 (API 28)

I want to have a foreground service and I wrote the codes.
But the problem is that the app works well on API 26 and below but not in API 28.
The problem in API 28 is that it works as a background service and if you close the app, service closes too.
Here is my code:
MyService:
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.widget.Toast;
public class MyService extends Service {
private Context context = null;
private static final int NOTIFICATION_ID = 1;
private static final String CHANNEL_ID = "ChargeScreenService";
private Looper serviceLooper;
private ServiceHandler serviceHandler;
private BatteryBroadCast batteryBroadCast;
private NotificationManager notificationManager;
private Notification notification;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
batteryBroadCast = new BatteryBroadCast(MyService.this);
batteryBroadCast.chargingChanges();
}
});
thread.start();
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
//stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work doesn't disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
serviceLooper = thread.getLooper();
serviceHandler = new ServiceHandler(serviceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Hi")
.setContentText("Hello")
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.setTicker("HI")
.setOngoing(true)
.build();
notificationManager.notify(NOTIFICATION_ID, notification);
} else {
notification = new Notification.Builder(this)
.setContentTitle("Hi")
.setContentText("Hello")
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.setTicker("HI")
.setOngoing(true)
.build();
}
startForeground(1, notification);
Message msg = serviceHandler.obtainMessage();
msg.arg1 = startId;
serviceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "ChargeScreenService";
String description = "Service";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
MainActivity:
...
startService.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
});
...
Finally, I added the permission in AndroidManifest file.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
And defined my service too.
<service
android:name=".MyService"
android:enabled="true" />
Testing devices:
Samsung galaxy J7 pro (Model number: SM-J730F) (real device)
Virtual device: Genymotion Android 6
If your app targets API level 26 or higher, the system imposes restrictions on running background services when the app itself isn't in the foreground. In most cases like this, your app should use a scheduled job instead.

Android NotificationListenerService#onNotificationRemoved(..., int reason) not called by System

Based on the Documentation on the Android Developer site, the onNotificationRemoved(with reason) method allows one to get the reason why a notification was dismissed e.g. user cleared all notifications, or just your notification etc.
I have tested some of the other callbacks i.e. onNotificationPosted and onNotificationRemoved without reason and they are successfully called.
Below is the implementation of the NotificationListenerService I created:
package com.solo.notificationlistener;
import android.app.Notification;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
public class MyNotificationListenerService extends NotificationListenerService {
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
if (sbn.getPackageName().equals(getBaseContext().getPackageName())) {
Notification notification = sbn.getNotification();
String notificationText = notification.extras.getString(Notification.EXTRA_TEXT);
Log.d(getClass().getSimpleName(),
String.format("Just posted notification: %s", notificationText));
}
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {
super.onNotificationRemoved(sbn);
if (sbn.getPackageName().equals(getBaseContext().getPackageName())) {
Notification notification = sbn.getNotification();
String notificationText = notification.extras.getString(Notification.EXTRA_TEXT);
Log.d(getClass().getSimpleName(),
String.format("Dismissed notification: %s", notificationText));
}
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, int reason) {
super.onNotificationRemoved(sbn, rankingMap, reason);
Log.d(getClass().getSimpleName(), "Dismissing with a reason");
if (sbn.getPackageName().equals(getBaseContext().getPackageName())) {
Notification notification = sbn.getNotification();
String notificationText = notification.extras.getString(Notification.EXTRA_TEXT);
Log.d(getClass().getSimpleName(),
String.format("Dismissed notification: %s\n Reason: %s",
notificationText,
(reason == NotificationListenerService.REASON_CANCEL) ?
"Specifically cancelled my app" :
"Cancelled all perhaps"
));
}
}
}
Any ideas on why this behaviour occurs?
Any assistance is much appreciated
OnNotificationRemoved with reason is for API >= 26
Could it be for that reason the method is not trigerring ?

Use Eddystone Beacon to Show notification in Android Status Bar

I've been able to successfully create an app (thanks davidgyoung!) that monitors beacons in the background and then subsequently opens the app in the background.
Now I would like my app to first prompt with a notification in the status bar saying something like "I've detected a beacon! Would you like to open out app?". Then the user would click on the notification to open the app or dismiss it and ignore the notification.
I've searched on stack overflow for something like but haven't had much success in finding something relevant to beacons. I did find this page that talks about adding StatusBar notifications but I'm not having much success.
Particularly its in my BeaconReferenceApplication.java and MonitoringActivity.java file. I think I put the code in the correct place (after didEnterRegion) but I have unresolved classes for areas like notificationButton, setLatestEventInfo, etc. Can someone help? Thanks in advance!
BeaconReferenceApplication.java:
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.Identifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.powersave.BackgroundPowerSaver;
import org.altbeacon.beacon.startup.RegionBootstrap;
import org.altbeacon.beacon.startup.BootstrapNotifier;
public class BeaconReferenceApplication extends Application implements BootstrapNotifier {
private static final String TAG = "BeaconReferenceApp";
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
private boolean haveDetectedBeaconsSinceBoot = false;
private MonitoringActivity monitoringActivity = null;
public void onCreate() {
super.onCreate();
BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
// By default the AndroidBeaconLibrary will only find AltBeacons. If you wish to make it
// find a different type of beacon, you must specify the byte layout for that beacon's
// advertisement with a line like below. The example shows how to find a beacon with the
// same byte layout as AltBeacon but with a beaconTypeCode of 0xaabb. To find the proper
// layout expression for other beacon types, do a web search for "setBeaconLayout"
// including the quotes.
//
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
Log.d(TAG, "setting up background monitoring for beacons and power saving");
// wake up the app when a beacon is seen
Region region = new Region("backgroundRegion", Identifier.parse("2F234454F4911BA9FFA6"), null, null);
regionBootstrap = new RegionBootstrap(this, region);
// simply constructing this class and holding a reference to it in your custom Application
// class will automatically cause the BeaconLibrary to save battery whenever the application
// is not visible. This reduces bluetooth power usage by about 60%
backgroundPowerSaver = new BackgroundPowerSaver(this);
// If you wish to test beacon detection in the Android Emulator, you can use code like this:
// BeaconManager.setBeaconSimulator(new TimedBeaconSimulator() );
// ((TimedBeaconSimulator) BeaconManager.getBeaconSimulator()).createTimedSimulatedBeacons();
}
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever a Beacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedBeaconsSinceBoot) {
Log.d(TAG, "sending notification to StatusBar");
#SuppressWarnings("deprecation")
private void Notify(String notificationTitle, String notificationMessage) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
#SuppressWarnings("deprecation")
Notification notification = new Notification(R.mipmap.ic_launcher,
"New Message", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MonitoringActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(MonitoringActivity.this, notificationTitle,
notificationMessage, pendingIntent);
notificationManager.notify(9999, notification);
}
}
} else {
if (monitoringActivity != null) {
Log.d(TAG, "auto launching MainActivity");
// The very first time since boot that we detect an beacon, we launch the
// MainActivity
Intent intent = new Intent(this, MonitoringActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Important: make sure to add android:launchMode="singleInstance" in the manifest
// to keep multiple copies of this activity from getting created if the user has
// already manually launched the app.
this.startActivity(intent);
haveDetectedBeaconsSinceBoot = true;
}
}
}
#Override
public void didExitRegion(Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I no longer see a beacon.");
}
}
#Override
public void didDetermineStateForRegion(int state, Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I have just switched from seeing/not seeing beacons: " + state);
}
}
private void sendNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setContentTitle("Beacon Reference Application")
.setContentText("An beacon is nearby.")
.setSmallIcon(R.mipmap.ic_launcher);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(new Intent(this, MonitoringActivity.class));
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build());
}
public void setMonitoringActivity(MonitoringActivity activity) {
this.monitoringActivity = activity;
}
}
MonitoringActivity.java:
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import org.altbeacon.beacon.BeaconManager;
public class MonitoringActivity extends Activity {
protected static final String TAG = "MonitoringActivity";
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
private WebView mWebView;
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_monitoring);
// code for button notification
Button notificationButton = (Button) findViewById(R.id.notificationButton);
notificationButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Notify("Title: Meeting with Business",
"Msg:Pittsburg 10:00 AM EST ");
}
});
// code for button notification
mWebView = (WebView) findViewById(R.id.activity_main_webview);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.loadUrl("http://communionchapelefca.org/edy-home");
mWebView.setWebViewClient(new MyAppWebViewClient());
verifyBluetooth();
Log.d(TAG, "Application just launched");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android M Permission check
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#TargetApi(23)
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
}
private class HelloWebViewClient extends WebViewClient{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public boolean shouldOverrideUrlLoading(WebView webView, String url)
{
webView.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
progressBar.setVisibility(view.GONE);
}
}
#Override
public void onBackPressed() {
if(mWebView.canGoBack()) {
mWebView.goBack();
} else {
super.onBackPressed();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
public void onRangingClicked(View view) {
Intent myIntent = new Intent(this, RangingActivity.class);
this.startActivity(myIntent);
}
#Override
public void onResume() {
super.onResume();
((BeaconReferenceApplication) this.getApplicationContext()).setMonitoringActivity(this);
}
#Override
public void onPause() {
super.onPause();
((BeaconReferenceApplication) this.getApplicationContext()).setMonitoringActivity(null);
}
private void verifyBluetooth() {
try {
if (!BeaconManager.getInstanceForApplication(this).checkAvailability()) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth not enabled");
builder.setMessage("Please enable bluetooth in settings and restart this application.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
finish();
System.exit(0);
}
});
builder.show();
}
}
catch (RuntimeException e) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth LE not available");
builder.setMessage("Sorry, this device does not support Bluetooth LE.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
finish();
System.exit(0);
}
});
builder.show();
}
}
}
So I was able to fix my problem by using the example from the Android Developers website for Notifications. I used their sample code, adapted it to my use, and then even further used .bigText to make my notification look great. Credit goes to them and daviggyoung for getting my app working. Thanks!
I also didnt need to edit my MonitoringActivity.java like I posted earlier.
final BeaconReferenceApplication.java:
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.Identifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.powersave.BackgroundPowerSaver;
import org.altbeacon.beacon.startup.RegionBootstrap;
import org.altbeacon.beacon.startup.BootstrapNotifier;
public class BeaconReferenceApplication extends Application implements BootstrapNotifier {
private static final String TAG = "BeaconReferenceApp";
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
private boolean haveDetectedBeaconsSinceBoot = false;
private MonitoringActivity monitoringActivity = null;
public void onCreate() {
super.onCreate();
BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
// By default the AndroidBeaconLibrary will only find AltBeacons. If you wish to make it
// find a different type of beacon, you must specify the byte layout for that beacon's
// advertisement with a line like below. The example shows how to find a beacon with the
// same byte layout as AltBeacon but with a beaconTypeCode of 0xaabb. To find the proper
// layout expression for other beacon types, do a web search for "setBeaconLayout"
// including the quotes.
//
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
Log.d(TAG, "setting up background monitoring for beacons and power saving");
// wake up the app when a beacon is seen
Region region = new Region("backgroundRegion", Identifier.parse("2F234454F4911BA9FFA6"), null, null);
regionBootstrap = new RegionBootstrap(this, region);
// simply constructing this class and holding a reference to it in your custom Application
// class will automatically cause the BeaconLibrary to save battery whenever the application
// is not visible. This reduces bluetooth power usage by about 60%
backgroundPowerSaver = new BackgroundPowerSaver(this);
// If you wish to test beacon detection in the Android Emulator, you can use code like this:
// BeaconManager.setBeaconSimulator(new TimedBeaconSimulator() );
// ((TimedBeaconSimulator) BeaconManager.getBeaconSimulator()).createTimedSimulatedBeacons();
}
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever a Beacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedBeaconsSinceBoot) {
Log.d(TAG, "sending notification to StatusBar");
//begin code for notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Message from Communion Chapel")
.setContentText("Welcome! Thanks for coming!")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("We noticed that you're here today, click here to open the app and get today's Sermon Notes and Bulletin."))
.setAutoCancel(true);
;
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MonitoringActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MonitoringActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(123, mBuilder.build());
}
}
#Override
public void didExitRegion(Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I no longer see a beacon.");
}
}
#Override
public void didDetermineStateForRegion(int state, Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I have just switched from seeing/not seeing beacons: " + state);
}
}
private void sendNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setContentTitle("Beacon Reference Application")
.setContentText("A beacon is nearby.")
.setSmallIcon(R.drawable.app_icon);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(new Intent(this, MonitoringActivity.class));
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build());
}
public void setMonitoringActivity(MonitoringActivity activity) {
this.monitoringActivity = activity;
}
}

Categories

Resources