content: package allen.town.podcast.core.pref;
  
  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;
          }
      }
  }
  