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.
This commit is contained in:
parent
955c2f5f6c
commit
568224ba78
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
105
src/org/fdroid/fdroid/data/QueryBuilder.java
Normal file
105
src/org/fdroid/fdroid/data/QueryBuilder.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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()) {
|
||||
|
@ -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.
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user