AlarmManager and BroadcastReceiver in Android Oreo+ - java

I am making an application that notifies the user at certain times of the day. Like an alarm clock. The code works normally in versions prior to Android Oreo.
From what I read, Android Oreo and later versions kill actions in the background and that's why I'm having the error below.
2020-07-13 20:31:06.766 1609-1737/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_REPLACED dat=package:studio.com.archeagemanager flg=0x4000010 (has extras) } to air.br.com.alelo.mobile.android/co.acoustic.mobile.push.sdk.wi.AlarmReceiver
It is as if the BroadcastService is simply not triggered when it should be. But when I open the app, it starts up instantly.
AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="owner.custom.permission" />
<permission
android:name="owner.custom.permission"
android:protectionLevel="signatureOrSystem">
</permission>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<application
android:allowBackup="true"
android:icon="#mipmap/app_icon_new"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".SplashScreenActivity"
android:theme="#style/AppCompat.TelaCheia">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
TabFragEventA.java (Here I put only the function that initiates the alarm)
public void startAlarm(int eventID) {
String[] NOTIFICATION_TITLES = {"Ocleera Rift", "Ocleera Rift", "Mistmerrow Conflict", "Mistmerrow Conflict",
"Mistmerrow Conflict", "Nation Construction Quests", "Diamond Shores", "Diamond Shores", "Battle of the Golden Plains",
"Battle of the Golden Plains", "Karkasse Ridgelands", "Kraken", "The Mirage Isle Fish Fest", "Red Dragon",
"Abyssal Attack", "Lusca Awakening", "Delphinad Ghostship", "Cattler Wrangler", "Legendary Chef", "+1"};
String notificationTitle = getString(R.string.contentTitle);
String notificationText = NOTIFICATION_TITLES[eventID] + getString(R.string.contentNotificationText);
int alarmHour = localHour.get(eventID);
int alarmMinute = localMinute.get(eventID);
// Decrease 5 minutes
if(alarmMinute == 0) {
alarmHour = alarmHour - 1;
alarmMinute = 55;
} else {
alarmMinute = alarmMinute - 5;
}
// Setting the alarm moment
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, alarmHour);
calendar.set(Calendar.MINUTE, alarmMinute);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
// Analyze if the alarm moment has passed
Calendar actualTime = Calendar.getInstance();
if(actualTime.getTimeInMillis() >= calendar.getTimeInMillis()) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
Intent intent = new Intent(getActivity().getApplicationContext(), AlarmReceiver.class);
intent.putExtra("contentTitle", notificationTitle);
intent.putExtra("contentText", notificationText);
/*if(eventID == 11 || eventID == 13) {
intent.putExtra("specificDayWeek", true);
} else {
intent.putExtra("specificDayWeek", false);
}*/
if(eventID == 12) {
intent.putExtra("castleSupply", true);
intent.putIntegerArrayListExtra("castleSupplyDayWeek", (ArrayList<Integer>) CastleSupply);
}
else if(eventID == 13) {
intent.putExtra("castleClaim", true);
intent.putIntegerArrayListExtra("castleClaimDayWeek", (ArrayList<Integer>) CastleClaim);
}
else if(eventID == 14) {
intent.putExtra("abyssalAttack", true);
intent.putIntegerArrayListExtra("abyssalDaysWeek", (ArrayList<Integer>) AbyssalDayWeek);
}
else if(eventID == 15) {
intent.putExtra("luscaAwakening", true);
intent.putIntegerArrayListExtra("luscaAwakeningDayWeek", (ArrayList<Integer>) LuscaAwakening);
} else {
intent.putExtra("abyssalAttack", false);
}
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
// PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity().getApplicationContext(), eventID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity().getApplicationContext(), eventID, intent, 0);
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String contentTitle = intent.getStringExtra("contentTitle");
String contentText = intent.getStringExtra("contentText");
String CHANNEL_ID = "my_channel_01";
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Channel Name";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
notificationManager.createNotificationChannel(mChannel);
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.icon_notification)
.setContentTitle(contentTitle)
.setContentText(contentText)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.icon_notification))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setVibrate(new long[]{800, 500, 600, 300});
notificationManager.notify(0, notificationBuilder.build());
Log.d("ALARMRECEIVER", "INSIDE");
}
}
I would like to know what to do to make the Broadcast Receiver work in the background. Or an alternative to set this alarm clock on Android Oreo + so that it notifies the user even with the application closed or in the background.

Android has a doze mode in which it goes to sleep after some inactivity, Even if you manage to do this on some phones chinese ROMs will trouble you for sure ( in which removing from recent apps works as force stopping application)
For your problem there are solutions Like Work manager , Foregroundservices ,jobscheduler it should work but again can't say for all the ROMs. I think right now there isn't a proper solution to this background processing.
But One thing you can do is sending a FCM notification from server with high priority.
You can see that Facebook and whatsapp can work in background because they are whitelisted by the companies. You can whitelist your application by enabling auto start from settings.But you need to do it manually which isnt a case when we talk about fb and whatsapp
Check this website for more details : https://dontkillmyapp.com/
With this issue Most affected are alarm clocks, health trackers, automation apps, calendars or simply anything which needs to do some job for you at a particular moment when you don’t use your phone.
With Android 6 (Marshmallow), Google has introduced Doze mode to the base Android, in an attempt to unify battery saving across the various Android phones.
Unfortunately, some manufacturers (e.g. Xiaomi, Huawei, OnePlus or even Samsung..) did not seem to catch that ball and they all have their own battery savers, usually very poorly written, saving battery only superficially with side effects.

Starting from Android oreo and up no more background services are supported. the suggestion from the developer documentation is to use a foreground service. To keep the foreground service running you need to hook it up with a notification. you can configure the notification to hide or not visible in the UI at all lately.
check this solution
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = this;
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("GPS Service")
.setContentText("GPS Service")
// .setLargeIcon(emailObject.getSenderAvatar())
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Ready\nAndroi " + android.os.Build.VERSION.SDK_INT))
.setPriority(Notification.PRIORITY_HIGH)
.setOngoing(true)
.build();
startForeground(1, notification);
getLocation();
//do heavy work on a background thread
locationModel = new LocationModel("", "", "", "", "");
LongOperation longOperation = new LongOperation();
longOperation.execute();
//stopSelf();
return START_STICKY;
}
and in the main activity onCreate
if (!isMyServiceRunning(ForegroundService.class)) {
BroadcastReceiver br = new GPSBroadcastReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
getApplicationContext().registerReceiver(br, filter);
}
checking whether the service is running
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
here is an example from one of my projects. Foreground service is the way to go!
some helpful sources.
foreground service example 1
foreground service example 2
repeating alarm manager example

If you are writing an Clock apps, use AlarmManager.setAlarmClock. It be allowed to trigger even if the system is in a low-power idle (a.k.a. doze) mode. When you set an AlarmClock, it's visible to the user. And SystemUI may show different icons or alarms.
If you just want to be triggered at certain time to do some work, there is no good way to escape the background limit.

Related

Foreground service not running when App exits

How can I keep the foreground service running even when the user quits the app?
I've tried running the service in another process, but the service still stops after I quit the app.
My AndroidManifest.xml:
<application
android:allowBackup="true"
android:dataExtractionRules="#xml/data_extraction_rules"
android:fullBackupContent="#xml/backup_rules"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.Test"
tools:targetApi="31">
<service
android:name=".Service"
android:enabled="true"
android:process=":service"
android:exported="false" />
<activity
android:process=":activity"
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Service.java:
public class CountdownService extends Service {
NotificationManager notificationManager;
private String createNotificationChannel(String channelId, String channelName) {
NotificationChannel chan = new NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(chan);
return channelId;
}
NotificationCompat.Builder builder;
#NonNull
private Notification getNotification() {
String channelId = createNotificationChannel("id", "name");
builder = new NotificationCompat.Builder(this, channelId);
return builder.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setPriority(PRIORITY_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.setContentText("Content Text")
.setSubText("Sub Text")
.setContentTitle("Content Title")
.build();
}
#Override
public void onCreate() {
super.onCreate();
startForeground(1, getNotification());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
And in MainActivity, I start the service like this:
Intent intent = new Intent(this, Service.class);
startForegroundService(intent);
I found that this application has only one process 'service' in the phone settings, but there is no 'activity' process, what is the problem? thanks.
Define what you mean by "exit." If you mean they go into recents and swipe the app away, or go into settings and force quit, no. That's the user saying "I want this app to end". That will kill all services. Something that could run even when the user says it shouldn't is basically malware.

WorkManager only executing periodic enqueued tasks when app opened

My app requires that a notification be sent twice a day. For testing purposes, I have shortened this time to 1 hour. This, of course, must be done in the background/when app is closed, so I have already tried AlarmManager and that did not work. I have therefore switched to WorkManager. someone suggested that I use periodicWork to accomplish my task but here is the issue:
WorkManager only executes all periodic work when the app is open
Another weird thing: If I leave the app alone for 3 hours, I will get way more than three notifications when I open the app.
I know for a fact that WorkManager is not executing because I have instantiated a Date Object whenever doWork() is called, and that timestamp from the date object is printed to the notification. This printed time will ALWAYS show as the time I have opened the app, meaning all of the queued work requests were executed at once when I opened the app.
Here is what is used to set the alarm. Note that cancelAlarm() does not cancel the alarm, but rather resets a shared preference I used for debugging
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter);
ToggleButton toggle = findViewById(R.id.toggleButton);
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
setAlarm();
} else {
cancelAlarm();
}
}
});
}
private void setAlarm() {
Constraints constraints = Constraints.NONE;
PeriodicWorkRequest testRequest = new PeriodicWorkRequest.Builder(ReminderWorker.class, 1, TimeUnit.HOURS)
.setConstraints(constraints)
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork("ReminderWork", ExistingPeriodicWorkPolicy.KEEP, testRequest);
}
private void cancelAlarm() {
SharedPreferences savedSharedPreferences = getApplicationContext().getSharedPreferences("USER_PREFERENCES", Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = savedSharedPreferences.edit();
editor.putInt("Test", 0);
editor.commit();
}
Here is the actual ReminderWorker class, I put a SHaredPreference variable to check the amount of times the worker fired, and a Date objectto check the time fired. These are printed in the notification.
public class ReminderWorker extends Worker {
int i;
public final String CHANNEL_ID = "MainChannel";
public ReminderWorker(#NonNull Context context, #NonNull WorkerParameters params) {
super(context, params);
}
#NonNull
#Override
public Result doWork() {
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
SharedPreferences savedSharedPreferences = getApplicationContext().getSharedPreferences("USER_PREFERENCES", Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = savedSharedPreferences.edit();
i = savedSharedPreferences.getInt("Test", 0) + 1;
editor.putInt("Test", i);
editor.commit();
createNotificationChannel();
buildNotification(cal);
return Result.success();
}
private void createNotificationChannel() {
String name = "Birthday Notifications";
String description = "Reminds you when your friends birthday approaches";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getApplicationContext().getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
private void buildNotification(Calendar cal) {
Context context = getApplicationContext();
Intent openTap = new Intent(context, EnterActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, openTap, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
builder.setSmallIcon(R.drawable.pix_cake);
builder.setContentTitle("TestNotification");
builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText("TestText" + i + " Time: " + cal.get(Calendar.HOUR) + ":" + cal.get(Calendar.MINUTE)));
builder.setPriority(NotificationCompat.PRIORITY_MAX);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(i, builder.build());
//notificationManager.cancelAll();
}
}
In case it is needed, here is my AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myfirstapp">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SET_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="#mipmap/main_icon"
android:label="#string/app_name"
android:roundIcon="#mipmap/main_icon_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".ListOfDaysActivity" />
<activity android:name=".MainActivity" />
<activity android:name=".EnterActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
No errors thrown, just not the result expected. I need a notification to show up roughly every hour but that simply isn't happening.Any way around this?
Do you remove the application from task manager? Which device are you using for testing? There are some devices that force close the app and WorkManager tasks are rescheduled once you open the app again.
This answer might help you understand what is going on - https://stackoverflow.com/a/52605503/1313699

Notification using Firebase and Android

I am trying to make an android application where I receive notification using firebase. I followed resources available over the internet.
All I want to do is send notification from firebase, the message that I receive I want to display it in TextView in main activity.
Currently I am testing in an emulator. There are few problems that I am not able to resolve.
I am able to send notification from firebase but:
When the application is running in foreground I don't receive a notification in the android notification panel and nothing happens in the main activity too. That is the text in TextView does not change.
When the application is running in background I do receive the notification in android notification panel with message sent from firebase, clicking the notification main activity opens but the text in TextView does not change.
Firebase Messaging Service
public class VAFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "VAFirebaseMessagingS";
public VAFirebaseMessagingService() {}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d(TAG, "From: " + remoteMessage.getFrom());
if(remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
sendNotification(remoteMessage.getData().get("text"));
}
if(remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Intent.EXTRA_TEXT, messageBody);
PendingIntent pendingIntent = PendingIntent
.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder.setSmallIcon(R.drawable.ic_stat_name);
notificationBuilder.setContentTitle("PFIVA");
notificationBuilder.setContentText(messageBody);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSound(defaultSoundUri);
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
Main Activity
public class MainActivity extends AppCompatActivity {
private TextView userFeedbackQuery;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userFeedbackQuery = (TextView) findViewById(R.id.pfiva_user_feedback_query);
final Intent intent = getIntent();
if(intent.hasExtra(Intent.EXTRA_TEXT)) {
String userFeedbackQueryText = intent.getStringExtra(Intent.EXTRA_TEXT);
userFeedbackQuery.setText(userFeedbackQueryText);
}
}
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.pfiva.mobile.voiceassistant">
<uses-permission android:name="android.permission.INTERNET" />
<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">
<activity android:name=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".messaging.FirebaseInstanceService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".messaging.VAFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
</application>
</manifest>
Please can someone guide what is wrong here? How can i solve the above two problems.
Thanks
After suggestions i made the below changes in Messaging Service, basically added notification channel.
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Intent.EXTRA_TEXT, messageBody);
PendingIntent pendingIntent = PendingIntent
.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
notificationBuilder.setSmallIcon(R.drawable.ic_stat_name);
notificationBuilder.setContentTitle("PFIVA");
notificationBuilder.setContentText(messageBody);
notificationBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSound(defaultSoundUri);
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// 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) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(0, notificationBuilder.build());
}
Problem i face now is that when the app is running in background, i do receive notification in notification panel and clicking on it open main activity but the text in TextView is not updated.
Two ideas to solve your issue:
Have you register your VAFirebaseMessagingService in your AndroidManifest.xml:
Since Android 8, you must use an Notification Channel to send push notifications. Android

Why my alarm not working with BOOT_COMPLETED

My app work when my android is not restart but when I turn off my Android the app not working despite I add BOOT_COMPLETED.
I have looked for similar questions but all of them work just as I do, I do not know what is wrong
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.proyect.d.alarm">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SET_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<service android:name=".BootService" />
<receiver
android:name=".RestartAlarmsReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name=".MyAlarmReceiver"
android:process=":remote" />
</application>
RestartAlarmsReciver
public class RestartAlarmsReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent i = new Intent(context, BootService.class);
ComponentName service = context.startService(i);
}
}
}
BootService: it's equals that my main AlarmService
public class BootService extends IntentService {
public BootService(String name) {
super(name);
}
private NotificationManager notificationManager;
private final int NOTIFICATION_ID = 1010;
private AdminSQLiteOpenHelper admin;
private Cursor fila;
private SQLiteDatabase bd;
private String alarm, descrip, title;
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Calendar calenda = Calendar.getInstance();
int hour, min, day, m, year;
String cadenaF, cadenaH, date_system, time_system;
day = calenda.get(Calendar.DAY_OF_MONTH);
m = calenda.get(Calendar.MONTH) + 1;
year = calenda.get(Calendar.YEAR);
hour = calenda.get(Calendar.HOUR_OF_DAY);
min = calenda.get(Calendar.MINUTE);
date_system = m + "-" + day + "-" + year + " ";
time_system = hour + ":" + min;
admin = new AdminSQLiteOpenHelper(getApplicationContext(), vars.bd, null, vars.version);
bd = admin.getWritableDatabase();
if (bd != null) {
fila = bd.rawQuery("SELECT * FROM alarma WHERE datea='" + date_system + "' AND timea= '" + time_system + "'", null);
if (fila.moveToFirst()) {
alarm = fila.getString(0);
title = fila.getString(1);
descrip = fila.getString(2);
triggerNotification(getApplicationContext(), title + "\n" + descrip);
}
}
bd.close();
}
private void triggerNotification(Context contexto, String t) {
Intent notificationIntent = new Intent(contexto, MainActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(contexto, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
long[] pattern = new long[]{2000, 1000, 2000};
NotificationCompat.Builder builder = new NotificationCompat.Builder(contexto);
builder.setContentIntent(contentIntent)
.setTicker("")
.setContentTitle("alarm ")
.setContentTitle("")
.setContentText(t)
.setContentInfo("Info")
.setLargeIcon(BitmapFactory.decodeResource(contexto.getResources(), R.drawable.ic_launcher_background))
.setSmallIcon(R.drawable.ic_launcher_background)
.setAutoCancel(true)
.setSound(defaultSound)
.setVibrate(pattern);
Notification notificacion = new NotificationCompat.BigTextStyle(builder)
.bigText(t)
.setBigContentTitle("example")
.setSummaryText("more example")
.build();
notificationManager = (NotificationManager) contexto.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notificacion);
}
}
Thanks
Can you change your receiver to add export and category?
<receiver android:name=".RestartAlarmsReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
As per official documentation
android:exported
Whether or not the broadcast receiver can receive messages from sources outside its application — "true" if it can, and "false" if not. If "false", the only messages the broadcast receiver can receive are those sent by components of the same application or applications with the same user ID.
The default value depends on whether the broadcast receiver contains intent filters. The absence of any filters means that it can be invoked only by Intent objects that specify its exact class name. This implies that the receiver is intended only for application-internal use (since others would not normally know the class name). So in this case, the default value is "false". On the other hand, the presence of at least one filter implies that the broadcast receiver is intended to receive intents broadcast by the system or other applications, so the default value is "true".
This attribute is not the only way to limit a broadcast receiver's external exposure. You can also use a permission to limit the external entities that can send it messages (see the permission attribute).
Hope this will help

How can I keep my app's notification displayed when my app is updated on Google Play store?

My app has a function of set-notification. Here is my code.
#SuppressWarnings("deprecation")
public static void setNotification(Context _context) {
NotificationManager notificationManager =
(NotificationManager) _context.getSystemService(Context.NOTIFICATION_SERVICE);
int icon_id = R.drawable.icon;
Notification notification = new Notification(icon_id,
_context.getString(R.string.app_name), System.currentTimeMillis());
//
Intent intent = new Intent(_context, MainActivity.class);
notification.flags = Notification.FLAG_ONGOING_EVENT;
PendingIntent contextIntent = PendingIntent.getActivity(_context, 0, intent, 0);
notification.setLatestEventInfo(_context,
_context.getString(R.string.app_name),
_context.getString(R.string.notify_summary), contextIntent);
notificationManager.notify(R.string.app_name, notification);
}
This code works fine. If my app is closed, notification keeps displayed.
But even if notification was set, the notification is cancelled when user will update my app version by Google Play store.
I know that...
The notification is cancelled when my app is uninstalled.
In fact an update is "uninstall and install".
How can I keep displayed when my app version is updated?
If I understood right you want displaying a notification after updating.
So you can implement receiver that listens updating of app or rebooting of device and shows notification again.
add to you manifest:
<receiver
android:name=".UpdatingReceiver"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
and implement receiver:
public class UpdatingReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) || Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) {
// check is need to show notification
}
}

Categories

Resources