How To Give Notifications On Android On Specific Time In Android Oreo?
Solution 1:
After looking at different posts and some research on AlarmManager
implementation, this is what worked for me.
The base for this is this post and Schedule repeating Alarms Android Documentation.
This is my current implementation:
I have a SwitchPreference
and a TimePicker
implementation is Settings
SwitchPreference to ask if user wants to enable Repeating Daily Notifications.
TimePicker to set the Notification time.
In MainActivity
's OnCreate
method or wherever you are reading the SharedPreferences
do this:
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
Boolean dailyNotify = sharedPref.getBoolean(SettingsActivity.KEY_PREF_DAILY_NOTIFICATION, true);
PackageManager pm = this.getPackageManager();
ComponentName receiver = new ComponentName(this, DeviceBootReceiver.class);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// if user enabled daily notificationsif (dailyNotify) {
//region Enable Daily Notifications
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, sharedPref.getInt("dailyNotificationHour", 7));
calendar.set(Calendar.MINUTE, sharedPref.getInt("dailyNotificationMin", 15));
calendar.set(Calendar.SECOND, 1);
// if notification time is before selected time, send notification the next dayif (calendar.before(Calendar.getInstance())) {
calendar.add(Calendar.DATE, 1);
}
if (manager != null) {
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
//To enable Boot Receiver class
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
//endregion
} else { //Disable Daily Notificationsif (PendingIntent.getBroadcast(this, 0, alarmIntent, 0) != null && manager != null) {
manager.cancel(pendingIntent);
//Toast.makeText(this,"Notifications were disabled",Toast.LENGTH_SHORT).show();
}
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
Next add AlarmReceiver
class that implements BroadcastReceiver
like this:
publicclassAlarmReceiverextendsBroadcastReceiver {
@OverridepublicvoidonReceive(Context context, Intent intent) {
SharedPreferencesprefs= PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(context));
SharedPreferences.EditorsharedPrefEditor= prefs.edit();
NotificationManagernm= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
IntentnotificationIntent=newIntent(context, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntentpendingI= PendingIntent.getActivity(context, 0,
notificationIntent, 0);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannelchannel=newNotificationChannel("default",
"Daily Notification",
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("Daily Notification");
if (nm != null) {
nm.createNotificationChannel(channel);
}
}
NotificationCompat.Builderb=newNotificationCompat.Builder(context, "default");
b.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher_foreground)
.setTicker("{Time to watch some cool stuff!}")
.setContentTitle("My Cool App")
.setContentText("Time to watch some cool stuff!")
.setContentInfo("INFO")
.setContentIntent(pendingI);
if (nm != null) {
nm.notify(1, b.build());
CalendarnextNotifyTime= Calendar.getInstance();
nextNotifyTime.add(Calendar.DATE, 1);
sharedPrefEditor.putLong("nextNotifyTime", nextNotifyTime.getTimeInMillis());
sharedPrefEditor.apply();
}
}
}
The system will turn off the AlarmManager
if Device is powered off or reboots, so restart it again on BOOT COMPLETE
add this class:
publicclassDeviceBootReceiverextendsBroadcastReceiver {
@OverridepublicvoidonReceive(Context context, Intent intent) {
if (Objects.equals(intent.getAction(), "android.intent.action.BOOT_COMPLETED")) {
// on device boot complete, reset the alarmIntentalarmIntent=newIntent(context, AlarmReceiver.class);
PendingIntentpendingIntent= PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
AlarmManagermanager= (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
finalSharedPreferencessharedPref= PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(context));
Calendarcalendar= Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, sharedPref.getInt("dailyNotificationHour", 7));
calendar.set(Calendar.MINUTE, sharedPref.getInt("dailyNotificationMin", 15));
calendar.set(Calendar.SECOND, 1);
CalendarnewC=newGregorianCalendar();
newC.setTimeInMillis(sharedPref.getLong("nextNotifyTime", Calendar.getInstance().getTimeInMillis()));
if (calendar.after(newC)) {
calendar.add(Calendar.HOUR, 1);
}
if (manager != null) {
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
}
}
And Finally do not forget to add these permissions to AndroidManidest
:
<uses-permissionandroid:name="android.permission.WAKE_LOCK" /><uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and register your receivers in AndroidManifest
<application
<!--YOURAPPLICATIONSTUFF--><receiverandroid:name=".DeviceBootReceiver"android:enabled="false"><intent-filter><actionandroid:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver><receiverandroid:name=".AlarmReceiver" />
The Notification
should be set by this at a specific time of the day specified by TimePicker
and if user enabled the SwitchPreference
.
Solution 2:
There are tons of examples of how to do this on StackOverflow, but unfortunately none of them work anymore because Google changed how the AlarmManager works.
- Android 6: Doze
- Android 7: Aggressive Doze [Disables CPU shortly after screen is turned OFF]
- Android 8: Additional restrictions on background services
The only AlarmManager option that allows a developer to wakeup a device at a specific time is AlarmManager.setAlarmClock.
In addition to the alarm, you can set an intent that will enable you to launch your app when the alarm is clicked.
The device can also be awoken at a specific time using a high priority FCM, Firebase Cloud Message.
But in summary, there is no other option: 'setExact' and associated methods no longer work as the name advertises.
Post a Comment for "How To Give Notifications On Android On Specific Time In Android Oreo?"