Using WorkManager for feed updates
This commit is contained in:
parent
d7768d33e2
commit
dbda4a9aa8
|
@ -207,7 +207,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
|||
|
||||
checkFirstLaunch();
|
||||
NotificationUtils.createChannels(this);
|
||||
UserPreferences.restartUpdateAlarm(false);
|
||||
}
|
||||
|
||||
private void saveLastNavFragment(String tag) {
|
||||
|
@ -474,7 +473,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
|||
protected void onResume() {
|
||||
super.onResume();
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (intent.hasExtra(EXTRA_FEED_ID) ||
|
||||
|
|
|
@ -178,7 +178,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
|||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
|
||||
|
||||
EventDistributor.getInstance().register(contentUpdate);
|
||||
EventBus.getDefault().register(this);
|
||||
|
|
|
@ -45,6 +45,7 @@ project.ext {
|
|||
targetSdkVersion = 26
|
||||
|
||||
supportVersion = "27.1.1"
|
||||
workManagerVersion = "1.0.1"
|
||||
awaitilityVersion = "3.1.2"
|
||||
commonsioVersion = "2.5"
|
||||
commonslangVersion = "3.6"
|
||||
|
|
|
@ -45,6 +45,8 @@ dependencies {
|
|||
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||
implementation "com.android.support:preference-v14:$supportVersion"
|
||||
implementation "com.android.support:percent:$supportVersion"
|
||||
implementation "android.arch.work:work-runtime:$workManagerVersion"
|
||||
|
||||
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||
implementation "org.apache.commons:commons-text:$commonstextVersion"
|
||||
implementation ("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
|
||||
|
|
|
@ -41,29 +41,10 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".receiver.AlarmUpdateReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||
<data
|
||||
android:path="de.danoeh.antennapod"
|
||||
android:scheme="package" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".receiver.FeedUpdateReceiver"
|
||||
android:label="@string/feed_update_receiver_name"
|
||||
android:exported="true"> <!-- allow feeds update to be triggered by external apps -->
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".service.FeedUpdateJobService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" >
|
||||
|
||||
</service>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -561,7 +561,7 @@ public class UserPreferences {
|
|||
.apply();
|
||||
// when updating with an interval, we assume the user wants
|
||||
// to update *now* and then every 'hours' interval thereafter.
|
||||
restartUpdateAlarm(true);
|
||||
restartUpdateAlarm();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -571,7 +571,7 @@ public class UserPreferences {
|
|||
prefs.edit()
|
||||
.putString(PREF_UPDATE_INTERVAL, hourOfDay + ":" + minute)
|
||||
.apply();
|
||||
restartUpdateAlarm(false);
|
||||
restartUpdateAlarm();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -814,18 +814,23 @@ public class UserPreferences {
|
|||
}
|
||||
}
|
||||
|
||||
public static void restartUpdateAlarm(boolean now) {
|
||||
int[] timeOfDay = getUpdateTimeOfDay();
|
||||
Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay));
|
||||
if (timeOfDay.length == 2) {
|
||||
AutoUpdateManager.restartUpdateTimeOfDayAlarm(context, timeOfDay[0], timeOfDay[1]);
|
||||
/**
|
||||
*
|
||||
* @return true if auto update is set to a specific time
|
||||
* false if auto update is set to interval
|
||||
*/
|
||||
public static boolean isAutoUpdateTimeOfDay() {
|
||||
return getUpdateTimeOfDay().length == 2;
|
||||
}
|
||||
|
||||
public static void restartUpdateAlarm() {
|
||||
if (isAutoUpdateTimeOfDay()) {
|
||||
int[] timeOfDay = getUpdateTimeOfDay();
|
||||
Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay));
|
||||
AutoUpdateManager.restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]);
|
||||
} else {
|
||||
long milliseconds = getUpdateInterval();
|
||||
long startTrigger = milliseconds;
|
||||
if (now) {
|
||||
startTrigger = TimeUnit.SECONDS.toMillis(10);
|
||||
}
|
||||
AutoUpdateManager.restartUpdateIntervalAlarm(context, startTrigger, milliseconds);
|
||||
AutoUpdateManager.restartUpdateIntervalAlarm(milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package de.danoeh.antennapod.core.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
|
||||
/** Listens for events that make it necessary to reset the update alarm. */
|
||||
public class AlarmUpdateReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "AlarmUpdateReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Received intent");
|
||||
if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
|
||||
Log.d(TAG, "Resetting update alarm after reboot");
|
||||
} else if (TextUtils.equals(intent.getAction(), Intent.ACTION_PACKAGE_REPLACED)) {
|
||||
Log.d(TAG, "Resetting update alarm after app upgrade");
|
||||
}
|
||||
ClientConfig.initialize(context);
|
||||
UserPreferences.restartUpdateAlarm(false);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,7 +21,6 @@ public class FeedUpdateReceiver extends BroadcastReceiver {
|
|||
Log.d(TAG, "Received intent");
|
||||
ClientConfig.initialize(context);
|
||||
FeedUpdateUtils.startAutoUpdate(context, null);
|
||||
UserPreferences.restartUpdateAlarm(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
package de.danoeh.antennapod.core.service;
|
||||
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobService;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.FeedUpdateUtils;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public class FeedUpdateJobService extends JobService {
|
||||
private static final String TAG = "FeedUpdateJobService";
|
||||
|
||||
@Override
|
||||
public boolean onStartJob(JobParameters params) {
|
||||
Log.d(TAG, "Job started");
|
||||
ClientConfig.initialize(getApplicationContext());
|
||||
|
||||
FeedUpdateUtils.startAutoUpdate(getApplicationContext(), () -> {
|
||||
UserPreferences.restartUpdateAlarm(false);
|
||||
jobFinished(params, false); // needsReschedule = false
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStopJob(JobParameters params) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package de.danoeh.antennapod.core.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.FeedUpdateUtils;
|
||||
import org.awaitility.Awaitility;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class FeedUpdateWorker extends Worker {
|
||||
|
||||
public FeedUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) {
|
||||
super(context, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Result doWork() {
|
||||
ClientConfig.initialize(getApplicationContext());
|
||||
|
||||
AtomicBoolean finished = new AtomicBoolean(false);
|
||||
FeedUpdateUtils.startAutoUpdate(getApplicationContext(), () -> finished.set(true));
|
||||
Awaitility.await().until(finished::get);
|
||||
|
||||
if (UserPreferences.isAutoUpdateTimeOfDay()) {
|
||||
// WorkManager does not allow to set specific time for repeated tasks.
|
||||
// We repeatedly schedule a OneTimeWorkRequest instead.
|
||||
UserPreferences.restartUpdateAlarm();
|
||||
}
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
}
|
|
@ -1,29 +1,21 @@
|
|||
package de.danoeh.antennapod.core.util.download;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import androidx.work.NetworkType;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.FeedUpdateWorker;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver;
|
||||
import de.danoeh.antennapod.core.service.FeedUpdateJobService;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.FeedUpdateUtils;
|
||||
|
||||
public class AutoUpdateManager {
|
||||
private static final int JOB_ID_FEED_UPDATE = 42;
|
||||
private static final String WORK_ID_FEED_UPDATE = FeedUpdateWorker.class.getName();
|
||||
private static final String TAG = "AutoUpdateManager";
|
||||
|
||||
private AutoUpdateManager() {
|
||||
|
@ -33,20 +25,22 @@ public class AutoUpdateManager {
|
|||
/**
|
||||
* Sets the interval in which the feeds are refreshed automatically
|
||||
*/
|
||||
public static void restartUpdateIntervalAlarm(Context context, long triggerAtMillis, long intervalMillis) {
|
||||
public static void restartUpdateIntervalAlarm(long intervalMillis) {
|
||||
Log.d(TAG, "Restarting update alarm.");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
restartJobServiceInterval(context, intervalMillis);
|
||||
} else {
|
||||
restartAlarmManagerInterval(context, triggerAtMillis, intervalMillis);
|
||||
}
|
||||
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(FeedUpdateWorker.class,
|
||||
intervalMillis, TimeUnit.MILLISECONDS)
|
||||
.setConstraints(getConstraints())
|
||||
.build();
|
||||
|
||||
WorkManager.getInstance().enqueueUniquePeriodicWork(
|
||||
WORK_ID_FEED_UPDATE, ExistingPeriodicWorkPolicy.REPLACE, workRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets time of day the feeds are refreshed automatically
|
||||
*/
|
||||
public static void restartUpdateTimeOfDayAlarm(Context context, int hoursOfDay, int minute) {
|
||||
public static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) {
|
||||
Log.d(TAG, "Restarting update alarm.");
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
|
@ -56,130 +50,25 @@ public class AutoUpdateManager {
|
|||
if (alarm.before(now) || alarm.equals(now)) {
|
||||
alarm.add(Calendar.DATE, 1);
|
||||
}
|
||||
long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis();
|
||||
restartJobServiceTriggerAt(context, triggerAtMillis);
|
||||
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class)
|
||||
.setConstraints(getConstraints())
|
||||
.setInitialDelay(triggerAtMillis, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
|
||||
WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE, ExistingWorkPolicy.REPLACE, workRequest);
|
||||
}
|
||||
|
||||
private static Constraints getConstraints() {
|
||||
Constraints.Builder constraints = new Constraints.Builder();
|
||||
|
||||
if (UserPreferences.isAllowMobileUpdate()) {
|
||||
constraints.setRequiredNetworkType(NetworkType.CONNECTED);
|
||||
} else {
|
||||
restartAlarmManagerTimeOfDay(context, alarm);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
private static JobInfo.Builder getFeedUpdateJobBuilder(Context context) {
|
||||
ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class);
|
||||
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_FEED_UPDATE, serviceComponent);
|
||||
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
builder.setPersisted(true);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
private static void restartJobServiceInterval(Context context, long intervalMillis) {
|
||||
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
|
||||
if (jobScheduler == null) {
|
||||
Log.d(TAG, "JobScheduler was null.");
|
||||
return;
|
||||
}
|
||||
|
||||
JobInfo oldJob = jobScheduler.getPendingJob(JOB_ID_FEED_UPDATE);
|
||||
if (oldJob != null && oldJob.getIntervalMillis() == intervalMillis) {
|
||||
Log.d(TAG, "JobScheduler was already set at interval " + intervalMillis + ", ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
JobInfo.Builder builder = getFeedUpdateJobBuilder(context);
|
||||
builder.setPeriodic(intervalMillis);
|
||||
jobScheduler.cancel(JOB_ID_FEED_UPDATE);
|
||||
|
||||
if (intervalMillis <= 0) {
|
||||
Log.d(TAG, "Automatic update was deactivated");
|
||||
return;
|
||||
}
|
||||
|
||||
jobScheduler.schedule(builder.build());
|
||||
Log.d(TAG, "JobScheduler was set at interval " + intervalMillis);
|
||||
}
|
||||
|
||||
private static void restartAlarmManagerInterval(Context context, long triggerAtMillis, long intervalMillis) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
if (alarmManager == null) {
|
||||
Log.d(TAG, "AlarmManager was null");
|
||||
return;
|
||||
}
|
||||
|
||||
PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0,
|
||||
new Intent(context, FeedUpdateReceiver.class), 0);
|
||||
alarmManager.cancel(updateIntent);
|
||||
|
||||
if (intervalMillis <= 0) {
|
||||
Log.d(TAG, "Automatic update was deactivated");
|
||||
return;
|
||||
}
|
||||
|
||||
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + triggerAtMillis,
|
||||
updateIntent);
|
||||
Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h");
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
private static void restartJobServiceTriggerAt(Context context, long triggerAtMillis) {
|
||||
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
|
||||
if (jobScheduler == null) {
|
||||
Log.d(TAG, "JobScheduler was null.");
|
||||
return;
|
||||
}
|
||||
|
||||
JobInfo.Builder builder = getFeedUpdateJobBuilder(context);
|
||||
builder.setMinimumLatency(triggerAtMillis);
|
||||
jobScheduler.cancel(JOB_ID_FEED_UPDATE);
|
||||
jobScheduler.schedule(builder.build());
|
||||
Log.d(TAG, "JobScheduler was set for " + triggerAtMillis);
|
||||
}
|
||||
|
||||
private static void restartAlarmManagerTimeOfDay(Context context, Calendar alarm) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
if (alarmManager == null) {
|
||||
Log.d(TAG, "AlarmManager was null");
|
||||
return;
|
||||
}
|
||||
|
||||
PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0,
|
||||
new Intent(context, FeedUpdateReceiver.class), 0);
|
||||
alarmManager.cancel(updateIntent);
|
||||
|
||||
Log.d(TAG, "Alarm set for: " + alarm.toString() + " : " + alarm.getTimeInMillis());
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP,
|
||||
alarm.getTimeInMillis(),
|
||||
updateIntent);
|
||||
Log.d(TAG, "Changed alarm to new time of day " + alarm.get(Calendar.HOUR_OF_DAY) + ":" + alarm.get(Calendar.MINUTE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the app should refresh all feeds, i.e. if the last auto refresh failed.
|
||||
*
|
||||
* The feeds are only refreshed if an update interval or time of day is set and the last
|
||||
* (successful) refresh was before the last interval or more than a day ago, respectively.
|
||||
*
|
||||
*/
|
||||
public static void checkShouldRefreshFeeds(Context context) {
|
||||
long interval = 0;
|
||||
if(UserPreferences.getUpdateInterval() > 0) {
|
||||
interval = UserPreferences.getUpdateInterval();
|
||||
} else if(UserPreferences.getUpdateTimeOfDay().length > 0){
|
||||
interval = TimeUnit.DAYS.toMillis(1);
|
||||
}
|
||||
if(interval == 0) { // auto refresh is disabled
|
||||
return;
|
||||
}
|
||||
long lastRefresh = DBTasks.getLastRefreshAllFeedsTimeMillis(context);
|
||||
Log.d(TAG, "last refresh: " + Converter.getDurationStringLocalized(context,
|
||||
System.currentTimeMillis() - lastRefresh) + " ago");
|
||||
if(lastRefresh <= System.currentTimeMillis() - interval) {
|
||||
FeedUpdateUtils.startAutoUpdate(context, null);
|
||||
constraints.setRequiredNetworkType(NetworkType.UNMETERED);
|
||||
}
|
||||
constraints.setRequiresCharging(!UserPreferences.isEnableAutodownloadOnBattery());
|
||||
return constraints.build();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue