Skip to content

Commit

Permalink
Use alarm clock for scheduling message sends.
Browse files Browse the repository at this point in the history
  • Loading branch information
cody-signal authored and greyson-signal committed Feb 14, 2023
1 parent 56b35f3 commit 3a0dbe6
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4648,16 +4648,20 @@ public List<MessageRecord> getScheduledMessagesBefore(long time) {
}
}

public @Nullable Long getOldestScheduledSendTimestamp() {
public @Nullable MessageRecord getOldestScheduledSendTimestamp() {
String[] columns = new String[] { SCHEDULED_DATE };
String selection = STORY_TYPE + " = ? AND " + PARENT_STORY_ID + " <= ? AND " + SCHEDULED_DATE + " != ?";
String[] args = SqlUtil.buildArgs(0, 0, -1);
String order = SCHEDULED_DATE + " ASC, " + ID + " ASC";
String limit = "1";

try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, columns, selection, args, null, null, order, limit)) {
return cursor != null && cursor.moveToNext() ? cursor.getLong(0) : null;
try (MmsReader reader = mmsReaderFor(getReadableDatabase().query(TABLE_NAME, MMS_PROJECTION, selection, args, null, null, order, limit))) {
if (reader.getNext() != null) {
return reader.getCurrent();
}
}

return null;
}

public Cursor getMessagesForNotificationState(Collection<DefaultMessageNotifier.StickyThread> stickyThreads) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ protected long getDelayForEvent(@NonNull ViewOnceExpirationInfo event) {

@AnyThread
@Override
protected void scheduleAlarm(@NonNull Application application, long delay) {
protected void scheduleAlarm(@NonNull Application application, ViewOnceExpirationInfo event, long delay) {
setAlarm(application, delay, ViewOnceAlarm.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ExpiringStoriesManager(
override fun getDelayForEvent(event: Event): Long = event.delay

@WorkerThread
override fun scheduleAlarm(application: Application, delay: Long) {
override fun scheduleAlarm(application: Application, event: Event, delay: Long) {
setAlarm(application, delay, ExpireStoriesAlarm::class.java)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected long getDelayForEvent(@NonNull PendingRetryReceiptModel event) {

@AnyThread
@Override
protected void scheduleAlarm(@NonNull Application application, long delay) {
protected void scheduleAlarm(@NonNull Application application, PendingRetryReceiptModel event, long delay) {
setAlarm(application, delay, PendingRetryReceiptAlarm.class);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package org.thoughtcrime.securesms.service

import android.app.Application
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.conversation.ConversationIntents
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.IndividualSendJob
import org.thoughtcrime.securesms.jobs.PushGroupSendJob
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.ServiceUtil
import kotlin.time.Duration.Companion.seconds

/**
Expand All @@ -32,12 +38,12 @@ class ScheduledMessageManager(
@Suppress("UsePropertyAccessSyntax")
@WorkerThread
override fun getNextClosestEvent(): Event? {
val oldestTimestamp = messagesTable.getOldestScheduledSendTimestamp() ?: return null
val oldestMessage = messagesTable.getOldestScheduledSendTimestamp() as? MediaMmsMessageRecord ?: return null

val delay = (oldestTimestamp - System.currentTimeMillis()).coerceAtLeast(0)
val delay = (oldestMessage.scheduledDate - System.currentTimeMillis()).coerceAtLeast(0)
Log.i(TAG, "The next scheduled message needs to be sent in $delay ms.")

return Event(delay)
return Event(delay, oldestMessage.recipient.id, oldestMessage.threadId)
}

@WorkerThread
Expand All @@ -60,11 +66,20 @@ class ScheduledMessageManager(
override fun getDelayForEvent(event: Event): Long = event.delay

@WorkerThread
override fun scheduleAlarm(application: Application, delay: Long) {
trySetExactAlarm(application, System.currentTimeMillis() + delay, ScheduledMessagesAlarm::class.java)
override fun scheduleAlarm(application: Application, event: Event, delay: Long) {
val conversationIntent = ConversationIntents.createBuilder(application, event.recipientId, event.threadId).build()

ServiceUtil.getAlarmManager(application)

trySetExactAlarm(
application,
System.currentTimeMillis() + delay,
ScheduledMessagesAlarm::class.java,
PendingIntent.getActivity(application, 0, conversationIntent, PendingIntentFlags.mutable())
)
}

data class Event(val delay: Long)
data class Event(val delay: Long, val recipientId: RecipientId, val threadId: Long)

class ScheduledMessagesAlarm : BroadcastReceiver() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
Expand Down Expand Up @@ -54,7 +55,7 @@ public void scheduleIfNecessary() {
scheduleIfNecessary();
}, delay);

scheduleAlarm(application, delay);
scheduleAlarm(application, event, delay);
}
});
}
Expand Down Expand Up @@ -82,12 +83,12 @@ public void scheduleIfNecessary() {
* use {@link #setAlarm(Context, long, Class)} as a helper method.
*/
@AnyThread
protected abstract void scheduleAlarm(@NonNull Application application, long delay);
protected abstract void scheduleAlarm(@NonNull Application application, E event, long delay);

/**
* Helper method to set an alarm.
*/
protected static void setAlarm(@NonNull Context context, long delay, @NonNull Class alarmClass) {
protected static void setAlarm(@NonNull Context context, long delay, @NonNull Class<? extends BroadcastReceiver> alarmClass) {
Intent intent = new Intent(context, alarmClass);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntentFlags.mutable());
AlarmManager alarmManager = ServiceUtil.getAlarmManager(context);
Expand All @@ -96,7 +97,7 @@ protected static void setAlarm(@NonNull Context context, long delay, @NonNull Cl
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, pendingIntent);
}

protected static void trySetExactAlarm(@NonNull Context context, long timestamp, @NonNull Class alarmClass) {
protected static void trySetExactAlarm(@NonNull Context context, long timestamp, @NonNull Class<? extends BroadcastReceiver> alarmClass, @NonNull PendingIntent showIntent) {
Intent intent = new Intent(context, alarmClass);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntentFlags.mutable());
AlarmManager alarmManager = ServiceUtil.getAlarmManager(context);
Expand All @@ -106,11 +107,7 @@ protected static void trySetExactAlarm(@NonNull Context context, long timestamp,
boolean hasManagerPermission = Build.VERSION.SDK_INT < 31 || alarmManager.canScheduleExactAlarms();
if (hasManagerPermission) {
try {
if (Build.VERSION.SDK_INT >= 23) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timestamp, pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timestamp, pendingIntent);
}
alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(timestamp, showIntent), pendingIntent);
return;
} catch (Exception e) {
Log.w(TAG, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ protected long getDelayForEvent(@NonNull TrimEvent event) {
}

@Override
protected void scheduleAlarm(@NonNull Application application, long delay) {
protected void scheduleAlarm(@NonNull Application application, TrimEvent event, long delay) {
setAlarm(application, delay, TrimThreadsByDateAlarm.class);
}

Expand Down

0 comments on commit 3a0dbe6

Please sign in to comment.