From bac0ae8f25a955b6cfbe70a12389a67dfb6146e4 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 11 Jun 2019 22:56:04 +0200 Subject: [PATCH] show all installed apps as possibilities for panic uninstall F-Droid should be able to uninstall any app, in theory, not just the apps that are listed in the index. This lays some groundwork for moving swap's SelectAppsView to the standard AppList elements used everywhere else. It also does a little bit towards getting rid of InstalledApp in favor of just reusing App. --- .../panic/SelectInstalledAppsActivity.java | 9 +--- .../fdroid/data/InstalledAppProvider.java | 52 ++++++++++++++++++- .../views/apps/AppListItemController.java | 11 +++- .../installed/InstalledAppListAdapter.java | 5 +- .../fdroid/data/InstalledAppProviderTest.java | 37 +++++++++++++ 5 files changed, 102 insertions(+), 12 deletions(-) diff --git a/app/src/full/java/org/fdroid/fdroid/views/panic/SelectInstalledAppsActivity.java b/app/src/full/java/org/fdroid/fdroid/views/panic/SelectInstalledAppsActivity.java index 3d222cff9..73ba4db50 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/panic/SelectInstalledAppsActivity.java +++ b/app/src/full/java/org/fdroid/fdroid/views/panic/SelectInstalledAppsActivity.java @@ -40,8 +40,7 @@ import android.widget.TextView; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; -import org.fdroid.fdroid.data.AppProvider; -import org.fdroid.fdroid.data.Schema; +import org.fdroid.fdroid.data.InstalledAppProvider; import org.fdroid.fdroid.views.installed.InstalledAppListAdapter; public class SelectInstalledAppsActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks { @@ -89,11 +88,7 @@ public class SelectInstalledAppsActivity extends AppCompatActivity implements Lo @NonNull @Override public Loader onCreateLoader(int id, Bundle args) { - return new CursorLoader( - this, - AppProvider.getInstalledUri(), - Schema.AppMetadataTable.Cols.ALL, - null, null, null); + return new CursorLoader(this, InstalledAppProvider.getAllAppsUri(), null, null, null, null); } @Override diff --git a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java index 548ad2fdb..5790a3117 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java @@ -15,9 +15,12 @@ import android.text.TextUtils; import android.util.Log; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.data.Schema.AppMetadataTable; import org.fdroid.fdroid.data.Schema.InstalledAppTable; import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols; +import org.fdroid.fdroid.data.Schema.PackageTable; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -28,6 +31,23 @@ public class InstalledAppProvider extends FDroidProvider { public static class Helper { + public static App[] all(Context context) { + ArrayList appList = new ArrayList<>(); + Cursor cursor = context.getContentResolver().query(InstalledAppProvider.getAllAppsUri(), + null, null, null, null); + if (cursor != null) { + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + appList.add(new App(cursor)); + cursor.moveToNext(); + } + } + cursor.close(); + } + return appList.toArray(new App[0]); + } + /** * @return The keys are the package names, and their corresponding values are * the {@link PackageInfo#lastUpdateTime last update time} in milliseconds. @@ -79,6 +99,8 @@ public class InstalledAppProvider extends FDroidProvider { private static final String PATH_SEARCH = "search"; private static final int CODE_SEARCH = CODE_SINGLE + 1; + private static final String PATH_ALL_APPS = "allApps"; + private static final int CODE_ALL_APPS = CODE_SEARCH + 1; private static final UriMatcher MATCHER = new UriMatcher(-1); @@ -99,6 +121,7 @@ public class InstalledAppProvider extends FDroidProvider { static { MATCHER.addURI(getAuthority(), null, CODE_LIST); MATCHER.addURI(getAuthority(), PATH_SEARCH + "/*", CODE_SEARCH); + MATCHER.addURI(getAuthority(), PATH_ALL_APPS, CODE_ALL_APPS); MATCHER.addURI(getAuthority(), "*", CODE_SINGLE); } @@ -106,6 +129,10 @@ public class InstalledAppProvider extends FDroidProvider { return Uri.parse("content://" + getAuthority()); } + public static Uri getAllAppsUri() { + return getContentUri().buildUpon().appendPath(PATH_ALL_APPS).build(); + } + /** * @return the {@link Uri} that points to a specific installed app */ @@ -228,6 +255,7 @@ public class InstalledAppProvider extends FDroidProvider { } QuerySelection selection = new QuerySelection(customSelection, selectionArgs); + QueryBuilder query = null; switch (MATCHER.match(uri)) { case CODE_LIST: selection = selectNotSystemSignature(selection); @@ -241,16 +269,30 @@ public class InstalledAppProvider extends FDroidProvider { selection = selection.add(querySearch(uri.getLastPathSegment())); break; + case CODE_ALL_APPS: + selection = selectNotSystemSignature(selection); + query = new QueryBuilder(); + query.addField(Cols._ID); + query.appendField(Cols.APPLICATION_LABEL, null, Schema.AppMetadataTable.Cols.NAME); + query.appendField(Cols.VERSION_CODE, null, AppMetadataTable.Cols.UPSTREAM_VERSION_CODE); + query.appendField(Cols.VERSION_NAME, null, AppMetadataTable.Cols.UPSTREAM_VERSION_NAME); + query.appendField(PackageTable.Cols.PACKAGE_NAME, PackageTable.NAME, + AppMetadataTable.Cols.Package.PACKAGE_NAME); + break; + default: String message = "Invalid URI for installed app content provider: " + uri; Log.e(TAG, message); throw new UnsupportedOperationException(message); } - QueryBuilder query = new QueryBuilder(); - if (projection == null || projection.length == 0) { + if (query != null) { // NOPMD + // the fields are already setup above + } else if (projection == null || projection.length == 0) { + query = new QueryBuilder(); query.addFields(Cols.ALL); } else { + query = new QueryBuilder(); query.addFields(projection); } query.addSelection(selection); @@ -279,6 +321,12 @@ public class InstalledAppProvider extends FDroidProvider { return count; } + /** + * {@link Cols.Package#NAME} is not included in the database here, because + * it is included only in the {@link PackageTable}, since there are large + * cross-table queries needed to handle the complexity of multiple repos + * potentially serving the same apps. + */ @Override public Uri insert(@NonNull Uri uri, ContentValues values) { diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java index e8825bbbf..0b87fc5c7 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java @@ -7,6 +7,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.graphics.Outline; import android.net.Uri; import android.os.Build; @@ -186,7 +187,15 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { public void bindModel(@NonNull App app) { currentApp = app; - ImageLoader.getInstance().displayImage(app.iconUrl, icon, Utils.getRepoAppDisplayImageOptions()); + if (app.iconUrl == null) { + try { + icon.setImageDrawable(activity.getPackageManager().getApplicationIcon(app.packageName)); + } catch (PackageManager.NameNotFoundException e) { + // ignored + } + } else { + ImageLoader.getInstance().displayImage(app.iconUrl, icon, Utils.getRepoAppDisplayImageOptions()); + } // Figures out the current install/update/download/etc status for the app we are viewing. // Then, asks the view to update itself to reflect this status. diff --git a/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppListAdapter.java b/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppListAdapter.java index b5ca5d692..57976a62b 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppListAdapter.java +++ b/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppListAdapter.java @@ -2,6 +2,7 @@ package org.fdroid.fdroid.views.installed; import android.app.Activity; import android.database.Cursor; +import android.provider.BaseColumns; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; @@ -9,7 +10,6 @@ import android.view.View; import android.view.ViewGroup; import org.fdroid.fdroid.R; import org.fdroid.fdroid.data.App; -import org.fdroid.fdroid.data.Schema; public class InstalledAppListAdapter extends RecyclerView.Adapter { @@ -30,7 +30,8 @@ public class InstalledAppListAdapter extends RecyclerView.Adapter