Follow up on acb48752c
.
Just have the subclass call that method to guarantee that everything is
initialized.
93 lines
2.7 KiB
Java
93 lines
2.7 KiB
Java
package org.thoughtcrime.securesms.service;
|
|
|
|
import android.app.AlarmManager;
|
|
import android.app.Application;
|
|
import android.app.PendingIntent;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.os.Handler;
|
|
import android.os.HandlerThread;
|
|
|
|
import androidx.annotation.AnyThread;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.WorkerThread;
|
|
|
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
|
|
|
/**
|
|
* Class to help manage scheduling events to happen in the future, whether the app is open or not.
|
|
*/
|
|
public abstract class TimedEventManager<E> {
|
|
|
|
private final Application application;
|
|
private final Handler handler;
|
|
|
|
public TimedEventManager(@NonNull Application application, @NonNull String threadName) {
|
|
HandlerThread handlerThread = new HandlerThread(threadName);
|
|
handlerThread.start();
|
|
|
|
this.application = application;
|
|
this.handler = new Handler(handlerThread.getLooper());
|
|
}
|
|
|
|
/**
|
|
* Should be called whenever the underlying data of events has changed. Will appropriately
|
|
* schedule new event executions.
|
|
*/
|
|
public void scheduleIfNecessary() {
|
|
handler.removeCallbacksAndMessages(null);
|
|
|
|
handler.post(() -> {
|
|
E event = getNextClosestEvent();
|
|
|
|
if (event != null) {
|
|
long delay = getDelayForEvent(event);
|
|
|
|
handler.postDelayed(() -> {
|
|
executeEvent(event);
|
|
scheduleIfNecessary();
|
|
}, delay);
|
|
|
|
scheduleAlarm(application, delay);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @return The next event that should be executed, or {@code null} if there are no events to execute.
|
|
*/
|
|
@WorkerThread
|
|
protected @Nullable abstract E getNextClosestEvent();
|
|
|
|
/**
|
|
* Execute the provided event.
|
|
*/
|
|
@WorkerThread
|
|
protected abstract void executeEvent(@NonNull E event);
|
|
|
|
/**
|
|
* @return How long before the provided event should be executed.
|
|
*/
|
|
@WorkerThread
|
|
protected abstract long getDelayForEvent(@NonNull E event);
|
|
|
|
/**
|
|
* Schedules an alarm to call {@link #scheduleIfNecessary()} after the specified delay. You can
|
|
* use {@link #setAlarm(Context, long, Class)} as a helper method.
|
|
*/
|
|
@AnyThread
|
|
protected abstract void scheduleAlarm(@NonNull Application application, long delay);
|
|
|
|
/**
|
|
* Helper method to set an alarm.
|
|
*/
|
|
protected static void setAlarm(@NonNull Context context, long delay, @NonNull Class alarmClass) {
|
|
Intent intent = new Intent(context, alarmClass);
|
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
|
|
AlarmManager alarmManager = ServiceUtil.getAlarmManager(context);
|
|
|
|
alarmManager.cancel(pendingIntent);
|
|
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, pendingIntent);
|
|
}
|
|
}
|