From 568224ba787b2d178434d8bbc137e7bbfa498148 Mon Sep 17 00:00:00 2001 From: Peter Serwylo <peter@ivt.com.au> Date: Sat, 15 Feb 2014 20:57:18 +1100 Subject: [PATCH] s/curVersion/upstreamVersion/g, added suggestedVersion. Refactored QueryBuilder. In order to support suggested version, I didn't want to have both suggested version + versionCode in the App table. Rather, just the code, and then use that (and the apps id) to join onto the apk table. This is something we wanted to do elsewhere, so I refactored the QueryBuilder class from the ApkProvider so that it can also be used by the AppProvider. --- TODO-before-release.md | 6 - src/org/fdroid/fdroid/AppDetails.java | 16 +- src/org/fdroid/fdroid/RepoXMLHandler.java | 6 +- src/org/fdroid/fdroid/UpdateService.java | 11 +- src/org/fdroid/fdroid/data/ApkProvider.java | 68 ++------ src/org/fdroid/fdroid/data/App.java | 41 +++-- src/org/fdroid/fdroid/data/AppProvider.java | 147 ++++++++++++------ src/org/fdroid/fdroid/data/DBHelper.java | 7 +- src/org/fdroid/fdroid/data/QueryBuilder.java | 105 +++++++++++++ .../fdroid/fdroid/views/AppListAdapter.java | 6 +- .../views/fragments/AppListFragment.java | 6 +- 11 files changed, 272 insertions(+), 147 deletions(-) create mode 100644 src/org/fdroid/fdroid/data/QueryBuilder.java diff --git a/TODO-before-release.md b/TODO-before-release.md index e635a2463..bcca63f4e 100644 --- a/TODO-before-release.md +++ b/TODO-before-release.md @@ -3,9 +3,3 @@ These issues are a must-fix before the next stable release: * Right after updating a repo, `Recently Updated` shows the apps correctly but the new apks don't show up on App Details until the whole app is restarted (or until the repos are wiped and re-downloaded) - -* `App.curVersion` is now used in some places where before we used - `App.curApk.version`, which means that e.g. app lists now show the current - version at upstream and not the latest stable version in the repository - (highly misleading to users, who might end up looking for versions not in - the repo yet) diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 0cafa5e91..2e8f49867 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -128,7 +128,7 @@ public class AppDetails extends ListActivity { holder.version.setText(getString(R.string.version) + " " + apk.version - + (apk.vercode == app.curVercode ? " ☆" : "")); + + (apk.vercode == app.suggestedVercode ? " ☆" : "")); if (apk.vercode == app.getInstalledVerCode(getContext()) && mInstalledSigID != null && apk.sig != null @@ -534,7 +534,7 @@ public class AppDetails extends ListActivity { Apk curApk = null; for (int i = 0; i < adapter.getCount(); i ++) { Apk apk = adapter.getItem(i); - if (apk.vercode == app.curVercode) { + if (apk.vercode == app.suggestedVercode) { curApk = apk; break; } @@ -678,7 +678,7 @@ public class AppDetails extends ListActivity { } // Check count > 0 due to incompatible apps resulting in an empty list. - if (app.getInstalledVersion(this) == null && app.curVercode > 0 && + if (app.getInstalledVersion(this) == null && app.suggestedVercode > 0 && adapter.getCount() > 0) { MenuItemCompat.setShowAsAction(menu.add( Menu.NONE, INSTALL, 1, R.string.menu_install) @@ -716,7 +716,7 @@ public class AppDetails extends ListActivity { menu.add(Menu.NONE, IGNORETHIS, 2, R.string.menu_ignore_this) .setIcon(android.R.drawable.ic_menu_close_clear_cancel) .setCheckable(true) - .setChecked(app.ignoreThisUpdate >= app.curVercode); + .setChecked(app.ignoreThisUpdate >= app.suggestedVercode); } if (app.webURL.length() > 0) { menu.add(Menu.NONE, WEBSITE, 3, R.string.menu_website).setIcon( @@ -783,8 +783,8 @@ public class AppDetails extends ListActivity { case INSTALL: // Note that this handles updating as well as installing. - if (app.curVercode > 0) { - final Apk apkToInstall = ApkProvider.Helper.find(this, app.id, app.curVercode); + if (app.suggestedVercode > 0) { + final Apk apkToInstall = ApkProvider.Helper.find(this, app.id, app.suggestedVercode); install(apkToInstall); } return true; @@ -799,10 +799,10 @@ public class AppDetails extends ListActivity { return true; case IGNORETHIS: - if (app.ignoreThisUpdate >= app.curVercode) + if (app.ignoreThisUpdate >= app.suggestedVercode) app.ignoreThisUpdate = 0; else - app.ignoreThisUpdate = app.curVercode; + app.ignoreThisUpdate = app.suggestedVercode; item.setChecked(app.ignoreThisUpdate > 0); return true; diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index a123c70ed..1c7fb5009 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -226,12 +226,12 @@ public class RepoXMLHandler extends DefaultHandler { curapp.lastUpdated = null; } } else if (curel.equals("marketversion")) { - curapp.curVersion = str; + curapp.upstreamVersion = str; } else if (curel.equals("marketvercode")) { try { - curapp.curVercode = Integer.parseInt(str); + curapp.upstreamVercode = Integer.parseInt(str); } catch (NumberFormatException ex) { - curapp.curVercode = -1; + curapp.upstreamVercode = -1; } } else if (curel.equals("categories")) { curapp.categories = Utils.CommaSeparatedList.make(str); diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index dc3aa0711..bd53a2f36 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -400,19 +400,19 @@ public class UpdateService extends IntentService implements ProgressListener { private static void calcCurrentApkForApp(App app, List<Apk> apksForApp) { Apk latestApk = null; // Try and return the real current version first. It will find the - // closest version smaller than the curVercode, being the same + // closest version smaller than the upstreamVercode, being the same // vercode if it exists. - if (app.curVercode > 0) { + if (app.upstreamVercode > 0) { int latestcode = -1; for (Apk apk : apksForApp) { if ((!app.compatible || apk.compatible) - && apk.vercode <= app.curVercode + && apk.vercode <= app.upstreamVercode && apk.vercode > latestcode) { latestApk = apk; latestcode = apk.vercode; } } - } else if (app.curVercode == -1) { + } else if (app.upstreamVercode == -1) { // If the current version was not set we return the most recent apk. int latestCode = -1; for (Apk apk : apksForApp) { @@ -425,8 +425,7 @@ public class UpdateService extends IntentService implements ProgressListener { } if (latestApk != null) { - app.curVercode = latestApk.vercode; - app.curVersion = latestApk.version; + app.suggestedVercode = latestApk.vercode; } } diff --git a/src/org/fdroid/fdroid/data/ApkProvider.java b/src/org/fdroid/fdroid/data/ApkProvider.java index 0d070653f..8216c3c86 100644 --- a/src/org/fdroid/fdroid/data/ApkProvider.java +++ b/src/org/fdroid/fdroid/data/ApkProvider.java @@ -221,15 +221,16 @@ public class ApkProvider extends FDroidProvider { return matcher; } - private static class QueryBuilder { - - private StringBuilder fields = new StringBuilder(); - private StringBuilder tables = new StringBuilder(DBHelper.TABLE_APK + " AS apk"); - private String selection = null; - private String orderBy = null; + private static class Query extends QueryBuilder { private boolean repoTableRequired = false; + @Override + protected String getRequiredTables() { + return DBHelper.TABLE_APK + " AS apk"; + } + + @Override public void addField(String field) { if (REPO_FIELDS.containsKey(field)) { addRepoField(REPO_FIELDS.get(field), field); @@ -242,63 +243,14 @@ public class ApkProvider extends FDroidProvider { } } - public void addRepoField(String field, String alias) { + private void addRepoField(String field, String alias) { if (!repoTableRequired) { repoTableRequired = true; - tables.append(" LEFT JOIN "); - tables.append(DBHelper.TABLE_REPO); - tables.append(" AS repo ON (apk.repo = repo._id) "); + leftJoin(DBHelper.TABLE_REPO, "repo", "apk.repo = repo._id"); } appendField(field, "repo", alias); } - private void appendField(String field) { - appendField(field, null, null); - } - - private void appendField(String field, String tableAlias) { - appendField(field, tableAlias, null); - } - - private void appendField(String field, String tableAlias, - String fieldAlias) { - if (fields.length() != 0) { - fields.append(','); - } - - if (tableAlias != null) { - fields.append(tableAlias).append('.'); - } - - fields.append(field); - - if (fieldAlias != null) { - fields.append(" AS ").append(fieldAlias); - } - } - - public void addSelection(String selection) { - this.selection = selection; - } - - public void addOrderBy(String orderBy) { - this.orderBy = orderBy; - } - - @Override - public String toString() { - - StringBuilder suffix = new StringBuilder(); - if (selection != null) { - suffix.append(" WHERE ").append(selection); - } - - if (orderBy != null) { - suffix.append(" ORDER BY ").append(orderBy); - } - - return "SELECT " + fields + " FROM " + tables + suffix; - } } private QuerySelection queryApp(String appId) { @@ -377,7 +329,7 @@ public class ApkProvider extends FDroidProvider { throw new UnsupportedOperationException("Invalid URI for apk content provider: " + uri); } - QueryBuilder queryBuilder = new QueryBuilder(); + Query queryBuilder = new Query(); for (String field : projection) { queryBuilder.addField(field); } diff --git a/src/org/fdroid/fdroid/data/App.java b/src/org/fdroid/fdroid/data/App.java index cec9b452f..30688b21a 100644 --- a/src/org/fdroid/fdroid/data/App.java +++ b/src/org/fdroid/fdroid/data/App.java @@ -41,8 +41,18 @@ public class App extends ValueObject implements Comparable<App> { public String flattrID; - public String curVersion; - public int curVercode; + public String upstreamVersion; + public int upstreamVercode; + + /** + * Unlike other public fields, this is only accessible via a getter, to + * emphasise that setting it wont do anything. In order to change this, + * you need to change suggestedVercode to an apk which is in the apk table. + */ + private String suggestedVersion; + + public int suggestedVercode; + public Date added; public Date lastUpdated; @@ -114,10 +124,14 @@ public class App extends ValueObject implements Comparable<App> { dogecoinAddr = cursor.getString(i); } else if (column.equals(AppProvider.DataColumns.FLATTR_ID)) { flattrID = cursor.getString(i); - } else if (column.equals(AppProvider.DataColumns.CURRENT_VERSION)) { - curVersion = cursor.getString(i); - } else if (column.equals(AppProvider.DataColumns.CURRENT_VERSION_CODE)) { - curVercode = cursor.getInt(i); + } else if (column.equals(AppProvider.DataColumns.SuggestedApk.VERSION)) { + suggestedVersion = cursor.getString(i); + } else if (column.equals(AppProvider.DataColumns.SUGGESTED_VERSION_CODE)) { + suggestedVercode = cursor.getInt(i); + } else if (column.equals(AppProvider.DataColumns.UPSTREAM_VERSION_CODE)) { + upstreamVercode = cursor.getInt(i); + } else if (column.equals(AppProvider.DataColumns.UPSTREAM_VERSION)) { + upstreamVersion = cursor.getString(i); } else if (column.equals(AppProvider.DataColumns.ADDED)) { added = ValueObject.toDate(cursor.getString(i)); } else if (column.equals(AppProvider.DataColumns.LAST_UPDATED)) { @@ -158,8 +172,9 @@ public class App extends ValueObject implements Comparable<App> { values.put(AppProvider.DataColumns.FLATTR_ID, flattrID); values.put(AppProvider.DataColumns.ADDED, added == null ? "" : Utils.DATE_FORMAT.format(added)); values.put(AppProvider.DataColumns.LAST_UPDATED, added == null ? "" : Utils.DATE_FORMAT.format(lastUpdated)); - values.put(AppProvider.DataColumns.CURRENT_VERSION, curVersion); - values.put(AppProvider.DataColumns.CURRENT_VERSION_CODE, curVercode); + values.put(AppProvider.DataColumns.SUGGESTED_VERSION_CODE, suggestedVercode); + values.put(AppProvider.DataColumns.UPSTREAM_VERSION, upstreamVersion); + values.put(AppProvider.DataColumns.UPSTREAM_VERSION_CODE, upstreamVercode); values.put(AppProvider.DataColumns.CATEGORIES, Utils.CommaSeparatedList.str(categories)); values.put(AppProvider.DataColumns.ANTI_FEATURES, Utils.CommaSeparatedList.str(antiFeatures)); values.put(AppProvider.DataColumns.REQUIREMENTS, Utils.CommaSeparatedList.str(requirements)); @@ -207,9 +222,9 @@ public class App extends ValueObject implements Comparable<App> { */ public boolean hasUpdates(Context context) { boolean updates = false; - if (curVercode > 0) { + if (suggestedVercode > 0) { int installedVerCode = getInstalledVerCode(context); - updates = (installedVerCode > 0 && installedVerCode < curVercode); + updates = (installedVerCode > 0 && installedVerCode < suggestedVercode); } return updates; } @@ -218,7 +233,7 @@ public class App extends ValueObject implements Comparable<App> { // to be notified about them public boolean canAndWantToUpdate(Context context) { boolean canUpdate = hasUpdates(context); - boolean wantsUpdate = !ignoreAllUpdates && ignoreThisUpdate < curVercode; + boolean wantsUpdate = !ignoreAllUpdates && ignoreThisUpdate < suggestedVercode; return canUpdate && wantsUpdate && !isFiltered(); } @@ -227,4 +242,8 @@ public class App extends ValueObject implements Comparable<App> { public boolean isFiltered() { return new AppFilter().filter(this); } + + public String getSuggestedVersion() { + return suggestedVersion; + } } diff --git a/src/org/fdroid/fdroid/data/AppProvider.java b/src/org/fdroid/fdroid/data/AppProvider.java index f404df0c0..9475cfb62 100644 --- a/src/org/fdroid/fdroid/data/AppProvider.java +++ b/src/org/fdroid/fdroid/data/AppProvider.java @@ -60,7 +60,7 @@ public class AppProvider extends FDroidProvider { public static List<String> categories(Context context) { ContentResolver resolver = context.getContentResolver(); Uri uri = getContentUri(); - String[] projection = { "DISTINCT " + DataColumns.CATEGORIES }; + String[] projection = { DataColumns.CATEGORIES }; Cursor cursor = resolver.query(uri, projection, null, null, null ); Set<String> categorySet = new HashSet<String>(); if (cursor != null) { @@ -110,7 +110,7 @@ public class AppProvider extends FDroidProvider { public interface DataColumns { - public static final String _ID = "rowid as _id"; + public static final String _ID = "rowid as _id"; // Required for CursorLoaders public static final String _COUNT = "_count"; public static final String IS_COMPATIBLE = "compatible"; public static final String APP_ID = "id"; @@ -127,8 +127,9 @@ public class AppProvider extends FDroidProvider { public static final String LITECOIN_ADDR = "litecoinAddr"; public static final String DOGECOIN_ADDR = "dogecoinAddr"; public static final String FLATTR_ID = "flattrID"; - public static final String CURRENT_VERSION = "curVersion"; - public static final String CURRENT_VERSION_CODE = "curVercode"; + public static final String SUGGESTED_VERSION_CODE = "suggestedVercode"; + public static final String UPSTREAM_VERSION = "upstreamVersion"; + public static final String UPSTREAM_VERSION_CODE = "upstreamVercode"; public static final String CURRENT_APK = null; public static final String ADDED = "added"; public static final String LAST_UPDATED = "lastUpdated"; @@ -147,16 +148,73 @@ public class AppProvider extends FDroidProvider { public static final String UPDATED = null; public static final String APKS = null; + public interface SuggestedApk { + public static final String VERSION = "suggestedApkVersion"; + } + public static String[] ALL = { IS_COMPATIBLE, APP_ID, NAME, SUMMARY, ICON, DESCRIPTION, LICENSE, WEB_URL, TRACKER_URL, SOURCE_URL, DONATE_URL, BITCOIN_ADDR, LITECOIN_ADDR, DOGECOIN_ADDR, FLATTR_ID, - CURRENT_VERSION, CURRENT_VERSION_CODE, ADDED, LAST_UPDATED, + UPSTREAM_VERSION, UPSTREAM_VERSION_CODE, ADDED, LAST_UPDATED, CATEGORIES, ANTI_FEATURES, REQUIREMENTS, IGNORE_ALLUPDATES, - IGNORE_THISUPDATE, ICON_URL + IGNORE_THISUPDATE, ICON_URL, SUGGESTED_VERSION_CODE, + SuggestedApk.VERSION }; } + private static class Query extends QueryBuilder { + + private boolean isSuggestedApkTableAdded = false; + + private boolean categoryFieldAdded = false; + + @Override + protected String getRequiredTables() { + return DBHelper.TABLE_APP; + } + + @Override + protected boolean isDistinct() { + return fieldCount() == 1 && categoryFieldAdded; + } + + @Override + public void addField(String field) { + if (field.equals(DataColumns.SuggestedApk.VERSION)) { + addSuggestedApkVersionField(); + } else if (field.equals(DataColumns._COUNT)) { + appendCountField(); + } else { + if (field.equals(DataColumns.CATEGORIES)) { + categoryFieldAdded = true; + } + appendField(field, "fdroid_app"); + } + } + + private void appendCountField() { + appendField("COUNT(*) AS " + DataColumns._COUNT); + } + + private void addSuggestedApkVersionField() { + addSuggestedApkField( + ApkProvider.DataColumns.VERSION, + DataColumns.SuggestedApk.VERSION); + } + + private void addSuggestedApkField(String fieldName, String alias) { + if (!isSuggestedApkTableAdded) { + isSuggestedApkTableAdded = true; + leftJoin( + DBHelper.TABLE_APK, + "suggestedApk", + "fdroid_app.suggestedVercode = suggestedApk.vercode AND fdroid_app.id = suggestedApk.id"); + } + appendField(fieldName, "suggestedApk", alias); + } + } + private static final String PROVIDER_NAME = "AppProvider"; private static final UriMatcher matcher = new UriMatcher(-1); @@ -274,18 +332,18 @@ public class AppProvider extends FDroidProvider { private QuerySelection queryCanUpdate() { Map<String, PackageInfo> installedApps = Utils.getInstalledApps(getContext()); - String ignoreCurrent = " ignoreThisUpdate != curVercode "; - String ignoreAll = " ignoreAllUpdates != 1 "; + String ignoreCurrent = " fdroid_app.ignoreThisUpdate != fdroid_app.suggestedVercode "; + String ignoreAll = " fdroid_app.ignoreAllUpdates != 1 "; String ignore = " ( " + ignoreCurrent + " AND " + ignoreAll + " ) "; StringBuilder where = new StringBuilder( ignore + " AND ( 0 "); String[] selectionArgs = new String[installedApps.size() * 2]; int i = 0; for (PackageInfo info : installedApps.values() ) { - where.append(" OR ( ") - .append(AppProvider.DataColumns.APP_ID) - .append(" = ? AND ") - .append(DataColumns.CURRENT_VERSION_CODE) + where.append(" OR ( fdroid_app.") + .append(DataColumns.APP_ID) + .append(" = ? AND fdroid_app.") + .append(DataColumns.SUGGESTED_VERSION_CODE) .append(" > ?) "); selectionArgs[ i * 2 ] = info.packageName; selectionArgs[ i * 2 + 1 ] = Integer.toString(info.versionCode); @@ -302,7 +360,7 @@ public class AppProvider extends FDroidProvider { String[] selectionArgs = new String[installedApps.size()]; int i = 0; for (Map.Entry<String, PackageInfo> entry : installedApps.entrySet() ) { - where.append(" OR ") + where.append(" OR fdroid_app.") .append(AppProvider.DataColumns.APP_ID) .append(" = ? "); selectionArgs[i] = entry.getKey(); @@ -316,27 +374,29 @@ public class AppProvider extends FDroidProvider { private QuerySelection querySearch(String keywords) { keywords = "%" + keywords + "%"; String selection = - "id like ? OR " + - "name like ? OR " + - "summary like ? OR " + - "description like ? "; + "fdroid_app.id like ? OR " + + "fdroid_app.name like ? OR " + + "fdroid_app.summary like ? OR " + + "fdroid_app.description like ? "; String[] args = new String[] { keywords, keywords, keywords, keywords}; return new QuerySelection(selection, args); } + private QuerySelection querySingle(String id) { + String selection = "fdroid_app.id = ?"; + String[] args = { id }; + return new QuerySelection(selection, args); + } + private QuerySelection queryNewlyAdded() { - String selection = "added > ?"; - String[] args = new String[] { - Utils.DATE_FORMAT.format(Preferences.get().calcMaxHistory()) - }; + String selection = "fdroid_app.added > ?"; + String[] args = { Utils.DATE_FORMAT.format(Preferences.get().calcMaxHistory()) }; return new QuerySelection(selection, args); } private QuerySelection queryRecentlyUpdated() { - String selection = "added != lastUpdated AND lastUpdated > ?"; - String[] args = new String[] { - Utils.DATE_FORMAT.format(Preferences.get().calcMaxHistory()) - }; + String selection = "fdroid_app.added != fdroid_app.lastUpdated AND fdroid_app.lastUpdated > ?"; + String[] args = { Utils.DATE_FORMAT.format(Preferences.get().calcMaxHistory()) }; return new QuerySelection(selection, args); } @@ -344,11 +404,11 @@ public class AppProvider extends FDroidProvider { // TODO: In the future, add a new table for categories, // so we can join onto it. String selection = - " categories = ? OR " + // Only category e.g. "internet" - " categories LIKE ? OR " + // First category e.g. "internet,%" - " categories LIKE ? OR " + // Last category e.g. "%,internet" - " categories LIKE ? "; // One of many categories e.g. "%,internet,%" - String[] args = new String[] { + " fdroid_app.categories = ? OR " + // Only category e.g. "internet" + " fdroid_app.categories LIKE ? OR " + // First category e.g. "internet,%" + " fdroid_app.categories LIKE ? OR " + // Last category e.g. "%,internet" + " fdroid_app.categories LIKE ? "; // One of many categories e.g. "%,internet,%" + String[] args = { category, category + ",%", "%," + category, @@ -364,7 +424,7 @@ public class AppProvider extends FDroidProvider { private QuerySelection queryApps(String appIds) { String[] args = appIds.split(","); - String selection = "id IN (" + generateQuestionMarksForInClause(args.length) + ")"; + String selection = "fdroid_app.id IN (" + generateQuestionMarksForInClause(args.length) + ")"; return new QuerySelection(selection, args); } @@ -376,9 +436,7 @@ public class AppProvider extends FDroidProvider { break; case CODE_SINGLE: - query = query.add( - DataColumns.APP_ID + " = ?", - new String[] { uri.getLastPathSegment() } ); + query = query.add(querySingle(uri.getLastPathSegment())); break; case CAN_UPDATE: @@ -406,12 +464,12 @@ public class AppProvider extends FDroidProvider { break; case RECENTLY_UPDATED: - sortOrder = DataColumns.LAST_UPDATED + " DESC"; + sortOrder = " fdroid_app.lastUpdated DESC"; query = query.add(queryRecentlyUpdated()); break; case NEWLY_ADDED: - sortOrder = DataColumns.ADDED + " DESC"; + sortOrder = " fdroid_app.added DESC"; query = query.add(queryNewlyAdded()); break; @@ -421,18 +479,15 @@ public class AppProvider extends FDroidProvider { } if (AppProvider.DataColumns.NAME.equals(sortOrder)) { - sortOrder = " lower( " + sortOrder + " ) "; + sortOrder = " lower( fdroid_app." + sortOrder + " ) "; } - for (String field : projection) { - if (field.equals(DataColumns._COUNT)) { - projection = new String[] { "COUNT(*) AS " + DataColumns._COUNT }; - break; - } - } + Query q = new Query(); + q.addFields(projection); + q.addSelection(query.getSelection()); + q.addOrderBy(sortOrder); - Cursor cursor = read().query(getTableName(), projection, query.getSelection(), - query.getArgs(), null, null, sortOrder); + Cursor cursor = read().rawQuery(q.toString(), query.getArgs()); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } @@ -472,7 +527,7 @@ public class AppProvider extends FDroidProvider { switch (matcher.match(uri)) { case CODE_SINGLE: - query = query.add(new QuerySelection("id = ?", new String[] { uri.getLastPathSegment()})); + query = query.add(querySingle(uri.getLastPathSegment())); break; default: diff --git a/src/org/fdroid/fdroid/data/DBHelper.java b/src/org/fdroid/fdroid/data/DBHelper.java index 2a531362f..43a435efd 100644 --- a/src/org/fdroid/fdroid/data/DBHelper.java +++ b/src/org/fdroid/fdroid/data/DBHelper.java @@ -67,8 +67,9 @@ public class DBHelper extends SQLiteOpenHelper { + "webURL text, " + "trackerURL text, " + "sourceURL text, " - + "curVersion text," - + "curVercode integer," + + "suggestedVercode text," + + "upstreamVersion text," + + "upstreamVercode integer," + "antiFeatures string," + "donateURL string," + "bitcoinAddr string," @@ -85,7 +86,7 @@ public class DBHelper extends SQLiteOpenHelper { + "iconUrl text, " + "primary key(id));"; - private static final int DB_VERSION = 40; + private static final int DB_VERSION = 41; private Context context; diff --git a/src/org/fdroid/fdroid/data/QueryBuilder.java b/src/org/fdroid/fdroid/data/QueryBuilder.java new file mode 100644 index 000000000..6c988efc0 --- /dev/null +++ b/src/org/fdroid/fdroid/data/QueryBuilder.java @@ -0,0 +1,105 @@ +package org.fdroid.fdroid.data; + +import java.util.ArrayList; +import java.util.List; + +abstract class QueryBuilder { + + private List<String> fields = new ArrayList<String>(); + private StringBuilder tables = new StringBuilder(getRequiredTables()); + private String selection = null; + private String orderBy = null; + + protected abstract String getRequiredTables(); + + public abstract void addField(String field); + + protected int fieldCount() { + return fields.size(); + } + + public void addFields(String[] fields) { + for (String field : fields) { + addField(field); + } + } + + protected boolean isDistinct() { + return false; + } + + protected void appendField(String field) { + appendField(field, null, null); + } + + protected void appendField(String field, String tableAlias) { + appendField(field, tableAlias, null); + } + + protected final void appendField(String field, String tableAlias, + String fieldAlias) { + + StringBuilder fieldBuilder = new StringBuilder(); + + if (tableAlias != null) { + fieldBuilder.append(tableAlias).append('.'); + } + + fieldBuilder.append(field); + + if (fieldAlias != null) { + fieldBuilder.append(" AS ").append(fieldAlias); + } + + fields.add(fieldBuilder.toString()); + } + + public void addSelection(String selection) { + this.selection = selection; + } + + public void addOrderBy(String orderBy) { + this.orderBy = orderBy; + } + + protected final void leftJoin(String table, String alias, + String condition) { + tables.append(" LEFT JOIN "); + tables.append(table); + if (alias != null) { + tables.append(" AS "); + tables.append(alias); + } + tables.append(" ON ("); + tables.append(condition); + tables.append(")"); + } + + private String fieldsSql() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < fields.size(); i ++) { + if (i > 0) { + sb.append(','); + } + sb.append(fields.get(i)); + } + return sb.toString(); + } + + private String whereSql() { + return selection != null ? " WHERE " + selection : ""; + } + + private String orderBySql() { + return orderBy != null ? " ORDER BY " + orderBy : ""; + } + + private String tablesSql() { + return tables.toString(); + } + + public String toString() { + String distinct = isDistinct() ? " DISTINCT " : ""; + return "SELECT " + distinct + fieldsSql() + " FROM " + tablesSql() + whereSql() + orderBySql(); + } +} diff --git a/src/org/fdroid/fdroid/views/AppListAdapter.java b/src/org/fdroid/fdroid/views/AppListAdapter.java index 5659283fd..ca0336d87 100644 --- a/src/org/fdroid/fdroid/views/AppListAdapter.java +++ b/src/org/fdroid/fdroid/views/AppListAdapter.java @@ -130,14 +130,14 @@ abstract public class AppListAdapter extends CursorAdapter { private String getVersionInfo(App app) { - if (app.curVercode <= 0) { + if (app.suggestedVercode <= 0) { return null; } PackageInfo installedInfo = app.getInstalledInfo(mContext); if (installedInfo == null) { - return ellipsize(app.curVersion, 12); + return ellipsize(app.getSuggestedVersion(), 12); } String installedVersionString = installedInfo.versionName; @@ -145,7 +145,7 @@ abstract public class AppListAdapter extends CursorAdapter { if (app.canAndWantToUpdate(mContext) && showStatusUpdate()) { return ellipsize(installedVersionString, 8) + - " → " + ellipsize(app.curVersion, 8); + " → " + ellipsize(app.getSuggestedVersion(), 8); } if (installedVersionCode > 0 && showStatusInstalled()) { diff --git a/src/org/fdroid/fdroid/views/fragments/AppListFragment.java b/src/org/fdroid/fdroid/views/fragments/AppListFragment.java index 3ad2c08a3..b3f2a91a4 100644 --- a/src/org/fdroid/fdroid/views/fragments/AppListFragment.java +++ b/src/org/fdroid/fdroid/views/fragments/AppListFragment.java @@ -27,7 +27,7 @@ abstract public class AppListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> { public static final String[] APP_PROJECTION = { - AppProvider.DataColumns._ID, + AppProvider.DataColumns._ID, // Required for cursor loader to work. AppProvider.DataColumns.APP_ID, AppProvider.DataColumns.NAME, AppProvider.DataColumns.SUMMARY, @@ -35,8 +35,8 @@ abstract public class AppListFragment extends ListFragment implements AppProvider.DataColumns.LICENSE, AppProvider.DataColumns.ICON, AppProvider.DataColumns.ICON_URL, - AppProvider.DataColumns.CURRENT_VERSION, - AppProvider.DataColumns.CURRENT_VERSION_CODE, + AppProvider.DataColumns.SuggestedApk.VERSION, + AppProvider.DataColumns.SUGGESTED_VERSION_CODE, AppProvider.DataColumns.REQUIREMENTS, // Needed for filtering apps that require root. }; -- GitLab