From 8be147c603d92c9520adeaa2b9e9f8ce6b76fa40 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 5 May 2020 19:03:44 +0200 Subject: Added on-demand configuration for stream vs download --- .../de/danoeh/antennapod/core/ClientConfig.java | 2 + .../core/preferences/UsageStatistics.java | 73 ++++++++++++++++++++++ .../core/preferences/UserPreferences.java | 6 +- core/src/main/res/layout/popup_bubble_view.xml | 40 ++++++++++++ core/src/main/res/values/strings.xml | 5 ++ .../de/danoeh/antennapod/core/ClientConfig.java | 2 + 6 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/preferences/UsageStatistics.java create mode 100644 core/src/main/res/layout/popup_bubble_view.xml (limited to 'core/src') diff --git a/core/src/free/java/de/danoeh/antennapod/core/ClientConfig.java b/core/src/free/java/de/danoeh/antennapod/core/ClientConfig.java index eea7d0ace..3c1eda242 100644 --- a/core/src/free/java/de/danoeh/antennapod/core/ClientConfig.java +++ b/core/src/free/java/de/danoeh/antennapod/core/ClientConfig.java @@ -4,6 +4,7 @@ import android.content.Context; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.SleepTimerPreferences; +import de.danoeh.antennapod.core.preferences.UsageStatistics; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; import de.danoeh.antennapod.core.storage.PodDBAdapter; @@ -42,6 +43,7 @@ public class ClientConfig { } PodDBAdapter.init(context); UserPreferences.init(context); + UsageStatistics.init(context); PlaybackPreferences.init(context); NetworkUtils.init(context); AntennapodHttpClient.setCacheDirectory(new File(context.getCacheDir(), "okhttp")); diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UsageStatistics.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UsageStatistics.java new file mode 100644 index 000000000..a5b00b08c --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UsageStatistics.java @@ -0,0 +1,73 @@ +package de.danoeh.antennapod.core.preferences; + +import android.content.Context; +import android.content.SharedPreferences; +import androidx.annotation.NonNull; + +import java.util.Calendar; + +/** + * Collects statistics about the app usage. The statistics are used to allow on-demand configuration: + * "Looks like you stream a lot. Do you want to toggle the 'Prefer streaming' setting?". + * The data is only stored locally on the device. It is NOT used for analytics/tracking. + * 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 UsageStatistics { + private UsageStatistics() { + + } + + private static final String PREF_DB_NAME = "UsageStatistics"; + private static final float MOVING_AVERAGE_WEIGHT = 0.8f; + private static final float MOVING_AVERAGE_BIAS_THRESHOLD = 0.1f; + private static final long ASK_AGAIN_LATER_DELAY = 1000 * 3600 * 24 * 10; // 10 days + private static final String SUFFIX_HIDDEN_UNTIL = "_hiddenUntil"; + private static SharedPreferences prefs; + + public static final StatsAction ACTION_STREAM = new StatsAction("downloadVsStream", 0); + public static final StatsAction ACTION_DOWNLOAD = new StatsAction("downloadVsStream", 1); + + /** + * Sets up the UsageStatistics class. + * + * @throws IllegalArgumentException if context is null + */ + public static void init(@NonNull Context context) { + prefs = context.getSharedPreferences(PREF_DB_NAME, Context.MODE_PRIVATE); + } + + public static void logAction(StatsAction action) { + int numExecutions = prefs.getInt(action.type + action.value, 0); + float movingAverage = prefs.getFloat(action.type, 0.5f); + prefs.edit() + .putInt(action.type + action.value, numExecutions + 1) + .putFloat(action.type, MOVING_AVERAGE_WEIGHT * movingAverage + + (1 - MOVING_AVERAGE_WEIGHT) * action.value) + .apply(); + } + + public static boolean hasSignificantBiasTo(StatsAction action) { + final float movingAverage = prefs.getFloat(action.type, 0.5f); + final long askAfter = prefs.getLong(action.type + SUFFIX_HIDDEN_UNTIL, 0); + return Math.abs(action.value - movingAverage) < MOVING_AVERAGE_BIAS_THRESHOLD + && Calendar.getInstance().getTimeInMillis() > askAfter; + } + + public static void askAgainLater(StatsAction action) { + prefs.edit().putLong(action.type + SUFFIX_HIDDEN_UNTIL, + Calendar.getInstance().getTimeInMillis() + ASK_AGAIN_LATER_DELAY) + .apply(); + } + + public static final class StatsAction { + public final String type; + public final int value; + + public StatsAction(String type, int value) { + this.type = type; + this.value = value; + } + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index cb5a405c0..14900ac20 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -996,10 +996,14 @@ public class UserPreferences { return prefs.getBoolean(PREF_TIME_RESPECTS_SPEED, false); } - public static boolean streamOverDownload() { + public static boolean isStreamOverDownload() { return prefs.getBoolean(PREF_STREAM_OVER_DOWNLOAD, false); } + public static void setStreamOverDownload(boolean stream) { + prefs.edit().putBoolean(PREF_STREAM_OVER_DOWNLOAD, stream).apply(); + } + /** * Returns if the queue is in keep sorted mode. * diff --git a/core/src/main/res/layout/popup_bubble_view.xml b/core/src/main/res/layout/popup_bubble_view.xml new file mode 100644 index 000000000..6b2e16f99 --- /dev/null +++ b/core/src/main/res/layout/popup_bubble_view.xml @@ -0,0 +1,40 @@ + + + + + + + +