diff options
Diffstat (limited to 'core/src')
4 files changed, 81 insertions, 20 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/SyncServiceEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/SyncServiceEvent.java new file mode 100644 index 000000000..7aa5f6bf1 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/event/SyncServiceEvent.java @@ -0,0 +1,13 @@ +package de.danoeh.antennapod.core.event; + +public class SyncServiceEvent { + private final int messageResId; + + public SyncServiceEvent(int messageResId) { + this.messageResId = messageResId; + } + + public int getMessageResId() { + return messageResId; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java index 6ca3d3422..a31c19562 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java @@ -19,6 +19,7 @@ import androidx.work.WorkManager; import androidx.work.Worker; import androidx.work.WorkerParameters; import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.core.event.SyncServiceEvent; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -39,6 +40,7 @@ import de.danoeh.antennapod.core.sync.model.UploadChangesResponse; import de.danoeh.antennapod.core.util.URLChecker; import de.danoeh.antennapod.core.util.gui.NotificationUtils; import org.apache.commons.lang3.StringUtils; +import org.greenrobot.eventbus.EventBus; import org.json.JSONArray; import org.json.JSONException; @@ -55,6 +57,7 @@ public class SyncService extends Worker { private static final String PREF_QUEUED_FEEDS_REMOVED = "sync_removed"; private static final String PREF_QUEUED_EPISODE_ACTIONS = "sync_queued_episode_actions"; private static final String PREF_LAST_SYNC_ATTEMPT_TIMESTAMP = "last_sync_attempt_timestamp"; + private static final String PREF_LAST_SYNC_ATTEMPT_SUCCESS = "last_sync_attempt_success"; private static final String TAG = "SyncService"; private static final String WORK_ID_SYNC = "SyncServiceWorkId"; private static final Object lock = new Object(); @@ -69,20 +72,26 @@ public class SyncService extends Worker { @NonNull public Result doWork() { syncServiceImpl = new GpodnetService(AntennapodHttpClient.getHttpClient(), GpodnetService.DEFAULT_BASE_HOST); + SharedPreferences.Editor prefs = getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + .edit(); + prefs.putLong(PREF_LAST_SYNC_ATTEMPT_TIMESTAMP, System.currentTimeMillis()).apply(); try { syncServiceImpl.login(); + EventBus.getDefault().post(new SyncServiceEvent(R.string.sync_status_subscriptions)); syncSubscriptions(); + EventBus.getDefault().post(new SyncServiceEvent(R.string.sync_status_episodes)); syncEpisodeActions(); syncServiceImpl.logout(); clearErrorNotifications(); + EventBus.getDefault().post(new SyncServiceEvent(R.string.sync_status_success)); + prefs.putBoolean(PREF_LAST_SYNC_ATTEMPT_SUCCESS, true).apply(); return Result.success(); } catch (SyncServiceException e) { + EventBus.getDefault().post(new SyncServiceEvent(R.string.sync_status_error)); + prefs.putBoolean(PREF_LAST_SYNC_ATTEMPT_SUCCESS, false).apply(); e.printStackTrace(); updateErrorNotification(e); return Result.failure(); - } finally { - getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit() - .putLong(PREF_LAST_SYNC_ATTEMPT_TIMESTAMP, System.currentTimeMillis()).apply(); } } @@ -145,18 +154,9 @@ public class SyncService extends Worker { } public static void sync(Context context) { - Constraints.Builder constraints = new Constraints.Builder(); - if (UserPreferences.isAllowMobileFeedRefresh()) { - constraints.setRequiredNetworkType(NetworkType.CONNECTED); - } else { - constraints.setRequiredNetworkType(NetworkType.UNMETERED); - } - - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(SyncService.class) - .setConstraints(constraints.build()) - .setInitialDelay(5L, TimeUnit.SECONDS) // Give it some time, so other actions can be queued - .build(); + OneTimeWorkRequest workRequest = getWorkRequest().build(); WorkManager.getInstance().enqueueUniqueWork(WORK_ID_SYNC, ExistingWorkPolicy.REPLACE, workRequest); + EventBus.getDefault().post(new SyncServiceEvent(R.string.sync_status_started)); } public static void fullSync(Context context) { @@ -167,9 +167,35 @@ public class SyncService extends Worker { .putLong(PREF_LAST_SYNC_ATTEMPT_TIMESTAMP, 0) .apply(); } - sync(context); + OneTimeWorkRequest workRequest = getWorkRequest() + .setInitialDelay(0L, TimeUnit.SECONDS) + .build(); + WorkManager.getInstance().enqueueUniqueWork(WORK_ID_SYNC, ExistingWorkPolicy.REPLACE, workRequest); + EventBus.getDefault().post(new SyncServiceEvent(R.string.sync_status_started)); } + private static OneTimeWorkRequest.Builder getWorkRequest() { + Constraints.Builder constraints = new Constraints.Builder(); + if (UserPreferences.isAllowMobileFeedRefresh()) { + constraints.setRequiredNetworkType(NetworkType.CONNECTED); + } else { + constraints.setRequiredNetworkType(NetworkType.UNMETERED); + } + + return new OneTimeWorkRequest.Builder(SyncService.class) + .setConstraints(constraints.build()) + .setInitialDelay(5L, TimeUnit.SECONDS); // Give it some time, so other actions can be queued + } + + public static boolean isLastSyncSuccessful(Context context) { + return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + .getBoolean(PREF_LAST_SYNC_ATTEMPT_SUCCESS, false); + } + + public static long getLastSyncAttempt(Context context) { + return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + .getLong(PREF_LAST_SYNC_ATTEMPT_TIMESTAMP, 0); + } private List<EpisodeAction> getQueuedEpisodeActions() { ArrayList<EpisodeAction> actions = new ArrayList<>(); @@ -281,6 +307,7 @@ public class SyncService extends Worker { // upload local actions List<EpisodeAction> queuedEpisodeActions = getQueuedEpisodeActions(); if (lastSync == 0) { + EventBus.getDefault().post(new SyncServiceEvent(R.string.sync_status_upload_played)); List<FeedItem> readItems = DBReader.getPlayedItems(); Log.d(TAG, "First sync. Upload state for all " + readItems.size() + " played episodes"); for (FeedItem item : readItems) { @@ -300,7 +327,8 @@ public class SyncService extends Worker { } if (queuedEpisodeActions.size() > 0) { synchronized (lock) { - Log.d(TAG, "Uploading actions: " + StringUtils.join(queuedEpisodeActions, ", ")); + Log.d(TAG, "Uploading " + queuedEpisodeActions.size() + " actions: " + + StringUtils.join(queuedEpisodeActions, ", ")); UploadChangesResponse postResponse = syncServiceImpl.uploadEpisodeActions(queuedEpisodeActions); newTimeStamp = postResponse.timestamp; Log.d(TAG, "Upload episode response: " + postResponse); diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java index 678545321..327232e1d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.core.sync.gpoddernet; +import android.util.Log; import androidx.annotation.NonNull; import de.danoeh.antennapod.core.preferences.GpodnetPreferences; import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetDevice; @@ -42,8 +43,10 @@ import java.util.List; * Communicates with the gpodder.net service. */ public class GpodnetService implements ISyncService { + public static final String TAG = "GpodnetService"; public static final String DEFAULT_BASE_HOST = "gpodder.net"; private static final String BASE_SCHEME = "https"; + private static final int UPLOAD_BULK_SIZE = 30; private static final MediaType TEXT = MediaType.parse("plain/text; charset=utf-8"); private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); private final String baseHost; @@ -415,12 +418,24 @@ public class GpodnetService implements ISyncService { @Override public UploadChangesResponse uploadEpisodeActions(List<EpisodeAction> episodeActions) throws SyncServiceException { requireLoggedIn(); + UploadChangesResponse response = null; + for (int i = 0; i < episodeActions.size(); i += UPLOAD_BULK_SIZE) { + response = uploadEpisodeActionsPartial(episodeActions, + i, Math.min(episodeActions.size(), i + UPLOAD_BULK_SIZE)); + } + return response; + } + + private UploadChangesResponse uploadEpisodeActionsPartial(List<EpisodeAction> episodeActions, int from, int to) + throws SyncServiceException { try { + Log.d(TAG, "Uploading partial actions " + from + " to " + to + " of " + episodeActions.size()); URL url = new URI(BASE_SCHEME, baseHost, String.format( "/api/2/episodes/%s.json", username), null).toURL(); final JSONArray list = new JSONArray(); - for (EpisodeAction episodeAction : episodeActions) { + for (int i = from; i < to; i++) { + EpisodeAction episodeAction = episodeActions.get(i); JSONObject obj = episodeAction.writeToJSONObject(); if (obj != null) { obj.put("device", GpodnetPreferences.getDeviceID()); @@ -437,7 +452,6 @@ public class GpodnetService implements ISyncService { e.printStackTrace(); throw new SyncServiceException(e); } - } /** diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 694ea0df2..829355f81 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -441,8 +441,6 @@ <string name="pref_gpodnet_sync_changes_sum">Sync subscription and episode state changes with gpodder.net.</string> <string name="pref_gpodnet_full_sync_title">Full sync now</string> <string name="pref_gpodnet_full_sync_sum">Sync all subscriptions and episode states with gpodder.net.</string> - <string name="pref_gpodnet_sync_sum_last_sync_line">Last sync attempt: %1$s (%2$s)</string> - <string name="pref_gpodnet_sync_started">Sync started</string> <string name="pref_gpodnet_login_status"><![CDATA[Logged in as <i>%1$s</i> with device <i>%2$s</i>]]></string> <string name="pref_gpodnet_notifications_title">Show sync error notifications</string> <string name="pref_gpodnet_notifications_sum">This setting does not apply to authentication errors.</string> @@ -536,6 +534,14 @@ <string name="search_label">Search</string> <string name="no_results_for_query">No results were found for \"%1$s\"</string> + <!-- Synchronization --> + <string name="sync_status_started">Sync started</string> + <string name="sync_status_episodes">Synchronizing episodes…</string> + <string name="sync_status_upload_played">Uploading played status…</string> + <string name="sync_status_subscriptions">Synchronizing subscriptions…</string> + <string name="sync_status_success">Synchronization successful</string> + <string name="sync_status_error">Synchronization failed</string> + <!-- import and export --> <string name="import_export_summary">Move subscriptions and queue to another device</string> <string name="database">Database</string> |