From bf9179391bbe401dbf807fa5243d05298ed98461 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 2 Jul 2018 19:00:32 +0200 Subject: [PATCH] Add notification uris to ApiAppDao --- .../keychain/daos/ApiAppDao.java | 8 ++ .../keychain/daos/DatabaseNotifyManager.java | 20 ++- .../keychain/livedata/ApiAppsLiveData.java | 113 +++++++++++++++++ .../keychain/remote/ui/AppsListFragment.java | 117 +++--------------- 4 files changed, 156 insertions(+), 102 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/ApiAppsLiveData.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/ApiAppDao.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/ApiAppDao.java index 50a273391..79e87bf81 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/ApiAppDao.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/ApiAppDao.java @@ -78,12 +78,16 @@ public class ApiAppDao extends AbstractDao { InsertApiApp statement = new ApiAppsModel.InsertApiApp(getWritableDb()); statement.bind(apiApp.package_name(), apiApp.package_signature()); statement.executeInsert(); + + getDatabaseNotifyManager().notifyApiAppChange(apiApp.package_name()); } public void deleteApiApp(String packageName) { DeleteByPackageName deleteByPackageName = new DeleteByPackageName(getWritableDb()); deleteByPackageName.bind(packageName); deleteByPackageName.executeUpdateDelete(); + + getDatabaseNotifyManager().notifyApiAppChange(packageName); } public HashSet getAllowedKeyIdsForApp(String packageName) { @@ -108,12 +112,16 @@ public class ApiAppDao extends AbstractDao { statement.bind(packageName, keyId); statement.execute(); } + + getDatabaseNotifyManager().notifyApiAppChange(packageName); } public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) { InsertAllowedKey statement = new InsertAllowedKey(getWritableDb()); statement.bind(packageName, allowedKeyId); statement.execute(); + + getDatabaseNotifyManager().notifyApiAppChange(packageName); } public List getAllApiApps() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/DatabaseNotifyManager.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/DatabaseNotifyManager.java index c2709e614..ee81a5f14 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/DatabaseNotifyManager.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/daos/DatabaseNotifyManager.java @@ -9,7 +9,8 @@ import org.sufficientlysecure.keychain.Constants; public class DatabaseNotifyManager { - private static final Uri BASE_URI = Uri.parse("content://" + Constants.PROVIDER_AUTHORITY); + private static final Uri URI_KEYS = Uri.parse("content://" + Constants.PROVIDER_AUTHORITY + "/keys"); + private static final Uri URI_APPS = Uri.parse("content://" + Constants.PROVIDER_AUTHORITY + "/apps"); private ContentResolver contentResolver; @@ -42,11 +43,24 @@ public class DatabaseNotifyManager { contentResolver.notifyChange(uri, null); } + public void notifyApiAppChange(String apiApp) { + Uri uri = getNotifyUriPackageName(apiApp); + contentResolver.notifyChange(uri, null); + } + public static Uri getNotifyUriAllKeys() { - return BASE_URI; + return URI_KEYS; } public static Uri getNotifyUriMasterKeyId(long masterKeyId) { - return BASE_URI.buildUpon().appendPath(Long.toString(masterKeyId)).build(); + return URI_KEYS.buildUpon().appendPath(Long.toString(masterKeyId)).build(); + } + + public static Uri getNotifyUriAllApps() { + return URI_APPS; + } + + public static Uri getNotifyUriPackageName(String packageName) { + return URI_APPS.buildUpon().appendPath(packageName).build(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/ApiAppsLiveData.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/ApiAppsLiveData.java new file mode 100644 index 000000000..374b53dd6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/ApiAppsLiveData.java @@ -0,0 +1,113 @@ +package org.sufficientlysecure.keychain.livedata; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.daos.ApiAppDao; +import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager; +import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData.ListedApp; +import org.sufficientlysecure.keychain.model.ApiApp; +import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData; + + +public class ApiAppsLiveData extends AsyncTaskLiveData> { + private final ApiAppDao apiAppDao; + private final PackageManager packageManager; + + public ApiAppsLiveData(Context context) { + super(context, DatabaseNotifyManager.getNotifyUriAllApps()); + + packageManager = getContext().getPackageManager(); + apiAppDao = ApiAppDao.getInstance(context); + } + + @Override + protected List asyncLoadData() { + ArrayList result = new ArrayList<>(); + + loadRegisteredApps(result); + addPlaceholderApps(result); + + Collections.sort(result, (o1, o2) -> o1.readableName.compareTo(o2.readableName)); + return result; + } + + private void loadRegisteredApps(ArrayList result) { + List registeredApiApps = apiAppDao.getAllApiApps(); + + for (ApiApp apiApp : registeredApiApps) { + ListedApp listedApp; + try { + ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.package_name(), 0); + CharSequence applicationLabel = packageManager.getApplicationLabel(ai); + Drawable applicationIcon = packageManager.getApplicationIcon(ai); + + listedApp = new ListedApp(apiApp.package_name(), true, true, applicationLabel, applicationIcon, null); + } catch (PackageManager.NameNotFoundException e) { + listedApp = new ListedApp(apiApp.package_name(), false, true, apiApp.package_name(), null, null); + } + result.add(listedApp); + } + } + + private void addPlaceholderApps(ArrayList result) { + for (ListedApp placeholderApp : PLACERHOLDER_APPS) { + if (!containsByPackageName(result, placeholderApp.packageName)) { + try { + packageManager.getApplicationInfo(placeholderApp.packageName, 0); + result.add(placeholderApp.withIsInstalled()); + } catch (PackageManager.NameNotFoundException e) { + result.add(placeholderApp); + } + } + } + } + + private boolean containsByPackageName(ArrayList result, String packageName) { + for (ListedApp app : result) { + if (packageName.equals(app.packageName)) { + return true; + } + } + return false; + } + + + public static class ListedApp { + public final String packageName; + public final boolean isInstalled; + public final boolean isRegistered; + public final String readableName; + public final Drawable applicationIcon; + public final Integer applicationIconRes; + + ListedApp(String packageName, boolean isInstalled, boolean isRegistered, CharSequence readableName, + Drawable applicationIcon, Integer applicationIconRes) { + this.packageName = packageName; + this.isInstalled = isInstalled; + this.isRegistered = isRegistered; + this.readableName = readableName.toString(); + this.applicationIcon = applicationIcon; + this.applicationIconRes = applicationIconRes; + } + + public ListedApp withIsInstalled() { + return new ListedApp(packageName, true, isRegistered, readableName, applicationIcon, applicationIconRes); + } + } + + private static final ListedApp[] PLACERHOLDER_APPS = { + new ListedApp("com.fsck.k9", false, false, "K-9 Mail", null, R.drawable.apps_k9), + new ListedApp("com.zeapo.pwdstore", false, false, "Password Store", null, R.drawable.apps_password_store), + new ListedApp("eu.siacs.conversations", false, false, "Conversations (Instant Messaging)", null, + R.drawable.apps_conversations) + }; +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java index 87aea3bd4..13406266e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java @@ -18,18 +18,18 @@ package org.sufficientlysecure.keychain.remote.ui; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProviders; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.Adapter; @@ -40,11 +40,10 @@ import android.widget.ImageView; import android.widget.TextView; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.model.ApiApp; -import org.sufficientlysecure.keychain.daos.ApiAppDao; +import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData; +import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData.ListedApp; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment.ApiAppAdapter; import org.sufficientlysecure.keychain.ui.base.RecyclerFragment; -import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData; import timber.log.Timber; @@ -61,7 +60,8 @@ public class AppsListFragment extends RecyclerFragment { setAdapter(adapter); setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); - new ApiAppsLiveData(getContext()).observe(this, this::onLoad); + ApiAppsViewModel viewModel = ViewModelProviders.of(this).get(ApiAppsViewModel.class); + viewModel.getListedAppLiveData(requireContext()).observe(this, this::onLoad); } private void onLoad(List apiApps) { @@ -85,7 +85,7 @@ public class AppsListFragment extends RecyclerFragment { startActivity(intent); } else { Intent i; - PackageManager manager = getActivity().getPackageManager(); + PackageManager manager = requireActivity().getPackageManager(); try { i = manager.getLaunchIntentForPackage(listedApp.packageName); if (i == null) { @@ -121,13 +121,14 @@ public class AppsListFragment extends RecyclerFragment { inflater = LayoutInflater.from(context); } + @NonNull @Override - public ApiAppViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public ApiAppViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new ApiAppViewHolder(inflater.inflate(R.layout.api_apps_adapter_list_item, parent, false)); } @Override - public void onBindViewHolder(ApiAppViewHolder holder, int position) { + public void onBindViewHolder(@NonNull ApiAppViewHolder holder, int position) { ListedApp item = data.get(position); holder.bind(item); } @@ -168,97 +169,15 @@ public class AppsListFragment extends RecyclerFragment { } } - public static class ApiAppsLiveData extends AsyncTaskLiveData> { - private final ApiAppDao apiAppDao; - private final PackageManager packageManager; + public static class ApiAppsViewModel extends ViewModel { + LiveData> listedAppLiveData; - ApiAppsLiveData(Context context) { - super(context, null); - - packageManager = getContext().getPackageManager(); - apiAppDao = ApiAppDao.getInstance(context); - } - - @Override - protected List asyncLoadData() { - ArrayList result = new ArrayList<>(); - - loadRegisteredApps(result); - addPlaceholderApps(result); - - Collections.sort(result, (o1, o2) -> o1.readableName.compareTo(o2.readableName)); - return result; - } - - private void loadRegisteredApps(ArrayList result) { - List registeredApiApps = apiAppDao.getAllApiApps(); - - for (ApiApp apiApp : registeredApiApps) { - ListedApp listedApp; - try { - ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.package_name(), 0); - CharSequence applicationLabel = packageManager.getApplicationLabel(ai); - Drawable applicationIcon = packageManager.getApplicationIcon(ai); - - listedApp = new ListedApp(apiApp.package_name(), true, true, applicationLabel, applicationIcon, null); - } catch (PackageManager.NameNotFoundException e) { - listedApp = new ListedApp(apiApp.package_name(), false, true, apiApp.package_name(), null, null); - } - result.add(listedApp); + LiveData> getListedAppLiveData(Context context) { + if (listedAppLiveData == null) { + listedAppLiveData = new ApiAppsLiveData(context); } - } - - private void addPlaceholderApps(ArrayList result) { - for (ListedApp placeholderApp : PLACERHOLDER_APPS) { - if (!containsByPackageName(result, placeholderApp.packageName)) { - try { - packageManager.getApplicationInfo(placeholderApp.packageName, 0); - result.add(placeholderApp.withIsInstalled()); - } catch (PackageManager.NameNotFoundException e) { - result.add(placeholderApp); - } - } - } - } - - private boolean containsByPackageName(ArrayList result, String packageName) { - for (ListedApp app : result) { - if (packageName.equals(app.packageName)) { - return true; - } - } - return false; + return listedAppLiveData; } } - public static class ListedApp { - final String packageName; - final boolean isInstalled; - final boolean isRegistered; - final String readableName; - final Drawable applicationIcon; - final Integer applicationIconRes; - - ListedApp(String packageName, boolean isInstalled, boolean isRegistered, CharSequence readableName, - Drawable applicationIcon, Integer applicationIconRes) { - this.packageName = packageName; - this.isInstalled = isInstalled; - this.isRegistered = isRegistered; - this.readableName = readableName.toString(); - this.applicationIcon = applicationIcon; - this.applicationIconRes = applicationIconRes; - } - - public ListedApp withIsInstalled() { - return new ListedApp(packageName, true, isRegistered, readableName, applicationIcon, applicationIconRes); - } - } - - private static final ListedApp[] PLACERHOLDER_APPS = { - new ListedApp("com.fsck.k9", false, false, "K-9 Mail", null, R.drawable.apps_k9), - new ListedApp("com.zeapo.pwdstore", false, false, "Password Store", null, R.drawable.apps_password_store), - new ListedApp("eu.siacs.conversations", false, false, "Conversations (Instant Messaging)", null, - R.drawable.apps_conversations) - }; - }