I'm making an reminder app, so I need to send notification every x minutes, as I researched I found that I need to use AlarmManager ( idk if I can use any other method ). So I'm trying to use AlarmManager to fire Notification. It works only when I'm using the phone if phone is locked alarm does not fire, when I unlock the phone then fires.
This is my AndroidManifest.xml:
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".util.NotificationAlarmReceiver"/>
<receiver android:name=".util.BootCompletedReceiver"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" android:enabled="true" android:exported="true">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.ACTION_BOOT_COMPLETED"/>
<action android:name="android.intent.action.REBOOT"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
<action android:name="android.intent.action.ACTION_SHUTDOWN"/>
</intent-filter>
</receiver>
So I have to receivers one for notification and one to Activate alarmManager on boot.
On NotificationAlarmReceiver that extends BroadcastReceiver I'm also trying to use WakeLock:
@Override public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "com.test.reminder:WakeLockForNotification");
wl.acquire(60 * 1000L /*1 minute*/);
// Notification code is here.
wl.release();
}
So I'm trying to wakeup show notification then release, but only does not wakeup. And this is the code I use to set Alarm:
Intent intentAlarm = new Intent(this, NotificationAlarmReceiver.class);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(ALARM_SERVICE);
PendingIntent pi = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.getBroadcast(this, Constants.ALARM_ID, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE) : PendingIntent.getBroadcast(this, Constants.ALARM_ID, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+tinyDB.getLong(Constants.notification_interval_key,AlarmManager.INTERVAL_HALF_HOUR), tinyDB.getLong(Constants.notification_interval_key,AlarmManager.INTERVAL_HALF_HOUR), pi);
So is there any solution to show notification every time is needed. I also read on android documentation to not use exact alarm manager, I also saw someone used job scheduler, but i'm not familiar with that, but also with that they had problems, so any idea or solution will be appriciated.
I went through this process myself. The documentation surrounding alarms/timers is unnecessarily confusing. To simplify things, if your app is actually a reminder app and the user truly expects a notification to occur precisely every X minutes, then it is OK to use exact alarms.
But be careful because the Android gods hate common sense and any sort of consistency. The only reliable exact alarm is
setAlarmClock(), especially when you are dealing with Doze mode. Also, while the namesetExactAndAllowWhileIdle()may sound like it will always execute exactly, it doesn't per the documentation:The last part is the part the ruins any hope for using
setExactAndAllowWhileIdle()as a repeating alarm.And contrary to what you might think, you do not want
setInexactRepeating()or evensetRepeating(). If you look closely enough, the little note at the bottom of the documentation says:So, to actually implement reliable repeating exact alarms, you must schedule the first alarm using
setAlarmClock()and everytime the alarm goes off, schedule the next notification/alarm usingsetAlarmClock(). As a tip for developing this, you can store information about when to schedule the next alarm in the extras of the Broadcast Intent.Here is the sad part: the above may work for AOSP but other vendors take liberties in how they manage alarms. See https://dontkillmyapp.com/ for who those vendors are.
Some extra information:
AlarmManager already provides a wake lock in the BroadcastReceiver's
onRecieve()method, as described here:As pointed out in the comments of the question, in order to use exact alarms (and therefore
setAlarmClock()), you need to declare theSCHEDULE_EXACT_ALARMpermission in your manifest. Be aware that this is a special permission and can be revoked. You can use thecanScheduleExactAlarmsto determine if the permission is revoked. I recommend looking at the documentation for that and forACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED, to see how to handle the permission being revoked.