mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 08:39:22 +01:00
Periodic alarm to check for messages.
This commit is contained in:
committed by
Cody Henthorne
parent
29d66f2b92
commit
98cb6b457c
@@ -11,6 +11,6 @@ public class BootReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(context));
|
||||
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a delayed foreground notification.
|
||||
* <p>
|
||||
* With this, you can {@link #close()} it to dismiss or prevent it showing if it hasn't already.
|
||||
* <p>
|
||||
* You can also {@link #showNow()} to show if it's not already. This returns a regular {@link NotificationController} which can be updated if required.
|
||||
*/
|
||||
public abstract class DelayedNotificationController implements AutoCloseable {
|
||||
|
||||
private static final String TAG = Log.tag(DelayedNotificationController.class);
|
||||
|
||||
public static final long SHOW_WITHOUT_DELAY = 0;
|
||||
public static final long DO_NOT_SHOW = -1;
|
||||
|
||||
private DelayedNotificationController() {}
|
||||
|
||||
static DelayedNotificationController create(long delayMillis, @NonNull Create createTask) {
|
||||
if (delayMillis == SHOW_WITHOUT_DELAY) return new Shown(createTask.create());
|
||||
if (delayMillis == DO_NOT_SHOW) return new NoShow();
|
||||
if (delayMillis > 0) return new DelayedShow(delayMillis, createTask);
|
||||
|
||||
throw new IllegalArgumentException("Illegal delay " + delayMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the foreground notification if it's not already showing.
|
||||
* <p>
|
||||
* If it does show, it returns a regular {@link NotificationController} which you can use to update its message or progress.
|
||||
*/
|
||||
public abstract @Nullable NotificationController showNow();
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
private static final class NoShow extends DelayedNotificationController {
|
||||
|
||||
@Override
|
||||
public @Nullable NotificationController showNow() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Shown extends DelayedNotificationController {
|
||||
|
||||
private final NotificationController controller;
|
||||
|
||||
Shown(@NonNull NotificationController controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.controller.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationController showNow() {
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DelayedShow extends DelayedNotificationController {
|
||||
|
||||
private final Create createTask;
|
||||
private final Handler handler;
|
||||
private final Runnable start;
|
||||
private NotificationController notificationController;
|
||||
private boolean isClosed;
|
||||
|
||||
private DelayedShow(long delayMillis, @NonNull Create createTask) {
|
||||
this.createTask = createTask;
|
||||
this.handler = new Handler(Looper.getMainLooper());
|
||||
this.start = this::start;
|
||||
|
||||
handler.postDelayed(start, delayMillis);
|
||||
}
|
||||
|
||||
private void start() {
|
||||
SignalExecutors.BOUNDED.execute(this::showNowInner);
|
||||
}
|
||||
|
||||
public synchronized @NonNull NotificationController showNow() {
|
||||
if (isClosed) {
|
||||
throw new AssertionError("showNow called after close");
|
||||
}
|
||||
return Objects.requireNonNull(showNowInner());
|
||||
}
|
||||
|
||||
private synchronized @Nullable NotificationController showNowInner() {
|
||||
if (notificationController != null) {
|
||||
return notificationController;
|
||||
}
|
||||
|
||||
if (!isClosed) {
|
||||
Log.i(TAG, "Starting foreground service");
|
||||
notificationController = createTask.create();
|
||||
return notificationController;
|
||||
} else {
|
||||
Log.i(TAG, "Did not start foreground service as close has been called");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
handler.removeCallbacks(start);
|
||||
isClosed = true;
|
||||
if (notificationController != null) {
|
||||
Log.d(TAG, "Closing");
|
||||
notificationController.close();
|
||||
} else {
|
||||
Log.d(TAG, "Never showed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Create {
|
||||
@NonNull NotificationController create();
|
||||
}
|
||||
}
|
||||
@@ -58,11 +58,14 @@ public final class GenericForegroundService extends Service {
|
||||
|
||||
synchronized (GenericForegroundService.class) {
|
||||
String action = intent.getAction();
|
||||
if (ACTION_START.equals(action)) handleStart(intent);
|
||||
else if (ACTION_STOP .equals(action)) handleStop(intent);
|
||||
else throw new IllegalStateException(String.format("Action needs to be %s or %s.", ACTION_START, ACTION_STOP));
|
||||
|
||||
updateNotification();
|
||||
if (action != null) {
|
||||
if (ACTION_START.equals(action)) handleStart(intent);
|
||||
else if (ACTION_STOP .equals(action)) handleStop(intent);
|
||||
else throw new IllegalStateException(String.format("Action needs to be %s or %s.", ACTION_START, ACTION_STOP));
|
||||
|
||||
updateNotification();
|
||||
}
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
@@ -117,6 +120,15 @@ public final class GenericForegroundService extends Service {
|
||||
return binder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for {@param delayMillis} ms before starting the foreground task.
|
||||
* <p>
|
||||
* The delayed notification controller can also shown on demand and promoted to a regular notification controller to update the message etc.
|
||||
*/
|
||||
public static DelayedNotificationController startForegroundTaskDelayed(@NonNull Context context, @NonNull String task, long delayMillis) {
|
||||
return DelayedNotificationController.create(delayMillis, () -> startForegroundTask(context, task));
|
||||
}
|
||||
|
||||
public static NotificationController startForegroundTask(@NonNull Context context, @NonNull String task) {
|
||||
return startForegroundTask(context, task, DEFAULTS.channelId);
|
||||
}
|
||||
@@ -135,6 +147,7 @@ public final class GenericForegroundService extends Service {
|
||||
intent.putExtra(EXTRA_ICON_RES, iconRes);
|
||||
intent.putExtra(EXTRA_ID, id);
|
||||
|
||||
Log.i(TAG, String.format(Locale.US, "Starting foreground service (%s) id=%d", task, id));
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
|
||||
return new NotificationController(context, id);
|
||||
@@ -145,6 +158,7 @@ public final class GenericForegroundService extends Service {
|
||||
intent.setAction(ACTION_STOP);
|
||||
intent.putExtra(EXTRA_ID, id);
|
||||
|
||||
Log.i(TAG, String.format(Locale.US, "Stopping foreground service id=%d", id));
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,17 @@ import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public final class NotificationController implements AutoCloseable {
|
||||
public final class NotificationController implements AutoCloseable,
|
||||
ServiceConnection
|
||||
{
|
||||
private static final String TAG = Log.tag(NotificationController.class);
|
||||
|
||||
private final @NonNull Context context;
|
||||
private final int id;
|
||||
private final Context context;
|
||||
private final int id;
|
||||
|
||||
private int progress;
|
||||
private int progressMax;
|
||||
@@ -30,22 +35,7 @@ public final class NotificationController implements AutoCloseable {
|
||||
}
|
||||
|
||||
private void bindToService() {
|
||||
context.bindService(new Intent(context, GenericForegroundService.class), new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
GenericForegroundService.LocalBinder binder = (GenericForegroundService.LocalBinder) service;
|
||||
GenericForegroundService genericForegroundService = binder.getService();
|
||||
|
||||
NotificationController.this.service.set(genericForegroundService);
|
||||
|
||||
updateProgressOnService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
service.set(null);
|
||||
}
|
||||
}, Context.BIND_AUTO_CREATE);
|
||||
context.bindService(new Intent(context, GenericForegroundService.class), this, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@@ -54,6 +44,7 @@ public final class NotificationController implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
context.unbindService(this);
|
||||
GenericForegroundService.stopForegroundTask(context, id);
|
||||
}
|
||||
|
||||
@@ -87,4 +78,23 @@ public final class NotificationController implements AutoCloseable {
|
||||
|
||||
genericForegroundService.replaceProgress(id, progressMax, progress, indeterminate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
Log.i(TAG, "Service connected " + name);
|
||||
|
||||
GenericForegroundService.LocalBinder binder = (GenericForegroundService.LocalBinder) service;
|
||||
GenericForegroundService genericForegroundService = binder.getService();
|
||||
|
||||
this.service.set(genericForegroundService);
|
||||
|
||||
updateProgressOnService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
Log.i(TAG, "Service disconnected " + name);
|
||||
|
||||
service.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ public abstract class PersistentAlarmManagerListener extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.i(TAG, String.format("%s#onReceive(%s)", getClass().getSimpleName(), intent.getAction()));
|
||||
|
||||
long scheduledTime = getNextScheduledExecutionTime(context);
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
Intent alarmIntent = new Intent(context, getClass());
|
||||
@@ -27,7 +29,7 @@ public abstract class PersistentAlarmManagerListener extends BroadcastReceiver {
|
||||
scheduledTime = onAlarm(context, scheduledTime);
|
||||
}
|
||||
|
||||
Log.i(TAG, getClass() + " scheduling for: " + scheduledTime);
|
||||
Log.i(TAG, getClass() + " scheduling for: " + scheduledTime + " action: " + intent.getAction());
|
||||
|
||||
alarmManager.cancel(pendingIntent);
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
||||
|
||||
Reference in New Issue
Block a user