Clarify some of the database stuff around database providers.
Includes: * One of the functions querying for apps did not correctly specify the repository the repos came from. * Fix deletion code which refered to incorrect field. * Cleanup code style in some places.
This commit is contained in:
parent
f2a58ad67f
commit
01b8f7f4bf
@ -424,7 +424,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
"You tried to query " + apkDetails.length);
|
||||
}
|
||||
String alias = includeAlias ? "apk." : "";
|
||||
String metadataAlias = includeAlias ? "app." : "";
|
||||
final String[] args = new String[apkDetails.length * 2];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < apkDetails.length; i++) {
|
||||
@ -436,12 +435,24 @@ public class ApkProvider extends FDroidProvider {
|
||||
if (i != 0) {
|
||||
sb.append(" OR ");
|
||||
}
|
||||
sb.append(" ( ")
|
||||
.append(metadataAlias)
|
||||
.append(AppMetadataTable.Cols.PACKAGE_ID)
|
||||
.append(" = (")
|
||||
.append(getPackageIdFromPackageNameQuery())
|
||||
.append(") AND ")
|
||||
sb.append(" ( ");
|
||||
|
||||
if (includeAlias) {
|
||||
// This is the simpler way to figure out the package name of a row in the apk table.
|
||||
// It requires slightly less work for sqlite3 than the alternative below.
|
||||
sb.append("app.")
|
||||
.append(AppMetadataTable.Cols.PACKAGE_ID)
|
||||
.append(" = (")
|
||||
.append(getPackageIdFromPackageNameQuery())
|
||||
.append(") ");
|
||||
} else {
|
||||
sb.append(Cols.APP_ID)
|
||||
.append(" IN (")
|
||||
.append(getMetadataIdFromPackageNameQuery())
|
||||
.append(")");
|
||||
}
|
||||
|
||||
sb.append(" AND ")
|
||||
.append(alias)
|
||||
.append(Cols.VERSION_CODE)
|
||||
.append(" = ? ) ");
|
||||
|
@ -155,6 +155,10 @@ public class AppProvider extends FDroidProvider {
|
||||
return cursorToApp(resolver.query(uri, projection, null, null, null));
|
||||
}
|
||||
|
||||
public static App findSpecificApp(ContentResolver resolver, String packageName, long repoId) {
|
||||
return findSpecificApp(resolver, packageName, repoId, Cols.ALL);
|
||||
}
|
||||
|
||||
private static App cursorToApp(Cursor cursor) {
|
||||
App app = null;
|
||||
if (cursor != null) {
|
||||
@ -434,7 +438,7 @@ public class AppProvider extends FDroidProvider {
|
||||
private static final String PATH_SEARCH_REPO = "searchRepo";
|
||||
private static final String PATH_NO_APKS = "noApks";
|
||||
protected static final String PATH_APPS = "apps";
|
||||
protected static final String PATH_APP = "app";
|
||||
protected static final String PATH_SPECIFIC_APP = "app";
|
||||
private static final String PATH_RECENTLY_UPDATED = "recentlyUpdated";
|
||||
private static final String PATH_NEWLY_ADDED = "newlyAdded";
|
||||
private static final String PATH_CATEGORY = "category";
|
||||
@ -471,7 +475,7 @@ public class AppProvider extends FDroidProvider {
|
||||
MATCHER.addURI(getAuthority(), PATH_INSTALLED, INSTALLED);
|
||||
MATCHER.addURI(getAuthority(), PATH_NO_APKS, NO_APKS);
|
||||
MATCHER.addURI(getAuthority(), PATH_HIGHEST_PRIORITY + "/*", HIGHEST_PRIORITY);
|
||||
MATCHER.addURI(getAuthority(), PATH_APP + "/#/*", CODE_SINGLE);
|
||||
MATCHER.addURI(getAuthority(), PATH_SPECIFIC_APP + "/#/*", CODE_SINGLE);
|
||||
}
|
||||
|
||||
public static Uri getContentUri() {
|
||||
@ -528,7 +532,7 @@ public class AppProvider extends FDroidProvider {
|
||||
public static Uri getSpecificAppUri(String packageName, long repoId) {
|
||||
return getContentUri()
|
||||
.buildUpon()
|
||||
.appendPath(PATH_APP)
|
||||
.appendPath(PATH_SPECIFIC_APP)
|
||||
.appendPath(Long.toString(repoId))
|
||||
.appendPath(packageName)
|
||||
.build();
|
||||
|
@ -158,7 +158,11 @@ public abstract class FDroidProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
protected String getPackageIdFromPackageNameQuery() {
|
||||
/**
|
||||
* Helper function to be used when you need to know the primary key from the package table
|
||||
* when all you have is the package name.
|
||||
*/
|
||||
protected static String getPackageIdFromPackageNameQuery() {
|
||||
return "SELECT " + Schema.PackageTable.Cols.ROW_ID + " FROM " + Schema.PackageTable.NAME + " WHERE " + Schema.PackageTable.Cols.PACKAGE_NAME + " = ?";
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,12 @@ import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable;
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable.Cols;
|
||||
|
||||
public class PackageProvider extends FDroidProvider {
|
||||
|
||||
private static final String TAG = "PackageProvider";
|
||||
|
||||
public static final class Helper {
|
||||
private Helper() { }
|
||||
|
||||
@ -126,18 +123,13 @@ public class PackageProvider extends FDroidProvider {
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
QuerySelection selection = new QuerySelection(customSelection, selectionArgs);
|
||||
|
||||
switch (MATCHER.match(uri)) {
|
||||
case CODE_SINGLE:
|
||||
selection = selection.add(querySingle(uri.getLastPathSegment()));
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Invalid URI for content provider: " + uri);
|
||||
throw new UnsupportedOperationException("Invalid URI for content provider: " + uri);
|
||||
if (MATCHER.match(uri) != CODE_SINGLE) {
|
||||
throw new UnsupportedOperationException("Invalid URI for content provider: " + uri);
|
||||
}
|
||||
|
||||
QuerySelection selection = new QuerySelection(customSelection, selectionArgs)
|
||||
.add(querySingle(uri.getLastPathSegment()));
|
||||
|
||||
Query query = new Query();
|
||||
query.addSelection(selection);
|
||||
query.addFields(projection);
|
||||
@ -152,7 +144,7 @@ public class PackageProvider extends FDroidProvider {
|
||||
* Deleting of packages is not required.
|
||||
* It doesn't matter if we have a package name in the database after the package is no longer
|
||||
* present in the repo any more. They wont take up much space, and it is the presence of rows
|
||||
* in the {@link Schema.MetadataTable} which decides whether something is available in the
|
||||
* in the {@link Schema.AppMetadataTable} which decides whether something is available in the
|
||||
* F-Droid client or not.
|
||||
*/
|
||||
@Override
|
||||
@ -167,6 +159,10 @@ public class PackageProvider extends FDroidProvider {
|
||||
return getPackageIdUri(rowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Package names never change. If a package name has changed, then that means that it is a
|
||||
* new app all together as far as Android is concerned.
|
||||
*/
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
throw new UnsupportedOperationException("Update not supported for " + uri + ".");
|
||||
|
@ -144,7 +144,7 @@ public class RepoPersister {
|
||||
packageNames.add(app.packageName);
|
||||
}
|
||||
String[] projection = {Schema.AppMetadataTable.Cols.ROW_ID, Schema.AppMetadataTable.Cols.Package.PACKAGE_NAME};
|
||||
List<App> fromDb = TempAppProvider.Helper.findByPackageNames(context, packageNames, projection);
|
||||
List<App> fromDb = TempAppProvider.Helper.findByPackageNames(context, packageNames, repo.id, projection);
|
||||
|
||||
Map<String, Long> ids = new HashMap<>(fromDb.size());
|
||||
for (App app : fromDb) {
|
||||
@ -205,7 +205,7 @@ public class RepoPersister {
|
||||
* <strong>Does not do any checks to see if the app already exists or not.</strong>
|
||||
*/
|
||||
private ContentProviderOperation updateExistingApp(App app) {
|
||||
Uri uri = TempAppProvider.getAppUri(app.packageName, app.repoId);
|
||||
Uri uri = TempAppProvider.getSpecificTempAppUri(app.packageName, app.repoId);
|
||||
return ContentProviderOperation.newUpdate(uri).withValues(app.toContentValues()).build();
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import java.util.List;
|
||||
|
||||
import org.fdroid.fdroid.data.Schema.ApkTable;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable;
|
||||
|
||||
/**
|
||||
@ -41,8 +42,8 @@ public class TempAppProvider extends AppProvider {
|
||||
static {
|
||||
MATCHER.addURI(getAuthority(), PATH_INIT, CODE_INIT);
|
||||
MATCHER.addURI(getAuthority(), PATH_COMMIT, CODE_COMMIT);
|
||||
MATCHER.addURI(getAuthority(), PATH_APPS + "/*", APPS);
|
||||
MATCHER.addURI(getAuthority(), PATH_APP + "/#/*", CODE_SINGLE);
|
||||
MATCHER.addURI(getAuthority(), PATH_APPS + "/#/*", APPS);
|
||||
MATCHER.addURI(getAuthority(), PATH_SPECIFIC_APP + "/#/*", CODE_SINGLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -58,24 +59,36 @@ public class TempAppProvider extends AppProvider {
|
||||
return Uri.parse("content://" + getAuthority());
|
||||
}
|
||||
|
||||
public static Uri getAppUri(String packageName, long repoId) {
|
||||
/**
|
||||
* 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_APP)
|
||||
.appendPath(PATH_SPECIFIC_APP)
|
||||
.appendPath(Long.toString(repoId))
|
||||
.appendPath(packageName)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Uri getAppsUri(List<String> apps) {
|
||||
public static Uri getAppsUri(List<String> apps, long repoId) {
|
||||
return getContentUri().buildUpon()
|
||||
.appendPath(PATH_APPS)
|
||||
.appendPath(Long.toString(repoId))
|
||||
.appendPath(TextUtils.join(",", apps))
|
||||
.build();
|
||||
}
|
||||
|
||||
private AppQuerySelection queryApps(String packageNames) {
|
||||
return queryPackageNames(packageNames, PackageTable.NAME + "." + PackageTable.Cols.PACKAGE_NAME);
|
||||
private AppQuerySelection queryRepoApps(long repoId, String packageNames) {
|
||||
return queryPackageNames(packageNames, PackageTable.NAME + "." + PackageTable.Cols.PACKAGE_NAME)
|
||||
.add(queryRepo(repoId));
|
||||
}
|
||||
|
||||
private AppQuerySelection queryRepo(long repoId) {
|
||||
String[] args = new String[] {Long.toString(repoId)};
|
||||
String selection = getTableName() + "." + Cols.REPO_ID + " = ? ";
|
||||
return new AppQuerySelection(selection, args);
|
||||
}
|
||||
|
||||
public static class Helper {
|
||||
@ -90,8 +103,8 @@ public class TempAppProvider extends AppProvider {
|
||||
TempApkProvider.Helper.init(context);
|
||||
}
|
||||
|
||||
public static List<App> findByPackageNames(Context context, List<String> packageNames, String[] projection) {
|
||||
Uri uri = getAppsUri(packageNames);
|
||||
public static List<App> findByPackageNames(Context context, List<String> packageNames, long repoId, String[] projection) {
|
||||
Uri uri = getAppsUri(packageNames, repoId);
|
||||
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
|
||||
return AppProvider.Helper.cursorToList(cursor);
|
||||
}
|
||||
@ -138,7 +151,7 @@ public class TempAppProvider extends AppProvider {
|
||||
QuerySelection query = new QuerySelection(where, whereArgs).add(querySingleForUpdate(packageName, repoId));
|
||||
|
||||
// Package names for apps cannot change...
|
||||
values.remove(AppMetadataTable.Cols.Package.PACKAGE_NAME);
|
||||
values.remove(Cols.Package.PACKAGE_NAME);
|
||||
|
||||
int count = db().update(getTableName(), values, query.getSelection(), query.getArgs());
|
||||
if (!isApplyingBatch()) {
|
||||
@ -152,7 +165,8 @@ public class TempAppProvider extends AppProvider {
|
||||
AppQuerySelection selection = new AppQuerySelection(customSelection, selectionArgs);
|
||||
switch (MATCHER.match(uri)) {
|
||||
case APPS:
|
||||
selection = selection.add(queryApps(uri.getLastPathSegment()));
|
||||
List<String> segments = uri.getPathSegments();
|
||||
selection = selection.add(queryRepoApps(Long.parseLong(segments.get(1)), segments.get(2)));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import org.fdroid.fdroid.compat.PackageManagerCompat;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.Schema;
|
||||
import org.fdroid.fdroid.net.Downloader;
|
||||
import org.fdroid.fdroid.net.DownloaderService;
|
||||
|
||||
@ -259,7 +260,7 @@ public class InstallManagerService extends Service {
|
||||
App app = getAppFromActive(downloadUrl);
|
||||
if (app == null) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
app = AppProvider.Helper.findByPackageName(resolver, apk.packageName, apk.repo);
|
||||
app = AppProvider.Helper.findSpecificApp(resolver, apk.packageName, apk.repo);
|
||||
}
|
||||
// show notification if app details is not visible
|
||||
if (app != null && AppDetails.isAppVisible(app.packageName)) {
|
||||
@ -346,7 +347,8 @@ public class InstallManagerService extends Service {
|
||||
String name = getAppName(apk);
|
||||
if (TextUtils.isEmpty(name) || name.equals(new App().name)) {
|
||||
ContentResolver resolver = getContentResolver();
|
||||
App app = AppProvider.Helper.findByPackageName(resolver, apk.packageName, apk.repo);
|
||||
App app = AppProvider.Helper.findSpecificApp(resolver, apk.packageName, apk.repo,
|
||||
new String[] {Schema.AppMetadataTable.Cols.NAME});
|
||||
if (app == null || TextUtils.isEmpty(app.name)) {
|
||||
return; // do not have a name to display, so leave notification as is
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
|
||||
intent = getIntent();
|
||||
Uri uri = intent.getData();
|
||||
Apk apk = ApkProvider.Helper.findByUri(this, uri, Schema.ApkTable.Cols.ALL);
|
||||
app = AppProvider.Helper.findByPackageName(getContentResolver(), apk.packageName, apk.repo, Schema.AppMetadataTable.Cols.ALL);
|
||||
app = AppProvider.Helper.findSpecificApp(getContentResolver(), apk.packageName, apk.repo, Schema.AppMetadataTable.Cols.ALL);
|
||||
|
||||
appDiff = new AppDiff(getPackageManager(), apk);
|
||||
|
||||
|
@ -289,7 +289,7 @@ public class SwapAppsView extends ListView implements
|
||||
public void onChange(boolean selfChange) {
|
||||
Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
app = AppProvider.Helper.findByPackageName(getActivity().getContentResolver(),
|
||||
app = AppProvider.Helper.findSpecificApp(getActivity().getContentResolver(),
|
||||
app.packageName, app.repoId, AppMetadataTable.Cols.ALL);
|
||||
resetView();
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public class ProviderUriTests {
|
||||
packageNames.add("org.fdroid.fdroid");
|
||||
packageNames.add("com.example.com");
|
||||
|
||||
assertValidUri(resolver, TempAppProvider.getAppsUri(packageNames), "content://org.fdroid.fdroid.data.TempAppProvider/apps/org.fdroid.fdroid%2Ccom.example.com", projection);
|
||||
assertValidUri(resolver, TempAppProvider.getAppsUri(packageNames, 1), "content://org.fdroid.fdroid.data.TempAppProvider/apps/1/org.fdroid.fdroid%2Ccom.example.com", projection);
|
||||
assertValidUri(resolver, TempAppProvider.getContentUri(), "content://org.fdroid.fdroid.data.TempAppProvider", projection);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.RepoUpdater.UpdateException;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.data.Schema;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable.Cols;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricGradleTestRunner;
|
||||
@ -147,7 +147,7 @@ public class AcceptableMultiRepoUpdaterTest extends MultiRepoUpdaterTest {
|
||||
|
||||
private void disableRepo(Repo repo) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(Schema.RepoTable.Cols.IN_USE, 0);
|
||||
values.put(Cols.IN_USE, 0);
|
||||
RepoProvider.Helper.update(context, repo, values);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,30 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest {
|
||||
@StringDef({"Conflicting", "Normal"})
|
||||
public @interface RepoIdentifier {}
|
||||
|
||||
/*
|
||||
*This test fails due to issue #568 (https://gitlab.com/fdroid/fdroidclient/issues/568).
|
||||
@Test
|
||||
public void appsRemovedFromRepo() throws RepoUpdater.UpdateException {
|
||||
assertEquals(0, AppProvider.Helper.all(context.getContentResolver()).size());
|
||||
|
||||
updateMain();
|
||||
Repo repo = RepoProvider.Helper.findByAddress(context, REPO_MAIN_URI);
|
||||
|
||||
assertEquals(3, AppProvider.Helper.all(context.getContentResolver()).size());
|
||||
assertEquals(6, ApkProvider.Helper.findByRepo(context, repo, Schema.ApkTable.Cols.ALL).size());
|
||||
assertEquals(3, ApkProvider.Helper.findByPackageName(context, "org.adaway").size());
|
||||
assertEquals(2, ApkProvider.Helper.findByPackageName(context, "com.uberspot.a2048").size());
|
||||
assertEquals(1, ApkProvider.Helper.findByPackageName(context, "siir.es.adbWireless").size());
|
||||
|
||||
RepoUpdater updater = new RepoUpdater(context, RepoProvider.Helper.findByAddress(context, repo.address));
|
||||
updateRepo(updater, "multiRepo.conflicting.jar");
|
||||
|
||||
assertEquals(2, AppProvider.Helper.all(context.getContentResolver()).size());
|
||||
assertEquals(6, ApkProvider.Helper.findByRepo(context, repo, Schema.ApkTable.Cols.ALL).size());
|
||||
assertEquals(4, ApkProvider.Helper.findByPackageName(context, "org.adaway").size());
|
||||
assertEquals(2, ApkProvider.Helper.findByPackageName(context, "org.dgtale.icsimport").size());
|
||||
}*/
|
||||
|
||||
@Test
|
||||
public void mainRepo() throws RepoUpdater.UpdateException {
|
||||
assertEmpty();
|
||||
|
Loading…
x
Reference in New Issue
Block a user