aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/DataStore.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/DataStore.java')
-rw-r--r--main/src/cgeo/geocaching/DataStore.java668
1 files changed, 327 insertions, 341 deletions
diff --git a/main/src/cgeo/geocaching/DataStore.java b/main/src/cgeo/geocaching/DataStore.java
index e404b22..b7ca577 100644
--- a/main/src/cgeo/geocaching/DataStore.java
+++ b/main/src/cgeo/geocaching/DataStore.java
@@ -11,29 +11,34 @@ import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.files.LocalStorage;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.list.AbstractList;
import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.search.SearchSuggestionCursor;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.Version;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
-import rx.android.observables.AndroidObservable;
+import rx.Observable;
+import rx.Observable.OnSubscribe;
+import rx.Subscriber;
+import rx.android.app.AppObservable;
+import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
-import rx.util.async.Async;
import android.app.Activity;
import android.app.ProgressDialog;
@@ -58,6 +63,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
+import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -68,6 +74,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
public class DataStore {
@@ -111,35 +118,32 @@ public class DataStore {
"cg_caches.direction," + // 16
"cg_caches.distance," + // 17
"cg_caches.terrain," + // 18
- "cg_caches.latlon," + // 19
- "cg_caches.location," + // 20
- "cg_caches.personal_note," + // 21
- "cg_caches.shortdesc," + // 22
- "cg_caches.favourite_cnt," + // 23
- "cg_caches.rating," + // 24
- "cg_caches.votes," + // 25
- "cg_caches.myvote," + // 26
- "cg_caches.disabled," + // 27
- "cg_caches.archived," + // 28
- "cg_caches.members," + // 29
- "cg_caches.found," + // 30
- "cg_caches.favourite," + // 31
- "cg_caches.inventoryunknown," + // 32
- "cg_caches.onWatchlist," + // 33
- "cg_caches.reliable_latlon," + // 34
- "cg_caches.coordsChanged," + // 35
- "cg_caches.latitude," + // 36
- "cg_caches.longitude," + // 37
- "cg_caches.finalDefined," + // 38
- "cg_caches._id," + // 39
- "cg_caches.inventorycoins," + // 40
- "cg_caches.inventorytags," + // 41
- "cg_caches.logPasswordRequired"; // 42
-
- //TODO: remove "latlon" field from cache table
+ "cg_caches.location," + // 19
+ "cg_caches.personal_note," + // 20
+ "cg_caches.shortdesc," + // 21
+ "cg_caches.favourite_cnt," + // 22
+ "cg_caches.rating," + // 23
+ "cg_caches.votes," + // 24
+ "cg_caches.myvote," + // 25
+ "cg_caches.disabled," + // 26
+ "cg_caches.archived," + // 27
+ "cg_caches.members," + // 28
+ "cg_caches.found," + // 29
+ "cg_caches.favourite," + // 30
+ "cg_caches.inventoryunknown," + // 31
+ "cg_caches.onWatchlist," + // 32
+ "cg_caches.reliable_latlon," + // 33
+ "cg_caches.coordsChanged," + // 34
+ "cg_caches.latitude," + // 35
+ "cg_caches.longitude," + // 36
+ "cg_caches.finalDefined," + // 37
+ "cg_caches._id," + // 38
+ "cg_caches.inventorycoins," + // 39
+ "cg_caches.inventorytags," + // 40
+ "cg_caches.logPasswordRequired"; // 41
/** The list of fields needed for mapping. */
- private static final String[] WAYPOINT_COLUMNS = new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own", "visited" };
+ private static final String[] WAYPOINT_COLUMNS = new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latitude", "longitude", "note", "own", "visited" };
/** Number of days (as ms) after temporarily saved caches are deleted */
private final static long DAYS_AFTER_CACHE_IS_DELETED = 3 * 24 * 60 * 60 * 1000;
@@ -147,7 +151,7 @@ public class DataStore {
/**
* holds the column indexes of the cache table to avoid lookups
*/
- private static CacheCache cacheCache = new CacheCache();
+ private static final CacheCache cacheCache = new CacheCache();
private static SQLiteDatabase database = null;
private static final int dbVersion = 68;
public static final int customListIdOffset = 10;
@@ -162,7 +166,7 @@ public class DataStore {
private static final @NonNull String dbTableLogImages = "cg_logImages";
private static final @NonNull String dbTableLogsOffline = "cg_logs_offline";
private static final @NonNull String dbTableTrackables = "cg_trackables";
- private static final @NonNull String dbTableSearchDestionationHistory = "cg_search_destination_history";
+ private static final @NonNull String dbTableSearchDestinationHistory = "cg_search_destination_history";
private static final @NonNull String dbCreateCaches = ""
+ "create table " + dbTableCaches + " ("
+ "_id integer primary key autoincrement, "
@@ -183,7 +187,6 @@ public class DataStore {
+ "size text, "
+ "difficulty float, "
+ "terrain float, "
- + "latlon text, "
+ "location text, "
+ "direction double, "
+ "distance double, "
@@ -214,9 +217,7 @@ public class DataStore {
+ "create table " + dbTableLists + " ("
+ "_id integer primary key autoincrement, "
+ "title text not null, "
- + "updated long not null, "
- + "latitude double, "
- + "longitude double "
+ + "updated long not null"
+ "); ";
private static final String dbCreateAttributes = ""
+ "create table " + dbTableAttributes + " ("
@@ -235,7 +236,6 @@ public class DataStore {
+ "prefix text, "
+ "lookup text, "
+ "name text, "
- + "latlon text, "
+ "latitude double, "
+ "longitude double, "
+ "note text, "
@@ -303,13 +303,23 @@ public class DataStore {
+ "); ";
private static final String dbCreateSearchDestinationHistory = ""
- + "create table " + dbTableSearchDestionationHistory + " ("
+ + "create table " + dbTableSearchDestinationHistory + " ("
+ "_id integer primary key autoincrement, "
+ "date long not null, "
+ "latitude double, "
+ "longitude double "
+ "); ";
+ private static final Observable<Integer> allCachesCountObservable = Observable.create(new OnSubscribe<Integer>() {
+ @Override
+ public void call(final Subscriber<? super Integer> subscriber) {
+ if (isInitialized()) {
+ subscriber.onNext(getAllCachesCount());
+ subscriber.onCompleted();
+ }
+ }
+ }).timeout(500, TimeUnit.MILLISECONDS).retry(10).subscribeOn(Schedulers.io());
+
private static boolean newlyCreatedDatabase = false;
private static boolean databaseCleaned = false;
@@ -358,11 +368,12 @@ public class DataStore {
}
cacheCache.removeAllFromCache();
- PreparedStatements.clearPreparedStatements();
+ PreparedStatement.clearPreparedStatements();
database.close();
database = null;
}
+ @NonNull
public static File getBackupFileInternal() {
return new File(LocalStorage.getStorage(), "cgeo.sqlite");
}
@@ -391,16 +402,15 @@ public class DataStore {
* Move the database to/from external cgdata in a new thread,
* showing a progress window
*
- * @param fromActivity
*/
public static void moveDatabase(final Activity fromActivity) {
final ProgressDialog dialog = ProgressDialog.show(fromActivity, fromActivity.getString(R.string.init_dbmove_dbmove), fromActivity.getString(R.string.init_dbmove_running), true, false);
- AndroidObservable.bindActivity(fromActivity, Async.fromCallable(new Func0<Boolean>() {
+ AppObservable.bindActivity(fromActivity, Observable.defer(new Func0<Observable<Boolean>>() {
@Override
- public Boolean call() {
+ public Observable<Boolean> call() {
if (!LocalStorage.isExternalStorageAvailable()) {
Log.w("Database was not moved: external memory not available");
- return false;
+ return Observable.just(false);
}
closeDb();
@@ -409,7 +419,7 @@ public class DataStore {
if (!LocalStorage.copy(source, target)) {
Log.e("Database could not be moved to " + target);
init();
- return false;
+ return Observable.just(false);
}
if (!FileUtils.delete(source)) {
Log.e("Original database could not be deleted during move");
@@ -418,7 +428,7 @@ public class DataStore {
Log.i("Database was moved to " + target);
init();
- return true;
+ return Observable.just(true);
}
})).subscribeOn(Schedulers.io()).subscribe(new Action1<Boolean>() {
@Override
@@ -430,14 +440,17 @@ public class DataStore {
});
}
+ @NonNull
private static File databasePath(final boolean internal) {
return new File(internal ? LocalStorage.getInternalDbDirectory() : LocalStorage.getExternalDbDirectory(), dbName);
}
+ @NonNull
private static File databasePath() {
return databasePath(!Settings.isDbOnSDCard());
}
+ @NonNull
private static File databaseAlternatePath() {
return databasePath(Settings.isDbOnSDCard());
}
@@ -552,7 +565,7 @@ public class DataStore {
try {
db.execSQL(dbCreateSearchDestinationHistory);
- Log.i("Added table " + dbTableSearchDestionationHistory + ".");
+ Log.i("Added table " + dbTableSearchDestinationHistory + ".");
} catch (final Exception e) {
Log.e("Failed to upgrade to ver. 52", e);
}
@@ -638,7 +651,6 @@ public class DataStore {
+ "size text, "
+ "difficulty float, "
+ "terrain float, "
- + "latlon text, "
+ "location text, "
+ "direction double, "
+ "distance double, "
@@ -665,7 +677,7 @@ public class DataStore {
db.execSQL(dbCreateCachesTemp);
db.execSQL("insert into " + dbTableCachesTemp + " select _id,updated,detailed,detailedupdate,visiteddate,geocode,reason,cacheid,guid,type,name,own,owner,owner_real," +
- "hidden,hint,size,difficulty,terrain,latlon,location,direction,distance,latitude,longitude, 0," +
+ "hidden,hint,size,difficulty,terrain,location,direction,distance,latitude,longitude, 0," +
"personal_note,shortdesc,description,favourite_cnt,rating,votes,myvote,disabled,archived,members,found,favourite,inventorycoins," +
"inventorytags,inventoryunknown,onWatchlist from " + dbTableCaches);
db.execSQL("drop table " + dbTableCaches);
@@ -681,13 +693,12 @@ public class DataStore {
+ "prefix text, "
+ "lookup text, "
+ "name text, "
- + "latlon text, "
+ "latitude double, "
+ "longitude double, "
+ "note text "
+ "); ";
db.execSQL(dbCreateWaypointsTemp);
- db.execSQL("insert into " + dbTableWaypointsTemp + " select _id, geocode, updated, type, prefix, lookup, name, latlon, latitude, longitude, note from " + dbTableWaypoints);
+ db.execSQL("insert into " + dbTableWaypointsTemp + " select _id, geocode, updated, type, prefix, lookup, name, latitude, longitude, note from " + dbTableWaypoints);
db.execSQL("drop table " + dbTableWaypoints);
db.execSQL("alter table " + dbTableWaypointsTemp + " rename to " + dbTableWaypoints);
@@ -823,7 +834,7 @@ public class DataStore {
private static void sanityChecks(final SQLiteDatabase db) {
// Check that the history of searches is well formed as some dates seem to be missing according
// to NPE traces.
- final int staleHistorySearches = db.delete(dbTableSearchDestionationHistory, "date is null", null);
+ final int staleHistorySearches = db.delete(dbTableSearchDestinationHistory, "date is null", null);
if (staleHistorySearches > 0) {
Log.w(String.format(Locale.getDefault(), "DataStore.dbHelper.onOpen: removed %d bad search history entries", staleHistorySearches));
}
@@ -871,15 +882,17 @@ public class DataStore {
final File[] files = LocalStorage.getStorage().listFiles();
if (ArrayUtils.isNotEmpty(files)) {
final Pattern oldFilePattern = Pattern.compile("^[GC|TB|EC|GK|O][A-Z0-9]{4,7}$");
- final SQLiteStatement select = db.compileStatement("select count(*) from " + dbTableCaches + " where geocode = ?");
+ final SQLiteStatement select = PreparedStatement.CHECK_IF_PRESENT.getStatement();
final ArrayList<File> toRemove = new ArrayList<>(files.length);
for (final File file : files) {
if (file.isDirectory()) {
final String geocode = file.getName();
if (oldFilePattern.matcher(geocode).find()) {
- select.bindString(1, geocode);
- if (select.simpleQueryForLong() == 0) {
- toRemove.add(file);
+ synchronized (select) {
+ select.bindString(1, geocode);
+ if (select.simpleQueryForLong() == 0) {
+ toRemove.add(file);
+ }
}
}
}
@@ -887,15 +900,15 @@ public class DataStore {
// Use a background thread for the real removal to avoid keeping the database locked
// if we are called from within a transaction.
- new Thread(new Runnable() {
+ Schedulers.io().createWorker().schedule(new Action0() {
@Override
- public void run() {
+ public void call() {
for (final File dir : toRemove) {
Log.i("Removing obsolete cache directory for " + dir.getName());
- LocalStorage.deleteDirectory(dir);
+ FileUtils.deleteDirectory(dir);
}
}
- }).start();
+ });
}
}
@@ -933,7 +946,7 @@ public class DataStore {
int dataDetailed = 0;
try {
- Cursor cursor;
+ final Cursor cursor;
if (StringUtils.isNotBlank(geocode)) {
cursor = database.query(
@@ -1000,18 +1013,18 @@ public class DataStore {
final SQLiteStatement listId;
final String value;
if (StringUtils.isNotBlank(geocode)) {
- listId = PreparedStatements.getListIdOfGeocode();
+ listId = PreparedStatement.LIST_ID_OF_GEOCODE.getStatement();
value = geocode;
}
else {
- listId = PreparedStatements.getListIdOfGuid();
+ listId = PreparedStatement.LIST_ID_OF_GUID.getStatement();
value = guid;
}
synchronized (listId) {
listId.bindString(1, value);
- return listId.simpleQueryForLong() != StoredList.TEMPORARY_LIST_ID;
+ return listId.simpleQueryForLong() != StoredList.TEMPORARY_LIST.id;
}
- } catch (final SQLiteDoneException e) {
+ } catch (final SQLiteDoneException ignored) {
// Do nothing, it only means we have no information on the cache
} catch (final Exception e) {
Log.e("DataStore.isOffline", e);
@@ -1020,6 +1033,7 @@ public class DataStore {
return false;
}
+ @Nullable
public static String getGeocodeForGuid(final String guid) {
if (StringUtils.isBlank(guid)) {
return null;
@@ -1027,12 +1041,12 @@ public class DataStore {
init();
try {
- final SQLiteStatement description = PreparedStatements.getGeocodeOfGuid();
+ final SQLiteStatement description = PreparedStatement.GEOCODE_OF_GUID.getStatement();
synchronized (description) {
description.bindString(1, guid);
return description.simpleQueryForString();
}
- } catch (final SQLiteDoneException e) {
+ } catch (final SQLiteDoneException ignored) {
// Do nothing, it only means we have no information on the cache
} catch (final Exception e) {
Log.e("DataStore.getGeocodeForGuid", e);
@@ -1041,36 +1055,14 @@ public class DataStore {
return null;
}
- public static String getCacheidForGeocode(final String geocode) {
- if (StringUtils.isBlank(geocode)) {
- return null;
- }
- init();
-
- try {
- final SQLiteStatement description = PreparedStatements.getCacheIdOfGeocode();
- synchronized (description) {
- description.bindString(1, geocode);
- return description.simpleQueryForString();
- }
- } catch (final SQLiteDoneException e) {
- // Do nothing, it only means we have no information on the cache
- } catch (final Exception e) {
- Log.e("DataStore.getCacheidForGeocode", e);
- }
-
- return null;
- }
-
/**
* Save/store a cache to the CacheCache
*
* @param cache
* the Cache to save in the CacheCache/DB
- * @param saveFlags
*
*/
- public static void saveCache(final Geocache cache, final EnumSet<LoadFlags.SaveFlag> saveFlags) {
+ public static void saveCache(final Geocache cache, final Set<LoadFlags.SaveFlag> saveFlags) {
saveCaches(Collections.singletonList(cache), saveFlags);
}
@@ -1079,10 +1071,9 @@ public class DataStore {
*
* @param caches
* the caches to save in the CacheCache/DB
- * @param saveFlags
*
*/
- public static void saveCaches(final Collection<Geocache> caches, final EnumSet<LoadFlags.SaveFlag> saveFlags) {
+ public static void saveCaches(final Collection<Geocache> caches, final Set<LoadFlags.SaveFlag> saveFlags) {
if (CollectionUtils.isEmpty(caches)) {
return;
}
@@ -1116,7 +1107,9 @@ public class DataStore {
for (final Geocache cache : caches) {
final String geocode = cache.getGeocode();
final Geocache existingCache = existingCaches.get(geocode);
- final boolean dbUpdateRequired = !cache.gatherMissingFrom(existingCache) || cacheCache.getCacheFromCache(geocode) != null;
+ boolean dbUpdateRequired = !cache.gatherMissingFrom(existingCache) || cacheCache.getCacheFromCache(geocode) != null;
+ // parse the note AFTER merging the local information in
+ dbUpdateRequired |= cache.parseWaypointsFromNote();
cache.addStorageLocation(StorageLocation.CACHE);
cacheCache.putCacheInCache(cache);
@@ -1162,7 +1155,7 @@ public class DataStore {
values.put("hidden", hiddenDate.getTime());
}
values.put("hint", cache.getHint());
- values.put("size", cache.getSize() == null ? "" : cache.getSize().id);
+ values.put("size", cache.getSize().id);
values.put("difficulty", cache.getDifficulty());
values.put("terrain", cache.getTerrain());
values.put("location", cache.getLocation());
@@ -1228,7 +1221,7 @@ public class DataStore {
if (attributes.isEmpty()) {
return;
}
- final SQLiteStatement statement = PreparedStatements.getInsertAttribute();
+ final SQLiteStatement statement = PreparedStatement.INSERT_ATTRIBUTE.getStatement();
final long timestamp = System.currentTimeMillis();
for (final String attribute : attributes) {
statement.bindString(1, geocode);
@@ -1249,9 +1242,12 @@ public class DataStore {
init();
database.beginTransaction();
-
try {
- final SQLiteStatement insertDestination = PreparedStatements.getInsertSearchDestination(destination);
+ final SQLiteStatement insertDestination = PreparedStatement.INSERT_SEARCH_DESTINATION.getStatement();
+ insertDestination.bindLong(1, destination.getDate());
+ final Geopoint coords = destination.getCoords();
+ insertDestination.bindDouble(2, coords.getLatitude());
+ insertDestination.bindDouble(3, coords.getLongitude());
insertDestination.executeInsert();
database.setTransactionSuccessful();
} catch (final Exception e) {
@@ -1264,7 +1260,6 @@ public class DataStore {
public static boolean saveWaypoints(final Geocache cache) {
init();
database.beginTransaction();
-
try {
saveWaypointsWithoutTransaction(cache);
database.setTransactionSuccessful();
@@ -1294,7 +1289,6 @@ public class DataStore {
values.put("prefix", oneWaypoint.getPrefix());
values.put("lookup", oneWaypoint.getLookup());
values.put("name", oneWaypoint.getName());
- values.put("latlon", oneWaypoint.getLatlon());
putCoords(values, oneWaypoint.getCoords());
values.put("note", oneWaypoint.getNote());
values.put("own", oneWaypoint.isUserDefined() ? 1 : 0);
@@ -1315,7 +1309,6 @@ public class DataStore {
/**
* remove all waypoints of the given cache, where the id is not in the given list
*
- * @param cache
* @param remainingWaypointIds
* ids of waypoints which shall not be deleted
*/
@@ -1329,7 +1322,7 @@ public class DataStore {
*
* @param values
* a ContentValues to save coordinates in
- * @param oneWaypoint
+ * @param coords
* coordinates to save, or null to save empty coordinates
*/
private static void putCoords(final ContentValues values, final Geopoint coords) {
@@ -1348,6 +1341,7 @@ public class DataStore {
* index of the longitude column
* @return the coordinates, or null if latitude or longitude is null or the coordinates are invalid
*/
+ @Nullable
private static Geopoint getCoords(final Cursor cursor, final int indexLat, final int indexLon) {
if (cursor.isNull(indexLat) || cursor.isNull(indexLon)) {
return null;
@@ -1373,7 +1367,6 @@ public class DataStore {
values.put("prefix", waypoint.getPrefix());
values.put("lookup", waypoint.getLookup());
values.put("name", waypoint.getName());
- values.put("latlon", waypoint.getLatlon());
putCoords(values, waypoint.getCoords());
values.put("note", waypoint.getNote());
values.put("own", waypoint.isUserDefined() ? 1 : 0);
@@ -1410,7 +1403,7 @@ public class DataStore {
final List<Image> spoilers = cache.getSpoilers();
if (CollectionUtils.isNotEmpty(spoilers)) {
- final SQLiteStatement insertSpoiler = PreparedStatements.getInsertSpoiler();
+ final SQLiteStatement insertSpoiler = PreparedStatement.INSERT_SPOILER.getStatement();
final long timestamp = System.currentTimeMillis();
for (final Image spoiler : spoilers) {
insertSpoiler.bindString(1, geocode);
@@ -1420,8 +1413,7 @@ public class DataStore {
final String description = spoiler.getDescription();
if (description != null) {
insertSpoiler.bindString(5, description);
- }
- else {
+ } else {
insertSpoiler.bindNull(5);
}
insertSpoiler.executeInsert();
@@ -1429,11 +1421,21 @@ public class DataStore {
}
}
- public static void saveLogsWithoutTransaction(final String geocode, final Iterable<LogEntry> logs) {
+ public static void saveLogs(final String geocode, final Iterable<LogEntry> logs) {
+ database.beginTransaction();
+ try {
+ saveLogsWithoutTransaction(geocode, logs);
+ database.setTransactionSuccessful();
+ } finally {
+ database.endTransaction();
+ }
+ }
+
+ private static void saveLogsWithoutTransaction(final String geocode, final Iterable<LogEntry> logs) {
// TODO delete logimages referring these logs
database.delete(dbTableLogs, "geocode = ?", new String[]{geocode});
- final SQLiteStatement insertLog = PreparedStatements.getInsertLog();
+ final SQLiteStatement insertLog = PreparedStatement.INSERT_LOG.getStatement();
final long timestamp = System.currentTimeMillis();
for (final LogEntry log : logs) {
insertLog.bindString(1, geocode);
@@ -1446,7 +1448,7 @@ public class DataStore {
insertLog.bindLong(8, log.friend ? 1 : 0);
final long logId = insertLog.executeInsert();
if (log.hasLogImages()) {
- final SQLiteStatement insertImage = PreparedStatements.getInsertLogImage();
+ final SQLiteStatement insertImage = PreparedStatement.INSERT_LOG_IMAGE.getStatement();
for (final Image img : log.getLogImages()) {
insertImage.bindLong(1, logId);
insertImage.bindString(2, img.getTitle());
@@ -1464,7 +1466,7 @@ public class DataStore {
final Map<LogType, Integer> logCounts = cache.getLogCounts();
if (MapUtils.isNotEmpty(logCounts)) {
final Set<Entry<LogType, Integer>> logCountsItems = logCounts.entrySet();
- final SQLiteStatement insertLogCounts = PreparedStatements.getInsertLogCounts();
+ final SQLiteStatement insertLogCounts = PreparedStatement.INSERT_LOG_COUNTS.getStatement();
final long timestamp = System.currentTimeMillis();
for (final Entry<LogType, Integer> pair : logCountsItems) {
insertLogCounts.bindString(1, geocode);
@@ -1526,6 +1528,7 @@ public class DataStore {
}
}
+ @Nullable
public static Viewport getBounds(final Set<String> geocodes) {
if (CollectionUtils.isEmpty(geocodes)) {
return null;
@@ -1542,6 +1545,7 @@ public class DataStore {
* The Geocode GCXXXX
* @return the loaded cache (if found). Can be null
*/
+ @Nullable
public static Geocache loadCache(final String geocode, final EnumSet<LoadFlag> loadFlags) {
if (StringUtils.isBlank(geocode)) {
throw new IllegalArgumentException("geocode must not be empty");
@@ -1554,15 +1558,15 @@ public class DataStore {
/**
* Load caches.
*
- * @param geocodes
* @return Set of loaded caches. Never null.
*/
+ @NonNull
public static Set<Geocache> loadCaches(final Collection<String> geocodes, final EnumSet<LoadFlag> loadFlags) {
if (CollectionUtils.isEmpty(geocodes)) {
return new HashSet<>();
}
- final Set<Geocache> result = new HashSet<>();
+ final Set<Geocache> result = new HashSet<>(geocodes.size());
final Set<String> remaining = new HashSet<>(geocodes);
if (loadFlags.contains(LoadFlag.CACHE_BEFORE)) {
@@ -1609,10 +1613,9 @@ public class DataStore {
/**
* Load caches.
*
- * @param geocodes
- * @param loadFlags
* @return Set of loaded caches. Never null.
*/
+ @NonNull
private static Set<Geocache> loadCachesFromGeocodes(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) {
if (CollectionUtils.isEmpty(geocodes)) {
return Collections.emptySet();
@@ -1640,7 +1643,7 @@ public class DataStore {
int logIndex = -1;
while (cursor.moveToNext()) {
- final Geocache cache = DataStore.createCacheFromDatabaseContent(cursor);
+ final Geocache cache = createCacheFromDatabaseContent(cursor);
if (loadFlags.contains(LoadFlag.ATTRIBUTES)) {
cache.setAttributes(loadAttributes(cache.getGeocode()));
@@ -1699,11 +1702,9 @@ public class DataStore {
/**
* Builds a where for a viewport with the size enhanced by 50%.
*
- * @param dbTable
- * @param viewport
- * @return
*/
+ @NonNull
private static StringBuilder buildCoordinateWhere(final String dbTable, final Viewport viewport) {
return viewport.resize(1.5).sqlWhere(dbTable);
}
@@ -1711,9 +1712,9 @@ public class DataStore {
/**
* creates a Cache from the cursor. Doesn't next.
*
- * @param cursor
* @return Cache from DB
*/
+ @NonNull
private static Geocache createCacheFromDatabaseContent(final Cursor cursor) {
final Geocache cache = new Geocache();
@@ -1750,31 +1751,32 @@ public class DataStore {
}
cache.setTerrain(cursor.getFloat(18));
// do not set cache.location
- cache.setCoords(getCoords(cursor, 36, 37));
- cache.setPersonalNote(cursor.getString(21));
+ cache.setPersonalNote(cursor.getString(20));
// do not set cache.shortdesc
// do not set cache.description
- cache.setFavoritePoints(cursor.getInt(23));
- cache.setRating(cursor.getFloat(24));
- cache.setVotes(cursor.getInt(25));
- cache.setMyVote(cursor.getFloat(26));
- cache.setDisabled(cursor.getInt(27) == 1);
- cache.setArchived(cursor.getInt(28) == 1);
- cache.setPremiumMembersOnly(cursor.getInt(29) == 1);
- cache.setFound(cursor.getInt(30) == 1);
- cache.setFavorite(cursor.getInt(31) == 1);
- cache.setInventoryItems(cursor.getInt(32));
- cache.setOnWatchlist(cursor.getInt(33) == 1);
- cache.setReliableLatLon(cursor.getInt(34) > 0);
- cache.setUserModifiedCoords(cursor.getInt(35) > 0);
- cache.setFinalDefined(cursor.getInt(38) > 0);
- cache.setLogPasswordRequired(cursor.getInt(42) > 0);
+ cache.setFavoritePoints(cursor.getInt(22));
+ cache.setRating(cursor.getFloat(23));
+ cache.setVotes(cursor.getInt(24));
+ cache.setMyVote(cursor.getFloat(25));
+ cache.setDisabled(cursor.getInt(26) == 1);
+ cache.setArchived(cursor.getInt(27) == 1);
+ cache.setPremiumMembersOnly(cursor.getInt(28) == 1);
+ cache.setFound(cursor.getInt(29) == 1);
+ cache.setFavorite(cursor.getInt(30) == 1);
+ cache.setInventoryItems(cursor.getInt(31));
+ cache.setOnWatchlist(cursor.getInt(32) == 1);
+ cache.setReliableLatLon(cursor.getInt(33) > 0);
+ cache.setUserModifiedCoords(cursor.getInt(34) > 0);
+ cache.setCoords(getCoords(cursor, 35, 36));
+ cache.setFinalDefined(cursor.getInt(37) > 0);
+ cache.setLogPasswordRequired(cursor.getInt(41) > 0);
Log.d("Loading " + cache.toString() + " (" + cache.getListId() + ") from DB");
return cache;
}
+ @Nullable
public static List<String> loadAttributes(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1792,6 +1794,7 @@ public class DataStore {
GET_STRING_0);
}
+ @Nullable
public static Waypoint loadWaypoint(final int id) {
if (id == 0) {
return null;
@@ -1818,6 +1821,7 @@ public class DataStore {
return waypoint;
}
+ @Nullable
public static List<Waypoint> loadWaypoints(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1840,6 +1844,7 @@ public class DataStore {
});
}
+ @NonNull
private static Waypoint createWaypointFromDatabaseContent(final Cursor cursor) {
final String name = cursor.getString(cursor.getColumnIndex("name"));
final WaypointType type = WaypointType.findById(cursor.getString(cursor.getColumnIndex("type")));
@@ -1850,13 +1855,13 @@ public class DataStore {
waypoint.setGeocode(cursor.getString(cursor.getColumnIndex("geocode")));
waypoint.setPrefix(cursor.getString(cursor.getColumnIndex("prefix")));
waypoint.setLookup(cursor.getString(cursor.getColumnIndex("lookup")));
- waypoint.setLatlon(cursor.getString(cursor.getColumnIndex("latlon")));
waypoint.setCoords(getCoords(cursor, cursor.getColumnIndex("latitude"), cursor.getColumnIndex("longitude")));
waypoint.setNote(cursor.getString(cursor.getColumnIndex("note")));
return waypoint;
}
+ @Nullable
private static List<Image> loadSpoilers(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1885,8 +1890,9 @@ public class DataStore {
*
* @return A list of previously entered destinations or an empty list.
*/
+ @NonNull
public static List<Destination> loadHistoryOfSearchedLocations() {
- return queryToColl(dbTableSearchDestionationHistory,
+ return queryToColl(dbTableSearchDestinationHistory,
new String[]{"_id", "date", "latitude", "longitude"},
"latitude IS NOT NULL AND longitude IS NOT NULL",
null,
@@ -1908,7 +1914,7 @@ public class DataStore {
database.beginTransaction();
try {
- database.delete(dbTableSearchDestionationHistory, null, null);
+ database.delete(dbTableSearchDestinationHistory, null, null);
database.setTransactionSuccessful();
return true;
} catch (final Exception e) {
@@ -1921,7 +1927,6 @@ public class DataStore {
}
/**
- * @param geocode
* @return an immutable, non null list of logs
*/
@NonNull
@@ -1935,7 +1940,7 @@ public class DataStore {
init();
final Cursor cursor = database.rawQuery(
- /* 0 1 2 3 4 5 6 7 8 9 10 */
+ // 0 1 2 3 4 5 6 7 8 9 10
"SELECT cg_logs._id as cg_logs_id, type, author, log, date, found, friend, " + dbTableLogImages + "._id as cg_logImages_id, log_id, title, url"
+ " FROM " + dbTableLogs + " LEFT OUTER JOIN " + dbTableLogImages
+ " ON ( cg_logs._id = log_id ) WHERE geocode = ? ORDER BY date desc, cg_logs._id asc", new String[]{geocode});
@@ -1963,6 +1968,7 @@ public class DataStore {
return Collections.unmodifiableList(logs);
}
+ @Nullable
public static Map<LogType, Integer> loadLogCounts(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1970,7 +1976,7 @@ public class DataStore {
init();
- final Map<LogType, Integer> logCounts = new HashMap<>();
+ final Map<LogType, Integer> logCounts = new EnumMap<>(LogType.class);
final Cursor cursor = database.query(
dbTableLogCount,
@@ -1991,6 +1997,7 @@ public class DataStore {
return logCounts;
}
+ @Nullable
private static List<Trackable> loadInventory(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -2019,6 +2026,7 @@ public class DataStore {
return trackables;
}
+ @Nullable
public static Trackable loadTrackable(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -2043,6 +2051,7 @@ public class DataStore {
return trackable;
}
+ @NonNull
private static Trackable createTrackableFromDatabaseContent(final Cursor cursor) {
final Trackable trackable = new Trackable();
trackable.setGeocode(cursor.getString(cursor.getColumnIndex("tbcode")));
@@ -2067,9 +2076,6 @@ public class DataStore {
/**
* Number of caches stored for a given type and/or list
*
- * @param cacheType
- * @param list
- * @return
*/
public static int getAllStoredCachesCount(final CacheType cacheType, final int list) {
if (cacheType == null) {
@@ -2081,37 +2087,29 @@ public class DataStore {
init();
try {
- final StringBuilder sql = new StringBuilder("select count(_id) from " + dbTableCaches + " where detailed = 1");
- String typeKey;
- int reasonIndex;
- if (cacheType != CacheType.ALL) {
- sql.append(" and type = ?");
- typeKey = cacheType.id;
- reasonIndex = 2;
- }
- else {
- typeKey = "all_types";
- reasonIndex = 1;
- }
- String listKey;
- if (list == PseudoList.ALL_LIST.id) {
- sql.append(" and reason > 0");
- listKey = "all_list";
- } else {
- sql.append(" and reason = ?");
- listKey = "list";
- }
-
- final String key = "CountCaches_" + typeKey + "_" + listKey;
+ final SQLiteStatement compiledStmnt;
+ synchronized (PreparedStatement.COUNT_TYPE_LIST) {
+ // All the statements here are used only once and are protected through the current synchronized block
+ if (list == PseudoList.ALL_LIST.id) {
+ if (cacheType == CacheType.ALL) {
+ compiledStmnt = PreparedStatement.COUNT_ALL_TYPES_ALL_LIST.getStatement();
+ } else {
+ compiledStmnt = PreparedStatement.COUNT_TYPE_ALL_LIST.getStatement();
+ compiledStmnt.bindString(1, cacheType.id);
+ }
+ } else {
+ if (cacheType == CacheType.ALL) {
+ compiledStmnt = PreparedStatement.COUNT_ALL_TYPES_LIST.getStatement();
+ compiledStmnt.bindLong(1, list);
+ } else {
+ compiledStmnt = PreparedStatement.COUNT_TYPE_LIST.getStatement();
+ compiledStmnt.bindString(1, cacheType.id);
+ compiledStmnt.bindLong(1, list);
+ }
+ }
- final SQLiteStatement compiledStmnt = PreparedStatements.getStatement(key, sql.toString());
- if (cacheType != CacheType.ALL) {
- compiledStmnt.bindString(1, cacheType.id);
- }
- if (list != PseudoList.ALL_LIST.id) {
- compiledStmnt.bindLong(reasonIndex, list);
+ return (int) compiledStmnt.simpleQueryForLong();
}
- return (int) compiledStmnt.simpleQueryForLong();
} catch (final Exception e) {
Log.e("DataStore.loadAllStoredCachesCount", e);
}
@@ -2123,7 +2121,7 @@ public class DataStore {
init();
try {
- return (int) PreparedStatements.getCountHistoryCaches().simpleQueryForLong();
+ return (int) PreparedStatement.HISTORY_COUNT.simpleQueryForLong();
} catch (final Exception e) {
Log.e("DataStore.getAllHistoricCachesCount", e);
}
@@ -2131,6 +2129,7 @@ public class DataStore {
return 0;
}
+ @NonNull
private static<T, U extends Collection<? super T>> U queryToColl(@NonNull final String table,
final String[] columns,
final String selection,
@@ -2162,10 +2161,9 @@ public class DataStore {
*
* @param coords
* the current coordinates to sort by distance, or null to sort by geocode
- * @param cacheType
- * @param listId
* @return a non-null set of geocodes
*/
+ @NonNull
private static Set<String> loadBatchOfStoredGeocodes(final Geopoint coords, final CacheType cacheType, final int listId) {
if (cacheType == null) {
throw new IllegalArgumentException("cacheType must not be null");
@@ -2212,6 +2210,7 @@ public class DataStore {
}
}
+ @NonNull
private static Set<String> loadBatchOfHistoricGeocodes(final boolean detailedOnly, final CacheType cacheType) {
final StringBuilder selection = new StringBuilder("visiteddate > 0");
@@ -2243,11 +2242,13 @@ public class DataStore {
}
/** Retrieve all stored caches from DB */
+ @NonNull
public static SearchResult loadCachedInViewport(final Viewport viewport, final CacheType cacheType) {
return loadInViewport(false, viewport, cacheType);
}
/** Retrieve stored caches from DB with listId >= 1 */
+ @NonNull
public static SearchResult loadStoredInViewport(final Viewport viewport, final CacheType cacheType) {
return loadInViewport(true, viewport, cacheType);
}
@@ -2255,15 +2256,12 @@ public class DataStore {
/**
* Loads the geocodes of caches in a viewport from CacheCache and/or Database
*
- * @param stored
- * True - query only stored caches, False - query cached ones as well
- * @param centerLat
- * @param centerLon
- * @param spanLat
- * @param spanLon
- * @param cacheType
- * @return Set with geocodes
+ * @param stored {@code true} to query caches stored in the database, {@code false} to also use the CacheCache
+ * @param viewport the viewport defining the area to scan
+ * @param cacheType the cache type
+ * @return the matching caches
*/
+ @NonNull
private static SearchResult loadInViewport(final boolean stored, final Viewport viewport, final CacheType cacheType) {
final Set<String> geocodes = new HashSet<>();
@@ -2306,72 +2304,78 @@ public class DataStore {
}
/**
- * Remove caches with listId = 0
- *
- * @param more
- * true = all caches false = caches stored 3 days or more before
+ * Remove caches with listId = 0 in the background. Once it has been executed once it will not do anything.
+ * This must be called from the UI thread to ensure synchronization of an internal variable.
*/
- public static void clean(final boolean more) {
+ public static void cleanIfNeeded(final Context context) {
if (databaseCleaned) {
return;
}
+ databaseCleaned = true;
- Log.d("Database clean: started");
+ Schedulers.io().createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ Log.d("Database clean: started");
+ try {
+ final int version = Version.getVersionCode(context);
+ final Set<String> geocodes = new HashSet<>();
+ if (version != Settings.getVersion()) {
+ queryToColl(dbTableCaches,
+ new String[]{"geocode"},
+ "reason = 0",
+ null,
+ null,
+ null,
+ null,
+ null,
+ geocodes,
+ GET_STRING_0);
+ } else {
+ final long timestamp = System.currentTimeMillis() - DAYS_AFTER_CACHE_IS_DELETED;
+ final String timestampString = Long.toString(timestamp);
+ queryToColl(dbTableCaches,
+ new String[]{"geocode"},
+ "reason = 0 and detailed < ? and detailedupdate < ? and visiteddate < ?",
+ new String[]{timestampString, timestampString, timestampString},
+ null,
+ null,
+ null,
+ null,
+ geocodes,
+ GET_STRING_0);
+ }
- try {
- Set<String> geocodes = new HashSet<>();
- if (more) {
- queryToColl(dbTableCaches,
- new String[]{"geocode"},
- "reason = 0",
- null,
- null,
- null,
- null,
- null,
- geocodes,
- GET_STRING_0);
- } else {
- final long timestamp = System.currentTimeMillis() - DAYS_AFTER_CACHE_IS_DELETED;
- final String timestampString = Long.toString(timestamp);
- queryToColl(dbTableCaches,
- new String[]{"geocode"},
- "reason = 0 and detailed < ? and detailedupdate < ? and visiteddate < ?",
- new String[]{timestampString, timestampString, timestampString},
- null,
- null,
- null,
- null,
- geocodes,
- GET_STRING_0);
- }
+ final Set<String> withoutOfflineLogs = exceptCachesWithOfflineLog(geocodes);
+ Log.d("Database clean: removing " + withoutOfflineLogs.size() + " geocaches from listId=0");
+ removeCaches(withoutOfflineLogs, LoadFlags.REMOVE_ALL);
- geocodes = exceptCachesWithOfflineLog(geocodes);
+ // This cleanup needs to be kept in place for about one year so that older log images records are
+ // cleaned. TO BE REMOVED AFTER 2015-03-24.
+ Log.d("Database clean: removing obsolete log images records");
+ database.delete(dbTableLogImages, "log_id NOT IN (SELECT _id FROM " + dbTableLogs + ")", null);
- if (!geocodes.isEmpty()) {
- Log.d("Database clean: removing " + geocodes.size() + " geocaches from listId=0");
- removeCaches(geocodes, LoadFlags.REMOVE_ALL);
- }
+ // Remove the obsolete "_others" directory where the user avatar used to be stored.
+ FileUtils.deleteDirectory(LocalStorage.getStorageDir("_others"));
- // This cleanup needs to be kept in place for about one year so that older log images records are
- // cleaned. TO BE REMOVED AFTER 2015-03-24.
- Log.d("Database clean: removing obsolete log images records");
- database.delete(dbTableLogImages, "log_id NOT IN (SELECT _id FROM " + dbTableLogs + ")", null);
- } catch (final Exception e) {
- Log.w("DataStore.clean", e);
- }
+ if (version > -1) {
+ Settings.setVersion(version);
+ }
+ } catch (final Exception e) {
+ Log.w("DataStore.clean", e);
+ }
- Log.d("Database clean: finished");
- databaseCleaned = true;
+ Log.d("Database clean: finished");
+ }
+ });
}
/**
* remove all geocodes from the given list of geocodes where an offline log exists
*
- * @param geocodes
- * @return
*/
- private static Set<String> exceptCachesWithOfflineLog(final Set<String> geocodes) {
+ @NonNull
+ private static Set<String> exceptCachesWithOfflineLog(@NonNull final Set<String> geocodes) {
if (geocodes.isEmpty()) {
return geocodes;
}
@@ -2448,7 +2452,7 @@ public class DataStore {
// Delete cache directories
for (final String geocode : geocodes) {
- LocalStorage.deleteDirectory(LocalStorage.getStorageDir(geocode));
+ FileUtils.deleteDirectory(LocalStorage.getStorageDir(geocode));
}
}
}
@@ -2480,6 +2484,7 @@ public class DataStore {
return id != -1;
}
+ @Nullable
public static LogEntry loadLogOffline(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -2528,13 +2533,11 @@ public class DataStore {
init();
- final Set<String> geocodes = new HashSet<>(caches.size());
for (final Geocache cache : caches) {
- geocodes.add(cache.getGeocode());
cache.setLogOffline(false);
}
- database.execSQL(String.format("DELETE FROM %s where %s", dbTableLogsOffline, whereGeocodeIn(geocodes)));
+ database.execSQL(String.format("DELETE FROM %s where %s", dbTableLogsOffline, whereGeocodeIn(Geocache.getGeocodes(caches))));
}
public static boolean hasLogOffline(final String geocode) {
@@ -2544,7 +2547,7 @@ public class DataStore {
init();
try {
- final SQLiteStatement logCount = PreparedStatements.getLogCountOfGeocode();
+ final SQLiteStatement logCount = PreparedStatement.LOG_COUNT_OF_GEOCODE.getStatement();
synchronized (logCount) {
logCount.bindString(1, geocode);
return logCount.simpleQueryForLong() > 0;
@@ -2565,8 +2568,7 @@ public class DataStore {
database.beginTransaction();
try {
- final SQLiteStatement setVisit = PreparedStatements.getUpdateVisitDate();
-
+ final SQLiteStatement setVisit = PreparedStatement.UPDATE_VISIT_DATE.getStatement();
for (final String geocode : geocodes) {
setVisit.bindLong(1, visitedDate);
setVisit.bindString(2, geocode);
@@ -2584,7 +2586,7 @@ public class DataStore {
final Resources res = CgeoApplication.getInstance().getResources();
final List<StoredList> lists = new ArrayList<>();
- lists.add(new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatements.getCountCachesOnStandardList().simpleQueryForLong()));
+ lists.add(new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatement.COUNT_CACHES_ON_STANDARD_LIST.simpleQueryForLong()));
try {
final String query = "SELECT l._id as _id, l.title as title, COUNT(c._id) as count" +
@@ -2600,6 +2602,7 @@ public class DataStore {
return lists;
}
+ @NonNull
private static ArrayList<StoredList> getListsFromCursor(final Cursor cursor) {
final int indexId = cursor.getColumnIndex("_id");
final int indexTitle = cursor.getColumnIndex("title");
@@ -2613,6 +2616,7 @@ public class DataStore {
});
}
+ @NonNull
public static StoredList getList(final int id) {
init();
if (id >= customListIdOffset) {
@@ -2636,15 +2640,20 @@ public class DataStore {
}
// fall back to standard list in case of invalid list id
- if (id == StoredList.STANDARD_LIST_ID || id >= customListIdOffset) {
- return new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatements.getCountCachesOnStandardList().simpleQueryForLong());
- }
-
- return null;
+ return new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatement.COUNT_CACHES_ON_STANDARD_LIST.simpleQueryForLong());
}
public static int getAllCachesCount() {
- return (int) PreparedStatements.getCountAllCaches().simpleQueryForLong();
+ return (int) PreparedStatement.COUNT_ALL_CACHES.simpleQueryForLong();
+ }
+
+ /**
+ * Count all caches in the background.
+ *
+ * @return an observable containing a unique element if the caches could be counted, or an error otherwise
+ */
+ public static Observable<Integer> getAllCachesCountObservable() {
+ return allCachesCountObservable;
}
/**
@@ -2710,7 +2719,6 @@ public class DataStore {
/**
* Remove a list. Caches in the list are moved to the standard list.
*
- * @param listId
* @return true if the list got deleted, false else
*/
public static boolean removeList(final int listId) {
@@ -2727,7 +2735,7 @@ public class DataStore {
if (cnt > 0) {
// move caches from deleted list to standard list
- final SQLiteStatement moveToStandard = PreparedStatements.getMoveToStandardList();
+ final SQLiteStatement moveToStandard = PreparedStatement.MOVE_TO_STANDARD_LIST.getStatement();
moveToStandard.bindLong(1, listId);
moveToStandard.execute();
@@ -2759,7 +2767,7 @@ public class DataStore {
}
init();
- final SQLiteStatement move = PreparedStatements.getMoveToList();
+ final SQLiteStatement move = PreparedStatement.MOVE_TO_LIST.getStatement();
database.beginTransaction();
try {
@@ -2787,7 +2795,7 @@ public class DataStore {
database.beginTransaction();
try {
- database.delete(dbTableSearchDestionationHistory, "_id = " + destination.getId(), null);
+ database.delete(dbTableSearchDestinationHistory, "_id = " + destination.getId(), null);
database.setTransactionSuccessful();
return true;
} catch (final Exception e) {
@@ -2802,9 +2810,8 @@ public class DataStore {
/**
* Load the lazily initialized fields of a cache and return them as partial cache (all other fields unset).
*
- * @param geocode
- * @return
*/
+ @NonNull
public static Geocache loadCacheTexts(final String geocode) {
final Geocache partial = new Geocache();
@@ -2835,7 +2842,7 @@ public class DataStore {
}
cursor.close();
- } catch (final SQLiteDoneException e) {
+ } catch (final SQLiteDoneException ignored) {
// Do nothing, it only means we have no information on the cache
} catch (final Exception e) {
Log.e("DataStore.getCacheDescription", e);
@@ -2862,11 +2869,12 @@ public class DataStore {
* Creates the WHERE clause for matching multiple geocodes. This automatically converts all given codes to
* UPPERCASE.
*/
+ @NonNull
private static StringBuilder whereGeocodeIn(final Collection<String> geocodes) {
final StringBuilder whereExpr = new StringBuilder("geocode in (");
final Iterator<String> iterator = geocodes.iterator();
while (true) {
- whereExpr.append(DatabaseUtils.sqlEscapeString(StringUtils.upperCase(iterator.next())));
+ DatabaseUtils.appendEscapedSQLString(whereExpr, StringUtils.upperCase(iterator.next()));
if (!iterator.hasNext()) {
break;
}
@@ -2878,12 +2886,9 @@ public class DataStore {
/**
* Loads all Waypoints in the coordinate rectangle.
*
- * @param excludeDisabled
- * @param excludeMine
- * @param type
- * @return
*/
+ @NonNull
public static Set<Waypoint> loadWaypoints(final Viewport viewport, final boolean excludeMine, final boolean excludeDisabled, final CacheType type) {
final StringBuilder where = buildCoordinateWhere(dbTableWaypoints, viewport);
if (excludeMine) {
@@ -2914,103 +2919,71 @@ public class DataStore {
}
public static void saveChangedCache(final Geocache cache) {
- DataStore.saveCache(cache, cache.getStorageLocation().contains(StorageLocation.DATABASE) ? LoadFlags.SAVE_ALL : EnumSet.of(SaveFlag.CACHE));
+ DataStore.saveCache(cache, cache.inDatabase() ? LoadFlags.SAVE_ALL : EnumSet.of(SaveFlag.CACHE));
}
- private static class PreparedStatements {
-
- private static HashMap<String, SQLiteStatement> statements = new HashMap<>();
-
- public static SQLiteStatement getMoveToStandardList() {
- return getStatement("MoveToStandardList", "UPDATE " + dbTableCaches + " SET reason = " + StoredList.STANDARD_LIST_ID + " WHERE reason = ?");
- }
+ private static enum PreparedStatement {
- public static SQLiteStatement getMoveToList() {
- return getStatement("MoveToList", "UPDATE " + dbTableCaches + " SET reason = ? WHERE geocode = ?");
- }
+ HISTORY_COUNT("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE visiteddate > 0"),
+ MOVE_TO_STANDARD_LIST("UPDATE " + dbTableCaches + " SET reason = " + StoredList.STANDARD_LIST_ID + " WHERE reason = ?"),
+ MOVE_TO_LIST("UPDATE " + dbTableCaches + " SET reason = ? WHERE geocode = ?"),
+ UPDATE_VISIT_DATE("UPDATE " + dbTableCaches + " SET visiteddate = ? WHERE geocode = ?"),
+ INSERT_LOG_IMAGE("INSERT INTO " + dbTableLogImages + " (log_id, title, url) VALUES (?, ?, ?)"),
+ INSERT_LOG_COUNTS("INSERT INTO " + dbTableLogCount + " (geocode, updated, type, count) VALUES (?, ?, ?, ?)"),
+ INSERT_SPOILER("INSERT INTO " + dbTableSpoilers + " (geocode, updated, url, title, description) VALUES (?, ?, ?, ?, ?)"),
+ LOG_COUNT_OF_GEOCODE("SELECT count(_id) FROM " + DataStore.dbTableLogsOffline + " WHERE geocode = ?"),
+ COUNT_CACHES_ON_STANDARD_LIST("SELECT count(_id) FROM " + dbTableCaches + " WHERE reason = " + StoredList.STANDARD_LIST_ID),
+ COUNT_ALL_CACHES("SELECT count(_id) FROM " + dbTableCaches + " WHERE reason >= " + StoredList.STANDARD_LIST_ID),
+ INSERT_LOG("INSERT INTO " + dbTableLogs + " (geocode, updated, type, author, log, date, found, friend) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"),
+ INSERT_ATTRIBUTE("INSERT INTO " + dbTableAttributes + " (geocode, updated, attribute) VALUES (?, ?, ?)"),
+ LIST_ID_OF_GEOCODE("SELECT reason FROM " + dbTableCaches + " WHERE geocode = ?"),
+ LIST_ID_OF_GUID("SELECT reason FROM " + dbTableCaches + " WHERE guid = ?"),
+ GEOCODE_OF_GUID("SELECT geocode FROM " + dbTableCaches + " WHERE guid = ?"),
+ INSERT_SEARCH_DESTINATION("INSERT INTO " + dbTableSearchDestinationHistory + " (date, latitude, longitude) VALUES (?, ?, ?)"),
+ COUNT_TYPE_ALL_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND type = ? AND reason > 0"), // See use of COUNT_TYPE_LIST for synchronization
+ COUNT_ALL_TYPES_ALL_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND reason > 0"), // See use of COUNT_TYPE_LIST for synchronization
+ COUNT_TYPE_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND type = ? AND reason = ?"),
+ COUNT_ALL_TYPES_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND reason = ?"), // See use of COUNT_TYPE_LIST for synchronization
+ CHECK_IF_PRESENT("SELECT COUNT(*) FROM " + dbTableCaches + " WHERE geocode = ?");
- public static SQLiteStatement getUpdateVisitDate() {
- return getStatement("UpdateVisitDate", "UPDATE " + dbTableCaches + " SET visiteddate = ? WHERE geocode = ?");
- }
+ private static final List<PreparedStatement> statements = new ArrayList<>();
- public static SQLiteStatement getInsertLogImage() {
- return getStatement("InsertLogImage", "INSERT INTO " + dbTableLogImages + " (log_id, title, url) VALUES (?, ?, ?)");
- }
+ @Nullable
+ private volatile SQLiteStatement statement = null; // initialized lazily
+ final String query;
- public static SQLiteStatement getInsertLogCounts() {
- return getStatement("InsertLogCounts", "INSERT INTO " + dbTableLogCount + " (geocode, updated, type, count) VALUES (?, ?, ?, ?)");
+ PreparedStatement(final String query) {
+ this.query = query;
}
- public static SQLiteStatement getInsertSpoiler() {
- return getStatement("InsertSpoiler", "INSERT INTO " + dbTableSpoilers + " (geocode, updated, url, title, description) VALUES (?, ?, ?, ?, ?)");
+ public long simpleQueryForLong() {
+ return getStatement().simpleQueryForLong();
}
- public static SQLiteStatement getInsertSearchDestination(final Destination destination) {
- final SQLiteStatement statement = getStatement("InsertSearch", "INSERT INTO " + dbTableSearchDestionationHistory + " (date, latitude, longitude) VALUES (?, ?, ?)");
- statement.bindLong(1, destination.getDate());
- final Geopoint coords = destination.getCoords();
- statement.bindDouble(2, coords.getLatitude());
- statement.bindDouble(3, coords.getLongitude());
+ private SQLiteStatement getStatement() {
+ if (statement == null) {
+ synchronized (statements) {
+ if (statement == null) {
+ init();
+ statement = database.compileStatement(query);
+ statements.add(this);
+ }
+ }
+ }
return statement;
}
private static void clearPreparedStatements() {
- for (final SQLiteStatement statement : statements.values()) {
- statement.close();
+ for (final PreparedStatement preparedStatement : statements) {
+ final SQLiteStatement statement = preparedStatement.statement;
+ if (statement != null) {
+ statement.close();
+ preparedStatement.statement = null;
+ }
}
statements.clear();
}
- private static synchronized SQLiteStatement getStatement(final String key, final String query) {
- SQLiteStatement statement = statements.get(key);
- if (statement == null) {
- init();
- statement = database.compileStatement(query);
- statements.put(key, statement);
- }
- return statement;
- }
-
- public static SQLiteStatement getCountHistoryCaches() {
- return getStatement("HistoryCount", "select count(_id) from " + dbTableCaches + " where visiteddate > 0");
- }
-
- private static SQLiteStatement getLogCountOfGeocode() {
- return getStatement("LogCountFromGeocode", "SELECT count(_id) FROM " + DataStore.dbTableLogsOffline + " WHERE geocode = ?");
- }
-
- private static SQLiteStatement getCountCachesOnStandardList() {
- return getStatement("CountStandardList", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason = " + StoredList.STANDARD_LIST_ID);
- }
-
- private static SQLiteStatement getCountAllCaches() {
- return getStatement("CountAllLists", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason >= " + StoredList.STANDARD_LIST_ID);
- }
-
- private static SQLiteStatement getInsertLog() {
- return getStatement("InsertLog", "INSERT INTO " + dbTableLogs + " (geocode, updated, type, author, log, date, found, friend) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
- }
-
- private static SQLiteStatement getInsertAttribute() {
- return getStatement("InsertAttribute", "INSERT INTO " + dbTableAttributes + " (geocode, updated, attribute) VALUES (?, ?, ?)");
- }
-
- private static SQLiteStatement getListIdOfGeocode() {
- return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE geocode = ?");
- }
-
- private static SQLiteStatement getListIdOfGuid() {
- return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE guid = ?");
- }
-
- private static SQLiteStatement getCacheIdOfGeocode() {
- return getStatement("cacheIdFromGeocode", "SELECT cacheid FROM " + dbTableCaches + " WHERE geocode = ?");
- }
-
- private static SQLiteStatement getGeocodeOfGuid() {
- return getStatement("geocodeFromGuid", "SELECT geocode FROM " + dbTableCaches + " WHERE guid = ?");
- }
-
}
public static void saveVisitDate(final String geocode) {
@@ -3018,9 +2991,10 @@ public class DataStore {
}
public static void markDropped(final List<Geocache> caches) {
- moveToList(caches, StoredList.TEMPORARY_LIST_ID);
+ moveToList(caches, StoredList.TEMPORARY_LIST.id);
}
+ @Nullable
public static Viewport getBounds(final String geocode) {
if (geocode == null) {
return null;
@@ -3033,11 +3007,13 @@ public class DataStore {
setVisitDate(Arrays.asList(selected), 0);
}
+ @NonNull
public static SearchResult getBatchOfStoredCaches(final Geopoint coords, final CacheType cacheType, final int listId) {
final Set<String> geocodes = DataStore.loadBatchOfStoredGeocodes(coords, cacheType, listId);
return new SearchResult(geocodes, DataStore.getAllStoredCachesCount(cacheType, listId));
}
+ @NonNull
public static SearchResult getHistoryOfCaches(final boolean detailedOnly, final CacheType cacheType) {
final Set<String> geocodes = DataStore.loadBatchOfHistoricGeocodes(detailedOnly, cacheType);
return new SearchResult(geocodes, DataStore.getAllHistoryCachesCount());
@@ -3051,6 +3027,7 @@ public class DataStore {
return false;
}
+ @NonNull
public static Set<String> getCachedMissingFromSearch(final SearchResult searchResult, final Set<Tile> tiles, final IConnector connector, final int maxZoom) {
// get cached CacheListActivity
@@ -3081,6 +3058,7 @@ public class DataStore {
return missingFromSearch;
}
+ @Nullable
public static Cursor findSuggestions(final String searchTerm) {
// require 3 characters, otherwise there are to many results
if (StringUtils.length(searchTerm) < 3) {
@@ -3116,6 +3094,7 @@ public class DataStore {
cursor.close();
}
+ @NonNull
private static String getSuggestionArgument(final String input) {
return "%" + StringUtils.trim(input) + "%";
}
@@ -3143,6 +3122,7 @@ public class DataStore {
cursor.close();
}
+ @NonNull
public static String[] getSuggestions(final String table, final String column, final String input) {
try {
final Cursor cursor = database.rawQuery("SELECT DISTINCT " + column
@@ -3152,26 +3132,31 @@ public class DataStore {
return cursorToColl(cursor, new LinkedList<String>(), GET_STRING_0).toArray(new String[cursor.getCount()]);
} catch (final RuntimeException e) {
Log.e("cannot get suggestions from " + table + "->" + column + " for input '" + input + "'", e);
- return new String[0];
+ return ArrayUtils.EMPTY_STRING_ARRAY;
}
}
+ @NonNull
public static String[] getSuggestionsOwnerName(final String input) {
return getSuggestions(dbTableCaches, "owner_real", input);
}
+ @NonNull
public static String[] getSuggestionsTrackableCode(final String input) {
return getSuggestions(dbTableTrackables, "tbcode", input);
}
+ @NonNull
public static String[] getSuggestionsFinderName(final String input) {
return getSuggestions(dbTableLogs, "author", input);
}
+ @NonNull
public static String[] getSuggestionsGeocode(final String input) {
return getSuggestions(dbTableCaches, "geocode", input);
}
+ @NonNull
public static String[] getSuggestionsKeyword(final String input) {
return getSuggestions(dbTableCaches, "name", input);
}
@@ -3180,6 +3165,7 @@ public class DataStore {
*
* @return list of last caches opened in the details view, ordered by most recent first
*/
+ @NonNull
public static ArrayList<Geocache> getLastOpenedCaches() {
final List<String> geocodes = Settings.getLastOpenedCaches();
final Set<Geocache> cachesSet = DataStore.loadCaches(geocodes, LoadFlags.LOAD_CACHE_OR_DB);