Remove now-unneccesary "update" code from repo updater.
Now that we need only "insert" new apps rather than" * Identify if an app exists * If so, update * If not, insert There is much less code required for all of this stuff.
This commit is contained in:
parent
5bde27daa8
commit
e26748e0e0
@ -94,17 +94,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
return findApkFromAnyRepo(context, packageName, versionCode, signature, Cols.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all apks for a particular app, but limit it to those originating from the
|
||||
* specified repo.
|
||||
*/
|
||||
public static List<Apk> findByUri(Context context, Repo repo, List<App> apps, String[] projection) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
final Uri uri = getContentUriForApps(repo, apps);
|
||||
Cursor cursor = resolver.query(uri, projection, null, null, null);
|
||||
return cursorToList(cursor);
|
||||
}
|
||||
|
||||
public static Apk findApkFromAnyRepo(Context context, String packageName, int versionCode,
|
||||
@Nullable String signature, String[] projection) {
|
||||
final Uri uri = getApkFromAnyRepoUri(packageName, versionCode, signature);
|
||||
@ -137,36 +126,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
return cursorToList(cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns apks in the database, which have the same packageName and version as
|
||||
* one of the apks in the "apks" argument.
|
||||
*/
|
||||
public static List<Apk> knownApks(Context context, List<Apk> apks, String[] fields) {
|
||||
if (apks.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<Apk> knownApks = new ArrayList<>();
|
||||
if (apks.size() > ApkProvider.MAX_APKS_TO_QUERY) {
|
||||
int middle = apks.size() / 2;
|
||||
List<Apk> apks1 = apks.subList(0, middle);
|
||||
List<Apk> apks2 = apks.subList(middle, apks.size());
|
||||
knownApks.addAll(knownApks(context, apks1, fields));
|
||||
knownApks.addAll(knownApks(context, apks2, fields));
|
||||
} else {
|
||||
knownApks.addAll(knownApksSafe(context, apks, fields));
|
||||
}
|
||||
return knownApks;
|
||||
|
||||
}
|
||||
|
||||
private static List<Apk> knownApksSafe(final Context context, final List<Apk> apks, final String[] fields) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
final Uri uri = getContentUri(apks);
|
||||
Cursor cursor = resolver.query(uri, fields, null, null, null);
|
||||
return cursorToList(cursor);
|
||||
}
|
||||
|
||||
public static List<Apk> findByRepo(Context context, Repo repo, String[] fields) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
final Uri uri = getRepoUri(repo.getId());
|
||||
@ -206,9 +165,7 @@ public class ApkProvider extends FDroidProvider {
|
||||
private static final int CODE_PACKAGE = CODE_SINGLE + 1;
|
||||
private static final int CODE_REPO = CODE_PACKAGE + 1;
|
||||
private static final int CODE_APKS = CODE_REPO + 1;
|
||||
private static final int CODE_REPO_APPS = CODE_APKS + 1;
|
||||
protected static final int CODE_REPO_APK = CODE_REPO_APPS + 1;
|
||||
private static final int CODE_APK_ROW_ID = CODE_REPO_APK + 1;
|
||||
private static final int CODE_APK_ROW_ID = CODE_APKS + 1;
|
||||
static final int CODE_APK_FROM_ANY_REPO = CODE_APK_ROW_ID + 1;
|
||||
static final int CODE_APK_FROM_REPO = CODE_APK_FROM_ANY_REPO + 1;
|
||||
|
||||
@ -218,8 +175,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
private static final String PATH_APKS = "apks";
|
||||
private static final String PATH_APP = "app";
|
||||
private static final String PATH_REPO = "repo";
|
||||
private static final String PATH_REPO_APPS = "repo-apps";
|
||||
protected static final String PATH_REPO_APK = "repo-apk";
|
||||
private static final String PATH_APK_ROW_ID = "apk-rowId";
|
||||
|
||||
private static final UriMatcher MATCHER = new UriMatcher(-1);
|
||||
@ -238,8 +193,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
MATCHER.addURI(getAuthority(), PATH_APK_FROM_REPO + "/#/#", CODE_APK_FROM_REPO);
|
||||
MATCHER.addURI(getAuthority(), PATH_APKS + "/*", CODE_APKS);
|
||||
MATCHER.addURI(getAuthority(), PATH_APP + "/*", CODE_PACKAGE);
|
||||
MATCHER.addURI(getAuthority(), PATH_REPO_APPS + "/#/*", CODE_REPO_APPS);
|
||||
MATCHER.addURI(getAuthority(), PATH_REPO_APK + "/#/*", CODE_REPO_APK);
|
||||
MATCHER.addURI(getAuthority(), PATH_APK_ROW_ID + "/#", CODE_APK_ROW_ID);
|
||||
MATCHER.addURI(getAuthority(), null, CODE_LIST);
|
||||
}
|
||||
@ -293,51 +246,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Uri getContentUriForApps(Repo repo, List<App> apps) {
|
||||
return getContentUri()
|
||||
.buildUpon()
|
||||
.appendPath(PATH_REPO_APPS)
|
||||
.appendPath(Long.toString(repo.id))
|
||||
.appendPath(buildAppString(apps))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intentionally left protected because it will break if apks is larger than
|
||||
* {@link org.fdroid.fdroid.data.ApkProvider#MAX_APKS_TO_QUERY}. Instead of using
|
||||
* this directly, think about using
|
||||
* {@link ApkProvider.Helper#knownApks(android.content.Context, java.util.List, String[])}
|
||||
*/
|
||||
static Uri getContentUri(List<Apk> apks) {
|
||||
return getContentUri().buildUpon()
|
||||
.appendPath(PATH_APKS)
|
||||
.appendPath(buildApkString(apks))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected static String buildApkString(List<Apk> apks) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < apks.size(); i++) {
|
||||
if (i != 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
final Apk apk = apks.get(i);
|
||||
builder.append(apk.appId).append(':').append(apk.versionCode);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String buildAppString(List<App> apks) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < apks.size(); i++) {
|
||||
if (i != 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(apks.get(i).packageName);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableName() {
|
||||
return ApkTable.NAME;
|
||||
@ -470,10 +378,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
return new QuerySelection(selection, args);
|
||||
}
|
||||
|
||||
private QuerySelection queryRepoApps(long repoId, String packageNames) {
|
||||
return queryRepo(repoId).add(AppProvider.queryPackageNames(packageNames, "pkg." + PackageTable.Cols.PACKAGE_NAME));
|
||||
}
|
||||
|
||||
protected QuerySelection queryApks(String apkKeys) {
|
||||
return queryApks(apkKeys, true);
|
||||
}
|
||||
@ -547,11 +451,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
query = query.add(queryRepo(Long.parseLong(uri.getLastPathSegment())));
|
||||
break;
|
||||
|
||||
case CODE_REPO_APPS:
|
||||
List<String> pathSegments = uri.getPathSegments();
|
||||
query = query.add(queryRepoApps(Long.parseLong(pathSegments.get(1)), pathSegments.get(2)));
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Invalid URI for apk content provider: " + uri);
|
||||
throw new UnsupportedOperationException("Invalid URI for apk content provider: " + uri);
|
||||
@ -611,12 +510,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
query = query.add(queryApks(uri.getLastPathSegment(), false));
|
||||
break;
|
||||
|
||||
// TODO: Add tests for this.
|
||||
case CODE_REPO_APK:
|
||||
List<String> pathSegments = uri.getPathSegments();
|
||||
query = query.add(queryRepo(Long.parseLong(pathSegments.get(1)))).add(queryApks(pathSegments.get(2)));
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Invalid URI for apk content provider: " + uri);
|
||||
throw new UnsupportedOperationException("Invalid URI for apk content provider: " + uri);
|
||||
@ -633,10 +526,7 @@ public class ApkProvider extends FDroidProvider {
|
||||
if (MATCHER.match(uri) != CODE_APK_FROM_REPO) {
|
||||
throw new UnsupportedOperationException("Cannot update anything other than a single apk.");
|
||||
}
|
||||
return performUpdateUnchecked(uri, values, where, whereArgs);
|
||||
}
|
||||
|
||||
protected int performUpdateUnchecked(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
validateFields(Cols.ALL, values);
|
||||
removeFieldsFromOtherTables(values);
|
||||
|
||||
|
@ -7,7 +7,6 @@ import android.content.OperationApplicationException;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.fdroid.fdroid.CompatibilityChecker;
|
||||
import org.fdroid.fdroid.RepoUpdater;
|
||||
@ -18,7 +17,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class RepoPersister {
|
||||
|
||||
private static final String TAG = "RepoPersister";
|
||||
@ -84,7 +82,7 @@ public class RepoPersister {
|
||||
}
|
||||
|
||||
if (apksToSave.size() > 0 || appsToSave.size() > 0) {
|
||||
Utils.debugLog(TAG, "Flushing details of up to " + MAX_APP_BUFFER + " apps and their packages to the database.");
|
||||
Utils.debugLog(TAG, "Flushing details of up to " + MAX_APP_BUFFER + " apps/packages to the database.");
|
||||
Map<String, Long> appIds = flushAppsToDbInBatch();
|
||||
flushApksToDbInBatch(appIds);
|
||||
apksToSave.clear();
|
||||
@ -103,12 +101,7 @@ public class RepoPersister {
|
||||
|
||||
calcApkCompatibilityFlags(apksToSaveList);
|
||||
|
||||
ArrayList<ContentProviderOperation> apkOperations = new ArrayList<>();
|
||||
ContentProviderOperation clearOrphans = deleteOrphanedApks(appsToSave, apksToSave);
|
||||
if (clearOrphans != null) {
|
||||
apkOperations.add(clearOrphans);
|
||||
}
|
||||
apkOperations.addAll(insertOrUpdateApks(apksToSaveList));
|
||||
ArrayList<ContentProviderOperation> apkOperations = insertApks(apksToSaveList);
|
||||
|
||||
try {
|
||||
context.getContentResolver().applyBatch(TempApkProvider.getAuthority(), apkOperations);
|
||||
@ -123,7 +116,7 @@ public class RepoPersister {
|
||||
* can be returned and the relevant apks can be joined to the app table correctly.
|
||||
*/
|
||||
private Map<String, Long> flushAppsToDbInBatch() throws RepoUpdater.UpdateException {
|
||||
ArrayList<ContentProviderOperation> appOperations = insertOrUpdateApps(appsToSave);
|
||||
ArrayList<ContentProviderOperation> appOperations = insertApps(appsToSave);
|
||||
|
||||
try {
|
||||
context.getContentResolver().applyBatch(TempAppProvider.getAuthority(), appOperations);
|
||||
@ -144,7 +137,12 @@ public class RepoPersister {
|
||||
for (App app : apps) {
|
||||
packageNames.add(app.packageName);
|
||||
}
|
||||
String[] projection = {Schema.AppMetadataTable.Cols.ROW_ID, Schema.AppMetadataTable.Cols.Package.PACKAGE_NAME};
|
||||
|
||||
String[] projection = {
|
||||
Schema.AppMetadataTable.Cols.ROW_ID,
|
||||
Schema.AppMetadataTable.Cols.Package.PACKAGE_NAME,
|
||||
};
|
||||
|
||||
List<App> fromDb = TempAppProvider.Helper.findByPackageNames(context, packageNames, repo.id, projection);
|
||||
|
||||
Map<String, Long> ids = new HashMap<>(fromDb.size());
|
||||
@ -154,138 +152,27 @@ public class RepoPersister {
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on whether the {@link App}s have been added to the database previously, this
|
||||
* will queue up an update or an insert {@link ContentProviderOperation} for each app.
|
||||
*/
|
||||
private ArrayList<ContentProviderOperation> insertOrUpdateApps(List<App> apps) {
|
||||
private ArrayList<ContentProviderOperation> insertApps(List<App> apps) {
|
||||
ArrayList<ContentProviderOperation> operations = new ArrayList<>(apps.size());
|
||||
for (App app : apps) {
|
||||
/*if (isAppInDatabase(app)) {
|
||||
operations.add(updateExistingApp(app));
|
||||
} else {
|
||||
*/operations.add(insertNewApp(app));
|
||||
/*}*/
|
||||
ContentValues values = app.toContentValues();
|
||||
Uri uri = TempAppProvider.getContentUri();
|
||||
operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build());
|
||||
}
|
||||
return operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on whether the .apks have been added to the database previously, this
|
||||
* will queue up an update or an insert {@link ContentProviderOperation} for each package.
|
||||
*/
|
||||
private ArrayList<ContentProviderOperation> insertOrUpdateApks(List<Apk> packages) {
|
||||
/*String[] projection = new String[]{
|
||||
Schema.ApkTable.Cols.Package.PACKAGE_NAME,
|
||||
Schema.ApkTable.Cols.VERSION_CODE,
|
||||
Schema.ApkTable.Cols.REPO_ID,
|
||||
Schema.ApkTable.Cols.APP_ID,
|
||||
};
|
||||
List<Apk> existingApks = ApkProvider.Helper.knownApks(context, packages, projection);*/
|
||||
private ArrayList<ContentProviderOperation> insertApks(List<Apk> packages) {
|
||||
ArrayList<ContentProviderOperation> operations = new ArrayList<>(packages.size());
|
||||
for (Apk apk : packages) {
|
||||
/*boolean exists = false;
|
||||
for (Apk existing : existingApks) {
|
||||
if (existing.repoId == apk.repoId && existing.packageName.equals(apk.packageName) && existing.versionCode == apk.versionCode) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
operations.add(updateExistingApk(apk));
|
||||
} else {
|
||||
*/operations.add(insertNewApk(apk));
|
||||
/*}*/
|
||||
ContentValues values = apk.toContentValues();
|
||||
Uri uri = TempApkProvider.getContentUri();
|
||||
operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build());
|
||||
}
|
||||
|
||||
return operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an update {@link ContentProviderOperation} for the {@link App} in question.
|
||||
* <strong>Does not do any checks to see if the app already exists or not.</strong>
|
||||
*/
|
||||
private ContentProviderOperation updateExistingApp(App app) {
|
||||
Uri uri = TempAppProvider.getSpecificTempAppUri(app.packageName, app.repoId);
|
||||
return ContentProviderOperation.newUpdate(uri).withValues(app.toContentValues()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an insert {@link ContentProviderOperation} for the {@link App} in question.
|
||||
* <strong>Does not do any checks to see if the app already exists or not.</strong>
|
||||
*/
|
||||
private ContentProviderOperation insertNewApp(App app) {
|
||||
ContentValues values = app.toContentValues();
|
||||
Uri uri = TempAppProvider.getContentUri();
|
||||
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks in the database to see which apps we already know about. Only
|
||||
* returns ids of apps that are in the database if they are in the "apps"
|
||||
* array.
|
||||
*/
|
||||
private boolean isAppInDatabase(App app) {
|
||||
String[] fields = {Schema.AppMetadataTable.Cols.Package.PACKAGE_NAME};
|
||||
App found = AppProvider.Helper.findSpecificApp(context.getContentResolver(), app.packageName, repo.id, fields);
|
||||
return found != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an update {@link ContentProviderOperation} for the {@link Apk} in question.
|
||||
* <strong>Does not do any checks to see if the apk already exists or not.</strong>
|
||||
*/
|
||||
private ContentProviderOperation updateExistingApk(final Apk apk) {
|
||||
Uri uri = TempApkProvider.getApkUri(apk);
|
||||
ContentValues values = apk.toContentValues();
|
||||
return ContentProviderOperation.newUpdate(uri).withValues(values).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an insert {@link ContentProviderOperation} for the {@link Apk} in question.
|
||||
* <strong>Does not do any checks to see if the apk already exists or not.</strong>
|
||||
*/
|
||||
private ContentProviderOperation insertNewApk(final Apk apk) {
|
||||
ContentValues values = apk.toContentValues();
|
||||
Uri uri = TempApkProvider.getContentUri();
|
||||
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all apks from the repo we are currently updating, that belong to the specified app,
|
||||
* and delete them as they are no longer provided by that repo.
|
||||
*/
|
||||
@Nullable
|
||||
private ContentProviderOperation deleteOrphanedApks(List<App> apps, Map<String, List<Apk>> packages) {
|
||||
String[] projection = new String[]{Schema.ApkTable.Cols.Package.PACKAGE_NAME, Schema.ApkTable.Cols.VERSION_CODE};
|
||||
List<Apk> existing = ApkProvider.Helper.findByUri(context, repo, apps, projection);
|
||||
List<Apk> toDelete = new ArrayList<>();
|
||||
|
||||
for (Apk existingApk : existing) {
|
||||
boolean shouldStay = false;
|
||||
|
||||
if (packages.containsKey(existingApk.packageName)) {
|
||||
for (Apk newApk : packages.get(existingApk.packageName)) {
|
||||
if (newApk.versionCode == existingApk.versionCode) {
|
||||
shouldStay = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldStay) {
|
||||
toDelete.add(existingApk);
|
||||
}
|
||||
}
|
||||
|
||||
if (toDelete.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
Uri uri = TempApkProvider.getApksUri(repo, toDelete);
|
||||
return ContentProviderOperation.newDelete(uri).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This cannot be offloaded to the database (as we did with the query which
|
||||
* updates apps, depending on whether their apks are compatible or not).
|
||||
|
@ -9,8 +9,6 @@ import android.net.Uri;
|
||||
import org.fdroid.fdroid.data.Schema.ApkTable;
|
||||
import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class does all of its operations in a temporary sqlite table.
|
||||
*/
|
||||
@ -31,7 +29,6 @@ public class TempApkProvider extends ApkProvider {
|
||||
MATCHER.addURI(getAuthority(), PATH_INIT + "/#", CODE_INIT);
|
||||
MATCHER.addURI(getAuthority(), PATH_APK_FROM_ANY_REPO + "/#/*", CODE_APK_FROM_ANY_REPO);
|
||||
MATCHER.addURI(getAuthority(), PATH_APK_FROM_REPO + "/#/#", CODE_APK_FROM_REPO);
|
||||
MATCHER.addURI(getAuthority(), PATH_REPO_APK + "/#/*", CODE_REPO_APK);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -52,24 +49,6 @@ public class TempApkProvider extends ApkProvider {
|
||||
return Uri.parse("content://" + getAuthority());
|
||||
}
|
||||
|
||||
public static Uri getApkUri(Apk apk) {
|
||||
return getContentUri()
|
||||
.buildUpon()
|
||||
.appendPath(PATH_APK_FROM_REPO)
|
||||
.appendPath(Long.toString(apk.appId))
|
||||
.appendPath(Integer.toString(apk.versionCode))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Uri getApksUri(Repo repo, List<Apk> apks) {
|
||||
return getContentUri()
|
||||
.buildUpon()
|
||||
.appendPath(PATH_REPO_APK)
|
||||
.appendPath(Long.toString(repo.id))
|
||||
.appendPath(buildApkString(apks))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static class Helper {
|
||||
|
||||
/**
|
||||
@ -102,30 +81,12 @@ public class TempApkProvider extends ApkProvider {
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
if (MATCHER.match(uri) != CODE_APK_FROM_REPO) {
|
||||
throw new UnsupportedOperationException("Cannot update anything other than a single apk.");
|
||||
}
|
||||
|
||||
return performUpdateUnchecked(uri, values, where, whereArgs);
|
||||
throw new UnsupportedOperationException("Invalid URI for apk content provider: " + uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String where, String[] whereArgs) {
|
||||
if (MATCHER.match(uri) != CODE_REPO_APK) {
|
||||
throw new UnsupportedOperationException("Invalid URI for apk content provider: " + uri);
|
||||
}
|
||||
|
||||
List<String> pathSegments = uri.getPathSegments();
|
||||
QuerySelection query = new QuerySelection(where, whereArgs)
|
||||
.add(queryRepo(Long.parseLong(pathSegments.get(1)), false))
|
||||
.add(queryApks(pathSegments.get(2), false));
|
||||
|
||||
int rowsAffected = db().delete(getTableName(), query.getSelection(), query.getArgs());
|
||||
if (!isApplyingBatch()) {
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
}
|
||||
return rowsAffected;
|
||||
|
||||
throw new UnsupportedOperationException("Invalid URI for apk content provider: " + uri);
|
||||
}
|
||||
|
||||
private void initTable(long repoIdBeingUpdated) {
|
||||
|
@ -8,7 +8,6 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.ApkTable;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
|
||||
@ -67,19 +66,6 @@ public class TempAppProvider extends AppProvider {
|
||||
return Uri.parse("content://" + getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link AppProvider#getSpecificAppUri(String, long)}, except loads data from the temp
|
||||
* table being used during a repo update rather than the persistent table.
|
||||
*/
|
||||
public static Uri getSpecificTempAppUri(String packageName, long repoId) {
|
||||
return getContentUri()
|
||||
.buildUpon()
|
||||
.appendPath(PATH_SPECIFIC_APP)
|
||||
.appendPath(Long.toString(repoId))
|
||||
.appendPath(packageName)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Uri getAppsUri(List<String> apps, long repoId) {
|
||||
return getContentUri().buildUpon()
|
||||
.appendPath(PATH_APPS)
|
||||
@ -156,47 +142,7 @@ public class TempAppProvider extends AppProvider {
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
if (MATCHER.match(uri) != CODE_SINGLE) {
|
||||
throw new UnsupportedOperationException("Update not supported for " + uri + ".");
|
||||
}
|
||||
|
||||
if (values.containsKey(Cols.DESCRIPTION) && values.getAsString(Cols.DESCRIPTION) == null) {
|
||||
// the database does not let a description be set as null
|
||||
values.put(Cols.DESCRIPTION, "");
|
||||
}
|
||||
|
||||
List<String> pathParts = uri.getPathSegments();
|
||||
String packageName = pathParts.get(2);
|
||||
long repoId = Long.parseLong(pathParts.get(1));
|
||||
QuerySelection query = new QuerySelection(where, whereArgs).add(querySingleForUpdate(packageName, repoId));
|
||||
|
||||
// Package names for apps cannot change...
|
||||
values.remove(Cols.Package.PACKAGE_NAME);
|
||||
|
||||
if (values.containsKey(Cols.ForWriting.Categories.CATEGORIES)) {
|
||||
String[] categories = Utils.parseCommaSeparatedString(
|
||||
values.getAsString(Cols.ForWriting.Categories.CATEGORIES));
|
||||
ensureCategories(categories, packageName, repoId);
|
||||
values.remove(Cols.ForWriting.Categories.CATEGORIES);
|
||||
}
|
||||
|
||||
int count = db().update(getTableName(), values, query.getSelection(), query.getArgs());
|
||||
if (!isApplyingBatch()) {
|
||||
getContext().getContentResolver().notifyChange(getHighestPriorityMetadataUri(packageName), null);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void ensureCategories(String[] categories, String packageName, long repoId) {
|
||||
Query query = new AppProvider.Query();
|
||||
query.addField(Cols.ROW_ID);
|
||||
query.addSelection(querySingle(packageName, repoId));
|
||||
Cursor cursor = db().rawQuery(query.toString(), query.getArgs());
|
||||
cursor.moveToFirst();
|
||||
long appMetadataId = cursor.getLong(0);
|
||||
cursor.close();
|
||||
|
||||
ensureCategories(categories, appMetadataId);
|
||||
throw new UnsupportedOperationException("Update not supported for " + uri + ".");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -238,69 +238,6 @@ public class ApkProviderTest extends FDroidProviderTest {
|
||||
assertEquals(10, apk.repoId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKnownApks() {
|
||||
|
||||
App fdroid = Assert.ensureApp(context, "org.fdroid.fdroid");
|
||||
for (int i = 0; i < 7; i++) {
|
||||
Assert.insertApk(context, fdroid, i);
|
||||
}
|
||||
|
||||
App exampleOrg = Assert.ensureApp(context, "org.example");
|
||||
for (int i = 0; i < 9; i++) {
|
||||
Assert.insertApk(context, exampleOrg, i);
|
||||
}
|
||||
|
||||
App exampleCom = Assert.ensureApp(context, "com.example");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Assert.insertApk(context, exampleCom, i);
|
||||
}
|
||||
|
||||
App thingo = Assert.ensureApp(context, "com.apk.thingo");
|
||||
Assert.insertApk(context, thingo, 1);
|
||||
|
||||
Apk[] known = {
|
||||
new MockApk(fdroid, 1),
|
||||
new MockApk(fdroid, 3),
|
||||
new MockApk(fdroid, 5),
|
||||
|
||||
new MockApk(exampleCom, 1),
|
||||
new MockApk(exampleCom, 2),
|
||||
};
|
||||
|
||||
Apk[] unknown = {
|
||||
new MockApk(fdroid, 7),
|
||||
new MockApk(fdroid, 9),
|
||||
new MockApk(fdroid, 11),
|
||||
new MockApk(fdroid, 13),
|
||||
|
||||
new MockApk(exampleCom, 3),
|
||||
new MockApk(exampleCom, 4),
|
||||
new MockApk(exampleCom, 5),
|
||||
|
||||
new MockApk(-10, 1),
|
||||
new MockApk(-10, 2),
|
||||
};
|
||||
|
||||
List<Apk> apksToCheck = new ArrayList<>(known.length + unknown.length);
|
||||
Collections.addAll(apksToCheck, known);
|
||||
Collections.addAll(apksToCheck, unknown);
|
||||
|
||||
String[] projection = {
|
||||
Cols.Package.PACKAGE_NAME,
|
||||
Cols.APP_ID,
|
||||
Cols.VERSION_CODE,
|
||||
};
|
||||
|
||||
List<Apk> knownApks = ApkProvider.Helper.knownApks(context, apksToCheck, projection);
|
||||
|
||||
assertResultCount(known.length, knownApks);
|
||||
|
||||
for (Apk knownApk : knownApks) {
|
||||
assertContains(knownApks, knownApk);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindByApp() {
|
||||
|
||||
|
@ -23,6 +23,7 @@ public abstract class FDroidProviderTest {
|
||||
|
||||
@After
|
||||
public final void tearDownBase() {
|
||||
CategoryProvider.Helper.clearCategoryIdCache();
|
||||
FDroidProvider.clearDbHelperSingleton();
|
||||
}
|
||||
|
||||
|
@ -140,29 +140,7 @@ public class ProviderUriTests {
|
||||
assertValidUri(resolver, ApkProvider.getContentUri(), "content://org.fdroid.fdroid.data.ApkProvider", projection);
|
||||
assertValidUri(resolver, ApkProvider.getAppUri("org.fdroid.fdroid"), "content://org.fdroid.fdroid.data.ApkProvider/app/org.fdroid.fdroid", projection);
|
||||
assertValidUri(resolver, ApkProvider.getApkFromAnyRepoUri(new MockApk("org.fdroid.fdroid", 100)), "content://org.fdroid.fdroid.data.ApkProvider/apk-any-repo/100/org.fdroid.fdroid", projection);
|
||||
assertValidUri(resolver, ApkProvider.getContentUri(apks), projection);
|
||||
assertValidUri(resolver, ApkProvider.getApkFromAnyRepoUri("org.fdroid.fdroid", 100, null), "content://org.fdroid.fdroid.data.ApkProvider/apk-any-repo/100/org.fdroid.fdroid", projection);
|
||||
assertValidUri(resolver, ApkProvider.getRepoUri(1000), "content://org.fdroid.fdroid.data.ApkProvider/repo/1000", projection);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void invalidApkUrisWithTooManyApks() {
|
||||
String[] projection = Schema.ApkTable.Cols.ALL;
|
||||
|
||||
List<Apk> manyApks = new ArrayList<>(ApkProvider.MAX_APKS_TO_QUERY - 5);
|
||||
for (int i = 0; i < ApkProvider.MAX_APKS_TO_QUERY - 1; i++) {
|
||||
manyApks.add(new MockApk("com.example." + i, i));
|
||||
}
|
||||
assertValidUri(resolver, ApkProvider.getContentUri(manyApks), projection);
|
||||
|
||||
manyApks.add(new MockApk("org.fdroid.fdroid.1", 1));
|
||||
manyApks.add(new MockApk("org.fdroid.fdroid.2", 2));
|
||||
|
||||
// Technically, it is a valid URI, because it doesn't
|
||||
// throw an UnsupportedOperationException. However it
|
||||
// is still not okay (we run out of bindable parameters
|
||||
// in the sqlite query.
|
||||
assertValidUri(resolver, ApkProvider.getContentUri(manyApks), projection);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user