mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Fix backup job background start restricitions with API31+.
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.app.ForegroundServiceStartNotAllowedException;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
@@ -18,6 +20,7 @@ import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.MainActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.whispersystems.signalservice.api.util.Preconditions;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -126,20 +129,39 @@ public final class GenericForegroundService extends Service {
|
||||
* 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.
|
||||
*
|
||||
* Do not call this method on API > 31
|
||||
*/
|
||||
public static DelayedNotificationController startForegroundTaskDelayed(@NonNull Context context, @NonNull String task, long delayMillis, @DrawableRes int iconRes) {
|
||||
return DelayedNotificationController.create(delayMillis, () -> startForegroundTask(context, task, DEFAULTS.channelId, iconRes));
|
||||
Preconditions.checkArgument(Build.VERSION.SDK_INT < 31);
|
||||
|
||||
return DelayedNotificationController.create(delayMillis, () -> {
|
||||
try {
|
||||
return startForegroundTask(context, task, DEFAULTS.channelId, iconRes);
|
||||
} catch (UnableToStartException e) {
|
||||
Log.w(TAG, "This should not happen on API < 31", e);
|
||||
throw new AssertionError(e.getCause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static NotificationController startForegroundTask(@NonNull Context context, @NonNull String task) {
|
||||
public static NotificationController startForegroundTask(@NonNull Context context, @NonNull String task) throws UnableToStartException {
|
||||
return startForegroundTask(context, task, DEFAULTS.channelId);
|
||||
}
|
||||
|
||||
public static NotificationController startForegroundTask(@NonNull Context context, @NonNull String task, @NonNull String channelId) {
|
||||
public static NotificationController startForegroundTask(@NonNull Context context, @NonNull String task, @NonNull String channelId)
|
||||
throws UnableToStartException
|
||||
{
|
||||
return startForegroundTask(context, task, channelId, DEFAULTS.iconRes);
|
||||
}
|
||||
|
||||
public static NotificationController startForegroundTask(@NonNull Context context, @NonNull String task, @NonNull String channelId, @DrawableRes int iconRes) {
|
||||
public static NotificationController startForegroundTask(
|
||||
@NonNull Context context,
|
||||
@NonNull String task,
|
||||
@NonNull String channelId,
|
||||
@DrawableRes int iconRes)
|
||||
throws UnableToStartException
|
||||
{
|
||||
final int id = NEXT_ID.getAndIncrement();
|
||||
|
||||
Intent intent = new Intent(context, GenericForegroundService.class);
|
||||
@@ -150,7 +172,17 @@ public final class GenericForegroundService extends Service {
|
||||
intent.putExtra(EXTRA_ID, id);
|
||||
|
||||
Log.i(TAG, String.format(Locale.US, "Starting foreground service (%s) id=%d", task, id));
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
|
||||
if (Build.VERSION.SDK_INT < 31) {
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
} else {
|
||||
try {
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
} catch (ForegroundServiceStartNotAllowedException e) {
|
||||
Log.e(TAG, "Unable to start foreground service", e);
|
||||
throw new UnableToStartException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return new NotificationController(context, id);
|
||||
}
|
||||
@@ -289,4 +321,10 @@ public final class GenericForegroundService extends Service {
|
||||
return GenericForegroundService.this;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class UnableToStartException extends Exception {
|
||||
public UnableToStartException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,27 @@ package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.JavaTimeExtensionsKt;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LocalBackupListener extends PersistentAlarmManagerListener {
|
||||
|
||||
private static final long INTERVAL = TimeUnit.DAYS.toMillis(1);
|
||||
|
||||
@Override
|
||||
protected boolean scheduleExact() {
|
||||
return Build.VERSION.SDK_INT >= 31;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getNextScheduledExecutionTime(Context context) {
|
||||
return TextSecurePreferences.getNextBackupTime(context);
|
||||
@@ -24,7 +32,7 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
|
||||
@Override
|
||||
protected long onAlarm(Context context, long scheduledTime) {
|
||||
if (SignalStore.settings().isBackupEnabled()) {
|
||||
LocalBackupJob.enqueue(false);
|
||||
LocalBackupJob.enqueue(scheduleExact());
|
||||
}
|
||||
|
||||
return setNextBackupTimeToIntervalFromNow(context);
|
||||
@@ -37,7 +45,20 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
|
||||
}
|
||||
|
||||
public static long setNextBackupTimeToIntervalFromNow(@NonNull Context context) {
|
||||
long nextTime = System.currentTimeMillis() + INTERVAL;
|
||||
long nextTime;
|
||||
|
||||
if (Build.VERSION.SDK_INT < 31) {
|
||||
nextTime = System.currentTimeMillis() + INTERVAL;
|
||||
} else {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime next = now.withHour(2).withMinute(0).withSecond(0);
|
||||
if (now.getHour() > 2) {
|
||||
next = next.plusDays(1);
|
||||
}
|
||||
|
||||
nextTime = JavaTimeExtensionsKt.toMillis(next);
|
||||
}
|
||||
|
||||
TextSecurePreferences.setNextBackupTime(context, nextTime);
|
||||
|
||||
return nextTime;
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import org.signal.core.util.PendingIntentFlags;
|
||||
import org.signal.core.util.logging.Log;
|
||||
@@ -35,9 +36,21 @@ public abstract class PersistentAlarmManagerListener extends BroadcastReceiver {
|
||||
|
||||
if (pendingIntent != null) {
|
||||
alarmManager.cancel(pendingIntent);
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
||||
if (scheduleExact() && Build.VERSION.SDK_INT >= 31) {
|
||||
if (alarmManager.canScheduleExactAlarms()) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
||||
} else {
|
||||
Log.w(TAG, "Unable to schedule exact alarm, permissionAllowed: " + alarmManager.canScheduleExactAlarms());
|
||||
}
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "PendingIntent somehow null, skipping");
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean scheduleExact() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user