package de.danoeh.antennapod.core.preferences; import android.content.Context; import android.content.SharedPreferences; import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.gpoddernet.GpodnetService; import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction; import de.danoeh.antennapod.core.service.GpodnetSyncService; /** * Manages preferences for accessing gpodder.net service */ public class GpodnetPreferences { private GpodnetPreferences(){} private static final String TAG = "GpodnetPreferences"; private static final String PREF_NAME = "gpodder.net"; public static final String PREF_GPODNET_USERNAME = "de.danoeh.antennapod.preferences.gpoddernet.username"; public static final String PREF_GPODNET_PASSWORD = "de.danoeh.antennapod.preferences.gpoddernet.password"; public static final String PREF_GPODNET_DEVICEID = "de.danoeh.antennapod.preferences.gpoddernet.deviceID"; public static final String PREF_GPODNET_HOSTNAME = "prefGpodnetHostname"; public static final String PREF_LAST_SUBSCRIPTION_SYNC_TIMESTAMP = "de.danoeh.antennapod.preferences.gpoddernet.last_sync_timestamp"; public static final String PREF_LAST_EPISODE_ACTIONS_SYNC_TIMESTAMP = "de.danoeh.antennapod.preferences.gpoddernet.last_episode_actions_sync_timestamp"; public static final String PREF_SYNC_ADDED = "de.danoeh.antennapod.preferences.gpoddernet.sync_added"; public static final String PREF_SYNC_REMOVED = "de.danoeh.antennapod.preferences.gpoddernet.sync_removed"; public static final String PREF_SYNC_EPISODE_ACTIONS = "de.danoeh.antennapod.preferences.gpoddernet.sync_queued_episode_actions"; private static String username; private static String password; private static String deviceID; private static String hostname; private static ReentrantLock feedListLock = new ReentrantLock(); private static Set<String> addedFeeds; private static Set<String> removedFeeds; private static List<GpodnetEpisodeAction> queuedEpisodeActions; /** * Last value returned by getSubscriptionChanges call. Will be used for all subsequent calls of getSubscriptionChanges. */ private static long lastSubscriptionSyncTimestamp; private static long lastEpisodeActionsSyncTimeStamp; private static boolean preferencesLoaded = false; private static SharedPreferences getPreferences() { return ClientConfig.applicationCallbacks.getApplicationInstance().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); } private static synchronized void ensurePreferencesLoaded() { if (!preferencesLoaded) { SharedPreferences prefs = getPreferences(); username = prefs.getString(PREF_GPODNET_USERNAME, null); password = prefs.getString(PREF_GPODNET_PASSWORD, null); deviceID = prefs.getString(PREF_GPODNET_DEVICEID, null); lastSubscriptionSyncTimestamp = prefs.getLong(PREF_LAST_SUBSCRIPTION_SYNC_TIMESTAMP, 0); lastEpisodeActionsSyncTimeStamp = prefs.getLong(PREF_LAST_EPISODE_ACTIONS_SYNC_TIMESTAMP, 0); addedFeeds = readListFromString(prefs.getString(PREF_SYNC_ADDED, "")); removedFeeds = readListFromString(prefs.getString(PREF_SYNC_REMOVED, "")); queuedEpisodeActions = readEpisodeActionsFromString(prefs.getString(PREF_SYNC_EPISODE_ACTIONS, "")); hostname = checkGpodnetHostname(prefs.getString(PREF_GPODNET_HOSTNAME, GpodnetService.DEFAULT_BASE_HOST)); preferencesLoaded = true; } } private static void writePreference(String key, String value) { SharedPreferences.Editor editor = getPreferences().edit(); editor.putString(key, value); editor.commit(); } private static void writePreference(String key, long value) { SharedPreferences.Editor editor = getPreferences().edit(); editor.putLong(key, value); editor.commit(); } private static void writePreference(String key, Collection<String> value) { SharedPreferences.Editor editor = getPreferences().edit(); editor.putString(key, writeListToString(value)); editor.commit(); } public static String getUsername() { ensurePreferencesLoaded(); return username; } public static void setUsername(String username) { GpodnetPreferences.username = username; writePreference(PREF_GPODNET_USERNAME, username); } public static String getPassword() { ensurePreferencesLoaded(); return password; } public static void setPassword(String password) { GpodnetPreferences.password = password; writePreference(PREF_GPODNET_PASSWORD, password); } public static String getDeviceID() { ensurePreferencesLoaded(); return deviceID; } public static void setDeviceID(String deviceID) { GpodnetPreferences.deviceID = deviceID; writePreference(PREF_GPODNET_DEVICEID, deviceID); } public static long getLastSubscriptionSyncTimestamp() { ensurePreferencesLoaded(); return lastSubscriptionSyncTimestamp; } public static void setLastSubscriptionSyncTimestamp(long timestamp) { GpodnetPreferences.lastSubscriptionSyncTimestamp = timestamp; writePreference(PREF_LAST_SUBSCRIPTION_SYNC_TIMESTAMP, timestamp); } public static long getLastEpisodeActionsSyncTimestamp() { ensurePreferencesLoaded(); return lastEpisodeActionsSyncTimeStamp; } public static void setLastEpisodeActionsSyncTimestamp(long timestamp) { GpodnetPreferences.lastEpisodeActionsSyncTimeStamp = timestamp; writePreference(PREF_LAST_EPISODE_ACTIONS_SYNC_TIMESTAMP, timestamp); } public static String getHostname() { ensurePreferencesLoaded(); return hostname; } public static void setHostname(String value) { value = checkGpodnetHostname(value); if (!value.equals(hostname)) { logout(); writePreference(PREF_GPODNET_HOSTNAME, value); hostname = value; } } public static void addAddedFeed(String feed) { ensurePreferencesLoaded(); feedListLock.lock(); if (addedFeeds.add(feed)) { writePreference(PREF_SYNC_ADDED, addedFeeds); } if (removedFeeds.remove(feed)) { writePreference(PREF_SYNC_REMOVED, removedFeeds); } feedListLock.unlock(); GpodnetSyncService.sendSyncSubscriptionsIntent(ClientConfig.applicationCallbacks.getApplicationInstance()); } public static void addRemovedFeed(String feed) { ensurePreferencesLoaded(); feedListLock.lock(); if (removedFeeds.add(feed)) { writePreference(PREF_SYNC_REMOVED, removedFeeds); } if (addedFeeds.remove(feed)) { writePreference(PREF_SYNC_ADDED, addedFeeds); } feedListLock.unlock(); GpodnetSyncService.sendSyncSubscriptionsIntent(ClientConfig.applicationCallbacks.getApplicationInstance()); } public static Set<String> getAddedFeedsCopy() { ensurePreferencesLoaded(); Set<String> copy = new HashSet<>(); feedListLock.lock(); copy.addAll(addedFeeds); feedListLock.unlock(); return copy; } public static void removeAddedFeeds(Collection<String> removed) { ensurePreferencesLoaded(); feedListLock.lock(); addedFeeds.removeAll(removed); writePreference(PREF_SYNC_ADDED, addedFeeds); feedListLock.unlock(); } public static Set<String> getRemovedFeedsCopy() { ensurePreferencesLoaded(); Set<String> copy = new HashSet<>(); feedListLock.lock(); copy.addAll(removedFeeds); feedListLock.unlock(); return copy; } public static void removeRemovedFeeds(Collection<String> removed) { ensurePreferencesLoaded(); feedListLock.lock(); removedFeeds.removeAll(removed); writePreference(PREF_SYNC_REMOVED, removedFeeds); feedListLock.unlock(); } public static void enqueueEpisodeAction(GpodnetEpisodeAction action) { ensurePreferencesLoaded(); feedListLock.lock(); queuedEpisodeActions.add(action); writePreference(PREF_SYNC_EPISODE_ACTIONS, writeEpisodeActionsToString(queuedEpisodeActions)); feedListLock.unlock(); GpodnetSyncService.sendSyncActionsIntent(ClientConfig.applicationCallbacks.getApplicationInstance()); } public static List<GpodnetEpisodeAction> getQueuedEpisodeActions() { ensurePreferencesLoaded(); List<GpodnetEpisodeAction> copy = new ArrayList<>(); feedListLock.lock(); copy.addAll(queuedEpisodeActions); feedListLock.unlock(); return copy; } public static void removeQueuedEpisodeActions(Collection<GpodnetEpisodeAction> queued) { ensurePreferencesLoaded(); feedListLock.lock(); queuedEpisodeActions.removeAll(queued); writePreference(PREF_SYNC_EPISODE_ACTIONS, writeEpisodeActionsToString(queuedEpisodeActions)); feedListLock.unlock(); } /** * Returns true if device ID, username and password have a non-null value */ public static boolean loggedIn() { ensurePreferencesLoaded(); return deviceID != null && username != null && password != null; } public static synchronized void logout() { if (BuildConfig.DEBUG) Log.d(TAG, "Logout: Clearing preferences"); setUsername(null); setPassword(null); setDeviceID(null); feedListLock.lock(); addedFeeds.clear(); writePreference(PREF_SYNC_ADDED, addedFeeds); removedFeeds.clear(); writePreference(PREF_SYNC_REMOVED, removedFeeds); queuedEpisodeActions.clear(); writePreference(PREF_SYNC_EPISODE_ACTIONS, writeEpisodeActionsToString(queuedEpisodeActions)); feedListLock.unlock(); setLastSubscriptionSyncTimestamp(0); } private static Set<String> readListFromString(String s) { Set<String> result = new HashSet<>(); for (String item : s.split(" ")) { result.add(item); } return result; } private static String writeListToString(Collection<String> c) { StringBuilder result = new StringBuilder(); for (String item : c) { result.append(item); result.append(" "); } return result.toString().trim(); } private static List<GpodnetEpisodeAction> readEpisodeActionsFromString(String s) { String[] lines = s.split("\n"); List<GpodnetEpisodeAction> result = new ArrayList<>(lines.length); for(String line : lines) { if(TextUtils.isEmpty(line)) { GpodnetEpisodeAction action = GpodnetEpisodeAction.readFromString(line); if(action != null) { result.add(GpodnetEpisodeAction.readFromString(line)); } } } return result; } private static String writeEpisodeActionsToString(Collection<GpodnetEpisodeAction> c) { StringBuilder result = new StringBuilder(); for(GpodnetEpisodeAction item : c) { result.append(item.writeToString()); result.append("\n"); } return result.toString(); } private static String checkGpodnetHostname(String value) { int startIndex = 0; if (value.startsWith("http://")) { startIndex = "http://".length(); } else if (value.startsWith("https://")) { startIndex = "https://".length(); } return value.substring(startIndex); } }