package de.danoeh.antennapod.core.preferences; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import java.io.File; import java.io.IOException; import java.net.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver; import de.danoeh.antennapod.core.service.download.ProxyConfig; import de.danoeh.antennapod.core.storage.APCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm; import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; import de.danoeh.antennapod.core.util.Converter; /** * Provides access to preferences set by the user in the settings screen. A * private instance of this class must first be instantiated via * init() or otherwise every public method will throw an Exception * when called. */ public class UserPreferences { private UserPreferences(){} public static final String IMPORT_DIR = "import/"; private static final String TAG = "UserPreferences"; // User Interface public static final String PREF_THEME = "prefTheme"; public static final String PREF_HIDDEN_DRAWER_ITEMS = "prefHiddenDrawerItems"; public static final String PREF_DRAWER_FEED_ORDER = "prefDrawerFeedOrder"; public static final String PREF_DRAWER_FEED_COUNTER = "prefDrawerFeedIndicator"; public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify"; public static final String PREF_PERSISTENT_NOTIFICATION = "prefPersistNotify"; public static final String PREF_COMPACT_NOTIFICATION_BUTTONS = "prefCompactNotificationButtons"; public static final String PREF_LOCKSCREEN_BACKGROUND = "prefLockscreenBackground"; public static final String PREF_SHOW_DOWNLOAD_REPORT = "prefShowDownloadReport"; // Queue public static final String PREF_QUEUE_ADD_TO_FRONT = "prefQueueAddToFront"; // Playback public static final String PREF_PAUSE_ON_HEADSET_DISCONNECT = "prefPauseOnHeadsetDisconnect"; public static final String PREF_UNPAUSE_ON_HEADSET_RECONNECT = "prefUnpauseOnHeadsetReconnect"; public static final String PREF_UNPAUSE_ON_BLUETOOTH_RECONNECT = "prefUnpauseOnBluetoothReconnect"; public static final String PREF_HARDWARE_FOWARD_BUTTON_SKIPS = "prefHardwareForwardButtonSkips"; public static final String PREF_FOLLOW_QUEUE = "prefFollowQueue"; public static final String PREF_SKIP_KEEPS_EPISODE = "prefSkipKeepsEpisode"; public static final String PREF_AUTO_DELETE = "prefAutoDelete"; public static final String PREF_SMART_MARK_AS_PLAYED_SECS = "prefSmartMarkAsPlayedSecs"; public static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray"; public static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss"; public static final String PREF_RESUME_AFTER_CALL = "prefResumeAfterCall"; // Network public static final String PREF_UPDATE_INTERVAL = "prefAutoUpdateIntervall"; public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate"; public static final String PREF_EPISODE_CLEANUP = "prefEpisodeCleanup"; public static final String PREF_PARALLEL_DOWNLOADS = "prefParallelDownloads"; public static final String PREF_EPISODE_CACHE_SIZE = "prefEpisodeCacheSize"; public static final String PREF_ENABLE_AUTODL = "prefEnableAutoDl"; public static final String PREF_ENABLE_AUTODL_ON_BATTERY = "prefEnableAutoDownloadOnBattery"; public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter"; public static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks"; public static final String PREF_PROXY_TYPE = "prefProxyType"; public static final String PREF_PROXY_HOST = "prefProxyHost"; public static final String PREF_PROXY_PORT = "prefProxyPort"; public static final String PREF_PROXY_USER = "prefProxyUser"; public static final String PREF_PROXY_PASSWORD = "prefProxyPassword"; // Services public static final String PREF_AUTO_FLATTR = "pref_auto_flattr"; public static final String PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD = "prefAutoFlattrPlayedDurationThreshold"; // Other public static final String PREF_DATA_FOLDER = "prefDataFolder"; public static final String PREF_IMAGE_CACHE_SIZE = "prefImageCacheSize"; // Mediaplayer public static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed"; private static final String PREF_FAST_FORWARD_SECS = "prefFastForwardSecs"; private static final String PREF_REWIND_SECS = "prefRewindSecs"; public static final String PREF_QUEUE_LOCKED = "prefQueueLocked"; public static final String IMAGE_CACHE_DEFAULT_VALUE = "100"; public static final int IMAGE_CACHE_SIZE_MINIMUM = 20; public static final String PREF_LEFT_VOLUME = "prefLeftVolume"; public static final String PREF_RIGHT_VOLUME = "prefRightVolume"; // Experimental public static final String PREF_SONIC = "prefSonic"; public static final String PREF_STEREO_TO_MONO = "PrefStereoToMono"; public static final String PREF_NORMALIZER = "prefNormalizer"; public static final String PREF_CAST_ENABLED = "prefCast"; //Used for enabling Chromecast support public static final int EPISODE_CLEANUP_QUEUE = -1; public static final int EPISODE_CLEANUP_NULL = -2; public static final int EPISODE_CLEANUP_DEFAULT = 0; // Constants private static final int NOTIFICATION_BUTTON_REWIND = 0; private static final int NOTIFICATION_BUTTON_FAST_FORWARD = 1; private static final int NOTIFICATION_BUTTON_SKIP = 2; private static int EPISODE_CACHE_SIZE_UNLIMITED = -1; public static final int FEED_ORDER_COUNTER = 0; public static final int FEED_ORDER_ALPHABETICAL = 1; public static final int FEED_ORDER_LAST_UPDATE = 2; public static final int FEED_COUNTER_SHOW_NEW_UNPLAYED_SUM = 0; public static final int FEED_COUNTER_SHOW_NEW = 1; public static final int FEED_COUNTER_SHOW_UNPLAYED = 2; public static final int FEED_COUNTER_SHOW_NONE = 3; private static Context context; private static SharedPreferences prefs; /** * Sets up the UserPreferences class. * * @throws IllegalArgumentException if context is null */ public static void init(@NonNull Context context) { Log.d(TAG, "Creating new instance of UserPreferences"); UserPreferences.context = context.getApplicationContext(); UserPreferences.prefs = PreferenceManager.getDefaultSharedPreferences(context); createImportDirectory(); createNoMediaFile(); } /** * Returns theme as R.style value * * @return R.style.Theme_AntennaPod_Light or R.style.Theme_AntennaPod_Dark */ public static int getTheme() { return readThemeValue(prefs.getString(PREF_THEME, "0")); } public static int getNoTitleTheme() { int theme = getTheme(); if (theme == R.style.Theme_AntennaPod_Dark) { return R.style.Theme_AntennaPod_Dark_NoTitle; } else { return R.style.Theme_AntennaPod_Light_NoTitle; } } public static List<String> getHiddenDrawerItems() { String hiddenItems = prefs.getString(PREF_HIDDEN_DRAWER_ITEMS, ""); return new ArrayList<>(Arrays.asList(TextUtils.split(hiddenItems, ","))); } public static List<Integer> getCompactNotificationButtons() { String[] buttons = TextUtils.split( prefs.getString(PREF_COMPACT_NOTIFICATION_BUTTONS, String.valueOf(NOTIFICATION_BUTTON_SKIP)), ","); List<Integer> notificationButtons = new ArrayList<>(); for (int i=0; i<buttons.length; i++) { notificationButtons.add(Integer.parseInt(buttons[i])); } return notificationButtons; } /** * Helper function to return whether the specified button should be shown on compact * notifications. * * @param buttonId Either NOTIFICATION_BUTTON_REWIND, NOTIFICATION_BUTTON_FAST_FORWARD or * NOTIFICATION_BUTTON_SKIP. * @return {@code true} if button should be shown, {@code false} otherwise */ private static boolean showButtonOnCompactNotification(int buttonId) { return getCompactNotificationButtons().contains(buttonId); } public static boolean showRewindOnCompactNotification() { return showButtonOnCompactNotification(NOTIFICATION_BUTTON_REWIND); } public static boolean showFastForwardOnCompactNotification() { return showButtonOnCompactNotification(NOTIFICATION_BUTTON_FAST_FORWARD); } public static boolean showSkipOnCompactNotification() { return showButtonOnCompactNotification(NOTIFICATION_BUTTON_SKIP); } public static int getFeedOrder() { String value = prefs.getString(PREF_DRAWER_FEED_ORDER, "0"); return Integer.parseInt(value); } public static int getFeedCounterSetting() { String value = prefs.getString(PREF_DRAWER_FEED_COUNTER, "0"); return Integer.parseInt(value); } /** * Returns notification priority. * * @return NotificationCompat.PRIORITY_MAX or NotificationCompat.PRIORITY_DEFAULT */ public static int getNotifyPriority() { if (prefs.getBoolean(PREF_EXPANDED_NOTIFICATION, false)) { return NotificationCompat.PRIORITY_MAX; } else { return NotificationCompat.PRIORITY_DEFAULT; } } /** * Returns true if notifications are persistent * * @return {@code true} if notifications are persistent, {@code false} otherwise */ public static boolean isPersistNotify() { return prefs.getBoolean(PREF_PERSISTENT_NOTIFICATION, true); } /** * Returns true if the lockscreen background should be set to the current episode's image * * @return {@code true} if the lockscreen background should be set, {@code false} otherwise */ public static boolean setLockscreenBackground() { return prefs.getBoolean(PREF_LOCKSCREEN_BACKGROUND, true); } /** * Returns true if download reports are shown * * @return {@code true} if download reports are shown, {@code false} otherwise */ public static boolean showDownloadReport() { return prefs.getBoolean(PREF_SHOW_DOWNLOAD_REPORT, true); } /** * Returns {@code true} if new queue elements are added to the front * * @return {@code true} if new queue elements are added to the front; {@code false} otherwise */ public static boolean enqueueAtFront() { return prefs.getBoolean(PREF_QUEUE_ADD_TO_FRONT, false); } public static boolean isPauseOnHeadsetDisconnect() { return prefs.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true); } public static boolean isUnpauseOnHeadsetReconnect() { return prefs.getBoolean(PREF_UNPAUSE_ON_HEADSET_RECONNECT, true); } public static boolean isUnpauseOnBluetoothReconnect() { return prefs.getBoolean(PREF_UNPAUSE_ON_BLUETOOTH_RECONNECT, false); } public static boolean shouldHardwareButtonSkip() { return prefs.getBoolean(PREF_HARDWARE_FOWARD_BUTTON_SKIPS, false); } public static boolean isFollowQueue() { return prefs.getBoolean(PREF_FOLLOW_QUEUE, true); } public static boolean shouldSkipKeepEpisode() { return prefs.getBoolean(PREF_SKIP_KEEPS_EPISODE, true); } public static boolean isAutoDelete() { return prefs.getBoolean(PREF_AUTO_DELETE, false); } public static int getSmartMarkAsPlayedSecs() { return Integer.parseInt(prefs.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30")); } public static boolean isAutoFlattr() { return prefs.getBoolean(PREF_AUTO_FLATTR, false); } public static String getPlaybackSpeed() { return prefs.getString(PREF_PLAYBACK_SPEED, "1.00"); } public static String[] getPlaybackSpeedArray() { return readPlaybackSpeedArray(prefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null)); } public static float getLeftVolume() { int volume = prefs.getInt(PREF_LEFT_VOLUME, 100); return Converter.getVolumeFromPercentage(volume); } public static float getRightVolume() { int volume = prefs.getInt(PREF_RIGHT_VOLUME, 100); return Converter.getVolumeFromPercentage(volume); } public static int getLeftVolumePercentage() { return prefs.getInt(PREF_LEFT_VOLUME, 100); } public static int getRightVolumePercentage() { return prefs.getInt(PREF_RIGHT_VOLUME, 100); } public static boolean shouldPauseForFocusLoss() { return prefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false); } public static long getUpdateInterval() { String updateInterval = prefs.getString(PREF_UPDATE_INTERVAL, "0"); if(!updateInterval.contains(":")) { return readUpdateInterval(updateInterval); } else { return 0; } } public static int[] getUpdateTimeOfDay() { String datetime = prefs.getString(PREF_UPDATE_INTERVAL, ""); if(datetime.length() >= 3 && datetime.contains(":")) { String[] parts = datetime.split(":"); int hourOfDay = Integer.parseInt(parts[0]); int minute = Integer.parseInt(parts[1]); return new int[] { hourOfDay, minute }; } else { return new int[0]; } } public static boolean isAllowMobileUpdate() { return prefs.getBoolean(PREF_MOBILE_UPDATE, false); } public static int getParallelDownloads() { return Integer.parseInt(prefs.getString(PREF_PARALLEL_DOWNLOADS, "4")); } public static int getEpisodeCacheSizeUnlimited() { return context.getResources().getInteger(R.integer.episode_cache_size_unlimited); } /** * Returns the capacity of the episode cache. This method will return the * negative integer EPISODE_CACHE_SIZE_UNLIMITED if the cache size is set to * 'unlimited'. */ public static int getEpisodeCacheSize() { return readEpisodeCacheSizeInternal(prefs.getString(PREF_EPISODE_CACHE_SIZE, "20")); } public static boolean isEnableAutodownload() { return prefs.getBoolean(PREF_ENABLE_AUTODL, false); } public static boolean isEnableAutodownloadOnBattery() { return prefs.getBoolean(PREF_ENABLE_AUTODL_ON_BATTERY, true); } public static boolean isEnableAutodownloadWifiFilter() { return prefs.getBoolean(PREF_ENABLE_AUTODL_WIFI_FILTER, false); } public static int getImageCacheSize() { String cacheSizeString = prefs.getString(PREF_IMAGE_CACHE_SIZE, IMAGE_CACHE_DEFAULT_VALUE); int cacheSizeInt = Integer.parseInt(cacheSizeString); // if the cache size is too small the user won't get any images at all // that's bad, force it back to the default. if (cacheSizeInt < IMAGE_CACHE_SIZE_MINIMUM) { prefs.edit().putString(PREF_IMAGE_CACHE_SIZE, IMAGE_CACHE_DEFAULT_VALUE).apply(); cacheSizeInt = Integer.parseInt(IMAGE_CACHE_DEFAULT_VALUE); } int cacheSizeMB = cacheSizeInt * 1024 * 1024; return cacheSizeMB; } public static int getFastFowardSecs() { return prefs.getInt(PREF_FAST_FORWARD_SECS, 30); } public static int getRewindSecs() { return prefs.getInt(PREF_REWIND_SECS, 30); } /** * Returns the time after which an episode should be auto-flattr'd in percent of the episode's * duration. */ public static float getAutoFlattrPlayedDurationThreshold() { return prefs.getFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD, 0.8f); } public static String[] getAutodownloadSelectedNetworks() { String selectedNetWorks = prefs.getString(PREF_AUTODL_SELECTED_NETWORKS, ""); return TextUtils.split(selectedNetWorks, ","); } public static void setProxyConfig(ProxyConfig config) { SharedPreferences.Editor editor = prefs.edit(); editor.putString(PREF_PROXY_TYPE, config.type.name()); if(TextUtils.isEmpty(config.host)) { editor.remove(PREF_PROXY_HOST); } else { editor.putString(PREF_PROXY_HOST, config.host); } if(config.port <= 0 || config.port > 65535) { editor.remove(PREF_PROXY_PORT); } else { editor.putInt(PREF_PROXY_PORT, config.port); } if(TextUtils.isEmpty(config.username)) { editor.remove(PREF_PROXY_USER); } else { editor.putString(PREF_PROXY_USER, config.username); } if(TextUtils.isEmpty(config.password)) { editor.remove(PREF_PROXY_PASSWORD); } else { editor.putString(PREF_PROXY_PASSWORD, config.password); } editor.apply(); } public static ProxyConfig getProxyConfig() { Proxy.Type type = Proxy.Type.valueOf(prefs.getString(PREF_PROXY_TYPE, Proxy.Type.DIRECT.name())); String host = prefs.getString(PREF_PROXY_HOST, null); int port = prefs.getInt(PREF_PROXY_PORT, 0); String username = prefs.getString(PREF_PROXY_USER, null); String password = prefs.getString(PREF_PROXY_PASSWORD, null); return new ProxyConfig(type, host, port, username, password); } public static boolean shouldResumeAfterCall() { return prefs.getBoolean(PREF_RESUME_AFTER_CALL, true); } public static boolean isQueueLocked() { return prefs.getBoolean(PREF_QUEUE_LOCKED, false); } public static void setPrefFastForwardSecs(int secs) { prefs.edit() .putInt(PREF_FAST_FORWARD_SECS, secs) .apply(); } public static void setPrefRewindSecs(int secs) { prefs.edit() .putInt(PREF_REWIND_SECS, secs) .apply(); } public static void setPlaybackSpeed(String speed) { prefs.edit() .putString(PREF_PLAYBACK_SPEED, speed) .apply(); } public static void setPlaybackSpeedArray(String[] speeds) { JSONArray jsonArray = new JSONArray(); for (String speed : speeds) { jsonArray.put(speed); } prefs.edit() .putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString()) .apply(); } public static void setVolume(int leftVolume, int rightVolume) { assert(0 <= leftVolume && leftVolume <= 100); assert(0 <= rightVolume && rightVolume <= 100); prefs.edit() .putInt(PREF_LEFT_VOLUME, leftVolume) .putInt(PREF_RIGHT_VOLUME, rightVolume) .apply(); } public static void setAutodownloadSelectedNetworks(String[] value) { prefs.edit() .putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value)) .apply(); } /** * Sets the update interval value. */ public static void setUpdateInterval(long hours) { prefs.edit() .putString(PREF_UPDATE_INTERVAL, String.valueOf(hours)) .apply(); // when updating with an interval, we assume the user wants // to update *now* and then every 'hours' interval thereafter. restartUpdateAlarm(true); } /** * Sets the update interval value. */ public static void setUpdateTimeOfDay(int hourOfDay, int minute) { prefs.edit() .putString(PREF_UPDATE_INTERVAL, hourOfDay + ":" + minute) .apply(); restartUpdateAlarm(false); } /** * Change the auto-flattr settings * * @param enabled Whether automatic flattring should be enabled at all * @param autoFlattrThreshold The percentage of playback time after which an episode should be * flattrd. Must be a value between 0 and 1 (inclusive) * */ public static void setAutoFlattrSettings( boolean enabled, float autoFlattrThreshold) { if(autoFlattrThreshold < 0.0 || autoFlattrThreshold > 1.0) { throw new IllegalArgumentException("Flattr threshold must be in range [0.0, 1.0]"); } prefs.edit() .putBoolean(PREF_AUTO_FLATTR, enabled) .putFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD, autoFlattrThreshold) .apply(); } public static void setHiddenDrawerItems(List<String> items) { String str = TextUtils.join(",", items); prefs.edit() .putString(PREF_HIDDEN_DRAWER_ITEMS, str) .apply(); } public static void setCompactNotificationButtons(List<Integer> items) { String str = TextUtils.join(",", items); prefs.edit() .putString(PREF_COMPACT_NOTIFICATION_BUTTONS, str) .apply(); } public static void setQueueLocked(boolean locked) { prefs.edit() .putBoolean(PREF_QUEUE_LOCKED, locked) .apply(); } private static int readThemeValue(String valueFromPrefs) { switch (Integer.parseInt(valueFromPrefs)) { case 0: return R.style.Theme_AntennaPod_Light; case 1: return R.style.Theme_AntennaPod_Dark; default: return R.style.Theme_AntennaPod_Light; } } private static long readUpdateInterval(String valueFromPrefs) { int hours = Integer.parseInt(valueFromPrefs); return TimeUnit.HOURS.toMillis(hours); } private static int readEpisodeCacheSizeInternal(String valueFromPrefs) { if (valueFromPrefs.equals(context.getString(R.string.pref_episode_cache_unlimited))) { return EPISODE_CACHE_SIZE_UNLIMITED; } else { return Integer.parseInt(valueFromPrefs); } } private static String[] readPlaybackSpeedArray(String valueFromPrefs) { String[] selectedSpeeds = null; // If this preference hasn't been set yet, return the default options if (valueFromPrefs == null) { selectedSpeeds = new String[] { "1.00", "1.25", "1.50", "1.75", "2.00" }; } else { try { JSONArray jsonArray = new JSONArray(valueFromPrefs); selectedSpeeds = new String[jsonArray.length()]; for (int i = 0; i < jsonArray.length(); i++) { selectedSpeeds[i] = jsonArray.getString(i); } } catch (JSONException e) { Log.e(TAG, "Got JSON error when trying to get speeds from JSONArray"); e.printStackTrace(); } } return selectedSpeeds; } public static boolean useSonic() { return prefs.getBoolean(PREF_SONIC, false); } public static void enableSonic(boolean enable) { prefs.edit() .putBoolean(PREF_SONIC, enable) .apply(); } public static boolean stereoToMono() { return prefs.getBoolean(PREF_STEREO_TO_MONO, false); } public static void stereoToMono(boolean enable) { prefs.edit() .putBoolean(PREF_STEREO_TO_MONO, enable) .apply(); } public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() { int cleanupValue = Integer.parseInt(prefs.getString(PREF_EPISODE_CLEANUP, "-1")); if (cleanupValue == EPISODE_CLEANUP_QUEUE) { return new APQueueCleanupAlgorithm(); } else if (cleanupValue == EPISODE_CLEANUP_NULL) { return new APNullCleanupAlgorithm(); } else { return new APCleanupAlgorithm(cleanupValue); } } /** * Return the folder where the app stores all of its data. This method will * return the standard data folder if none has been set by the user. * * @param type The name of the folder inside the data folder. May be null * when accessing the root of the data folder. * @return The data folder that has been requested or null if the folder * could not be created. */ public static File getDataFolder(String type) { String strDir = prefs.getString(PREF_DATA_FOLDER, null); if (strDir == null) { Log.d(TAG, "Using default data folder"); return context.getExternalFilesDir(type); } else { File dataDir = new File(strDir); if (!dataDir.exists()) { if (!dataDir.mkdir()) { Log.w(TAG, "Could not create data folder"); return null; } } if (type == null) { return dataDir; } else { // handle path separators String[] dirs = type.split("/"); for (int i = 0; i < dirs.length; i++) { if (dirs.length > 0) { if (i < dirs.length - 1) { dataDir = getDataFolder(dirs[i]); if (dataDir == null) { return null; } } type = dirs[i]; } } File typeDir = new File(dataDir, type); if (!typeDir.exists()) { if (dataDir.canWrite()) { if (!typeDir.mkdir()) { Log.e(TAG, "Could not create data folder named " + type); return null; } } } return typeDir; } } } public static void setDataFolder(String dir) { Log.d(TAG, "setDataFolder(dir: " + dir + ")"); prefs.edit() .putString(PREF_DATA_FOLDER, dir) .apply(); createImportDirectory(); } /** * Create a .nomedia file to prevent scanning by the media scanner. */ private static void createNoMediaFile() { File f = new File(context.getExternalFilesDir(null), ".nomedia"); if (!f.exists()) { try { f.createNewFile(); } catch (IOException e) { Log.e(TAG, "Could not create .nomedia file"); e.printStackTrace(); } Log.d(TAG, ".nomedia file created"); } } /** * Creates the import directory if it doesn't exist and if storage is * available */ private static void createImportDirectory() { File importDir = getDataFolder(IMPORT_DIR); if (importDir != null) { if (importDir.exists()) { Log.d(TAG, "Import directory already exists"); } else { Log.d(TAG, "Creating import directory"); importDir.mkdir(); } } else { Log.d(TAG, "Could not access external storage."); } } public static void restartUpdateAlarm(boolean now) { int[] timeOfDay = getUpdateTimeOfDay(); Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay)); if (timeOfDay.length == 2) { restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]); } else { long hours = getUpdateInterval(); long startTrigger = hours; if (now) { startTrigger = TimeUnit.SECONDS.toMillis(10); } restartUpdateIntervalAlarm(startTrigger, hours); } } /** * Sets the interval in which the feeds are refreshed automatically */ public static void restartUpdateIntervalAlarm(long triggerAtMillis, long intervalMillis) { Log.d(TAG, "Restarting update alarm."); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, FeedUpdateReceiver.class); PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmManager.cancel(updateIntent); if (intervalMillis > 0) { alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + triggerAtMillis, updateIntent); Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h"); } else { Log.d(TAG, "Automatic update was deactivated"); } } /** * Sets time of day the feeds are refreshed automatically */ public static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) { Log.d(TAG, "Restarting update alarm."); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, FeedUpdateReceiver.class), 0); alarmManager.cancel(updateIntent); Calendar now = Calendar.getInstance(); Calendar alarm = (Calendar)now.clone(); alarm.set(Calendar.HOUR_OF_DAY, hoursOfDay); alarm.set(Calendar.MINUTE, minute); if (alarm.before(now) || alarm.equals(now)) { alarm.add(Calendar.DATE, 1); } 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 " + hoursOfDay + ":" + minute); } /** * Reads episode cache size as it is saved in the episode_cache_size_values array. */ public static int readEpisodeCacheSize(String valueFromPrefs) { return readEpisodeCacheSizeInternal(valueFromPrefs); } /** * Evaluates whether Cast support (Chromecast, Audio Cast, etc) is enabled on the preferences. */ public static boolean isCastEnabled() { return prefs.getBoolean(PREF_CAST_ENABLED, false); } }