I need to show the user a notification at the same time every day (based on a user selecting the time it is shown). With API 25 and earlier I can use AlarmManager without a problem. However with API 26 (Oreo) it will crash my app if the app is in the background for more than a few minutes. Nothing I've done seems to prevent AlarmManager crashing after about a minute of the app being in the background.
Based on what I have seen online the only solution is to use a JobScheduler, but there doesn't seem to be anyway to have a JobScheduler start at a certain time and then recur every day. (I can have it run at a certain time by calling setOverrideDeadline or I can make it recurring by calling setPeriodic, but calling both throws and exception.)
This is my code for the JobScheduler (I have it set to recur every 15 seconds for testing, but I also want to be able to start it at a certain time):
private void setReminders(){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_BOOT_COMPLETED) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.RECEIVE_BOOT_COMPLETED }, 613);
return;
}
SharedPreferences sharedPreferences = this.getSharedPreferences(getString(R.string.shared_pref_file_name), ContextWrapper.MODE_PRIVATE);
boolean showReminder = sharedPreferences.getBoolean(getString(R.string.shared_pref_reminder_active_key), false);
int hour = sharedPreferences.getInt(getString(R.string.shared_pref_reminder_hour_key), 21);
int minute = sharedPreferences.getInt(getString(R.string.shared_pref_reminder_minute_key), 0);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
long startUpTime = Calendar.getInstance().getTimeInMillis() + 10000; //calendar.getTimeInMillis() + 10000;
JobInfo.Builder builder = new JobInfo.Builder( 613, new ComponentName(getPackageName(), SefiraReminderJobService.class.getName()));
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
.setOverrideDeadline(15000)
.setRequiresDeviceIdle(false)
.setRequiresCharging(false)
.setPersisted(true);
builder.setPeriodic(Math.max(15000, JobInfo.getMinPeriodMillis()));
JobScheduler jobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
if(jobScheduler.schedule(builder.build()) == JobScheduler.RESULT_FAILURE ) {
Log.w("MainActivity.setReminders", "Something went wrong when scheduling the reminders" );
}
}
This is my JobIntentService class:
public final class ReminderJobService extends JobIntentService {
private NotificationManager notificationManager;
private PendingIntent pendingIntent;
private static int NOTIFICATION_ID = 1234;
private static String NOTIFICATION_CHANNEL_ID = "my-reminder-channel";
private Notification notification;
#Override
protected void onHandleWork(#NonNull Intent intent) {
Context context = this.getApplicationContext();
notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, MainActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0, mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Reminders", NotificationManager.IMPORTANCE_DEFAULT);
// Configure the notification channel.
notificationChannel.setDescription("My Reminders");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_launcher_foreground)
//.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
//.setTicker("ticker value")
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
.setContentTitle("Reminder")
.setContentText("Reminder Message").build();
notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
notification.ledARGB = 0xFFFFA500;
notification.ledOnMS = 800;
notification.ledOffMS = 1000;
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
notificationManager.notify(NOTIFICATION_ID, notification);
} catch (Exception ex){
ex.printStackTrace();
}
}
}
My AndroidManifest contains the following:
<service android:name="ReminderJobService"
android:permission="android.permission.BIND_JOB_SERVICE"></service>
As well as:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
How can I send a recurring notification each day at a specific time on Android 26/8.0/Oreo even when the app is in the background?
This workable decision but with deprecated logic:
public scheduleEvent(int id, long scheduleTime) {
final PendingIntent pendingIntent = pendingIntent(id);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
}
private PendingIntent pendingIntent(int id) {
final Intent intent = new Intent(app, EventReceiver.class);
intent.setAction("some event " + id);
return PendingIntent.getBroadcast(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Create EventReceiver don't forget add it in AndroidManifest
public class EventReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final ComponentName comp = new ComponentName(context.getPackageName(), EventService.class.getName());
startWakefulService(context, intent.setComponent(comp));
}
}
Create EventService, also add it to the AndroidManifest
public class EventService extends IntentService {
#Override
protected void onHandleIntent(final Intent intent) {
//Your logic here
}
}
Related
I have created a sample notification for a project I am currently working on, using this code in the onCreate method of my Main Activity.
I have also got a TimePicker Fragment class, which as the name suggests, opens up a time picker dialogue which allows the user to set a specific time of day. Then, the hour and minutes are stored in DataSite.class, which holds a number of get and set methods. Below is the code for TimePicker.class:
public class TimePickerFragment extends DialogFragment
implements TimePickerDialog.OnTimeSetListener {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the current time as the default values for the picker
final Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
// Create a new instance of TimePickerDialog and return it
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
DataSite ds = new DataSite();
ds.setHour(hourOfDay);
ds.setMinute(minute);
}
}
In short, I would like to schedule the createNotificationChannel(); method call on the Main Activity, according to the hour and minutes the user has selected. As I said, the time information is stored in DataSite.
I have gotten the time picker working, and the notification shows as expected. All that I need now is a way to combine these two functionalities. As far as I can tell from other forum posts, I will have to use the Alarm Manager, but nothing I have read elsewhere works for me.
Edit: I have attempted to utilize the AlarmManager. Below you can see the full code I currently have so far:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_initial_screen);
.
.
.
.
.
Intent intent = new Intent(this, InitialScreen.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "reflectnotification")
.setSmallIcon(R.drawable.app_icon_background)
.setContentTitle("Reflect Reminder")
.setContentText("Time to Reflect on your selected Goal!")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Time to Reflect on your selected Goal!"))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
createNotificationChannel();
// notificationManager.notify(200, builder.build());
hour = ((DataSite)getApplication()).getHour();
minute = ((DataSite)getApplication()).getMinute();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
Toast.makeText(getApplicationContext(),"Picked time: "+ hour +":"+minute, Toast.LENGTH_LONG).show();
alarmMgr = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent intent2 = new Intent(getApplicationContext(), InitialScreen.class);
alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), 200, intent2, 0);
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);
}
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 = "Reflect Reminder";
String description = "Time to Reflect on your selected Goal!";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("reflectnotification", name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
If there is an exact time that the notification needs to be sent, you will want to use AlarmManager. See https://developer.android.com/training/scheduling/alarms
The docs describe when to use AlarmManager vs. other APIs: https://developer.android.com/guide/background#alarms
Okay After too much research and fighting with this finally I did it
Note: this is suitable for Android O+ Versions
In Activity Class
button.setOnClickListener(view -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Calendar calendar = Calendar.getInstance();
//10 is for how many seconds from now you want to schedule also you can create a custom instance of Callender to set on exact time
calendar.add(Calendar.SECOND, 10);
//function for Creating [Notification Channel][1]
createNotificationChannel();
//function for scheduling the notification
scheduleotification(calendar);
}
});
code for createNotificationChannel()
#RequiresApi(api = Build.VERSION_CODES.O)
public void createNotificationChannel() {
String id = "channelID";
String name = "Daily Alerts";
String des = "Channel Description A Brief";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setDescription(des);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
}
code for scheduleNotification(Calender calendar);
#RequiresApi(api = Build.VERSION_CODES.M)
public void scheduleNotification(Calendar calendar) {
Intent intent = new Intent(getApplicationContext(), Notification.class);
intent.putExtra("titleExtra", "Dynamic Title");
intent.putExtra("textExtra", "Dynamic Text Body");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
Toast.makeText(getApplicationContext(), "Scheduled ", Toast.LENGTH_LONG).show();
}
Notification.kt
class Notification : BroadcastReceiver()
{
override fun onReceive(context: Context, intent: Intent) {
message = intent.getStringExtra("textExtra").toString()
title = intent.getStringExtra("titleExtra").toString()
val notification =
NotificationCompat.Builder(context, channelID).setSmallIcon(R.drawable.notification)
.setContentText(message).setContentTitle(title).build()
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.notify(notificationId, notification)
}
}
I am trying to develop an application in which the user can create more than 1 alarms for the same time ,say, 09:48. And for this time, each alarm has to create its own notification which leads the user to an activity when the notification is clicked. The other alarms which were scheduled at the same time must keep ringing until their notifications are clicked. Now, I am able to create alarms for different times and get their corresponding notifications which lead to an activity in which the user can dismiss or snooze the alarm. However, when I schedule more than one alarm for the same time, only 1 alarm is ringing and the other one gets lost. I share my code pieces at the below.
public void schedule(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmBroadcastReceiver.class);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(context, alarmId, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
alarmPendingIntent
);
In my broadcastReceiver class:
private void startAlarmService(Context context, Intent intent) {
Intent intentService = new Intent(context, AlarmService.class);
Log.println(Log.DEBUG, "DEBUG", "************Alarm Broadcast Receiver**********");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intentService);
} else {
context.startService(intentService);
}
}
In my AlarmService :
#Override
public void onCreate() {
super.onCreate();
mediaPlayer = MediaPlayer.create(this, R.raw.alarm);
mediaPlayer.setLooping(true);
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, RingActivity.class);
int requestCode = new Random().nextInt(Integer.MAX_VALUE);
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, notificationIntent, 0);
//String alarmTitle = String.format("%s Alarm", intent.getStringExtra(TITLE));
int notificationId = new Random().nextInt(Integer.MAX_VALUE);
Notification notification = new NotificationCompat.Builder(this, String.valueOf(notificationId))
.setContentTitle("PASS1")
.setContentText("PASS2")
.setSmallIcon(R.drawable.pill)
.setContentIntent(pendingIntent)
.build();
mediaPlayer.start();
long[] pattern = { 0, 100, 1000 };
vibrator.vibrate(pattern, 0);
startForeground(1, notification);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
vibrator.cancel();
}
in this code
startForeground(1, notification);
you are using 1 as the id.
If a notification with the same id has already been posted by your application and has not yet been canceled, it will be replaced by the updated information.
So the second alarm notification with the same id (because you are using a fixed value of 1) is replacing the old one
guys, I am developing an alarm app in which alarm is triggering good and at the right time but the drawback is when the alarm is ringing with an activity then when we press the home button too it is ringing the real problem is when the application is closed by pressing the home button and pressing or swiping close all apps the application getting destroyed I need something like Google does like showing a notification and playing sound even if the application is closed.
So I think someone is having Idea about this issue.
Here is what from Google Clock
Googel Clock image
Because of android Q, I had developed something that when the user is alive at the time of alarm then we just show notification with the help of this.
public class DismissAlarmNotificationController {
public final int NOTIFICATION_ID = 1;
public static final String INTENT_KEY_NOTIFICATION_ID = "notificationId";
public final String CHANNEL_ID = "channel-01";
private NotificationManager notificationManager;
private Context context;
private final int IMPORTANCE = NotificationManager.IMPORTANCE_HIGH;
public DismissAlarmNotificationController(Context context) {
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
this.context = context;
}
public void showNotification() {
Intent fullScreenIntent = new Intent(context, DismissAlarmActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(context, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(
CHANNEL_ID, getChannelName(), IMPORTANCE);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_alarm_on_notification)
.setContentTitle(context.getString(R.string.dismiss_alarm_notification_title))
.setContentText(context.getString(R.string.dismiss_alarm_notification_body, getCurrentTime()))
.setAutoCancel(true)
.addAction(getDismissNotificationAction())
.setFullScreenIntent(fullScreenPendingIntent, true);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
public String getChannelName() {
return context.getString(R.string.app_name) + "Channel";
}
public void cancelNotification() {
notificationManager.cancelAll();
}
private NotificationCompat.Action getDismissNotificationAction() {
Intent dismissIntent = new Intent(context, DismissNotificationReceiver.class);
dismissIntent.putExtra(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID);
PendingIntent dismissNotificationPendingIntent = PendingIntent.getBroadcast(context, 0, dismissIntent, PendingIntent.FLAG_CANCEL_CURRENT);
return new NotificationCompat.Action.Builder(
0,
context.getString(R.string.dismiss_alarm_notification_dismiss_button_title),
dismissNotificationPendingIntent)
.build();
}
private String getCurrentTime() {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm");
Date currentTime = new Date();
return dateFormat.format(currentTime);
}
}
Thanks in advance.
Give a try to Android's WorkManager!
It lets you run background works even if the app is closed or the phone has been restarted.
Hope it will help!
bookAppoinmentBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
setAlarm(String time, String strDate);
}
});
public void setAlarm(String time, String strDate){
AlarmManager manager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
String hour=formateDateFromstring("HH:mm","HH",time);
String min=formateDateFromstring("HH:mm","mm",time);
String date=formateDateFromstring("yyyy-MM-dd","dd",strDate);
String month=formateDateFromstring("yyyy-MM-dd","MM",strDate);
String year=formateDateFromstring("yyyy-MM-dd","yyyy",strDate);
cal.set(Calendar.DATE, Integer.parseInt(date)); //1-31
cal.set(Calendar.MONTH, Integer.parseInt(month)); //first month is 0!!! January is zero!!!
cal.set(Calendar.YEAR, Integer.parseInt(year));//year...
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour)); //HOUR
cal.set(Calendar.MINUTE, Integer.parseInt(min)); //MIN
manager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
pendingIntent);
}
Here i am using alarm manager to send notification for the selected time and date.I tried sample project with the same code its working after that i integrated with my project its not working.
//Here is my code for receiver
public class ServiceReceiver extends BroadcastReceiver {
private Context mcontext;
#Override
public void onReceive(Context context, Intent intent) {
this.mcontext = context;
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.logob_icon_prestigesalon)
.setContentTitle("ABC")
.setContentText("time to go")
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManager notificationmanager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
notificationmanager.notify(0, builder.build());
}
}
After searching a lot, I have found how to sent notifications using Alarm Manager in Kotlin. I have added the following stuff. In here, I have schedule the alarm for every minutes, so that it will trigger in every minutes(For my case, checking a time from Realm Database, and fire notification on that particular time). This notification will trigger even when your app is closed( removed from recent task). But I don't know whether this is the correct way. I have tested in Android R(11) and also on emulator, in both case it works fines.
create a the following function and call from your activity
private fun scheduleAlarm() {
val alarmIntent = Intent(this, AlarmReceiver::class.java)
alarmIntent.putExtra("data", "Pass your message")
val pendingIntent =
PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
val afterOneMinutes = SystemClock.elapsedRealtime() + 1 * 1 * 1000
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) alarmManager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP, afterTwoMinutes, 1000 * 1, pendingIntent
) else alarmManager.setExact(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
afterOneMinutes , pendingIntent
)
}
You can set the repeating time in here,
val afterOneMinutes = SystemClock.elapsedRealtime() + 1 * 1 * 1000
Here I'm repeating in every one minutes.
The main logic comes in Broadcast Receiver class(My case)
class AlarmReceiver : BroadcastReceiver() {
#RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context, intent: Intent) {
Log.e("TAG", "Alarm received")
if("Your Condition")
{
sendNotification(context, intent.getStringExtra("data"))
}
}
#RequiresApi(Build.VERSION_CODES.O)
fun sendNotification(mcontext: Context, messageBody: String?)
{
val intent = Intent(mcontext, YourActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(
mcontext, 0 /* Request code */, intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
val notificationManager =
mcontext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val defaultSoundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(
mcontext.getString(R.string.default_notification_channel_id),
"Rewards Notifications",
NotificationManager.IMPORTANCE_DEFAULT
)
// Configure the notification channel.
notificationChannel.description = "Channel description"
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.GREEN
notificationChannel.vibrationPattern = longArrayOf(0, 500, 200, 500)
notificationChannel.enableVibration(true)
notificationManager.createNotificationChannel(notificationChannel)
}
val notificationBuilder = Notification.Builder(
mcontext,
mcontext.getString(R.string.default_notification_channel_id)
)
.setContentTitle(mcontext.getString(R.string.app_name))
.setContentText(messageBody)
.setAutoCancel(true)
.setSmallIcon(R.drawable.app_icon)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
}
}
In here, I have set a condition in onReceive() method. If condition is true, it fires the notification. You can also use firebase real-time database changes, time changes, database changes, or any other condtions, whatever you want.
Don't forget to register receiver in manifest
I hope it will useful for some peoples and happy coding..............
Basically, I am trying to build an alarm app which has some buttons with some predefined Date and Time. I have tried using AlarmManager and broadcast receiver in the first place but didn't work. So, I used foreground service with alarmManager but still, the alarm doesn't fire when the app is destroyed. I am a newbie. I tried searching the internet but I had no luck. Hope there is a lot of people here to help me out. Thanks in Advance.
Here I am just trying to set only one alarm for testing. Otherwise, I am using a variable as request code for multiple alarms.
AndroidManifest.xml
<receiver android:name=".AlarmReceiver" />
<activity
android:name=".Activity.PlayerDetailsActivity"
android:theme="#style/AppTheme.NoActionBar"></activity>
<activity android:name=".Activity.FixtureActivity" />
<service android:name=".MyService"/>
MyService.java
public class MyService extends Service {
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Started", Toast.LENGTH_SHORT).show();
Log.e("service","service");
long longExtra = intent.getLongExtra(Constants.ALARM_TIME, 0000);
//Testing Area Start
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(longExtra);
int mMin = calendar.get(Calendar.MINUTE);
int mMonth = calendar.get(Calendar.MONTH);
int mDay = calendar.get(Calendar.DAY_OF_MONTH);
int mHour = calendar.get(Calendar.HOUR_OF_DAY);
Log.e("hour min month day"," "+mHour + " : "+mMin+" month : "+mMonth+" "+" Date : "+mDay+" ");
String currentDateTime=getDeviceDateTime();
Log.e("CurrentdateTime",""+currentDateTime);
Log.e("longExtra",""+longExtra);
//Testing Area End
String CHANNEL_ID = "my_channel_01";
NotificationChannel channel = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channel = new NotificationChannel(CHANNEL_ID,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("dfdf")
.setSmallIcon(R.drawable.ic_notifications_black_24dp)
.setContentText("dfdfd").build();
startForeground(3, notification);
}
/*Intent alertIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Log.d("I",""+longExtra);
alarmManager.set(AlarmManager.RTC_WAKEUP, 6000000, PendingIntent.getBroadcast(getApplicationContext(), 0, alertIntent,
PendingIntent.FLAG_ONE_SHOT));*/
AlarmManager manager= (AlarmManager)getSystemService(ALARM_SERVICE);
Intent myIntent;
myIntent = new Intent(getApplicationContext(),AlarmReceiver.class);
myIntent.putExtra("check",true);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,myIntent,0);
Long finalTime =longExtra-System.currentTimeMillis();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
manager.setExact(AlarmManager.RTC_WAKEUP,longExtra,pendingIntent);
}
else
manager.set(AlarmManager.RTC_WAKEUP,longExtra,pendingIntent);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Alarmreceiver.java
public class AlarmReceiver extends BroadcastReceiver
{
public static final String CHANNEL_ID = "47";
#Override
public void onReceive(Context context, Intent intent)
{
intent = new Intent(context, SplashActivity.class);
intent.putExtra("not",true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationCompat = new NotificationCompat.Builder(context,CHANNEL_ID);
notificationCompat.setSmallIcon(R.drawable.ic_notifications_black_24dp);
notificationCompat.setContentTitle("My Noticiation");
notificationCompat.setContentText(getPreferences(context).getDateTime());
notificationCompat.setContentIntent(pendingIntent);
notificationCompat.setSound(alarmSound);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel name", importance);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
Notification notification = notificationCompat.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(100,notification);
Toast.makeText(context, "Alarm Working", Toast.LENGTH_SHORT).show();
}
}
you have to start your service so then it can set alarm and fire reciever
start it like this from your activity class
Intent intent=new Intent(this,MyService.class);
startService(intent);
Consider using JobScheduler as a persistence mechanism. It is wakeful and handles the wake locks for you. Only downside it's for Android SDK >= 21 (Lollipop).
There's also a new friend in town that does the backward compatibility for you: WorkManager and will work with all version of Android, even below Lollipop.
Intent myIntent;
myIntent = new Intent(this, AlarmReceiver.class);
myIntent.putExtra("check",true);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);
=============================
Would you change your above code like this ?
Intent myIntent;
myIntent = new Intent(this , MyService.class);
myIntent.setAction("REQUEST_FROM_ALARM_MANAGER");
PendingIntent pendingIntent = PendingIntent.getForegroundService(this,0,myIntent,0);
====================================================
And Service class
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mContext = this;
Log.e(TAG, "onStartCommand " + intent);
if(intent == null) {
return START_NOT_STICKY;
}
if("REQUEST_FROM_ALARM_MANAGER".equals(intent.getAction())){
// show Notification here for your foreground service
}
return START_NOT_STICKY;
}
You have to start a service that survive to your app, you can see here how to do it