From 2fe7faed6e92b93ec6c31af8c774b4cb306521ce Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 30 Jan 2018 21:30:57 +0100 Subject: [PATCH 1/7] convert panic preferences to standard Preferences code style Yes, this is an ugly and old style, but mixing styles only makes it worse. Plus it breaks the tests in some cases, since it makes Preferences depend on Resources. --- .../java/org/fdroid/fdroid/Preferences.java | 17 ++++++----------- app/src/main/res/values/attrs.xml | 5 ----- app/src/main/res/xml/preferences.xml | 4 ++-- app/src/main/res/xml/preferences_panic.xml | 2 +- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index 53b604cb6..7b59b3c95 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -2,7 +2,6 @@ package org.fdroid.fdroid; import android.content.Context; import android.content.SharedPreferences; -import android.content.res.Resources; import android.os.Build; import android.preference.PreferenceManager; import android.util.Log; @@ -39,10 +38,6 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh .putString(PREF_LOCAL_REPO_NAME, getDefaultLocalRepoName()) .apply(); } - Resources res = context.getResources(); - defaultPreventScreenshots = res.getBoolean(R.bool.defaultPreventScreenshots); - defaultPanicExit = res.getBoolean(R.bool.defaultPanicExit); - defaultHideOnLongPressSearch = res.getBoolean(R.bool.defaultHideOnLongPressSearch); } public static final String PREF_UPD_INTERVAL = "updateInterval"; @@ -94,9 +89,9 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh private static final boolean DEFAULT_SHOW_NFC_DURING_SWAP = true; private static final boolean DEFAULT_FORCE_OLD_INDEX = false; private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false; - private final boolean defaultPreventScreenshots; - private final boolean defaultPanicExit; - private final boolean defaultHideOnLongPressSearch; + private static final boolean DEFAULT_PREVENT_SCREENSHOTS = false; + private static final boolean DEFAULT_PANIC_EXIT = true; + private static final boolean DEFAULT_HIDE_ON_LONG_PRESS_SEARCH = false; public enum Theme { light, @@ -327,11 +322,11 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh } public boolean preventScreenshots() { - return preferences.getBoolean(PREF_PREVENT_SCREENSHOTS, defaultPreventScreenshots); + return preferences.getBoolean(PREF_PREVENT_SCREENSHOTS, DEFAULT_PREVENT_SCREENSHOTS); } public boolean panicExit() { - return preferences.getBoolean(PREF_PANIC_EXIT, defaultPanicExit); + return preferences.getBoolean(PREF_PANIC_EXIT, DEFAULT_PANIC_EXIT); } public boolean panicHide() { @@ -339,7 +334,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh } public boolean hideOnLongPressSearch() { - return preferences.getBoolean(PREF_HIDE_ON_LONG_PRESS_SEARCH, defaultHideOnLongPressSearch); + return preferences.getBoolean(PREF_HIDE_ON_LONG_PRESS_SEARCH, DEFAULT_HIDE_ON_LONG_PRESS_SEARCH); } /** diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 1c59a906b..95581fea5 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -14,11 +14,6 @@ - - false - true - false - 1337 diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index d165d4e0b..afd16ea34 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -95,13 +95,13 @@ android:title="@string/privacy"> diff --git a/app/src/main/res/xml/preferences_panic.xml b/app/src/main/res/xml/preferences_panic.xml index 79689c115..275510943 100644 --- a/app/src/main/res/xml/preferences_panic.xml +++ b/app/src/main/res/xml/preferences_panic.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools"> From d8879dd42572410883ff78c0ac28a41467e5de53 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 26 Jan 2018 17:42:59 +0100 Subject: [PATCH 2/7] make DBHelper follow the Java Singleton pattern It was already behaving like a singleton, but the code was spread around in other classes. DBHelper does not use a private constructor though since the tests prevent it. --- .../java/org/fdroid/fdroid/Preferences.java | 3 +- .../java/org/fdroid/fdroid/data/DBHelper.java | 26 +++++++++++++++-- .../fdroid/fdroid/data/FDroidProvider.java | 28 +++---------------- .../org/fdroid/fdroid/AntiFeaturesTest.java | 11 ++------ .../fdroid/data/AppPrefsProviderTest.java | 3 +- .../fdroid/fdroid/data/AppProviderTest.java | 8 +----- .../fdroid/data/FDroidProviderTest.java | 3 +- .../fdroid/data/InstalledAppProviderTest.java | 8 +----- .../fdroid/data/PreferredSignatureTest.java | 9 +----- .../fdroid/fdroid/data/ProviderUriTests.java | 2 +- .../fdroid/fdroid/data/RepoProviderTest.java | 1 - .../fdroid/data/SuggestedVersionTest.java | 8 +----- .../AcceptableMultiRepoUpdaterTest.java | 1 - .../fdroid/updater/IndexV1UpdaterTest.java | 8 +----- .../fdroid/updater/Issue763MultiRepo.java | 1 - .../fdroid/updater/MultiRepoUpdaterTest.java | 8 +----- .../updater/ProperMultiRepoUpdaterTest.java | 1 - .../fdroid/views/AppDetailsAdapterTest.java | 7 ++--- 18 files changed, 44 insertions(+), 92 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index 7b59b3c95..e7bd2dfa3 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -453,8 +453,9 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh * While it is likely that most places asking for preferences have access to a {@link Context}, * it is a minor convenience to be able to ask for preferences without. */ - public static void clearSingletonForTesting() { + public static void setupForTests(Context context) { instance = null; + setup(context); } /** diff --git a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java index 22555916b..6a07920b4 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java @@ -47,13 +47,20 @@ import org.fdroid.fdroid.data.Schema.RepoTable; import java.util.ArrayList; import java.util.List; +/** + * This is basically a singleton used to represent the database at the core + * of all of the {@link android.content.ContentProvider}s used at the core + * of this app. {@link DBHelper} is not {@code private} so that it can be easily + * used in test subclasses. + */ @SuppressWarnings("LineLength") -class DBHelper extends SQLiteOpenHelper { +public class DBHelper extends SQLiteOpenHelper { private static final String TAG = "DBHelper"; public static final int REPO_XML_ARG_COUNT = 8; + private static DBHelper instance; private static final String DATABASE_NAME = "fdroid"; private static final String CREATE_TABLE_PACKAGE = "CREATE TABLE " + PackageTable.NAME @@ -214,7 +221,22 @@ class DBHelper extends SQLiteOpenHelper { DBHelper(Context context) { super(context, DATABASE_NAME, null, DB_VERSION); - this.context = context; + this.context = context.getApplicationContext(); + } + + /** + * Only used for testing. Not quite sure how to mock a singleton variable like this. + */ + public static void clearDbHelperSingleton() { + instance = null; + } + + static synchronized DBHelper getInstance(Context context) { + if (instance == null) { + Utils.debugLog(TAG, "First time accessing database, creating new helper"); + instance = new DBHelper(context); + } + return instance; } @Override diff --git a/app/src/main/java/org/fdroid/fdroid/data/FDroidProvider.java b/app/src/main/java/org/fdroid/fdroid/data/FDroidProvider.java index da1bde5d1..4e561c407 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/FDroidProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/FDroidProvider.java @@ -5,16 +5,13 @@ import android.content.ContentProvider; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentValues; -import android.content.Context; import android.content.OperationApplicationException; import android.content.UriMatcher; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.os.Build; import android.support.annotation.NonNull; - import org.fdroid.fdroid.BuildConfig; -import org.fdroid.fdroid.Utils; import java.util.ArrayList; import java.util.HashSet; @@ -23,15 +20,13 @@ import java.util.Set; public abstract class FDroidProvider extends ContentProvider { - private static final String TAG = "FDroidProvider"; + public static final String TAG = "FDroidProvider"; static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".data"; - static final int CODE_LIST = 1; + static final int CODE_LIST = 1; static final int CODE_SINGLE = 2; - private static DBHelper dbHelper; - private boolean isApplyingBatch; protected abstract String getTableName(); @@ -73,28 +68,13 @@ public abstract class FDroidProvider extends ContentProvider { return result; } - /** - * Only used for testing. Not quite sure how to mock a singleton variable like this. - */ - public static void clearDbHelperSingleton() { - dbHelper = null; - } - - private static synchronized DBHelper getOrCreateDb(Context context) { - if (dbHelper == null) { - Utils.debugLog(TAG, "First time accessing database, creating new helper"); - dbHelper = new DBHelper(context); - } - return dbHelper; - } - @Override public boolean onCreate() { return true; } protected final synchronized SQLiteDatabase db() { - return getOrCreateDb(getContext().getApplicationContext()).getWritableDatabase(); + return DBHelper.getInstance(getContext()).getWritableDatabase(); } @Override @@ -154,7 +134,7 @@ public abstract class FDroidProvider extends ContentProvider { if (!isValid) { throw new IllegalArgumentException( - "Cannot save field '" + key + "' to provider " + getProviderName()); + "Cannot save field '" + key + "' to provider " + getProviderName()); } } } diff --git a/app/src/test/java/org/fdroid/fdroid/AntiFeaturesTest.java b/app/src/test/java/org/fdroid/fdroid/AntiFeaturesTest.java index 2adb32ef7..16b2f712e 100644 --- a/app/src/test/java/org/fdroid/fdroid/AntiFeaturesTest.java +++ b/app/src/test/java/org/fdroid/fdroid/AntiFeaturesTest.java @@ -2,7 +2,6 @@ package org.fdroid.fdroid; import android.app.Application; import android.content.ContentValues; - import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.App; @@ -12,7 +11,6 @@ import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.FDroidProviderTest; import org.fdroid.fdroid.data.InstalledAppTestUtils; import org.fdroid.fdroid.data.Schema; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -21,9 +19,9 @@ import org.robolectric.annotation.Config; import java.util.List; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; @Config(constants = BuildConfig.class, application = Application.class, sdk = 24) @RunWith(RobolectricTestRunner.class) @@ -35,7 +33,7 @@ public class AntiFeaturesTest extends FDroidProviderTest { @Before public void setup() { - Preferences.setup(context); + Preferences.setupForTests(context); ContentValues vulnValues = new ContentValues(1); vulnValues.put(Schema.ApkTable.Cols.AntiFeatures.ANTI_FEATURES, "KnownVuln,ContainsGreenButtons"); @@ -58,11 +56,6 @@ public class AntiFeaturesTest extends FDroidProviderTest { AppProvider.Helper.recalculatePreferredMetadata(context); } - @After - public void tearDown() { - Preferences.clearSingletonForTesting(); - } - private static String generateHash(String packageName, int versionCode) { return packageName + "-" + versionCode; } diff --git a/app/src/test/java/org/fdroid/fdroid/data/AppPrefsProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/AppPrefsProviderTest.java index 857424d3a..d0044c8ae 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/AppPrefsProviderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/AppPrefsProviderTest.java @@ -1,7 +1,6 @@ package org.fdroid.fdroid.data; import android.app.Application; - import org.fdroid.fdroid.Assert; import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.TestUtils; @@ -11,10 +10,10 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; @Config(constants = BuildConfig.class, application = Application.class, sdk = 24) @RunWith(RobolectricTestRunner.class) diff --git a/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java index fa230fdb9..6cc8803c7 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java @@ -10,7 +10,6 @@ import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,12 +39,7 @@ public class AppProviderTest extends FDroidProviderTest { @Before public void setup() { TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); - Preferences.setup(context); - } - - @After - public void tearDown() { - Preferences.clearSingletonForTesting(); + Preferences.setupForTests(context); } /** diff --git a/app/src/test/java/org/fdroid/fdroid/data/FDroidProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/FDroidProviderTest.java index d03b610a5..416f564c5 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/FDroidProviderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/FDroidProviderTest.java @@ -1,7 +1,6 @@ package org.fdroid.fdroid.data; import android.content.ContextWrapper; - import org.fdroid.fdroid.TestUtils; import org.junit.After; import org.junit.Before; @@ -24,7 +23,7 @@ public abstract class FDroidProviderTest { @After public final void tearDownBase() { CategoryProvider.Helper.clearCategoryIdCache(); - FDroidProvider.clearDbHelperSingleton(); + DBHelper.clearDbHelperSingleton(); } } diff --git a/app/src/test/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java index 405967a8a..5bbedaa8d 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java @@ -8,7 +8,6 @@ import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,12 +30,7 @@ public class InstalledAppProviderTest extends FDroidProviderTest { @Before public void setup() { TestUtils.registerContentProvider(InstalledAppProvider.getAuthority(), InstalledAppProvider.class); - Preferences.setup(context); - } - - @After - public void tearDown() { - Preferences.clearSingletonForTesting(); + Preferences.setupForTests(context); } @Test diff --git a/app/src/test/java/org/fdroid/fdroid/data/PreferredSignatureTest.java b/app/src/test/java/org/fdroid/fdroid/data/PreferredSignatureTest.java index d86510ef1..2d2ddf8ef 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/PreferredSignatureTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/PreferredSignatureTest.java @@ -2,11 +2,9 @@ package org.fdroid.fdroid.data; import android.app.Application; import android.content.Context; - import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.TestUtils; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -24,7 +22,7 @@ public class PreferredSignatureTest extends FDroidProviderTest { @Before public void setup() { TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); - Preferences.setup(context); + Preferences.setupForTests(context); // This is what the FDroidApp does when this preference is changed. Need to also do this under testing. Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() { @@ -35,11 +33,6 @@ public class PreferredSignatureTest extends FDroidProviderTest { }); } - @After - public void tearDown() { - Preferences.clearSingletonForTesting(); - } - private Repo createFDroidRepo() { return RepoProviderTest.insertRepo(context, "https://f-droid.org/fdroid/repo", "", "", ""); } diff --git a/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java b/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java index 44e29ff30..5f738bcc0 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java +++ b/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java @@ -39,7 +39,7 @@ public class ProviderUriTests { @After public void teardown() { - FDroidProvider.clearDbHelperSingleton(); + DBHelper.clearDbHelperSingleton(); } @Test diff --git a/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java index cbcd865d9..c7e75d6f9 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java @@ -26,7 +26,6 @@ import android.content.ContentValues; import android.content.Context; import android.net.Uri; import android.support.annotation.Nullable; - import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; diff --git a/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java b/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java index 4157de23b..269684c4d 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java @@ -5,7 +5,6 @@ import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -24,7 +23,7 @@ public class SuggestedVersionTest extends FDroidProviderTest { @Before public void setup() { TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); - Preferences.setup(context); + Preferences.setupForTests(context); // This is what the FDroidApp does when this preference is changed. Need to also do this under testing. Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() { @@ -35,11 +34,6 @@ public class SuggestedVersionTest extends FDroidProviderTest { }); } - @After - public void tearDown() { - Preferences.clearSingletonForTesting(); - } - @Test public void singleRepoSingleSig() { App singleApp = TestUtils.insertApp( diff --git a/app/src/test/java/org/fdroid/fdroid/updater/AcceptableMultiRepoUpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/AcceptableMultiRepoUpdaterTest.java index 0f7517c46..fe90ccc26 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/AcceptableMultiRepoUpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/AcceptableMultiRepoUpdaterTest.java @@ -4,7 +4,6 @@ package org.fdroid.fdroid.updater; import android.content.ContentValues; import android.support.annotation.NonNull; import android.util.Log; - import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.RepoUpdater.UpdateException; import org.fdroid.fdroid.data.Repo; diff --git a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java index 2da5c4260..58f1d7111 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java @@ -26,7 +26,6 @@ import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.RepoPushRequest; import org.fdroid.fdroid.mock.RepoDetails; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -66,12 +65,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { @Before public void setup() { - Preferences.setup(context); - } - - @After - public void tearDown() { - Preferences.clearSingletonForTesting(); + Preferences.setupForTests(context); } @Test diff --git a/app/src/test/java/org/fdroid/fdroid/updater/Issue763MultiRepo.java b/app/src/test/java/org/fdroid/fdroid/updater/Issue763MultiRepo.java index 4db34ac39..6f5608f4b 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/Issue763MultiRepo.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/Issue763MultiRepo.java @@ -1,7 +1,6 @@ package org.fdroid.fdroid.updater; import android.content.ContentValues; - import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.RepoUpdater; import org.fdroid.fdroid.data.Apk; diff --git a/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java index be5d81fe9..f7782553d 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java @@ -17,7 +17,6 @@ import org.fdroid.fdroid.data.FDroidProviderTest; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.Schema; -import org.junit.After; import org.junit.Before; import java.io.File; @@ -86,12 +85,7 @@ public abstract class MultiRepoUpdaterTest extends FDroidProviderTest { RepoProvider.Helper.remove(context, 3); RepoProvider.Helper.remove(context, 4); - Preferences.setup(context); - } - - @After - public final void tearDownMultiRepo() { - Preferences.clearSingletonForTesting(); + Preferences.setupForTests(context); } protected void assertApp(String packageName, int[] versionCodes) { diff --git a/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java index 2936110fa..aad16e4f8 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java @@ -4,7 +4,6 @@ package org.fdroid.fdroid.updater; import android.content.ContentValues; import android.support.annotation.StringDef; import android.util.Log; - import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.RepoUpdater; import org.fdroid.fdroid.TestUtils; diff --git a/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java b/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java index 73bbe5bf2..3532f1192 100644 --- a/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java @@ -14,7 +14,7 @@ import org.fdroid.fdroid.R; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProviderTest; -import org.fdroid.fdroid.data.FDroidProvider; +import org.fdroid.fdroid.data.DBHelper; import org.fdroid.fdroid.data.FDroidProviderTest; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProviderTest; @@ -36,7 +36,7 @@ public class AppDetailsAdapterTest extends FDroidProviderTest { @Before public void setup() { ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context)); - Preferences.setup(context); + Preferences.setupForTests(context); Repo repo = RepoProviderTest.insertRepo(context, "http://www.example.com/fdroid/repo", "", "", "Test Repo"); app = AppProviderTest.insertApp(contentResolver, context, "com.example.app", "Test App", @@ -46,8 +46,7 @@ public class AppDetailsAdapterTest extends FDroidProviderTest { @After public void teardown() { ImageLoader.getInstance().destroy(); - FDroidProvider.clearDbHelperSingleton(); - Preferences.clearSingletonForTesting(); + DBHelper.clearDbHelperSingleton(); } @Test From 6d011c3895185d356f8e6e7732762681c6e4a868 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 31 Jan 2018 16:18:13 +0100 Subject: [PATCH 3/7] use triedEmptyUpdate methods in Preferences throughout the codebase We have these methods, they should be used! --- .../java/org/fdroid/fdroid/data/DBHelper.java | 19 ++++++------------- .../fdroid/fdroid/data/DatabaseMigration.java | 2 ++ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java index 6a07920b4..966e00846 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java @@ -28,20 +28,19 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; - +import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Schema.AntiFeatureTable; import org.fdroid.fdroid.data.Schema.ApkAntiFeatureJoinTable; import org.fdroid.fdroid.data.Schema.ApkTable; -import org.fdroid.fdroid.data.Schema.CatJoinTable; -import org.fdroid.fdroid.data.Schema.PackageTable; -import org.fdroid.fdroid.data.Schema.AppPrefsTable; import org.fdroid.fdroid.data.Schema.AppMetadataTable; +import org.fdroid.fdroid.data.Schema.AppPrefsTable; +import org.fdroid.fdroid.data.Schema.CatJoinTable; import org.fdroid.fdroid.data.Schema.InstalledAppTable; +import org.fdroid.fdroid.data.Schema.PackageTable; import org.fdroid.fdroid.data.Schema.RepoTable; import java.util.ArrayList; @@ -1095,10 +1094,7 @@ public class DBHelper extends SQLiteOpenHelper { private void resetTransient(SQLiteDatabase db) { Utils.debugLog(TAG, "Removing app + apk tables so they can be recreated. Next time F-Droid updates it should trigger an index update."); - PreferenceManager.getDefaultSharedPreferences(context) - .edit() - .putBoolean("triedEmptyUpdate", false) - .apply(); + Preferences.get().setTriedEmptyUpdate(false); db.beginTransaction(); try { @@ -1150,10 +1146,7 @@ public class DBHelper extends SQLiteOpenHelper { return; } - PreferenceManager.getDefaultSharedPreferences(context) - .edit() - .putBoolean("triedEmptyUpdate", false) - .apply(); + Preferences.get().setTriedEmptyUpdate(false); db.execSQL("drop table " + AppMetadataTable.NAME); db.execSQL("drop table " + ApkTable.NAME); diff --git a/app/src/test/java/org/fdroid/fdroid/data/DatabaseMigration.java b/app/src/test/java/org/fdroid/fdroid/data/DatabaseMigration.java index 5a2707c06..fa6ff4d0d 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/DatabaseMigration.java +++ b/app/src/test/java/org/fdroid/fdroid/data/DatabaseMigration.java @@ -7,6 +7,7 @@ import android.content.ContextWrapper; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import org.fdroid.fdroid.BuildConfig; +import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.Utils; import org.junit.Before; @@ -34,6 +35,7 @@ public class DatabaseMigration { @Test public void migrationsFromDbVersion42Onward() { + Preferences.setupForTests(context); SQLiteOpenHelper opener = new MigrationRunningOpenHelper(context); opener.getReadableDatabase(); } From 8a8ca2e6f7e9e7a21166a57c932938c55ab024e4 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 29 Jan 2018 22:46:59 +0100 Subject: [PATCH 4/7] WifiStateChangeService: use Intent static start method pattern This is the standard pattern for starting IntentServices. It also makes it really easy to trace what is starting this Service. --- app/src/main/java/org/fdroid/fdroid/FDroidApp.java | 4 ++-- .../org/fdroid/fdroid/localrepo/type/WifiSwap.java | 13 +++++-------- .../fdroid/fdroid/net/WifiStateChangeService.java | 13 +++++++++++-- .../fdroid/receiver/WifiStateChangeReceiver.java | 5 +---- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index a1fade17c..af4fbc32f 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -386,12 +386,12 @@ public class FDroidApp extends Application { ImageLoader.getInstance().init(config); FDroidApp.initWifiSettings(); - startService(new Intent(this, WifiStateChangeService.class)); + WifiStateChangeService.start(this, null); // if the HTTPS pref changes, then update all affected things Preferences.get().registerLocalRepoHttpsListeners(new ChangeListener() { @Override public void onPreferenceChange() { - startService(new Intent(FDroidApp.this, WifiStateChangeService.class)); + WifiStateChangeService.start(getApplicationContext(), null); } }); diff --git a/app/src/main/java/org/fdroid/fdroid/localrepo/type/WifiSwap.java b/app/src/main/java/org/fdroid/fdroid/localrepo/type/WifiSwap.java index 60cbece5f..152877aec 100644 --- a/app/src/main/java/org/fdroid/fdroid/localrepo/type/WifiSwap.java +++ b/app/src/main/java/org/fdroid/fdroid/localrepo/type/WifiSwap.java @@ -2,23 +2,16 @@ package org.fdroid.fdroid.localrepo.type; import android.annotation.SuppressLint; import android.content.Context; -import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; - import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.localrepo.SwapService; import org.fdroid.fdroid.net.LocalHTTPD; import org.fdroid.fdroid.net.WifiStateChangeService; - -import java.io.IOException; -import java.net.BindException; -import java.util.Random; - import rx.Single; import rx.SingleSubscriber; import rx.android.schedulers.AndroidSchedulers; @@ -26,6 +19,10 @@ import rx.functions.Action1; import rx.functions.Func2; import rx.schedulers.Schedulers; +import java.io.IOException; +import java.net.BindException; +import java.util.Random; + @SuppressWarnings("LineLength") public class WifiSwap extends SwapType { @@ -143,7 +140,7 @@ public class WifiSwap extends SwapType { } catch (BindException e) { int prev = FDroidApp.port; FDroidApp.port = FDroidApp.port + new Random().nextInt(1111); - context.startService(new Intent(context, WifiStateChangeService.class)); + WifiStateChangeService.start(context, null); singleSubscriber.onError(new Exception("port " + prev + " occupied, trying on " + FDroidApp.port + "!")); } catch (IOException e) { Log.e(TAG, "Could not start local repo HTTP server", e); diff --git a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java index 1b41743ff..b098220a7 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java @@ -1,16 +1,17 @@ package org.fdroid.fdroid.net; import android.app.IntentService; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.net.DhcpInfo; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; - import org.apache.commons.net.util.SubnetUtils; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; @@ -34,7 +35,7 @@ import java.util.Locale; * which is how it can be triggered by code, or it came in from the system * via {@link org.fdroid.fdroid.receiver.WifiStateChangeReceiver}, in * which case an instance of {@link NetworkInfo} is included. - * + *

* The work is done in a {@link Thread} so that new incoming {@code Intents} * are not blocked by processing. A new {@code Intent} immediately nullifies * the current state because it means that something about the wifi has @@ -54,6 +55,14 @@ public class WifiStateChangeService extends IntentService { super("WifiStateChangeService"); } + public static void start(Context context, @Nullable Intent intent) { + if (intent == null) { + intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); + } + intent.setComponent(new ComponentName(context, WifiStateChangeService.class)); + context.startService(intent); + } + @Override protected void onHandleIntent(Intent intent) { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LOWEST); diff --git a/app/src/main/java/org/fdroid/fdroid/receiver/WifiStateChangeReceiver.java b/app/src/main/java/org/fdroid/fdroid/receiver/WifiStateChangeReceiver.java index 8521d1cad..2a8e11607 100644 --- a/app/src/main/java/org/fdroid/fdroid/receiver/WifiStateChangeReceiver.java +++ b/app/src/main/java/org/fdroid/fdroid/receiver/WifiStateChangeReceiver.java @@ -1,11 +1,9 @@ package org.fdroid.fdroid.receiver; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.net.wifi.WifiManager; - import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.net.WifiStateChangeService; @@ -15,8 +13,7 @@ public class WifiStateChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) { - intent.setComponent(new ComponentName(context, WifiStateChangeService.class)); - context.startService(intent); + WifiStateChangeService.start(context, intent); } else { Utils.debugLog(TAG, "received unsupported Intent: " + intent); } From 644849175102c8dcb0b24889718bb2527d0c66b8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 29 Jan 2018 22:47:20 +0100 Subject: [PATCH 5/7] WifiStateChangeService: exit after trying for 2 minutes It was tried until it got an IP address, but that will only happen if there is a wifi device configured. Since WifiStateChangeService is started when F-Droid starts, WifiStateChangeService could run for days if someone never connected to WiFi in that time. WifiStateChangeService is also started by NETWORK_STATE_CHANGED_ACTION so it should start each time there is a change to the WiFi connection. --- .../org/fdroid/fdroid/net/WifiStateChangeService.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java index b098220a7..fcd62ad6c 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java @@ -101,7 +101,7 @@ public class WifiStateChangeService extends IntentService { WifiInfo wifiInfo = null; int wifiState = wifiManager.getWifiState(); - + int retryCount = 0; while (FDroidApp.ipAddressString == null) { if (isInterrupted()) { // can be canceled by a change via WifiStateChangeReceiver return; @@ -116,7 +116,7 @@ public class WifiStateChangeService extends IntentService { try { FDroidApp.subnetInfo = new SubnetUtils(FDroidApp.ipAddressString, netmask).getInfo(); } catch (IllegalArgumentException e) { - // catch this mystery error: "java.lang.IllegalArgumentException: Could not parse [null/24]" + // catch mystery: "java.lang.IllegalArgumentException: Could not parse [null/24]" e.printStackTrace(); } } @@ -132,6 +132,11 @@ public class WifiStateChangeService extends IntentService { setIpInfoFromNetworkInterface(); } + if (retryCount > 120) { + return; + } + retryCount++; + if (FDroidApp.ipAddressString == null) { Thread.sleep(1000); Utils.debugLog(TAG, "waiting for an IP address..."); From 887c55247ad9d00869a012cc6935953fefd59aee Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 26 Jan 2018 11:46:04 +0100 Subject: [PATCH 6/7] force full index update when system locale changes The database currently only stores the active language. So if the user changes the system language of the phone, then the language of all the app descriptions will be out of sync until the next update. This forces an update when the locale is changed. This functionality is also needed for events like OS upgrades. closes #225 --- .../java/org/fdroid/fdroid/FDroidApp.java | 1 + .../java/org/fdroid/fdroid/UpdateService.java | 39 +++++++++++++------ .../java/org/fdroid/fdroid/data/DBHelper.java | 13 ++++++- .../fdroid/fdroid/localrepo/SwapService.java | 2 +- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index af4fbc32f..03518b11d 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -267,6 +267,7 @@ public class FDroidApp extends Application { public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Languages.setLanguage(this); + UpdateService.forceUpdateRepo(this); } @Override diff --git a/app/src/main/java/org/fdroid/fdroid/UpdateService.java b/app/src/main/java/org/fdroid/fdroid/UpdateService.java index e6a02303f..1b9a5a62b 100644 --- a/app/src/main/java/org/fdroid/fdroid/UpdateService.java +++ b/app/src/main/java/org/fdroid/fdroid/UpdateService.java @@ -40,11 +40,11 @@ import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; - import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; +import org.fdroid.fdroid.data.DBHelper; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.Schema; @@ -66,6 +66,7 @@ public class UpdateService extends IntentService { public static final String EXTRA_STATUS_CODE = "status"; public static final String EXTRA_ADDRESS = "address"; public static final String EXTRA_MANUAL_UPDATE = "manualUpdate"; + public static final String EXTRA_FORCED_UPDATE = "forcedUpdate"; public static final String EXTRA_PROGRESS = "progress"; public static final int STATUS_COMPLETE_WITH_CHANGES = 0; @@ -96,10 +97,10 @@ public class UpdateService extends IntentService { } public static void updateNow(Context context) { - updateRepoNow(null, context); + updateRepoNow(context, null); } - public static void updateRepoNow(String address, Context context) { + public static void updateRepoNow(Context context, String address) { Intent intent = new Intent(context, UpdateService.class); intent.putExtra(EXTRA_MANUAL_UPDATE, true); if (!TextUtils.isEmpty(address)) { @@ -108,6 +109,17 @@ public class UpdateService extends IntentService { context.startService(intent); } + /** + * For when an automatic process needs to force an index update, like + * when the system language changes, or the underlying OS was upgraded. + * This wipes the existing database before running the update! + */ + public static void forceUpdateRepo(Context context) { + Intent intent = new Intent(context, UpdateService.class); + intent.putExtra(EXTRA_FORCED_UPDATE, true); + context.startService(intent); + } + /** * 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 @@ -225,7 +237,7 @@ public class UpdateService extends IntentService { switch (resultCode) { case STATUS_INFO: notificationBuilder.setContentText(message) - .setCategory(NotificationCompat.CATEGORY_SERVICE); + .setCategory(NotificationCompat.CATEGORY_SERVICE); if (progress != -1) { notificationBuilder.setProgress(100, progress, false); } else { @@ -236,8 +248,8 @@ public class UpdateService extends IntentService { case STATUS_ERROR_GLOBAL: text = context.getString(R.string.global_error_updating_repos, message); notificationBuilder.setContentText(text) - .setCategory(NotificationCompat.CATEGORY_ERROR) - .setSmallIcon(android.R.drawable.ic_dialog_alert); + .setCategory(NotificationCompat.CATEGORY_ERROR) + .setSmallIcon(android.R.drawable.ic_dialog_alert); notificationManager.notify(NOTIFY_ID_UPDATING, notificationBuilder.build()); Toast.makeText(context, text, Toast.LENGTH_LONG).show(); break; @@ -254,8 +266,8 @@ public class UpdateService extends IntentService { } text = msgBuilder.toString(); notificationBuilder.setContentText(text) - .setCategory(NotificationCompat.CATEGORY_ERROR) - .setSmallIcon(android.R.drawable.ic_dialog_info); + .setCategory(NotificationCompat.CATEGORY_ERROR) + .setSmallIcon(android.R.drawable.ic_dialog_info); notificationManager.notify(NOTIFY_ID_UPDATING, notificationBuilder.build()); Toast.makeText(context, text, Toast.LENGTH_LONG).show(); break; @@ -264,7 +276,7 @@ public class UpdateService extends IntentService { case STATUS_COMPLETE_AND_SAME: text = context.getString(R.string.repos_unchanged); notificationBuilder.setContentText(text) - .setCategory(NotificationCompat.CATEGORY_SERVICE); + .setCategory(NotificationCompat.CATEGORY_SERVICE); notificationManager.notify(NOTIFY_ID_UPDATING, notificationBuilder.build()); break; } @@ -349,10 +361,12 @@ public class UpdateService extends IntentService { final long startTime = System.currentTimeMillis(); boolean manualUpdate = false; + boolean forcedUpdate = false; String address = null; if (intent != null) { address = intent.getStringExtra(EXTRA_ADDRESS); manualUpdate = intent.getBooleanExtra(EXTRA_MANUAL_UPDATE, false); + forcedUpdate = intent.getBooleanExtra(EXTRA_FORCED_UPDATE, false); } try { @@ -366,8 +380,8 @@ public class UpdateService extends IntentService { return; } - if (manualUpdate) { - Utils.debugLog(TAG, "manually requested update"); + if (manualUpdate || forcedUpdate) { + Utils.debugLog(TAG, "manually requested or forced update"); } else if (!verifyIsTimeForScheduledRun() || (netState == FLAG_NET_METERED && Preferences.get().isUpdateOnlyOnUnmeteredNetworks())) { Utils.debugLog(TAG, "don't run update"); @@ -404,6 +418,9 @@ public class UpdateService extends IntentService { sendStatus(this, STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); + if (forcedUpdate) { + DBHelper.resetTransient(this); + } try { RepoUpdater updater = new IndexV1Updater(this, repo); diff --git a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java index 966e00846..d4c671167 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java @@ -1091,8 +1091,17 @@ public class DBHelper extends SQLiteOpenHelper { db.execSQL("update " + RepoTable.NAME + " set " + RepoTable.Cols.LAST_ETAG + " = NULL"); } - private void resetTransient(SQLiteDatabase db) { - Utils.debugLog(TAG, "Removing app + apk tables so they can be recreated. Next time F-Droid updates it should trigger an index update."); + /** + * Resets all database tables that are generated from the index files downloaded + * from the active repositories. This will trigger the index file(s) to be + * downloaded processed on the next update. + */ + public static void resetTransient(Context context) { + resetTransient(getInstance(context).getWritableDatabase()); + } + + private static void resetTransient(SQLiteDatabase db) { + Utils.debugLog(TAG, "Removing all index tables, they will be recreated next time F-Droid updates."); Preferences.get().setTriedEmptyUpdate(false); diff --git a/app/src/main/java/org/fdroid/fdroid/localrepo/SwapService.java b/app/src/main/java/org/fdroid/fdroid/localrepo/SwapService.java index 5fb70b1bf..b3099cfb5 100644 --- a/app/src/main/java/org/fdroid/fdroid/localrepo/SwapService.java +++ b/app/src/main/java/org/fdroid/fdroid/localrepo/SwapService.java @@ -205,7 +205,7 @@ public class SwapService extends Service { askServerToSwapWithUs(peerRepo); } - UpdateService.updateRepoNow(peer.getRepoAddress(), this); + UpdateService.updateRepoNow(this, peer.getRepoAddress()); } private void askServerToSwapWithUs(final Repo repo) { From 29658259fae87cbc69b247c936c2e67df9e25926 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 29 Jan 2018 22:59:13 +0100 Subject: [PATCH 7/7] force clean index update when underlying OS is upgraded Things like permission support, locales, etc. can change when Android is updated. So the database should be rebuilt from scratch with a fresh download of the indexes. closes #780 --- app/src/main/java/org/fdroid/fdroid/FDroidApp.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index 03518b11d..18fc3d916 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -27,6 +27,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -415,6 +416,13 @@ public class FDroidApp extends Application { // find and process provisions if any. Provisioner.scanAndProcess(getApplicationContext()); + + // if the underlying OS version has changed, then fully rebuild the database + SharedPreferences atStartTime = getSharedPreferences("at-start-time", Context.MODE_PRIVATE); + if (Build.VERSION.SDK_INT != atStartTime.getInt("build-version", Build.VERSION.SDK_INT)) { + UpdateService.forceUpdateRepo(this); + } + atStartTime.edit().putInt("build-version", Build.VERSION.SDK_INT).apply(); } /**