Using the code of BroadcastReceiver
of the answer that refers and implementing what is referred to in the notes, it will be like this:
public class StartUpBootReceiver extends BroadcastReceiver {
private static String HOUR = "hour";
private static String MINUTE = "minute";
public static void setAlarm(Context context, int hour, int minute){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferences.edit()
.putInt(HOUR, hour)
.putInt(MINUTE, minute)
.apply();
setAlarm(context);
}
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
setAlarm(context);
Toast.makeText(context, "Alarm set", Toast.LENGTH_LONG).show();
}
}
private static void setAlarm(Context context) {
int hour = getHour(context);
int minute = getMinute(context);
if(hour == -1 || minute == -1){
//nenhum horário definido
return;
}
// Cria um Calendar para o horário estipulado
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
//Se já passou
if(isDateBeforeNow(calendar)){
//adiciona um dia
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
//PendingIntent para lançar o serviço
Intent serviceIntent = new Intent(context, BootService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
//Cancela um possível alarme existente
alarmManager.cancel(pendingIntent);
//Alarme que se repete todos os dias a uma determinada hora
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
pendingIntent);
}
private static int getHour(Context context){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getInt(HOUR, -1);
}
private static int getMinute(Context context){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getInt(MINUTE, -1);
}
private static boolean isDateBeforeNow(Calendar calendar){
return calendar.getTimeInMillis() <= System.currentTimeMillis();
}
}
Use the
StartUpBootReceiver.setAlarm(context, hour, minute);
to set / change the alarm time.
If the device is switched off, the alarm is re-registered when the device is switched on.
Declare BroadcastReceiver
in AndroidManifest.xml
<receiver android:name="aSuaPackage.StartUpBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Add the permission
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Implement the service to launch the notification:
public class BootService extends IntentService {
private PowerManager.WakeLock wakeLock;
public BootService() {
super("name");
}
@Override
public void onCreate() {
super.onCreate();
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "BootService");
wakeLock.acquire();
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//Lance a notificação aqui.
}
@Override
public void onDestroy() {
super.onDestroy();
if(wakeLock.isHeld()){
//Verificou-se que o iluminar do ecrã
//não acontecia devido ao WakeLock ser
//rapidamente libertado(apesar de PowerManager.ON_AFTER_RELEASE !?).
try {
//Atrasa a libertação do WakeLock
//de forma a permitir a iluminação do ecrâ.
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
wakeLock.release();
}
}
}
Declare it in AndroidManifest.xml
<service android:name=".BootService"/>
and add permission to get Wake Lock
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Note: The first release of an inexact repeating alarm , as highlighted in documentation will never be before the specified time, but may not occur for most of the time after time. If the replay interval is large and you set the alarm to a time thereafter, the first posting may only occur after the interval has elapsed.
An alternative is to use the setRepeating()
method instead of setInexactRepeating()
. However, from API 19 all "repeating alarms" are considered "inexact" .
The solution is to set an alarm using the set()
method and then add the interval to the calendar and set another alarm using setInexactRepeating()
.
A possible implementation for INTERVAL_DAY
will look like this:
public class StartUpBootReceiver extends BroadcastReceiver {
private static int REPEATING_ID = 1001;
private static int ON_TIME_ID = 1002;
private static String HOUR = "hour";
private static String MINUTE = "minute";
public static void setAlarm(Context context, int hour, int minute){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferences.edit()
.putInt(HOUR, hour)
.putInt(MINUTE, minute)
.apply();
setAlarm(context);
}
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
setAlarm(context);
Toast.makeText(context, "Alarm set", Toast.LENGTH_LONG).show();
}
}
private static void setAlarm(Context context) {
int hour = getHour(context);
int minute = getMinute(context);
if(hour == -1 || minute == -1){
//nenhum horário definido
return;
}
//Cancela possiveis alarmes existentes
cancelAlarm(context);
Calendar calendar = getCalendar(hour, minute);
//Se já passou
if(isDateBeforeNow(calendar)){
//adiciona um dia
calendar.add(Calendar.DAY_OF_MONTH, 1);
}else{
//Alarme para o horário especificado
setOneTimeAlarm(context, calendar);
//adiciona um dia para repetir o alarme no dia seguinte
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
//Repete o alarme no dia seguinte
setRepeatingAlarm(context, calendar);
}
private static void setRepeatingAlarm(Context context, Calendar calendar){
PendingIntent pendingIntent = getPendingIntent(context, REPEATING_ID);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
//Alarme que se repete todos os dias a uma determinada hora
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
pendingIntent);
}
private static void setOneTimeAlarm(Context context, Calendar calendar){
PendingIntent pendingIntent= getPendingIntent(context, ON_TIME_ID);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
//Alarme para o horário especificado
alarmManager.set(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
pendingIntent);
}
private static void cancelAlarm(Context context){
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(getPendingIntent(context, ON_TIME_ID));
alarmManager.cancel(getPendingIntent(context, REPEATING_ID));
}
private static PendingIntent getPendingIntent(Context context, int id){
//PendingIntent para lançar o serviço
Intent serviceIntent = new Intent(context, BootService.class);
return PendingIntent.getService(context, id, serviceIntent, 0);
}
private static Calendar getCalendar(int hour, int minute){
// Cria um Calendar para o horário especificado
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);
return calendar;
}
private static int getHour(Context context){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getInt(HOUR, -1);
}
private static int getMinute(Context context){
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getInt(MINUTE, -1);
}
private static boolean isDateBeforeNow(Calendar calendar){
return calendar.getTimeInMillis() <= System.currentTimeMillis();
}
}