From cbf1bda433a7b7a0de2690002202d6c77fae2c32 Mon Sep 17 00:00:00 2001
From: Hans-Christoph Steiner <hans@eds.org>
Date: Thu, 14 Apr 2016 19:28:52 -0400
Subject: [PATCH] add preference to set the time to keep cached APKs

This schedules CleanCacheService to run regularly, and delete files older
than the value set in the new "Keep cached apps" preference. It auto-
migrates the old "Cache packages" pref to the new one.  The default cache
time for people who did not have "Cache packages" enabled is one day.
---
 .../org/fdroid/fdroid/CleanCacheService.java  | 34 +++++++++++++------
 .../java/org/fdroid/fdroid/FDroidApp.java     |  2 +-
 .../java/org/fdroid/fdroid/Preferences.java   | 34 ++++++++++++++++---
 .../views/fragments/PreferencesFragment.java  |  6 ++--
 app/src/main/res/values/array.xml             |  9 +++++
 app/src/main/res/values/donottranslate.xml    |  9 +++++
 app/src/main/res/values/strings.xml           | 11 ++++--
 app/src/main/res/xml/preferences.xml          |  7 ++--
 8 files changed, 89 insertions(+), 23 deletions(-)

diff --git a/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java b/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java
index 48d5910c3..0838b6770 100644
--- a/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java
+++ b/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java
@@ -1,9 +1,13 @@
 package org.fdroid.fdroid;
 
+import android.app.AlarmManager;
 import android.app.IntentService;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Process;
+import android.os.SystemClock;
+import android.util.Log;
 
 import org.apache.commons.io.FileUtils;
 
@@ -18,9 +22,26 @@ import java.io.File;
 public class CleanCacheService extends IntentService {
     public static final String TAG = "CleanCacheService";
 
-    public static void start(Context context) {
+    /**
+     * Schedule or cancel this service to update the app index, according to the
+     * current preferences. Should be called a) at boot, b) if the preference
+     * is changed, or c) on startup, in case we get upgraded.
+     */
+    public static void schedule(Context context) {
+        long keepTime = Preferences.get().getKeepCacheTime();
+        long interval = 604800000; // 1 day
+        if (keepTime < interval) {
+            interval = keepTime * 1000;
+        }
+        Log.i(TAG, "schedule " + keepTime + " " + interval);
+
         Intent intent = new Intent(context, CleanCacheService.class);
-        context.startService(intent);
+        PendingIntent pending = PendingIntent.getService(context, 0, intent, 0);
+
+        AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        alarm.cancel(pending);
+        alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
+                SystemClock.elapsedRealtime() + 5000, interval, pending);
     }
 
     public CleanCacheService() {
@@ -30,14 +51,7 @@ public class CleanCacheService extends IntentService {
     @Override
     protected void onHandleIntent(Intent intent) {
         Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
-
-        int cachetime;
-        if (Preferences.get().shouldCacheApks()) {
-            cachetime = Integer.MAX_VALUE;
-        } else {
-            cachetime = 3600;  // keep for 1 hour to allow resumable downloads
-        }
-        Utils.clearOldFiles(Utils.getApkCacheDir(this), cachetime);
+        Utils.clearOldFiles(Utils.getApkCacheDir(this), Preferences.get().getKeepCacheTime());
         deleteStrayIndexFiles();
     }
 
diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
index 4213dce38..c774fccd9 100644
--- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
+++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
@@ -221,7 +221,7 @@ public class FDroidApp extends Application {
             }
         });
 
-        CleanCacheService.start(this);
+        CleanCacheService.schedule(this);
 
         UpdateService.schedule(getApplicationContext());
         bluetoothAdapter = getBluetoothAdapter();
diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java
index 326ac2107..160e655d3 100644
--- a/app/src/main/java/org/fdroid/fdroid/Preferences.java
+++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java
@@ -32,9 +32,11 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
 
     private static final String TAG = "Preferences";
 
+    private final Context context;
     private final SharedPreferences preferences;
 
     private Preferences(Context context) {
+        this.context = context;
         preferences = PreferenceManager.getDefaultSharedPreferences(context);
         preferences.registerOnSharedPreferenceChangeListener(this);
         if (preferences.getString(PREF_LOCAL_REPO_NAME, null) == null) {
@@ -52,7 +54,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
     public static final String PREF_INCOMP_VER = "incompatibleVersions";
     public static final String PREF_THEME = "theme";
     public static final String PREF_IGN_TOUCH = "ignoreTouchscreen";
-    public static final String PREF_CACHE_APK = "cacheDownloaded";
+    public static final String PREF_KEEP_CACHE_TIME = "keepCacheFor";
     public static final String PREF_UNSTABLE_UPDATES = "unstableUpdates";
     public static final String PREF_EXPERT = "expert";
     public static final String PREF_PRIVILEGED_INSTALLER = "privilegedInstaller";
@@ -72,7 +74,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
     private static final int DEFAULT_UPD_HISTORY = 14;
     private static final boolean DEFAULT_PRIVILEGED_INSTALLER = false;
     //private static final boolean DEFAULT_LOCAL_REPO_BONJOUR = true;
-    private static final boolean DEFAULT_CACHE_APK = false;
+    private static final long DEFAULT_KEEP_CACHE_SECONDS = 86400;  // one day
     private static final boolean DEFAULT_UNSTABLE_UPDATES = false;
     //private static final boolean DEFAULT_LOCAL_REPO_HTTPS = false;
     private static final boolean DEFAULT_INCOMP_VER = false;
@@ -139,8 +141,32 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
         PreferencesCompat.apply(preferences.edit().putBoolean(PREF_POST_PRIVILEGED_INSTALL, postInstall));
     }
 
-    public boolean shouldCacheApks() {
-        return preferences.getBoolean(PREF_CACHE_APK, DEFAULT_CACHE_APK);
+    /**
+     * Old preference replaced by {@link #PREF_KEEP_CACHE_TIME}
+     */
+    private static final String PREF_CACHE_APK = "cacheDownloaded";
+
+    /**
+     * Time in seconds to keep cached files.  Anything that has been around longer will be deleted
+     */
+    public long getKeepCacheTime() {
+        String value = preferences.getString(PREF_KEEP_CACHE_TIME, String.valueOf(DEFAULT_KEEP_CACHE_SECONDS));
+
+        if (preferences.contains(PREF_CACHE_APK)) {
+            if (preferences.getBoolean(PREF_CACHE_APK, false)) {
+                value = context.getString(R.string.keep_forever);
+            }
+            SharedPreferences.Editor editor = preferences.edit();
+            editor.remove(PREF_CACHE_APK);
+            editor.putString(PREF_KEEP_CACHE_TIME, value);
+            PreferencesCompat.apply(editor);
+        }
+
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            return DEFAULT_KEEP_CACHE_SECONDS;
+        }
     }
 
     public boolean getUnstableUpdates() {
diff --git a/app/src/main/java/org/fdroid/fdroid/views/fragments/PreferencesFragment.java b/app/src/main/java/org/fdroid/fdroid/views/fragments/PreferencesFragment.java
index a150db286..5043fc914 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/fragments/PreferencesFragment.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/fragments/PreferencesFragment.java
@@ -39,7 +39,7 @@ public class PreferencesFragment extends PreferenceFragment
         Preferences.PREF_IGN_TOUCH,
         Preferences.PREF_LOCAL_REPO_NAME,
         Preferences.PREF_LANGUAGE,
-        Preferences.PREF_CACHE_APK,
+        Preferences.PREF_KEEP_CACHE_TIME,
         Preferences.PREF_EXPERT,
         Preferences.PREF_PRIVILEGED_INSTALLER,
         Preferences.PREF_ENABLE_PROXY,
@@ -143,8 +143,8 @@ public class PreferencesFragment extends PreferenceFragment
                 }
                 break;
 
-            case Preferences.PREF_CACHE_APK:
-                checkSummary(key, R.string.cache_downloaded_on);
+            case Preferences.PREF_KEEP_CACHE_TIME:
+                entrySummary(key);
                 break;
 
             case Preferences.PREF_EXPERT:
diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml
index de5f1f86b..c575ea5a4 100644
--- a/app/src/main/res/values/array.xml
+++ b/app/src/main/res/values/array.xml
@@ -10,6 +10,15 @@
         <item>@string/interval_2w</item>
     </string-array>
 
+    <string-array name="keepCacheNames">
+        <item>@string/keep_hour</item>
+        <item>@string/keep_day</item>
+        <item>@string/keep_week</item>
+        <item>@string/keep_month</item>
+        <item>@string/keep_year</item>
+        <item>@string/keep_forever</item>
+    </string-array>
+
     <string-array name="themeNames">
         <item>@string/theme_light</item>
         <item>@string/theme_dark</item>
diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml
index d6a202fab..c7d387726 100644
--- a/app/src/main/res/values/donottranslate.xml
+++ b/app/src/main/res/values/donottranslate.xml
@@ -23,6 +23,15 @@
         <item>336</item>
     </string-array>
 
+    <string-array name="keepCacheValues">
+        <item>3600</item>
+        <item>86400</item>
+        <item>604800</item>
+        <item>2592000</item>
+        <item>31449600</item>
+        <item>2147483647</item>
+    </string-array>
+
     <string-array name="themeValues">
         <item>light</item>
         <item>dark</item>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d2203a659..2b2cb2c8b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -10,8 +10,8 @@
     <string name="by_author">by</string>
     <string name="delete">Delete</string>
     <string name="enable_nfc_send">Enable NFC Send…</string>
-    <string name="cache_downloaded">Cache packages</string>
-    <string name="cache_downloaded_on">Keep downloaded package files on device</string>
+    <string name="cache_downloaded">Keep cached apps</string>
+    <string name="cache_downloaded_on">Keep downloaded APK files on device</string>
     <string name="updates">Updates</string>
     <string name="unstable_updates">Unstable updates</string>
     <string name="unstable_updates_summary">Suggest updates to unstable versions</string>
@@ -383,6 +383,13 @@
     <string name="interval_1w">Weekly</string>
     <string name="interval_2w">Every 2 weeks</string>
 
+    <string name="keep_hour">1 Hour</string>
+    <string name="keep_day">1 Day</string>
+    <string name="keep_week">1 Week</string>
+    <string name="keep_month">1 Month</string>
+    <string name="keep_year">1 Year</string>
+    <string name="keep_forever">Forever</string>
+
     <string name="theme_light">Light</string>
     <string name="theme_dark">Dark</string>
     <string name="theme_night">Night</string>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 4b2c7d14f..31fb9aee9 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -73,9 +73,10 @@
             android:dependency="enableProxy" />
     </PreferenceCategory>
     <PreferenceCategory android:title="@string/other">
-        <CheckBoxPreference android:title="@string/cache_downloaded"
-            android:defaultValue="false"
-            android:key="cacheDownloaded" />
+        <ListPreference android:title="@string/cache_downloaded"
+            android:key="keepCacheFor"
+            android:entries="@array/keepCacheNames"
+            android:entryValues="@array/keepCacheValues" />
         <CheckBoxPreference android:title="@string/expert"
             android:defaultValue="false"
             android:key="expert" />