Merge branch 'force-updates' into 'master'

force updates after OS update and system locale changes

Closes #780 and #225

See merge request fdroid/fdroidclient!636
This commit is contained in:
Hans-Christoph Steiner 2018-02-05 23:13:53 +00:00
commit 606ef45bcd
28 changed files with 136 additions and 156 deletions

View File

@ -27,6 +27,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
@ -267,6 +268,7 @@ public class FDroidApp extends Application {
public void onConfigurationChanged(Configuration newConfig) { public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig);
Languages.setLanguage(this); Languages.setLanguage(this);
UpdateService.forceUpdateRepo(this);
} }
@Override @Override
@ -386,12 +388,12 @@ public class FDroidApp extends Application {
ImageLoader.getInstance().init(config); ImageLoader.getInstance().init(config);
FDroidApp.initWifiSettings(); FDroidApp.initWifiSettings();
startService(new Intent(this, WifiStateChangeService.class)); WifiStateChangeService.start(this, null);
// if the HTTPS pref changes, then update all affected things // if the HTTPS pref changes, then update all affected things
Preferences.get().registerLocalRepoHttpsListeners(new ChangeListener() { Preferences.get().registerLocalRepoHttpsListeners(new ChangeListener() {
@Override @Override
public void onPreferenceChange() { public void onPreferenceChange() {
startService(new Intent(FDroidApp.this, WifiStateChangeService.class)); WifiStateChangeService.start(getApplicationContext(), null);
} }
}); });
@ -414,6 +416,13 @@ public class FDroidApp extends Application {
// find and process provisions if any. // find and process provisions if any.
Provisioner.scanAndProcess(getApplicationContext()); 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();
} }
/** /**

View File

@ -2,7 +2,6 @@ package org.fdroid.fdroid;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Build; import android.os.Build;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
@ -39,10 +38,6 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
.putString(PREF_LOCAL_REPO_NAME, getDefaultLocalRepoName()) .putString(PREF_LOCAL_REPO_NAME, getDefaultLocalRepoName())
.apply(); .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"; 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_SHOW_NFC_DURING_SWAP = true;
private static final boolean DEFAULT_FORCE_OLD_INDEX = false; private static final boolean DEFAULT_FORCE_OLD_INDEX = false;
private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false; private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false;
private final boolean defaultPreventScreenshots; private static final boolean DEFAULT_PREVENT_SCREENSHOTS = false;
private final boolean defaultPanicExit; private static final boolean DEFAULT_PANIC_EXIT = true;
private final boolean defaultHideOnLongPressSearch; private static final boolean DEFAULT_HIDE_ON_LONG_PRESS_SEARCH = false;
public enum Theme { public enum Theme {
light, light,
@ -327,11 +322,11 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
} }
public boolean preventScreenshots() { public boolean preventScreenshots() {
return preferences.getBoolean(PREF_PREVENT_SCREENSHOTS, defaultPreventScreenshots); return preferences.getBoolean(PREF_PREVENT_SCREENSHOTS, DEFAULT_PREVENT_SCREENSHOTS);
} }
public boolean panicExit() { public boolean panicExit() {
return preferences.getBoolean(PREF_PANIC_EXIT, defaultPanicExit); return preferences.getBoolean(PREF_PANIC_EXIT, DEFAULT_PANIC_EXIT);
} }
public boolean panicHide() { public boolean panicHide() {
@ -339,7 +334,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
} }
public boolean hideOnLongPressSearch() { 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);
} }
/** /**
@ -458,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}, * 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. * 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; instance = null;
setup(context);
} }
/** /**

View File

@ -40,11 +40,11 @@ import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.DBHelper;
import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.Schema; 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_STATUS_CODE = "status";
public static final String EXTRA_ADDRESS = "address"; public static final String EXTRA_ADDRESS = "address";
public static final String EXTRA_MANUAL_UPDATE = "manualUpdate"; 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 String EXTRA_PROGRESS = "progress";
public static final int STATUS_COMPLETE_WITH_CHANGES = 0; public static final int STATUS_COMPLETE_WITH_CHANGES = 0;
@ -96,10 +97,10 @@ public class UpdateService extends IntentService {
} }
public static void updateNow(Context context) { 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 intent = new Intent(context, UpdateService.class);
intent.putExtra(EXTRA_MANUAL_UPDATE, true); intent.putExtra(EXTRA_MANUAL_UPDATE, true);
if (!TextUtils.isEmpty(address)) { if (!TextUtils.isEmpty(address)) {
@ -108,6 +109,17 @@ public class UpdateService extends IntentService {
context.startService(intent); 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 * 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 * current preferences. Should be called a) at boot, b) if the preference
@ -349,10 +361,12 @@ public class UpdateService extends IntentService {
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
boolean manualUpdate = false; boolean manualUpdate = false;
boolean forcedUpdate = false;
String address = null; String address = null;
if (intent != null) { if (intent != null) {
address = intent.getStringExtra(EXTRA_ADDRESS); address = intent.getStringExtra(EXTRA_ADDRESS);
manualUpdate = intent.getBooleanExtra(EXTRA_MANUAL_UPDATE, false); manualUpdate = intent.getBooleanExtra(EXTRA_MANUAL_UPDATE, false);
forcedUpdate = intent.getBooleanExtra(EXTRA_FORCED_UPDATE, false);
} }
try { try {
@ -366,8 +380,8 @@ public class UpdateService extends IntentService {
return; return;
} }
if (manualUpdate) { if (manualUpdate || forcedUpdate) {
Utils.debugLog(TAG, "manually requested update"); Utils.debugLog(TAG, "manually requested or forced update");
} else if (!verifyIsTimeForScheduledRun() } else if (!verifyIsTimeForScheduledRun()
|| (netState == FLAG_NET_METERED && Preferences.get().isUpdateOnlyOnUnmeteredNetworks())) { || (netState == FLAG_NET_METERED && Preferences.get().isUpdateOnlyOnUnmeteredNetworks())) {
Utils.debugLog(TAG, "don't run update"); 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)); sendStatus(this, STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address));
if (forcedUpdate) {
DBHelper.resetTransient(this);
}
try { try {
RepoUpdater updater = new IndexV1Updater(this, repo); RepoUpdater updater = new IndexV1Updater(this, repo);

View File

@ -28,32 +28,38 @@ import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.preference.PreferenceManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Schema.AntiFeatureTable; import org.fdroid.fdroid.data.Schema.AntiFeatureTable;
import org.fdroid.fdroid.data.Schema.ApkAntiFeatureJoinTable; import org.fdroid.fdroid.data.Schema.ApkAntiFeatureJoinTable;
import org.fdroid.fdroid.data.Schema.ApkTable; 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.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.InstalledAppTable;
import org.fdroid.fdroid.data.Schema.PackageTable;
import org.fdroid.fdroid.data.Schema.RepoTable; import org.fdroid.fdroid.data.Schema.RepoTable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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") @SuppressWarnings("LineLength")
class DBHelper extends SQLiteOpenHelper { public class DBHelper extends SQLiteOpenHelper {
private static final String TAG = "DBHelper"; private static final String TAG = "DBHelper";
public static final int REPO_XML_ARG_COUNT = 8; public static final int REPO_XML_ARG_COUNT = 8;
private static DBHelper instance;
private static final String DATABASE_NAME = "fdroid"; private static final String DATABASE_NAME = "fdroid";
private static final String CREATE_TABLE_PACKAGE = "CREATE TABLE " + PackageTable.NAME private static final String CREATE_TABLE_PACKAGE = "CREATE TABLE " + PackageTable.NAME
@ -214,7 +220,22 @@ class DBHelper extends SQLiteOpenHelper {
DBHelper(Context context) { DBHelper(Context context) {
super(context, DATABASE_NAME, null, DB_VERSION); 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 @Override
@ -1070,13 +1091,19 @@ class DBHelper extends SQLiteOpenHelper {
db.execSQL("update " + RepoTable.NAME + " set " + RepoTable.Cols.LAST_ETAG + " = NULL"); 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());
}
PreferenceManager.getDefaultSharedPreferences(context) private static void resetTransient(SQLiteDatabase db) {
.edit() Utils.debugLog(TAG, "Removing all index tables, they will be recreated next time F-Droid updates.");
.putBoolean("triedEmptyUpdate", false)
.apply(); Preferences.get().setTriedEmptyUpdate(false);
db.beginTransaction(); db.beginTransaction();
try { try {
@ -1128,10 +1155,7 @@ class DBHelper extends SQLiteOpenHelper {
return; return;
} }
PreferenceManager.getDefaultSharedPreferences(context) Preferences.get().setTriedEmptyUpdate(false);
.edit()
.putBoolean("triedEmptyUpdate", false)
.apply();
db.execSQL("drop table " + AppMetadataTable.NAME); db.execSQL("drop table " + AppMetadataTable.NAME);
db.execSQL("drop table " + ApkTable.NAME); db.execSQL("drop table " + ApkTable.NAME);

View File

@ -5,16 +5,13 @@ import android.content.ContentProvider;
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;
import android.content.ContentProviderResult; import android.content.ContentProviderResult;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException; import android.content.OperationApplicationException;
import android.content.UriMatcher; import android.content.UriMatcher;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
@ -23,15 +20,13 @@ import java.util.Set;
public abstract class FDroidProvider extends ContentProvider { 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 String AUTHORITY = BuildConfig.APPLICATION_ID + ".data";
static final int CODE_LIST = 1; static final int CODE_LIST = 1;
static final int CODE_SINGLE = 2; static final int CODE_SINGLE = 2;
private static DBHelper dbHelper;
private boolean isApplyingBatch; private boolean isApplyingBatch;
protected abstract String getTableName(); protected abstract String getTableName();
@ -73,28 +68,13 @@ public abstract class FDroidProvider extends ContentProvider {
return result; 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 @Override
public boolean onCreate() { public boolean onCreate() {
return true; return true;
} }
protected final synchronized SQLiteDatabase db() { protected final synchronized SQLiteDatabase db() {
return getOrCreateDb(getContext().getApplicationContext()).getWritableDatabase(); return DBHelper.getInstance(getContext()).getWritableDatabase();
} }
@Override @Override

View File

@ -205,7 +205,7 @@ public class SwapService extends Service {
askServerToSwapWithUs(peerRepo); askServerToSwapWithUs(peerRepo);
} }
UpdateService.updateRepoNow(peer.getRepoAddress(), this); UpdateService.updateRepoNow(this, peer.getRepoAddress());
} }
private void askServerToSwapWithUs(final Repo repo) { private void askServerToSwapWithUs(final Repo repo) {

View File

@ -2,23 +2,16 @@ package org.fdroid.fdroid.localrepo.type;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService; import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.net.LocalHTTPD; import org.fdroid.fdroid.net.LocalHTTPD;
import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.net.WifiStateChangeService;
import java.io.IOException;
import java.net.BindException;
import java.util.Random;
import rx.Single; import rx.Single;
import rx.SingleSubscriber; import rx.SingleSubscriber;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
@ -26,6 +19,10 @@ import rx.functions.Action1;
import rx.functions.Func2; import rx.functions.Func2;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
import java.io.IOException;
import java.net.BindException;
import java.util.Random;
@SuppressWarnings("LineLength") @SuppressWarnings("LineLength")
public class WifiSwap extends SwapType { public class WifiSwap extends SwapType {
@ -143,7 +140,7 @@ public class WifiSwap extends SwapType {
} catch (BindException e) { } catch (BindException e) {
int prev = FDroidApp.port; int prev = FDroidApp.port;
FDroidApp.port = FDroidApp.port + new Random().nextInt(1111); 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 + "!")); singleSubscriber.onError(new Exception("port " + prev + " occupied, trying on " + FDroidApp.port + "!"));
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Could not start local repo HTTP server", e); Log.e(TAG, "Could not start local repo HTTP server", e);

View File

@ -1,16 +1,17 @@
package org.fdroid.fdroid.net; package org.fdroid.fdroid.net;
import android.app.IntentService; import android.app.IntentService;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.DhcpInfo; import android.net.DhcpInfo;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.apache.commons.net.util.SubnetUtils; import org.apache.commons.net.util.SubnetUtils;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences; 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 * which is how it can be triggered by code, or it came in from the system
* via {@link org.fdroid.fdroid.receiver.WifiStateChangeReceiver}, in * via {@link org.fdroid.fdroid.receiver.WifiStateChangeReceiver}, in
* which case an instance of {@link NetworkInfo} is included. * which case an instance of {@link NetworkInfo} is included.
* * <p>
* The work is done in a {@link Thread} so that new incoming {@code Intents} * 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 * are not blocked by processing. A new {@code Intent} immediately nullifies
* the current state because it means that something about the wifi has * the current state because it means that something about the wifi has
@ -54,6 +55,14 @@ public class WifiStateChangeService extends IntentService {
super("WifiStateChangeService"); 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 @Override
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LOWEST); android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LOWEST);
@ -92,7 +101,7 @@ public class WifiStateChangeService extends IntentService {
WifiInfo wifiInfo = null; WifiInfo wifiInfo = null;
int wifiState = wifiManager.getWifiState(); int wifiState = wifiManager.getWifiState();
int retryCount = 0;
while (FDroidApp.ipAddressString == null) { while (FDroidApp.ipAddressString == null) {
if (isInterrupted()) { // can be canceled by a change via WifiStateChangeReceiver if (isInterrupted()) { // can be canceled by a change via WifiStateChangeReceiver
return; return;
@ -107,7 +116,7 @@ public class WifiStateChangeService extends IntentService {
try { try {
FDroidApp.subnetInfo = new SubnetUtils(FDroidApp.ipAddressString, netmask).getInfo(); FDroidApp.subnetInfo = new SubnetUtils(FDroidApp.ipAddressString, netmask).getInfo();
} catch (IllegalArgumentException e) { } 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(); e.printStackTrace();
} }
} }
@ -123,6 +132,11 @@ public class WifiStateChangeService extends IntentService {
setIpInfoFromNetworkInterface(); setIpInfoFromNetworkInterface();
} }
if (retryCount > 120) {
return;
}
retryCount++;
if (FDroidApp.ipAddressString == null) { if (FDroidApp.ipAddressString == null) {
Thread.sleep(1000); Thread.sleep(1000);
Utils.debugLog(TAG, "waiting for an IP address..."); Utils.debugLog(TAG, "waiting for an IP address...");

View File

@ -1,11 +1,9 @@
package org.fdroid.fdroid.receiver; package org.fdroid.fdroid.receiver;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.net.WifiStateChangeService;
@ -15,8 +13,7 @@ public class WifiStateChangeReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) { if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
intent.setComponent(new ComponentName(context, WifiStateChangeService.class)); WifiStateChangeService.start(context, intent);
context.startService(intent);
} else { } else {
Utils.debugLog(TAG, "received unsupported Intent: " + intent); Utils.debugLog(TAG, "received unsupported Intent: " + intent);
} }

View File

@ -14,11 +14,6 @@
<attr name="antiFeaturesWarning" format="reference" /> <attr name="antiFeaturesWarning" format="reference" />
</declare-styleable> </declare-styleable>
<!-- Default Preferences -->
<bool name="defaultPreventScreenshots">false</bool>
<bool name="defaultPanicExit">true</bool>
<bool name="defaultHideOnLongPressSearch">false</bool>
<integer name="unhidePin">1337</integer> <integer name="unhidePin">1337</integer>
</resources> </resources>

View File

@ -95,13 +95,13 @@
android:title="@string/privacy"> android:title="@string/privacy">
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/defaultPreventScreenshots" android:defaultValue="false"
android:key="preventScreenshots" android:key="preventScreenshots"
android:summary="@string/preventScreenshots_summary" android:summary="@string/preventScreenshots_summary"
android:title="@string/preventScreenshots_title"/> android:title="@string/preventScreenshots_title"/>
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/defaultHideOnLongPressSearch" android:defaultValue="false"
android:key="hideOnLongPressSearch" android:key="hideOnLongPressSearch"
android:summary="@string/hide_on_long_search_press_summary" android:summary="@string/hide_on_long_search_press_summary"
android:title="@string/hide_on_long_search_press_title"/> android:title="@string/hide_on_long_search_press_title"/>

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/defaultPanicExit" android:defaultValue="true"
android:key="pref_panic_exit" android:key="pref_panic_exit"
android:summary="@string/panic_exit_summary" android:summary="@string/panic_exit_summary"
android:title="@string/panic_exit_title"/> android:title="@string/panic_exit_title"/>

View File

@ -2,7 +2,6 @@ package org.fdroid.fdroid;
import android.app.Application; import android.app.Application;
import android.content.ContentValues; import android.content.ContentValues;
import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.App; 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.FDroidProviderTest;
import org.fdroid.fdroid.data.InstalledAppTestUtils; import org.fdroid.fdroid.data.InstalledAppTestUtils;
import org.fdroid.fdroid.data.Schema; import org.fdroid.fdroid.data.Schema;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -21,9 +19,9 @@ import org.robolectric.annotation.Config;
import java.util.List; import java.util.List;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@Config(constants = BuildConfig.class, application = Application.class, sdk = 24) @Config(constants = BuildConfig.class, application = Application.class, sdk = 24)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@ -35,7 +33,7 @@ public class AntiFeaturesTest extends FDroidProviderTest {
@Before @Before
public void setup() { public void setup() {
Preferences.setup(context); Preferences.setupForTests(context);
ContentValues vulnValues = new ContentValues(1); ContentValues vulnValues = new ContentValues(1);
vulnValues.put(Schema.ApkTable.Cols.AntiFeatures.ANTI_FEATURES, "KnownVuln,ContainsGreenButtons"); vulnValues.put(Schema.ApkTable.Cols.AntiFeatures.ANTI_FEATURES, "KnownVuln,ContainsGreenButtons");
@ -58,11 +56,6 @@ public class AntiFeaturesTest extends FDroidProviderTest {
AppProvider.Helper.recalculatePreferredMetadata(context); AppProvider.Helper.recalculatePreferredMetadata(context);
} }
@After
public void tearDown() {
Preferences.clearSingletonForTesting();
}
private static String generateHash(String packageName, int versionCode) { private static String generateHash(String packageName, int versionCode) {
return packageName + "-" + versionCode; return packageName + "-" + versionCode;
} }

View File

@ -1,7 +1,6 @@
package org.fdroid.fdroid.data; package org.fdroid.fdroid.data;
import android.app.Application; import android.app.Application;
import org.fdroid.fdroid.Assert; import org.fdroid.fdroid.Assert;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
@ -11,10 +10,10 @@ import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@Config(constants = BuildConfig.class, application = Application.class, sdk = 24) @Config(constants = BuildConfig.class, application = Application.class, sdk = 24)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)

View File

@ -10,7 +10,6 @@ import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -40,12 +39,7 @@ public class AppProviderTest extends FDroidProviderTest {
@Before @Before
public void setup() { public void setup() {
TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class);
Preferences.setup(context); Preferences.setupForTests(context);
}
@After
public void tearDown() {
Preferences.clearSingletonForTesting();
} }
/** /**

View File

@ -7,6 +7,7 @@ import android.content.ContextWrapper;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.junit.Before; import org.junit.Before;
@ -34,6 +35,7 @@ public class DatabaseMigration {
@Test @Test
public void migrationsFromDbVersion42Onward() { public void migrationsFromDbVersion42Onward() {
Preferences.setupForTests(context);
SQLiteOpenHelper opener = new MigrationRunningOpenHelper(context); SQLiteOpenHelper opener = new MigrationRunningOpenHelper(context);
opener.getReadableDatabase(); opener.getReadableDatabase();
} }

View File

@ -1,7 +1,6 @@
package org.fdroid.fdroid.data; package org.fdroid.fdroid.data;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -24,7 +23,7 @@ public abstract class FDroidProviderTest {
@After @After
public final void tearDownBase() { public final void tearDownBase() {
CategoryProvider.Helper.clearCategoryIdCache(); CategoryProvider.Helper.clearCategoryIdCache();
FDroidProvider.clearDbHelperSingleton(); DBHelper.clearDbHelperSingleton();
} }
} }

View File

@ -8,7 +8,6 @@ import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols; import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -31,12 +30,7 @@ public class InstalledAppProviderTest extends FDroidProviderTest {
@Before @Before
public void setup() { public void setup() {
TestUtils.registerContentProvider(InstalledAppProvider.getAuthority(), InstalledAppProvider.class); TestUtils.registerContentProvider(InstalledAppProvider.getAuthority(), InstalledAppProvider.class);
Preferences.setup(context); Preferences.setupForTests(context);
}
@After
public void tearDown() {
Preferences.clearSingletonForTesting();
} }
@Test @Test

View File

@ -2,11 +2,9 @@ package org.fdroid.fdroid.data;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -24,7 +22,7 @@ public class PreferredSignatureTest extends FDroidProviderTest {
@Before @Before
public void setup() { public void setup() {
TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); 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. // This is what the FDroidApp does when this preference is changed. Need to also do this under testing.
Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() { Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() {
@ -35,11 +33,6 @@ public class PreferredSignatureTest extends FDroidProviderTest {
}); });
} }
@After
public void tearDown() {
Preferences.clearSingletonForTesting();
}
private Repo createFDroidRepo() { private Repo createFDroidRepo() {
return RepoProviderTest.insertRepo(context, "https://f-droid.org/fdroid/repo", "", "", ""); return RepoProviderTest.insertRepo(context, "https://f-droid.org/fdroid/repo", "", "", "");
} }

View File

@ -39,7 +39,7 @@ public class ProviderUriTests {
@After @After
public void teardown() { public void teardown() {
FDroidProvider.clearDbHelperSingleton(); DBHelper.clearDbHelperSingleton();
} }
@Test @Test

View File

@ -26,7 +26,6 @@ import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;

View File

@ -5,7 +5,6 @@ import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -24,7 +23,7 @@ public class SuggestedVersionTest extends FDroidProviderTest {
@Before @Before
public void setup() { public void setup() {
TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); 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. // This is what the FDroidApp does when this preference is changed. Need to also do this under testing.
Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() { Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() {
@ -35,11 +34,6 @@ public class SuggestedVersionTest extends FDroidProviderTest {
}); });
} }
@After
public void tearDown() {
Preferences.clearSingletonForTesting();
}
@Test @Test
public void singleRepoSingleSig() { public void singleRepoSingleSig() {
App singleApp = TestUtils.insertApp( App singleApp = TestUtils.insertApp(

View File

@ -4,7 +4,6 @@ package org.fdroid.fdroid.updater;
import android.content.ContentValues; import android.content.ContentValues;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.RepoUpdater.UpdateException; import org.fdroid.fdroid.RepoUpdater.UpdateException;
import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.Repo;

View File

@ -26,7 +26,6 @@ import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.RepoPushRequest; import org.fdroid.fdroid.data.RepoPushRequest;
import org.fdroid.fdroid.mock.RepoDetails; import org.fdroid.fdroid.mock.RepoDetails;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -66,12 +65,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest {
@Before @Before
public void setup() { public void setup() {
Preferences.setup(context); Preferences.setupForTests(context);
}
@After
public void tearDown() {
Preferences.clearSingletonForTesting();
} }
@Test @Test

View File

@ -1,7 +1,6 @@
package org.fdroid.fdroid.updater; package org.fdroid.fdroid.updater;
import android.content.ContentValues; import android.content.ContentValues;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.RepoUpdater; import org.fdroid.fdroid.RepoUpdater;
import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Apk;

View File

@ -17,7 +17,6 @@ import org.fdroid.fdroid.data.FDroidProviderTest;
import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.Schema; import org.fdroid.fdroid.data.Schema;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.io.File; import java.io.File;
@ -86,12 +85,7 @@ public abstract class MultiRepoUpdaterTest extends FDroidProviderTest {
RepoProvider.Helper.remove(context, 3); RepoProvider.Helper.remove(context, 3);
RepoProvider.Helper.remove(context, 4); RepoProvider.Helper.remove(context, 4);
Preferences.setup(context); Preferences.setupForTests(context);
}
@After
public final void tearDownMultiRepo() {
Preferences.clearSingletonForTesting();
} }
protected void assertApp(String packageName, int[] versionCodes) { protected void assertApp(String packageName, int[] versionCodes) {

View File

@ -4,7 +4,6 @@ package org.fdroid.fdroid.updater;
import android.content.ContentValues; import android.content.ContentValues;
import android.support.annotation.StringDef; import android.support.annotation.StringDef;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.RepoUpdater; import org.fdroid.fdroid.RepoUpdater;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;

View File

@ -14,7 +14,7 @@ import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProviderTest; 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.FDroidProviderTest;
import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProviderTest; import org.fdroid.fdroid.data.RepoProviderTest;
@ -36,7 +36,7 @@ public class AppDetailsAdapterTest extends FDroidProviderTest {
@Before @Before
public void setup() { public void setup() {
ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context)); 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"); Repo repo = RepoProviderTest.insertRepo(context, "http://www.example.com/fdroid/repo", "", "", "Test Repo");
app = AppProviderTest.insertApp(contentResolver, context, "com.example.app", "Test App", app = AppProviderTest.insertApp(contentResolver, context, "com.example.app", "Test App",
@ -46,8 +46,7 @@ public class AppDetailsAdapterTest extends FDroidProviderTest {
@After @After
public void teardown() { public void teardown() {
ImageLoader.getInstance().destroy(); ImageLoader.getInstance().destroy();
FDroidProvider.clearDbHelperSingleton(); DBHelper.clearDbHelperSingleton();
Preferences.clearSingletonForTesting();
} }
@Test @Test