Added query for 'top X apps in category' and associated test
This commit is contained in:
parent
601c85103e
commit
a8d8e65698
@ -378,6 +378,7 @@ public class AppProvider extends FDroidProvider {
|
|||||||
private static final String PATH_HIGHEST_PRIORITY = "highestPriority";
|
private static final String PATH_HIGHEST_PRIORITY = "highestPriority";
|
||||||
private static final String PATH_CALC_PREFERRED_METADATA = "calcPreferredMetadata";
|
private static final String PATH_CALC_PREFERRED_METADATA = "calcPreferredMetadata";
|
||||||
private static final String PATH_CALC_SUGGESTED_APKS = "calcNonRepoDetailsFromIndex";
|
private static final String PATH_CALC_SUGGESTED_APKS = "calcNonRepoDetailsFromIndex";
|
||||||
|
private static final String PATH_TOP_FROM_CATEGORY = "topFromCategory";
|
||||||
|
|
||||||
private static final int CAN_UPDATE = CODE_SINGLE + 1;
|
private static final int CAN_UPDATE = CODE_SINGLE + 1;
|
||||||
private static final int INSTALLED = CAN_UPDATE + 1;
|
private static final int INSTALLED = CAN_UPDATE + 1;
|
||||||
@ -392,6 +393,7 @@ public class AppProvider extends FDroidProvider {
|
|||||||
private static final int SEARCH_CAN_UPDATE = SEARCH_INSTALLED + 1;
|
private static final int SEARCH_CAN_UPDATE = SEARCH_INSTALLED + 1;
|
||||||
private static final int HIGHEST_PRIORITY = SEARCH_CAN_UPDATE + 1;
|
private static final int HIGHEST_PRIORITY = SEARCH_CAN_UPDATE + 1;
|
||||||
private static final int CALC_PREFERRED_METADATA = HIGHEST_PRIORITY + 1;
|
private static final int CALC_PREFERRED_METADATA = HIGHEST_PRIORITY + 1;
|
||||||
|
private static final int TOP_FROM_CATEGORY = CALC_PREFERRED_METADATA + 1;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
MATCHER.addURI(getAuthority(), null, CODE_LIST);
|
MATCHER.addURI(getAuthority(), null, CODE_LIST);
|
||||||
@ -409,6 +411,7 @@ public class AppProvider extends FDroidProvider {
|
|||||||
MATCHER.addURI(getAuthority(), PATH_HIGHEST_PRIORITY + "/*", HIGHEST_PRIORITY);
|
MATCHER.addURI(getAuthority(), PATH_HIGHEST_PRIORITY + "/*", HIGHEST_PRIORITY);
|
||||||
MATCHER.addURI(getAuthority(), PATH_SPECIFIC_APP + "/#/*", CODE_SINGLE);
|
MATCHER.addURI(getAuthority(), PATH_SPECIFIC_APP + "/#/*", CODE_SINGLE);
|
||||||
MATCHER.addURI(getAuthority(), PATH_CALC_PREFERRED_METADATA, CALC_PREFERRED_METADATA);
|
MATCHER.addURI(getAuthority(), PATH_CALC_PREFERRED_METADATA, CALC_PREFERRED_METADATA);
|
||||||
|
MATCHER.addURI(getAuthority(), PATH_TOP_FROM_CATEGORY + "/#/*", TOP_FROM_CATEGORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri getContentUri() {
|
public static Uri getContentUri() {
|
||||||
@ -434,6 +437,14 @@ public class AppProvider extends FDroidProvider {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Uri getTopFromCategoryUri(String category, int limit) {
|
||||||
|
return getContentUri().buildUpon()
|
||||||
|
.appendPath(PATH_TOP_FROM_CATEGORY)
|
||||||
|
.appendPath(Integer.toString(limit))
|
||||||
|
.appendPath(category)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
public static Uri getInstalledUri() {
|
public static Uri getInstalledUri() {
|
||||||
return Uri.withAppendedPath(getContentUri(), PATH_INSTALLED);
|
return Uri.withAppendedPath(getContentUri(), PATH_INSTALLED);
|
||||||
}
|
}
|
||||||
@ -702,6 +713,8 @@ public class AppProvider extends FDroidProvider {
|
|||||||
// querying from.
|
// querying from.
|
||||||
boolean repoIsKnown = false;
|
boolean repoIsKnown = false;
|
||||||
|
|
||||||
|
int limit = 0;
|
||||||
|
|
||||||
switch (MATCHER.match(uri)) {
|
switch (MATCHER.match(uri)) {
|
||||||
case CALC_PREFERRED_METADATA:
|
case CALC_PREFERRED_METADATA:
|
||||||
updatePreferredMetadata();
|
updatePreferredMetadata();
|
||||||
@ -761,6 +774,13 @@ public class AppProvider extends FDroidProvider {
|
|||||||
includeSwap = false;
|
includeSwap = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOP_FROM_CATEGORY:
|
||||||
|
List<String> parts = uri.getPathSegments();
|
||||||
|
selection = selection.add(queryCategory(parts.get(2)));
|
||||||
|
limit = Integer.parseInt(parts.get(1));
|
||||||
|
includeSwap = false;
|
||||||
|
break;
|
||||||
|
|
||||||
case RECENTLY_UPDATED:
|
case RECENTLY_UPDATED:
|
||||||
sortOrder = getTableName() + "." + Cols.LAST_UPDATED + " DESC";
|
sortOrder = getTableName() + "." + Cols.LAST_UPDATED + " DESC";
|
||||||
selection = selection.add(queryRecentlyUpdated());
|
selection = selection.add(queryRecentlyUpdated());
|
||||||
@ -787,14 +807,14 @@ public class AppProvider extends FDroidProvider {
|
|||||||
selection = selection.add(queryHighestPriority());
|
selection = selection.add(queryHighestPriority());
|
||||||
}
|
}
|
||||||
|
|
||||||
return runQuery(uri, selection, projection, includeSwap, sortOrder);
|
return runQuery(uri, selection, projection, includeSwap, sortOrder, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method used by both the genuine {@link AppProvider} and the temporary version used
|
* Helper method used by both the genuine {@link AppProvider} and the temporary version used
|
||||||
* by the repo updater ({@link TempAppProvider}).
|
* by the repo updater ({@link TempAppProvider}).
|
||||||
*/
|
*/
|
||||||
protected Cursor runQuery(Uri uri, AppQuerySelection selection, String[] projection, boolean includeSwap, String sortOrder) {
|
protected Cursor runQuery(Uri uri, AppQuerySelection selection, String[] projection, boolean includeSwap, String sortOrder, int limit) {
|
||||||
if (!includeSwap) {
|
if (!includeSwap) {
|
||||||
selection = selection.add(queryExcludeSwap());
|
selection = selection.add(queryExcludeSwap());
|
||||||
}
|
}
|
||||||
@ -807,6 +827,7 @@ public class AppProvider extends FDroidProvider {
|
|||||||
query.addSelection(selection);
|
query.addSelection(selection);
|
||||||
query.addFields(projection); // TODO: Make the order of addFields/addSelection not dependent on each other...
|
query.addFields(projection); // TODO: Make the order of addFields/addSelection not dependent on each other...
|
||||||
query.addOrderBy(sortOrder);
|
query.addOrderBy(sortOrder);
|
||||||
|
query.addLimit(limit);
|
||||||
|
|
||||||
Cursor cursor = LoggingQuery.query(db(), query.toString(), query.getArgs());
|
Cursor cursor = LoggingQuery.query(db(), query.toString(), query.getArgs());
|
||||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||||
|
@ -14,6 +14,7 @@ abstract class QueryBuilder {
|
|||||||
private String selection;
|
private String selection;
|
||||||
private String[] selectionArgs;
|
private String[] selectionArgs;
|
||||||
private final List<OrderClause> orderBys = new ArrayList<>();
|
private final List<OrderClause> orderBys = new ArrayList<>();
|
||||||
|
private int limit = 0;
|
||||||
|
|
||||||
protected abstract String getRequiredTables();
|
protected abstract String getRequiredTables();
|
||||||
|
|
||||||
@ -88,6 +89,10 @@ abstract class QueryBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addLimit(int limit) {
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
public String[] getArgs() {
|
public String[] getArgs() {
|
||||||
List<String> args = new ArrayList<>();
|
List<String> args = new ArrayList<>();
|
||||||
|
|
||||||
@ -156,7 +161,11 @@ abstract class QueryBuilder {
|
|||||||
return tables.toString();
|
return tables.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String limitSql() {
|
||||||
|
return limit > 0 ? " LIMIT " + limit : "";
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SELECT " + distinctSql() + fieldsSql() + " FROM " + tablesSql() + whereSql() + groupBySql() + orderBySql();
|
return "SELECT " + distinctSql() + fieldsSql() + " FROM " + tablesSql() + whereSql() + groupBySql() + orderBySql() + limitSql();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ public class TempAppProvider extends AppProvider {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.runQuery(uri, selection, projection, true, sortOrder);
|
return super.runQuery(uri, selection, projection, true, sortOrder, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureTempTableDetached(SQLiteDatabase db) {
|
private void ensureTempTableDetached(SQLiteDatabase db) {
|
||||||
|
@ -88,6 +88,40 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
|||||||
AppProviderTest.assertContainsOnlyIds(apps, expectedPackages);
|
AppProviderTest.assertContainsOnlyIds(apps, expectedPackages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void topAppsFromCategory() {
|
||||||
|
insertAppWithCategory("com.dog", "Dog", "Animal");
|
||||||
|
insertAppWithCategory("com.cat", "Cat", "Animal");
|
||||||
|
insertAppWithCategory("com.bird", "Bird", "Animal");
|
||||||
|
insertAppWithCategory("com.snake", "Snake", "Animal");
|
||||||
|
insertAppWithCategory("com.rat", "Rat", "Animal");
|
||||||
|
|
||||||
|
insertAppWithCategory("com.rock", "Rock", "Mineral");
|
||||||
|
insertAppWithCategory("com.stone", "Stone", "Mineral");
|
||||||
|
insertAppWithCategory("com.boulder", "Boulder", "Mineral");
|
||||||
|
|
||||||
|
insertAppWithCategory("com.banana", "Banana", "Vegetable");
|
||||||
|
insertAppWithCategory("com.tomato", "Tomato", "Vegetable");
|
||||||
|
|
||||||
|
assertContainsOnly(topAppsFromCategory("Animal", 3), new String[] {"com.bird", "com.cat", "com.dog", });
|
||||||
|
assertContainsOnly(topAppsFromCategory("Animal", 2), new String[] {"com.bird", "com.cat", });
|
||||||
|
assertContainsOnly(topAppsFromCategory("Animal", 1), new String[] {"com.bird", });
|
||||||
|
|
||||||
|
assertContainsOnly(topAppsFromCategory("Mineral", 2), new String[] {"com.boulder", "com.rock", });
|
||||||
|
|
||||||
|
assertContainsOnly(topAppsFromCategory("Vegetable", 10), new String[] {"com.banana", "com.tomato", });
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] topAppsFromCategory(String category, int numToGet) {
|
||||||
|
List<App> apps = AppProvider.Helper.cursorToList(contentResolver.query(AppProvider.getTopFromCategoryUri(category, numToGet), Cols.ALL, null, null, Cols.NAME));
|
||||||
|
String[] packageNames = new String[apps.size()];
|
||||||
|
for (int i = 0; i < apps.size(); i++) {
|
||||||
|
packageNames[i] = apps.get(i).packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packageNames;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCategoriesSingle() {
|
public void testCategoriesSingle() {
|
||||||
insertAppWithCategory("com.dog", "Dog", "Animal");
|
insertAppWithCategory("com.dog", "Dog", "Animal");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user