Sync improvements
This commit is contained in:
parent
1f594ad311
commit
58f5c61a54
|
@ -2,6 +2,8 @@ package de.danoeh.antennapod.preferences;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
import de.danoeh.antennapod.AppConfig;
|
||||||
import de.danoeh.antennapod.PodcastApp;
|
import de.danoeh.antennapod.PodcastApp;
|
||||||
import de.danoeh.antennapod.service.GpodnetSyncService;
|
import de.danoeh.antennapod.service.GpodnetSyncService;
|
||||||
|
|
||||||
|
@ -127,7 +129,7 @@ public class GpodnetPreferences {
|
||||||
writePreference(PREF_SYNC_REMOVED, removedFeeds);
|
writePreference(PREF_SYNC_REMOVED, removedFeeds);
|
||||||
}
|
}
|
||||||
feedListLock.unlock();
|
feedListLock.unlock();
|
||||||
GpodnetSyncService.sendActionUploadIntent(PodcastApp.getInstance());
|
GpodnetSyncService.sendSyncIntent(PodcastApp.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addRemovedFeed(String feed) {
|
public static void addRemovedFeed(String feed) {
|
||||||
|
@ -140,7 +142,7 @@ public class GpodnetPreferences {
|
||||||
writePreference(PREF_SYNC_ADDED, addedFeeds);
|
writePreference(PREF_SYNC_ADDED, addedFeeds);
|
||||||
}
|
}
|
||||||
feedListLock.unlock();
|
feedListLock.unlock();
|
||||||
GpodnetSyncService.sendActionUploadIntent(PodcastApp.getInstance());
|
GpodnetSyncService.sendSyncIntent(PodcastApp.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> getAddedFeedsCopy() {
|
public static Set<String> getAddedFeedsCopy() {
|
||||||
|
@ -152,7 +154,7 @@ public class GpodnetPreferences {
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeAddedFeeds(Set<String> removed) {
|
public static void removeAddedFeeds(Collection<String> removed) {
|
||||||
ensurePreferencesLoaded();
|
ensurePreferencesLoaded();
|
||||||
feedListLock.lock();
|
feedListLock.lock();
|
||||||
addedFeeds.removeAll(removed);
|
addedFeeds.removeAll(removed);
|
||||||
|
@ -169,7 +171,7 @@ public class GpodnetPreferences {
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeRemovedFeeds(Set<String> removed) {
|
public static void removeRemovedFeeds(Collection<String> removed) {
|
||||||
ensurePreferencesLoaded();
|
ensurePreferencesLoaded();
|
||||||
removedFeeds.removeAll(removed);
|
removedFeeds.removeAll(removed);
|
||||||
writePreference(PREF_SYNC_REMOVED, removedFeeds);
|
writePreference(PREF_SYNC_REMOVED, removedFeeds);
|
||||||
|
@ -184,10 +186,15 @@ public class GpodnetPreferences {
|
||||||
return deviceID != null && username != null && password != null;
|
return deviceID != null && username != null && password != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void logout() {
|
public static synchronized void logout() {
|
||||||
|
if (AppConfig.DEBUG) Log.d(TAG, "Logout: Clearing preferences");
|
||||||
setUsername(null);
|
setUsername(null);
|
||||||
setPassword(null);
|
setPassword(null);
|
||||||
setDeviceID(null);
|
setDeviceID(null);
|
||||||
|
addedFeeds.clear();
|
||||||
|
writePreference(PREF_SYNC_ADDED, addedFeeds);
|
||||||
|
removedFeeds.clear();
|
||||||
|
writePreference(PREF_SYNC_REMOVED, removedFeeds);
|
||||||
setLastSyncTimestamp(0);
|
setLastSyncTimestamp(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,14 @@ import de.danoeh.antennapod.storage.*;
|
||||||
import de.danoeh.antennapod.util.NetworkUtils;
|
import de.danoeh.antennapod.util.NetworkUtils;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronizes local subscriptions with gpodder.net service. The service should be started with an ACTION_UPLOAD_CHANGES,
|
* Synchronizes local subscriptions with gpodder.net service. The service should be started with ACTION_SYNC as an action argument.
|
||||||
* ACTION_DOWNLOAD_CHANGES or ACTION_SYNC as an action argument. This class also provides static methods for starting the GpodnetSyncService.
|
* This class also provides static methods for starting the GpodnetSyncService.
|
||||||
*/
|
*/
|
||||||
public class GpodnetSyncService extends Service {
|
public class GpodnetSyncService extends Service {
|
||||||
private static final String TAG = "GpodnetSyncService";
|
private static final String TAG = "GpodnetSyncService";
|
||||||
|
@ -36,19 +37,6 @@ public class GpodnetSyncService extends Service {
|
||||||
|
|
||||||
public static final String ARG_ACTION = "action";
|
public static final String ARG_ACTION = "action";
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new upload action. The service will not upload immediately, but wait for a certain amount of time in
|
|
||||||
* case any other upload requests occur.
|
|
||||||
*/
|
|
||||||
public static final String ACTION_UPLOAD_CHANGES = "de.danoeh.antennapod.intent.action.upload_changes";
|
|
||||||
/**
|
|
||||||
* Starts a new download action. The service will download all changes in the subscription list since the last sync.
|
|
||||||
* New subscriptions will be added to the database, removed subscriptions will be removed from the database
|
|
||||||
*/
|
|
||||||
public static final String ACTION_DOWNLOAD_CHANGES = "de.danoeh.antennapod.intent.action.download_changes";
|
|
||||||
/**
|
|
||||||
* Starts a new upload action immediately and a new download action after that.
|
|
||||||
*/
|
|
||||||
public static final String ACTION_SYNC = "de.danoeh.antennapod.intent.action.sync";
|
public static final String ACTION_SYNC = "de.danoeh.antennapod.intent.action.sync";
|
||||||
|
|
||||||
private GpodnetService service;
|
private GpodnetService service;
|
||||||
|
@ -56,25 +44,11 @@ public class GpodnetSyncService extends Service {
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
final String action = (intent != null) ? intent.getStringExtra(ARG_ACTION) : null;
|
final String action = (intent != null) ? intent.getStringExtra(ARG_ACTION) : null;
|
||||||
if (action != null && action.equals(ACTION_UPLOAD_CHANGES)) {
|
if (action != null && action.equals(ACTION_SYNC)) {
|
||||||
Log.d(TAG, String.format("Waiting %d milliseconds before uploading changes", WAIT_INTERVAL));
|
Log.d(TAG, String.format("Waiting %d milliseconds before uploading changes", WAIT_INTERVAL));
|
||||||
|
syncWaiterThread.restart();
|
||||||
uploadWaiterThread.restart();
|
} else {
|
||||||
} else if (action != null && action.equals(ACTION_DOWNLOAD_CHANGES)) {
|
Log.e(TAG, "Received invalid intent: action argument is null or invalid");
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
downloadChanges();
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
} else if (action != null && action.equals(ACTION_SYNC)) {
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
downloadChanges();
|
|
||||||
uploadChanges();
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
}
|
}
|
||||||
return START_FLAG_REDELIVERY;
|
return START_FLAG_REDELIVERY;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +57,7 @@ public class GpodnetSyncService extends Service {
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if (AppConfig.DEBUG) Log.d(TAG, "onDestroy");
|
if (AppConfig.DEBUG) Log.d(TAG, "onDestroy");
|
||||||
uploadWaiterThread.interrupt();
|
syncWaiterThread.interrupt();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +66,7 @@ public class GpodnetSyncService extends Service {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GpodnetService tryLogin() throws GpodnetServiceException {
|
private synchronized GpodnetService tryLogin() throws GpodnetServiceException {
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
service = new GpodnetService();
|
service = new GpodnetService();
|
||||||
service.authenticate(GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
|
service.authenticate(GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
|
||||||
|
@ -100,58 +74,55 @@ public class GpodnetSyncService extends Service {
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void downloadChanges() {
|
private synchronized void syncChanges() {
|
||||||
if (GpodnetPreferences.loggedIn() && NetworkUtils.networkAvailable(GpodnetSyncService.this)) {
|
if (GpodnetPreferences.loggedIn() && NetworkUtils.networkAvailable(this)) {
|
||||||
if (AppConfig.DEBUG) Log.d(TAG, "Downloading changes");
|
final long timestamp = GpodnetPreferences.getLastSyncTimestamp();
|
||||||
try {
|
try {
|
||||||
|
final List<String> localSubscriptions = DBReader.getFeedListDownloadUrls(this);
|
||||||
GpodnetService service = tryLogin();
|
GpodnetService service = tryLogin();
|
||||||
GpodnetSubscriptionChange changes = service.getSubscriptionChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), GpodnetPreferences.getLastSyncTimestamp());
|
|
||||||
if (AppConfig.DEBUG) Log.d(TAG, "Changes " + changes.toString());
|
|
||||||
|
|
||||||
GpodnetPreferences.setLastSyncTimestamp(changes.getTimestamp());
|
if (timestamp == 0) {
|
||||||
List<String> subscriptionList = DBReader.getFeedListDownloadUrls(GpodnetSyncService.this);
|
// first sync: download all subscriptions...
|
||||||
|
GpodnetSubscriptionChange changes =
|
||||||
|
service.getSubscriptionChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), 0);
|
||||||
|
if (AppConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + changes);
|
||||||
|
processSubscriptionChanges(localSubscriptions, changes);
|
||||||
|
|
||||||
for (String downloadUrl : changes.getAdded()) {
|
// ... then upload all local subscriptions
|
||||||
if (!subscriptionList.contains(downloadUrl)) {
|
if (AppConfig.DEBUG) Log.d(TAG, "Uploading subscription list: " + localSubscriptions);
|
||||||
Feed feed = new Feed(downloadUrl, new Date());
|
GpodnetUploadChangesResponse uploadChangesResponse =
|
||||||
DownloadRequester.getInstance().downloadFeed(GpodnetSyncService.this, feed);
|
service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), localSubscriptions, new LinkedList<String>());
|
||||||
}
|
if (AppConfig.DEBUG) Log.d(TAG, "Uploading changes response: " + uploadChangesResponse);
|
||||||
}
|
DBWriter.updateFeedDownloadURLs(GpodnetSyncService.this, uploadChangesResponse.updatedUrls).get();
|
||||||
for (String downloadUrl : changes.getRemoved()) {
|
GpodnetPreferences.removeAddedFeeds(localSubscriptions);
|
||||||
DBTasks.removeFeedWithDownloadUrl(GpodnetSyncService.this, downloadUrl);
|
GpodnetPreferences.removeRemovedFeeds(GpodnetPreferences.getRemovedFeedsCopy());
|
||||||
|
GpodnetPreferences.setLastSyncTimestamp(uploadChangesResponse.timestamp);
|
||||||
|
} else {
|
||||||
|
Set<String> added = GpodnetPreferences.getAddedFeedsCopy();
|
||||||
|
Set<String> removed = GpodnetPreferences.getRemovedFeedsCopy();
|
||||||
|
|
||||||
|
// download remote changes first...
|
||||||
|
GpodnetSubscriptionChange subscriptionChanges = service.getSubscriptionChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), timestamp);
|
||||||
|
if (AppConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + subscriptionChanges);
|
||||||
|
processSubscriptionChanges(localSubscriptions, subscriptionChanges);
|
||||||
|
|
||||||
|
// ... then upload changes local changes
|
||||||
|
if (AppConfig.DEBUG) Log.d(TAG, String.format("Uploading subscriptions, Added: %s\nRemoved: %s",
|
||||||
|
added.toString(), removed));
|
||||||
|
GpodnetUploadChangesResponse uploadChangesResponse = service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), added, removed);
|
||||||
|
if (AppConfig.DEBUG) Log.d(TAG, "Upload subscriptions response: " + uploadChangesResponse);
|
||||||
|
|
||||||
|
GpodnetPreferences.removeAddedFeeds(added);
|
||||||
|
GpodnetPreferences.removeRemovedFeeds(removed);
|
||||||
|
DBWriter.updateFeedDownloadURLs(GpodnetSyncService.this, uploadChangesResponse.updatedUrls).get();
|
||||||
|
GpodnetPreferences.setLastSyncTimestamp(uploadChangesResponse.timestamp);
|
||||||
}
|
}
|
||||||
|
clearErrorNotifications();
|
||||||
} catch (GpodnetServiceException e) {
|
} catch (GpodnetServiceException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
updateErrorNotification(e);
|
updateErrorNotification(e);
|
||||||
} catch (DownloadRequestException e) {
|
} catch (DownloadRequestException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
|
||||||
}
|
|
||||||
stopSelf();
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void uploadChanges() {
|
|
||||||
if (GpodnetPreferences.loggedIn() && NetworkUtils.networkAvailable(GpodnetSyncService.this)) {
|
|
||||||
try {
|
|
||||||
if (AppConfig.DEBUG) Log.d(TAG, "Uploading subscription list");
|
|
||||||
GpodnetService service = tryLogin();
|
|
||||||
|
|
||||||
Set<String> added = GpodnetPreferences.getAddedFeedsCopy();
|
|
||||||
Set<String> removed = GpodnetPreferences.getRemovedFeedsCopy();
|
|
||||||
|
|
||||||
if (AppConfig.DEBUG) Log.d(TAG, String.format("Uploading subscriptions, Added: %s\nRemoved: %s",
|
|
||||||
added.toString(), removed.toString()));
|
|
||||||
|
|
||||||
GpodnetUploadChangesResponse response = service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), added, removed);
|
|
||||||
|
|
||||||
if (AppConfig.DEBUG) Log.d(TAG, "Upload subscriptions response: " + response.toString());
|
|
||||||
|
|
||||||
GpodnetPreferences.removeAddedFeeds(added);
|
|
||||||
GpodnetPreferences.removeRemovedFeeds(removed);
|
|
||||||
DBWriter.updateFeedDownloadURLs(GpodnetSyncService.this, response.updatedUrls).get();
|
|
||||||
} catch (GpodnetServiceException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
updateErrorNotification(e);
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
|
@ -161,6 +132,24 @@ public class GpodnetSyncService extends Service {
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void processSubscriptionChanges(List<String> localSubscriptions, GpodnetSubscriptionChange changes) throws DownloadRequestException {
|
||||||
|
for (String downloadUrl : changes.getAdded()) {
|
||||||
|
if (!localSubscriptions.contains(downloadUrl)) {
|
||||||
|
Feed feed = new Feed(downloadUrl, new Date());
|
||||||
|
DownloadRequester.getInstance().downloadFeed(this, feed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String downloadUrl : changes.getRemoved()) {
|
||||||
|
DBTasks.removeFeedWithDownloadUrl(GpodnetSyncService.this, downloadUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearErrorNotifications() {
|
||||||
|
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
nm.cancel(R.id.notification_gpodnet_sync_error);
|
||||||
|
nm.cancel(R.id.notification_gpodnet_sync_autherror);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateErrorNotification(GpodnetServiceException exception) {
|
private void updateErrorNotification(GpodnetServiceException exception) {
|
||||||
if (AppConfig.DEBUG) Log.d(TAG, "Posting error notification");
|
if (AppConfig.DEBUG) Log.d(TAG, "Posting error notification");
|
||||||
|
|
||||||
|
@ -186,10 +175,10 @@ public class GpodnetSyncService extends Service {
|
||||||
nm.notify(id, notification);
|
nm.notify(id, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WaiterThread uploadWaiterThread = new WaiterThread(WAIT_INTERVAL) {
|
private WaiterThread syncWaiterThread = new WaiterThread(WAIT_INTERVAL) {
|
||||||
@Override
|
@Override
|
||||||
public void onWaitCompleted() {
|
public void onWaitCompleted() {
|
||||||
uploadChanges();
|
syncChanges();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,22 +233,6 @@ public class GpodnetSyncService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendActionDownloadIntent(Context context) {
|
|
||||||
if (GpodnetPreferences.loggedIn()) {
|
|
||||||
Intent intent = new Intent(context, GpodnetSyncService.class);
|
|
||||||
intent.putExtra(ARG_ACTION, ACTION_DOWNLOAD_CHANGES);
|
|
||||||
context.startService(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendActionUploadIntent(Context context) {
|
|
||||||
if (GpodnetPreferences.loggedIn()) {
|
|
||||||
Intent intent = new Intent(context, GpodnetSyncService.class);
|
|
||||||
intent.putExtra(ARG_ACTION, ACTION_UPLOAD_CHANGES);
|
|
||||||
context.startService(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendSyncIntent(Context context) {
|
public static void sendSyncIntent(Context context) {
|
||||||
if (GpodnetPreferences.loggedIn()) {
|
if (GpodnetPreferences.loggedIn()) {
|
||||||
Intent intent = new Intent(context, GpodnetSyncService.class);
|
Intent intent = new Intent(context, GpodnetSyncService.class);
|
||||||
|
|
Loading…
Reference in New Issue