mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-31 21:41:33 +00:00
Clear DB on upgrade. Fix DB query for all folders.
This commit is contained in:
parent
4c711fd094
commit
d38a9d5275
7 changed files with 95 additions and 17 deletions
|
@ -16,6 +16,7 @@ import com.newsblur.fragment.FolderListFragment;
|
|||
import com.newsblur.fragment.LogoutDialogFragment;
|
||||
import com.newsblur.fragment.SyncUpdateFragment;
|
||||
import com.newsblur.service.SyncService;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.view.StateToggleButton.StateChangedListener;
|
||||
|
||||
public class Main extends NbFragmentActivity implements StateChangedListener, SyncUpdateFragment.SyncUpdateFragmentInterface {
|
||||
|
@ -29,6 +30,9 @@ public class Main extends NbFragmentActivity implements StateChangedListener, Sy
|
|||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
PrefsUtils.checkForUpgrade(this);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_PROGRESS);
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.newsblur.database;
|
|||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
|
||||
public class BlurDatabase extends SQLiteOpenHelper {
|
||||
|
|
|
@ -136,8 +136,17 @@ public class DatabaseConstants {
|
|||
FOLDER_TABLE + "." + FOLDER_ID, FOLDER_TABLE + "." + FOLDER_NAME, " SUM(" + FEED_POSITIVE_COUNT + ") AS " + SUM_POS, " SUM(" + FEED_NEUTRAL_COUNT + ") AS " + SUM_NEUT, " SUM(" + FEED_NEGATIVE_COUNT + ") AS " + SUM_NEG
|
||||
};
|
||||
|
||||
// this union clause lets folder queries also select the "root" folder that should appear whether or not it has unread stories
|
||||
private static final String FOLDER_UNION_ROOT = " OR " + DatabaseConstants.FOLDER_TABLE + "." + DatabaseConstants.FOLDER_NAME + "='" + AppConstants.ROOT_FOLDER + "'";
|
||||
// this union clause lets folder queries also select the "root" folder that should appear whether or not
|
||||
// it has unread stories. Note that this goes *before* the normal ALL_FOLDERS select statement. The zero-valued
|
||||
// pseudo-columns are safe because said columns are ignored for the root folder.
|
||||
public static final String FOLDER_UNION_ROOT = "SELECT " +
|
||||
FOLDER_ID + ", " +
|
||||
FOLDER_NAME +
|
||||
", 0 AS " + SUM_POS +
|
||||
", 0 AS " + SUM_NEUT +
|
||||
", 0 AS " + SUM_NEG +
|
||||
" FROM " + FOLDER_TABLE +
|
||||
" WHERE " + FOLDER_NAME + "='" + AppConstants.ROOT_FOLDER + "' UNION ";
|
||||
|
||||
private static final String FOLDER_INTELLIGENCE_ALL = " HAVING SUM(" + DatabaseConstants.FEED_NEGATIVE_COUNT + " + " + DatabaseConstants.FEED_NEUTRAL_COUNT + " + " + DatabaseConstants.FEED_POSITIVE_COUNT + ") >= 0";
|
||||
private static final String FOLDER_INTELLIGENCE_SOME = " HAVING SUM(" + DatabaseConstants.FEED_NEUTRAL_COUNT + " + " + DatabaseConstants.FEED_POSITIVE_COUNT + ") > 0";
|
||||
|
@ -186,19 +195,19 @@ public class DatabaseConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* Selection args to filter folders. This always additionally includes the root folder and assumes folders are joined with feed counts.
|
||||
* Selection args to filter folders.
|
||||
*/
|
||||
public static String getFolderSelectionFromState(int state) {
|
||||
String selection = null;
|
||||
switch (state) {
|
||||
case (AppConstants.STATE_ALL):
|
||||
selection = FOLDER_INTELLIGENCE_ALL + FOLDER_UNION_ROOT;
|
||||
selection = FOLDER_INTELLIGENCE_ALL;
|
||||
break;
|
||||
case (AppConstants.STATE_SOME):
|
||||
selection = FOLDER_INTELLIGENCE_SOME + FOLDER_UNION_ROOT;
|
||||
selection = FOLDER_INTELLIGENCE_SOME;
|
||||
break;
|
||||
case (AppConstants.STATE_BEST):
|
||||
selection = FOLDER_INTELLIGENCE_BEST + FOLDER_UNION_ROOT;
|
||||
selection = FOLDER_INTELLIGENCE_BEST;
|
||||
break;
|
||||
}
|
||||
return selection;
|
||||
|
|
|
@ -12,10 +12,18 @@ import android.util.Log;
|
|||
|
||||
import com.newsblur.util.AppConstants;
|
||||
|
||||
/**
|
||||
* A magic subclass of ContentProvider that enhances calls to the DB for presumably more simple caller syntax.
|
||||
*
|
||||
* TODO: the fact that most of the app uses this subclass of ContentProvider cast as such may
|
||||
* deepy confuse future maintainers as to why the methods within magically do far, far more
|
||||
* than suggested by the normal contract and provided args. When time and resources permit,
|
||||
* this paradigm could be replaced with a much more straightforward if slightly more verbose
|
||||
* use of Plain Old Raw Queries. Alternatively, the DB could be renormalized so that it is not
|
||||
* necessary to use queries of such intense complexity.
|
||||
*/
|
||||
public class FeedProvider extends ContentProvider {
|
||||
|
||||
private static final String TAG = "FeedProvider";
|
||||
|
||||
public static final String AUTHORITY = "com.newsblur";
|
||||
public static final String VERSION = "v1";
|
||||
|
||||
|
@ -67,7 +75,8 @@ public class FeedProvider extends ContentProvider {
|
|||
|
||||
private static UriMatcher uriMatcher;
|
||||
static {
|
||||
// TODO: Tidy this url-structure. It's not forward-facing but it's kind of a mess.
|
||||
// TODO: get rid of the hard-coded URL paths and replace then with the constant values in DatabaseConstants
|
||||
// that they actually represent.
|
||||
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
uriMatcher.addURI(AUTHORITY, VERSION + "/feeds/", ALL_FEEDS);
|
||||
uriMatcher.addURI(AUTHORITY, VERSION + "/social_feeds/", ALL_SOCIAL_FEEDS);
|
||||
|
@ -259,7 +268,7 @@ public class FeedProvider extends ContentProvider {
|
|||
break;
|
||||
|
||||
case UriMatcher.NO_MATCH:
|
||||
Log.e(TAG, "No match found for URI: " + uri.toString());
|
||||
Log.e(this.getClass().getName(), "No match found for URI: " + uri.toString());
|
||||
break;
|
||||
}
|
||||
return resultUri;
|
||||
|
@ -271,15 +280,28 @@ public class FeedProvider extends ContentProvider {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple utility wrapper that lets us log the insanely complex queries used below for debugging.
|
||||
*/
|
||||
class LoggingDatabase {
|
||||
SQLiteDatabase mdb;
|
||||
public LoggingDatabase(SQLiteDatabase db) {
|
||||
mdb = db;
|
||||
}
|
||||
public Cursor rawQuery(String sql, String[] selectionArgs) {
|
||||
//Log.d(LoggingDatabase.class.getName(), "rawQuery: " + sql);
|
||||
return mdb.rawQuery(sql, selectionArgs);
|
||||
}
|
||||
public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
|
||||
return mdb.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
|
||||
// TODO: the fact that most of the app uses this subclass of ContentProvider cast as such may
|
||||
// deepy confuse future maintainers as to why the .query() method magically does far, far more
|
||||
// than suggested by the normal contract and provided args. This method should be renamed
|
||||
// to make it painfully obvious that it expands upon the normal ContentProvider.query contract.
|
||||
|
||||
final SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
final SQLiteDatabase rdb = databaseHelper.getReadableDatabase();
|
||||
final LoggingDatabase db = new LoggingDatabase(rdb);
|
||||
switch (uriMatcher.match(uri)) {
|
||||
|
||||
// Query for all feeds (by default only return those that have unread items in them)
|
||||
|
@ -417,7 +439,9 @@ public class FeedProvider extends ContentProvider {
|
|||
|
||||
// Querying for all folders with unread items
|
||||
case ALL_FOLDERS:
|
||||
String folderQuery = "SELECT " + TextUtils.join(",", DatabaseConstants.FOLDER_COLUMNS) + " FROM " + DatabaseConstants.FEED_FOLDER_MAP_TABLE +
|
||||
// Note the extra special pre-select UNION clause here!
|
||||
String folderQuery = DatabaseConstants.FOLDER_UNION_ROOT +
|
||||
"SELECT " + TextUtils.join(",", DatabaseConstants.FOLDER_COLUMNS) + " FROM " + DatabaseConstants.FEED_FOLDER_MAP_TABLE +
|
||||
" INNER JOIN " + DatabaseConstants.FOLDER_TABLE +
|
||||
" ON " + DatabaseConstants.FEED_FOLDER_MAP_TABLE + "." + DatabaseConstants.FEED_FOLDER_FOLDER_NAME + " = " + DatabaseConstants.FOLDER_TABLE + "." + DatabaseConstants.FOLDER_NAME +
|
||||
" INNER JOIN " + DatabaseConstants.FEED_TABLE +
|
||||
|
|
|
@ -83,6 +83,13 @@ public class FeedFolderResponse {
|
|||
}
|
||||
socialFeeds = socialFeedsList.toArray(new SocialFeed[socialFeedsArray.size()]);
|
||||
}
|
||||
|
||||
// sometimes the API won't declare the top-level/root folder, but most of the
|
||||
// codebase expects it to exist. Declare it as empty if missing.
|
||||
if (!folders.containsKey(AppConstants.ROOT_FOLDER)) {
|
||||
folders.put(AppConstants.ROOT_FOLDER, new ArrayList<Long>());
|
||||
Log.d( this.getClass().getName(), "root folder was missing. added it.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,4 +17,6 @@ public class AppConstants {
|
|||
// the name to give the "root" folder in the local DB since the API does not assign it one.
|
||||
// this name should be unique and such that it will sort to the beginning of a list, ideally.
|
||||
public static final String ROOT_FOLDER = "0000_TOP_LEVEL_";
|
||||
|
||||
public static final String LAST_APP_VERSION = "LAST_APP_VERSION";
|
||||
}
|
||||
|
|
|
@ -11,9 +11,11 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.CompressFormat;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.util.Log;
|
||||
|
||||
import com.newsblur.activity.Login;
|
||||
import com.newsblur.database.BlurDatabase;
|
||||
|
@ -29,6 +31,35 @@ public class PrefsUtils {
|
|||
edit.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this is the first launch of the app after an upgrade, in which case
|
||||
* we clear the DB to prevent bugs associated with non-forward-compatibility.
|
||||
*/
|
||||
public static void checkForUpgrade(Context context) {
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
|
||||
|
||||
String version;
|
||||
try {
|
||||
version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
|
||||
} catch (NameNotFoundException nnfe) {
|
||||
Log.w(PrefsUtils.class.getName(), "could not determine app version");
|
||||
return;
|
||||
}
|
||||
Log.i(PrefsUtils.class.getName(), "launching version: " + version);
|
||||
|
||||
String oldVersion = prefs.getString(AppConstants.LAST_APP_VERSION, null);
|
||||
if ( (oldVersion == null) || (!oldVersion.equals(version)) ) {
|
||||
Log.i(PrefsUtils.class.getName(), "detected new version of app, clearing local data");
|
||||
// wipe the local DB
|
||||
BlurDatabase databaseHelper = new BlurDatabase(context.getApplicationContext());
|
||||
databaseHelper.dropAndRecreateTables();
|
||||
// store the current version
|
||||
prefs.edit().putString(AppConstants.LAST_APP_VERSION, version).commit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void logout(Context context) {
|
||||
|
||||
// TODO: stop or wait for any BG processes
|
||||
|
|
Loading…
Add table
Reference in a new issue