From 64bde4c6809936e24e64e51d91e96c26e42d2398 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 25 Jun 2018 14:12:22 +0200 Subject: [PATCH] extract findByUserId and findByEmail usage from KeychainProvider --- .../keychain/livedata/KeyInfoInteractor.java | 145 ------------------ .../keychain/livedata/KeyInfoLiveData.java | 38 ----- .../keychain/model/SubKey.java | 6 +- .../keychain/provider/KeyRepository.java | 10 ++ .../keychain/provider/KeychainContract.java | 12 -- .../keychain/provider/KeychainDatabase.java | 19 ++- .../keychain/provider/KeychainProvider.java | 50 +----- .../remote/ApiPendingIntentFactory.java | 2 +- .../remote/ui/SecurityProblemPresenter.java | 6 +- .../remote/ui/dialog/KeyInfoLoader.java | 76 --------- .../ui/dialog/RemoteDeduplicateActivity.java | 97 +++++++----- .../ui/dialog/RemoteDeduplicatePresenter.java | 63 +++----- ...RemoteSelectAuthenticationKeyActivity.java | 87 ++++++----- ...emoteSelectAuthenticationKeyPresenter.java | 53 ++----- .../ui/dialog/RemoteSelectIdKeyActivity.java | 95 ++++++++---- .../ui/dialog/RemoteSelectIdViewModel.java | 39 ----- .../RemoteSelectIdentityKeyPresenter.java | 74 +++++---- .../org/sufficientlysecure/keychain/Keys.sq | 37 +++-- 18 files changed, 305 insertions(+), 604 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoInteractor.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoLiveData.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/KeyInfoLoader.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdViewModel.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoInteractor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoInteractor.java deleted file mode 100644 index 173e58ac5..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoInteractor.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2017 Schürmann & Breitmoser GbR - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.livedata; - - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import android.content.ContentResolver; -import android.database.Cursor; -import android.net.Uri; -import android.support.annotation.Nullable; - -import com.google.auto.value.AutoValue; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.util.DatabaseUtil; - - -public class KeyInfoInteractor { - // These are the rows that we will retrieve. - private String[] QUERY_PROJECTION = new String[]{ - KeyRings._ID, - KeyRings.MASTER_KEY_ID, - KeyRings.CREATION, - KeyRings.HAS_ENCRYPT, - KeyRings.HAS_AUTHENTICATE_SECRET, - KeyRings.HAS_ANY_SECRET, - KeyRings.VERIFIED, - KeyRings.NAME, - KeyRings.EMAIL, - KeyRings.COMMENT, - KeyRings.IS_EXPIRED, - KeyRings.IS_REVOKED, - }; - private static final int INDEX_MASTER_KEY_ID = 1; - private static final int INDEX_CREATION = 2; - private static final int INDEX_HAS_ENCRYPT = 3; - private static final int INDEX_HAS_AUTHENTICATE = 4; - private static final int INDEX_HAS_ANY_SECRET = 5; - private static final int INDEX_VERIFIED = 6; - private static final int INDEX_NAME = 7; - private static final int INDEX_EMAIL = 8; - private static final int INDEX_COMMENT = 9; - - private static final String QUERY_WHERE_ALL = Tables.KEYS + "." + KeyRings.IS_REVOKED + - " = 0 AND " + KeyRings.IS_EXPIRED + " = 0"; - private static final String QUERY_WHERE_SECRET = Tables.KEYS + "." + KeyRings.IS_REVOKED + - " = 0 AND " + KeyRings.IS_EXPIRED + " = 0" + " AND " + KeyRings.HAS_ANY_SECRET + " != 0"; - private static final String QUERY_ORDER = Tables.KEYS + "." + KeyRings.CREATION + " DESC"; - - private final ContentResolver contentResolver; - - - public KeyInfoInteractor(ContentResolver contentResolver) { - this.contentResolver = contentResolver; - } - - public List loadKeyInfo(KeySelector keySelector) { - ArrayList keyInfos = new ArrayList<>(); - Cursor cursor; - - String selection = keySelector.isOnlySecret() ? QUERY_WHERE_SECRET : QUERY_WHERE_ALL; - String additionalSelection = keySelector.getSelection(); - - selection = DatabaseUtil.concatenateWhere(selection, additionalSelection); - cursor = contentResolver.query(keySelector.getKeyRingUri(), QUERY_PROJECTION, selection, null, QUERY_ORDER); - - if (cursor == null) { - return null; - } - - while (cursor.moveToNext()) { - KeyInfo keyInfo = KeyInfo.fromCursor(cursor); - keyInfos.add(keyInfo); - } - - return Collections.unmodifiableList(keyInfos); - } - - @AutoValue - public abstract static class KeyInfo { - public abstract long getMasterKeyId(); - public abstract long getCreationDate(); - public abstract boolean getHasEncrypt(); - public abstract boolean getHasAuthenticate(); - public abstract boolean getHasAnySecret(); - public abstract boolean getIsVerified(); - - @Nullable - public abstract String getName(); - @Nullable - public abstract String getEmail(); - @Nullable - public abstract String getComment(); - - static KeyInfo fromCursor(Cursor cursor) { - long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID); - long creationDate = cursor.getLong(INDEX_CREATION) * 1000L; - boolean hasEncrypt = cursor.getInt(INDEX_HAS_ENCRYPT) != 0; - boolean hasAuthenticate = cursor.getInt(INDEX_HAS_AUTHENTICATE) != 0; - boolean hasAnySecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0; - boolean isVerified = cursor.getInt(INDEX_VERIFIED) == 2; - - String name = cursor.getString(INDEX_NAME); - String email = cursor.getString(INDEX_EMAIL); - String comment = cursor.getString(INDEX_COMMENT); - - return new AutoValue_KeyInfoInteractor_KeyInfo( - masterKeyId, creationDate, hasEncrypt, hasAuthenticate, hasAnySecret, isVerified, name, email, comment); - } - } - - @AutoValue - public abstract static class KeySelector { - public abstract Uri getKeyRingUri(); - @Nullable - public abstract String getSelection(); - public abstract boolean isOnlySecret(); - - public static KeySelector create(Uri keyRingUri, String selection) { - return new AutoValue_KeyInfoInteractor_KeySelector(keyRingUri, selection, false); - } - - public static KeySelector createOnlySecret(Uri keyRingUri, String selection) { - return new AutoValue_KeyInfoInteractor_KeySelector(keyRingUri, selection, true); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoLiveData.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoLiveData.java deleted file mode 100644 index 502ab2f20..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyInfoLiveData.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.sufficientlysecure.keychain.livedata; - - -import java.util.List; - -import android.content.ContentResolver; -import android.content.Context; - -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector; -import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData; - - -public class KeyInfoLiveData extends AsyncTaskLiveData> { - private final KeyInfoInteractor keyInfoInteractor; - - private KeySelector keySelector; - - public KeyInfoLiveData(Context context, ContentResolver contentResolver) { - super(context, null); - - this.keyInfoInteractor = new KeyInfoInteractor(contentResolver); - } - - public void setKeySelector(KeySelector keySelector) { - this.keySelector = keySelector; - - updateDataInBackground(); - } - - @Override - protected List asyncLoadData() { - if (keySelector == null) { - return null; - } - return keyInfoInteractor.loadKeyInfo(keySelector); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/SubKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/SubKey.java index 0f5463810..b834bcdb2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/SubKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/SubKey.java @@ -15,8 +15,8 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; public abstract class SubKey implements KeysModel { public static final Factory FACTORY = new Factory<>(AutoValue_SubKey::new, CustomColumnAdapters.SECRET_KEY_TYPE_ADAPTER); - public static final SelectAllUnifiedKeyInfoMapper UNIFIED_KEY_INFO_MAPPER = - FACTORY.selectAllUnifiedKeyInfoMapper(AutoValue_SubKey_UnifiedKeyInfo::new); + public static final UnifiedKeyViewMapper UNIFIED_KEY_INFO_MAPPER = + FACTORY.selectUnifiedKeyInfoByMasterKeyIdMapper(AutoValue_SubKey_UnifiedKeyInfo::new); public static Mapper SUBKEY_MAPPER = new Mapper<>(FACTORY); public static RowMapper SKT_MAPPER = FACTORY.selectSecretKeyTypeMapper(); @@ -25,7 +25,7 @@ public abstract class SubKey implements KeysModel { } @AutoValue - public static abstract class UnifiedKeyInfo implements SelectAllUnifiedKeyInfoModel { + public static abstract class UnifiedKeyInfo implements KeysModel.UnifiedKeyViewModel { private List autocryptPackageNames; public boolean is_expired() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java index a88937e11..cab949179 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java @@ -264,11 +264,21 @@ public class KeyRepository extends AbstractDao { } } + public List getUnifiedKeyInfosByMailAddress(String mailAddress) { + SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%'); + return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); + } + public List getAllUnifiedKeyInfo() { SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo(); return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); } + public List getAllUnifiedKeyInfoWithSecret() { + SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret(); + return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); + } + public List getUserIds(long... masterKeyIds) { SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds); return mapAllRows(query, UserPacket.USER_ID_MAPPER::map); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index 3eced678e..7085ec839 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -100,9 +100,7 @@ public class KeychainContract { public static final String PATH_UNIFIED = "unified"; public static final String PATH_FIND = "find"; - public static final String PATH_BY_EMAIL = "email"; public static final String PATH_BY_SUBKEY = "subkey"; - public static final String PATH_BY_USER_ID = "user_id"; public static final String PATH_PUBLIC = "public"; public static final String PATH_USER_IDS = "user_ids"; @@ -140,16 +138,6 @@ public class KeychainContract { .appendPath(PATH_UNIFIED).build(); } - public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND) - .appendPath(PATH_BY_EMAIL).appendPath(email).build(); - } - - public static Uri buildUnifiedKeyRingsFindByUserIdUri(String query) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND) - .appendPath(PATH_BY_USER_ID).appendPath(query).build(); - } - public static Uri buildUnifiedKeyRingsFindBySubkeyUri(long subkey) { return CONTENT_URI.buildUpon().appendPath(PATH_FIND) .appendPath(PATH_BY_SUBKEY).appendPath(Long.toString(subkey)).build(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 2363bffe9..62e643b7d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.KeyMetadataModel; import org.sufficientlysecure.keychain.KeyRingsPublicModel; import org.sufficientlysecure.keychain.KeySignaturesModel; +import org.sufficientlysecure.keychain.KeysModel; import org.sufficientlysecure.keychain.UserPacketsModel; import org.sufficientlysecure.keychain.model.ApiApp; import org.sufficientlysecure.keychain.model.Certification; @@ -65,7 +66,7 @@ import timber.log.Timber; */ public class KeychainDatabase { private static final String DATABASE_NAME = "openkeychain.db"; - private static final int DATABASE_VERSION = 28; + private static final int DATABASE_VERSION = 29; private final SupportSQLiteOpenHelper supportSQLiteOpenHelper; private Context context; @@ -205,6 +206,7 @@ public class KeychainDatabase { db.execSQL(CREATE_OVERRIDDEN_WARNINGS); db.execSQL(AutocryptPeersModel.CREATE_TABLE); db.execSQL(ApiAppsModel.CREATE_TABLE); + db.execSQL(KeysModel.UNIFIEDKEYVIEW); db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysColumns.RANK + ", " + KeysColumns.MASTER_KEY_ID + ");"); db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsColumns.RANK + ", " @@ -429,16 +431,22 @@ public class KeychainDatabase { } } - case 26: { + case 26: migrateUpdatedKeysToKeyMetadataTable(db); - } - case 27: { + case 27: renameApiAutocryptPeersTable(db); - } + + case 28: + recreateUnifiedKeyView(db); } } + private void recreateUnifiedKeyView(SupportSQLiteDatabase db) { + db.execSQL("DROP VIEW IF EXISTS " + KeysModel.UNIFIEDKEYVIEW_VIEW_NAME); + db.execSQL(KeysModel.UNIFIEDKEYVIEW); + } + private void migrateSecretKeysFromDbToLocalStorage(SupportSQLiteDatabase db) throws IOException { LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context); Cursor cursor = db.query("SELECT master_key_id, key_ring_data FROM keyrings_secret"); @@ -456,7 +464,6 @@ public class KeychainDatabase { private void migrateUpdatedKeysToKeyMetadataTable(SupportSQLiteDatabase db) { try { db.execSQL("ALTER TABLE updated_keys RENAME TO key_metadata;"); - db.execSQL("UPDATE key_metadata SET last_updated = last_updated * 1000;"); } catch (SQLException e) { if (Constants.DEBUG) { Timber.e(e, "Ignoring migration exception, this probably happened before"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 1e4534125..ebc997f7a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -28,7 +28,6 @@ import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; -import android.database.DatabaseUtils; import android.database.sqlite.SQLiteConstraintException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; @@ -62,9 +61,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe private static final int KEY_RING_PUBLIC = 203; private static final int KEY_RING_CERTS = 205; - private static final int KEY_RINGS_FIND_BY_EMAIL = 400; private static final int KEY_RINGS_FIND_BY_SUBKEY = 401; - private static final int KEY_RINGS_FIND_BY_USER_ID = 402; private static final int KEY_SIGNATURES = 700; @@ -94,19 +91,12 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe /* * find by criteria other than master key id * - * key_rings/find/email/_ * key_rings/find/subkey/_ * */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" - + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_EMAIL + "/*", - KEY_RINGS_FIND_BY_EMAIL); matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*", KEY_RINGS_FIND_BY_SUBKEY); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" - + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_USER_ID + "/*", - KEY_RINGS_FIND_BY_USER_ID); /* * list key_ring specifics @@ -185,9 +175,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe switch (match) { case KEY_RING_UNIFIED: case KEY_RINGS_UNIFIED: - case KEY_RINGS_FIND_BY_EMAIL: - case KEY_RINGS_FIND_BY_SUBKEY: - case KEY_RINGS_FIND_BY_USER_ID: { + case KEY_RINGS_FIND_BY_SUBKEY: { HashMap projectionMap = new HashMap<>(); projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); @@ -351,42 +339,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe } break; } - case KEY_RINGS_FIND_BY_EMAIL: - case KEY_RINGS_FIND_BY_USER_ID: { - String chunks[] = uri.getLastPathSegment().split(" *, *"); - boolean gotCondition = false; - String emailWhere = ""; - // JAVA ♥ - for (int i = 0; i < chunks.length; ++i) { - if (chunks[i].length() == 0) { - continue; - } - if (i != 0) { - emailWhere += " OR "; - } - if (match == KEY_RINGS_FIND_BY_EMAIL) { - emailWhere += "tmp." + UserPackets.EMAIL + " LIKE " - + DatabaseUtils.sqlEscapeString(chunks[i]); - } else { - emailWhere += "tmp." + UserPackets.USER_ID + " LIKE " - + DatabaseUtils.sqlEscapeString("%" + chunks[i] + "%"); - } - gotCondition = true; - } - if(gotCondition) { - qb.appendWhere(" AND EXISTS (" - + " SELECT 1 FROM " + Tables.USER_PACKETS + " AS tmp" - + " WHERE tmp." + UserPackets.MASTER_KEY_ID - + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND (" + emailWhere + ")" - + ")"); - } else { - // TODO better way to do this? - Timber.e("Malformed find by email query!"); - qb.appendWhere(" AND 0"); - } - break; - } } if (TextUtils.isEmpty(sortOrder)) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ApiPendingIntentFactory.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ApiPendingIntentFactory.java index 7de402e69..bf5a1c3a1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ApiPendingIntentFactory.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ApiPendingIntentFactory.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.remote; + import java.util.ArrayList; import android.app.PendingIntent; @@ -25,7 +26,6 @@ import android.content.Intent; import android.os.Build; import org.sufficientlysecure.keychain.pgp.DecryptVerifySecurityProblem; -import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.remote.ui.RemoteBackupActivity; import org.sufficientlysecure.keychain.remote.ui.RemoteDisplayTransferCodeActivity; import org.sufficientlysecure.keychain.remote.ui.RemoteErrorActivity; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java index 3b8741458..b7109b1cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java @@ -207,9 +207,9 @@ class SecurityProblemPresenter { } void onClickViewKey() { - Intent viewKeyIntent = new Intent(context, ViewKeyActivity.class); - viewKeyIntent.setData(KeyRings.buildGenericKeyRingUri(viewKeyMasterKeyId)); - context.startActivity(viewKeyIntent); + Intent intent = new Intent(context, ViewKeyActivity.class); + intent.putExtra(ViewKeyActivity.EXTRA_MASTER_KEY_ID, viewKeyMasterKeyId); + context.startActivity(intent); } void onClickOverride() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/KeyInfoLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/KeyInfoLoader.java deleted file mode 100644 index 31c87ac58..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/KeyInfoLoader.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2017 Schürmann & Breitmoser GbR - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.remote.ui.dialog; - - -import java.util.List; - -import android.content.ContentResolver; -import android.content.Context; -import android.support.v4.content.AsyncTaskLoader; - -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector; - - -public class KeyInfoLoader extends AsyncTaskLoader> { - private final KeySelector keySelector; - - private List cachedResult; - private KeyInfoInteractor keyInfoInteractor; - - KeyInfoLoader(Context context, ContentResolver contentResolver, KeySelector keySelector) { - super(context); - - this.keySelector = keySelector; - this.keyInfoInteractor = new KeyInfoInteractor(contentResolver); - } - - @Override - public List loadInBackground() { - return keyInfoInteractor.loadKeyInfo(keySelector); - } - - @Override - public void deliverResult(List keySubkeyStatus) { - cachedResult = keySubkeyStatus; - - if (isStarted()) { - super.deliverResult(keySubkeyStatus); - } - } - - @Override - protected void onStartLoading() { - if (cachedResult != null) { - deliverResult(cachedResult); - } - - if (takeContentChanged() || cachedResult == null) { - forceLoad(); - } - } - - @Override - protected void onStopLoading() { - super.onStopLoading(); - - cachedResult = null; - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicateActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicateActivity.java index adb079821..1b62788c8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicateActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicateActivity.java @@ -23,6 +23,9 @@ import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -42,7 +45,6 @@ import android.text.format.DateUtils; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; @@ -50,8 +52,10 @@ import android.widget.TextView; import com.mikepenz.materialdrawer.util.KeyboardUtil; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.livedata.GenericLiveData; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; +import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicatePresenter.RemoteDeduplicateView; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.ui.util.ThemeChanger; @@ -63,8 +67,6 @@ public class RemoteDeduplicateActivity extends FragmentActivity { public static final String EXTRA_PACKAGE_NAME = "package_name"; public static final String EXTRA_DUPLICATE_EMAILS = "duplicate_emails"; - public static final int LOADER_ID_KEYS = 0; - private RemoteDeduplicatePresenter presenter; @@ -73,7 +75,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - presenter = new RemoteDeduplicatePresenter(getBaseContext(), LOADER_ID_KEYS); + presenter = new RemoteDeduplicatePresenter(getBaseContext(), this); KeyboardUtil.hideKeyboard(this); @@ -92,8 +94,43 @@ public class RemoteDeduplicateActivity extends FragmentActivity { String duplicateAddress = dupAddresses.get(0); String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); - presenter.setupFromIntentData(packageName, duplicateAddress); - presenter.startLoaders(getSupportLoaderManager()); + DeduplicateViewModel viewModel = ViewModelProviders.of(this).get(DeduplicateViewModel.class); + viewModel.setDuplicateAddress(duplicateAddress); + viewModel.setPackageName(packageName); + + presenter.setupFromViewModel(viewModel); + } + + public static class DeduplicateViewModel extends ViewModel { + private String duplicateAddress; + private LiveData> keyInfoLiveData; + private String packageName; + + public LiveData> getKeyInfoLiveData(Context context) { + if (keyInfoLiveData == null) { + keyInfoLiveData = new GenericLiveData<>(context, null, () -> { + KeyRepository keyRepository = KeyRepository.create(context); + return keyRepository.getUnifiedKeyInfosByMailAddress(duplicateAddress); + }); + } + return keyInfoLiveData; + } + + public void setDuplicateAddress(String duplicateAddress) { + this.duplicateAddress = duplicateAddress; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getPackageName() { + return packageName; + } + + public String getDuplicateAddress() { + return duplicateAddress; + } } public static class RemoteDeduplicateDialogFragment extends DialogFragment { @@ -107,7 +144,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); + Activity activity = requireActivity(); ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); @@ -135,7 +172,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - presenter = ((RemoteDeduplicateActivity) getActivity()).presenter; + presenter = ((RemoteDeduplicateActivity) requireActivity()).presenter; presenter.setView(mvpView); } @@ -202,7 +239,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity { } @Override - public void setKeyListData(List data) { + public void setKeyListData(List data) { keyChoiceAdapter.setData(data); } @@ -219,34 +256,17 @@ public class RemoteDeduplicateActivity extends FragmentActivity { } private void setupListenersForPresenter() { - buttonSelect.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - presenter.onClickSelect(); - } - }); - - buttonCancel.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - presenter.onClickCancel(); - } - }); - + buttonSelect.setOnClickListener(view -> presenter.onClickSelect()); + buttonCancel.setOnClickListener(view -> presenter.onClickCancel()); keyChoiceList.addOnItemTouchListener(new RecyclerItemClickListener(getContext(), - new RecyclerItemClickListener.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - presenter.onKeyItemClick(position); - } - })); + (view, position) -> presenter.onKeyItemClick(position))); } } private static class KeyChoiceAdapter extends Adapter { private final LayoutInflater layoutInflater; private final Resources resources; - private List data; + private List data; private Drawable iconUnselected; private Drawable iconSelected; private Integer activeItem; @@ -256,15 +276,16 @@ public class RemoteDeduplicateActivity extends FragmentActivity { this.resources = resources; } + @NonNull @Override - public KeyChoiceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public KeyChoiceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View keyChoiceItemView = layoutInflater.inflate(R.layout.duplicate_key_item, parent, false); return new KeyChoiceViewHolder(keyChoiceItemView); } @Override - public void onBindViewHolder(KeyChoiceViewHolder holder, int position) { - KeyInfo keyInfo = data.get(position); + public void onBindViewHolder(@NonNull KeyChoiceViewHolder holder, int position) { + UnifiedKeyInfo keyInfo = data.get(position); Drawable icon = (activeItem != null && position == activeItem) ? iconSelected : iconUnselected; holder.bind(keyInfo, icon); } @@ -274,7 +295,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity { return data != null ? data.size() : 0; } - public void setData(List data) { + public void setData(List data) { this.data = data; notifyDataSetChanged(); } @@ -319,11 +340,11 @@ public class RemoteDeduplicateActivity extends FragmentActivity { vIcon = itemView.findViewById(R.id.key_list_item_icon); } - void bind(KeyInfo keyInfo, Drawable selectionIcon) { - vName.setText(keyInfo.getName()); + void bind(UnifiedKeyInfo keyInfo, Drawable selectionIcon) { + vName.setText(keyInfo.name()); Context context = vCreation.getContext(); - String dateTime = DateUtils.formatDateTime(context, keyInfo.getCreationDate(), + String dateTime = DateUtils.formatDateTime(context, keyInfo.creation(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH); vCreation.setText(context.getString(R.string.label_key_created, dateTime)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicatePresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicatePresenter.java index a3ecadbe1..fd8a7ebae 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicatePresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteDeduplicatePresenter.java @@ -20,62 +20,59 @@ package org.sufficientlysecure.keychain.remote.ui.dialog; import java.util.List; +import android.arch.lifecycle.LifecycleOwner; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.Loader; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.remote.AutocryptInteractor; +import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicateActivity.DeduplicateViewModel; import timber.log.Timber; -class RemoteDeduplicatePresenter implements LoaderCallbacks> { +class RemoteDeduplicatePresenter { private final PackageManager packageManager; private final Context context; - private final int loaderId; + private final LifecycleOwner lifecycleOwner; private AutocryptInteractor autocryptInteractor; - private String duplicateAddress; + private DeduplicateViewModel viewModel; private RemoteDeduplicateView view; private Integer selectedItem; - private List keyInfoData; + private List keyInfoData; - RemoteDeduplicatePresenter(Context context, int loaderId) { + RemoteDeduplicatePresenter(Context context, LifecycleOwner lifecycleOwner) { this.context = context; + this.lifecycleOwner = lifecycleOwner; packageManager = context.getPackageManager(); - - this.loaderId = loaderId; } public void setView(RemoteDeduplicateView view) { this.view = view; } - void setupFromIntentData(String packageName, String duplicateAddress) { + void setupFromViewModel(DeduplicateViewModel viewModel) { + this.viewModel = viewModel; + this.autocryptInteractor = AutocryptInteractor.getInstance(context, viewModel.getPackageName()); + try { - setPackageInfo(packageName); + setPackageInfo(viewModel.getPackageName()); } catch (NameNotFoundException e) { Timber.e("Unable to find info of calling app!"); view.finishAsCancelled(); return; } - this.autocryptInteractor = AutocryptInteractor.getInstance(context, packageName); + view.setAddressText(viewModel.getDuplicateAddress()); - this.duplicateAddress = duplicateAddress; - view.setAddressText(duplicateAddress); + viewModel.getKeyInfoLiveData(context).observe(lifecycleOwner, this::onLoadKeyInfos); } private void setPackageInfo(String packageName) throws NameNotFoundException { @@ -85,31 +82,11 @@ class RemoteDeduplicatePresenter implements LoaderCallbacks> { view.setTitleClientIcon(appIcon); } - void startLoaders(LoaderManager loaderManager) { - loaderManager.restartLoader(loaderId, null, this); - } - - @Override - public Loader> onCreateLoader(int id, Bundle args) { - KeySelector keySelector = KeySelector.create( - KeyRings.buildUnifiedKeyRingsFindByEmailUri(duplicateAddress), null); - - return new KeyInfoLoader(context, context.getContentResolver(), keySelector); - } - - @Override - public void onLoadFinished(Loader> loader, List data) { + private void onLoadKeyInfos(List data) { this.keyInfoData = data; view.setKeyListData(data); } - @Override - public void onLoaderReset(Loader loader) { - if (view != null) { - view.setKeyListData(null); - } - } - void onClickSelect() { if (keyInfoData == null) { Timber.e("got click on select with no data…?"); @@ -120,8 +97,8 @@ class RemoteDeduplicatePresenter implements LoaderCallbacks> { return; } - long masterKeyId = keyInfoData.get(selectedItem).getMasterKeyId(); - autocryptInteractor.updateKeyGossipFromDedup(duplicateAddress, masterKeyId); + long masterKeyId = keyInfoData.get(selectedItem).master_key_id(); + autocryptInteractor.updateKeyGossipFromDedup(viewModel.getDuplicateAddress(), masterKeyId); view.finish(); } @@ -151,7 +128,7 @@ class RemoteDeduplicatePresenter implements LoaderCallbacks> { void setAddressText(String text); void setTitleClientIcon(Drawable drawable); - void setKeyListData(List data); + void setKeyListData(List data); void setActiveItem(Integer position); void setEnableSelectButton(boolean enabled); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyActivity.java index 9c722885a..eecb21837 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyActivity.java @@ -23,6 +23,9 @@ import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -42,7 +45,6 @@ import android.text.format.DateUtils; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; @@ -51,8 +53,10 @@ import android.widget.TextView; import com.mikepenz.materialdrawer.util.KeyboardUtil; import org.openintents.ssh.authentication.SshAuthenticationApi; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; +import org.sufficientlysecure.keychain.livedata.GenericLiveData; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.provider.ApiAppDao; +import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; @@ -64,8 +68,6 @@ import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickLis public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { public static final String EXTRA_PACKAGE_NAME = "package_name"; - public static final int LOADER_ID_KEYS = 0; - private RemoteSelectAuthenticationKeyPresenter presenter; private String packageName; @@ -75,7 +77,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - presenter = new RemoteSelectAuthenticationKeyPresenter(getBaseContext(), LOADER_ID_KEYS); + presenter = new RemoteSelectAuthenticationKeyPresenter(getBaseContext(), this); KeyboardUtil.hideKeyboard(this); @@ -92,8 +94,33 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { Intent intent = getIntent(); packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); - presenter.setupFromIntentData(packageName); - presenter.startLoaders(getSupportLoaderManager()); + SelectAuthKeyViewModel viewModel = ViewModelProviders.of(this).get(SelectAuthKeyViewModel.class); + viewModel.setPackageName(packageName); + + presenter.setupFromViewModel(viewModel); + } + + public static class SelectAuthKeyViewModel extends ViewModel { + private LiveData> keyInfoLiveData; + private String packageName; + + public LiveData> getKeyInfoLiveData(Context context) { + if (keyInfoLiveData == null) { + keyInfoLiveData = new GenericLiveData<>(context, null, () -> { + KeyRepository keyRepository = KeyRepository.create(context); + return keyRepository.getAllUnifiedKeyInfoWithSecret(); + }); + } + return keyInfoLiveData; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getPackageName() { + return packageName; + } } private void onKeySelected(long masterKeyId) { @@ -121,7 +148,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); + Activity activity = requireActivity(); ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); @@ -149,7 +176,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - presenter = ((RemoteSelectAuthenticationKeyActivity) getActivity()).presenter; + presenter = ((RemoteSelectAuthenticationKeyActivity) requireActivity()).presenter; presenter.setView(mvpView); } @@ -207,7 +234,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { } @Override - public void setKeyListData(List data) { + public void setKeyListData(List data) { keyChoiceAdapter.setData(data); } @@ -224,34 +251,17 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { } private void setupListenersForPresenter() { - buttonSelect.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - presenter.onClickSelect(); - } - }); - - buttonCancel.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - presenter.onClickCancel(); - } - }); - + buttonSelect.setOnClickListener(view -> presenter.onClickSelect()); + buttonCancel.setOnClickListener(view -> presenter.onClickCancel()); keyChoiceList.addOnItemTouchListener(new RecyclerItemClickListener(getContext(), - new RecyclerItemClickListener.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - presenter.onKeyItemClick(position); - } - })); + (view, position) -> presenter.onKeyItemClick(position))); } } private static class KeyChoiceAdapter extends Adapter { private final LayoutInflater layoutInflater; private final Resources resources; - private List data; + private List data; private Drawable iconUnselected; private Drawable iconSelected; private Integer activeItem; @@ -261,15 +271,16 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { this.resources = resources; } + @NonNull @Override - public KeyChoiceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public KeyChoiceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View keyChoiceItemView = layoutInflater.inflate(R.layout.authentication_key_item, parent, false); return new KeyChoiceViewHolder(keyChoiceItemView); } @Override - public void onBindViewHolder(KeyChoiceViewHolder holder, int position) { - KeyInfo keyInfo = data.get(position); + public void onBindViewHolder(@NonNull KeyChoiceViewHolder holder, int position) { + UnifiedKeyInfo keyInfo = data.get(position); Drawable icon = (activeItem != null && position == activeItem) ? iconSelected : iconUnselected; holder.bind(keyInfo, icon); } @@ -279,7 +290,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { return data != null ? data.size() : 0; } - public void setData(List data) { + public void setData(List data) { this.data = data; notifyDataSetChanged(); } @@ -324,11 +335,11 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity { vIcon = itemView.findViewById(R.id.key_list_item_icon); } - void bind(KeyInfo keyInfo, Drawable selectionIcon) { - vName.setText(keyInfo.getName()); + void bind(UnifiedKeyInfo keyInfo, Drawable selectionIcon) { + vName.setText(keyInfo.name()); Context context = vCreation.getContext(); - String dateTime = DateUtils.formatDateTime(context, keyInfo.getCreationDate(), + String dateTime = DateUtils.formatDateTime(context, keyInfo.creation(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH); vCreation.setText(context.getString(R.string.label_key_created, dateTime)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyPresenter.java index c9e0f70b0..24f93520a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectAuthenticationKeyPresenter.java @@ -20,52 +20,49 @@ package org.sufficientlysecure.keychain.remote.ui.dialog; import java.util.List; +import android.arch.lifecycle.LifecycleOwner; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.Loader; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; +import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyActivity.SelectAuthKeyViewModel; import timber.log.Timber; -class RemoteSelectAuthenticationKeyPresenter implements LoaderCallbacks> { +class RemoteSelectAuthenticationKeyPresenter { private final PackageManager packageManager; + private final LifecycleOwner lifecycleOwner; private final Context context; - private final int loaderId; private RemoteSelectAuthenticationKeyView view; private Integer selectedItem; - private List keyInfoData; + private List keyInfoData; - RemoteSelectAuthenticationKeyPresenter(Context context, int loaderId) { + RemoteSelectAuthenticationKeyPresenter(Context context, LifecycleOwner lifecycleOwner) { this.context = context; + this.lifecycleOwner = lifecycleOwner; packageManager = context.getPackageManager(); - - this.loaderId = loaderId; } public void setView(RemoteSelectAuthenticationKeyView view) { this.view = view; } - void setupFromIntentData(String packageName) { + void setupFromViewModel(SelectAuthKeyViewModel viewModel) { try { - setPackageInfo(packageName); + setPackageInfo(viewModel.getPackageName()); } catch (NameNotFoundException e) { Timber.e("Unable to find info of calling app!"); view.finishAsCancelled(); } + + viewModel.getKeyInfoLiveData(context).observe(lifecycleOwner, this::onLoadKeyInfos); } private void setPackageInfo(String packageName) throws NameNotFoundException { @@ -75,31 +72,11 @@ class RemoteSelectAuthenticationKeyPresenter implements LoaderCallbacks> onCreateLoader(int id, Bundle args) { - String selection = KeyRings.HAS_AUTHENTICATE_SECRET + " != 0"; - KeySelector keySelector = KeySelector.create( - KeyRings.buildUnifiedKeyRingsUri(), selection); - return new KeyInfoLoader(context, context.getContentResolver(), keySelector); - } - - @Override - public void onLoadFinished(Loader> loader, List data) { + private void onLoadKeyInfos(List data) { this.keyInfoData = data; view.setKeyListData(data); } - @Override - public void onLoaderReset(Loader loader) { - if (view != null) { - view.setKeyListData(null); - } - } - void onClickSelect() { if (keyInfoData == null) { Timber.e("got click on select with no data…?"); @@ -110,7 +87,7 @@ class RemoteSelectAuthenticationKeyPresenter implements LoaderCallbacks data); + void setKeyListData(List data); void setActiveItem(Integer position); void setEnableSelectButton(boolean enabled); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdKeyActivity.java index fa9674e73..790a830d2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdKeyActivity.java @@ -23,6 +23,8 @@ import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.ViewModel; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.DialogInterface; @@ -58,8 +60,11 @@ import android.widget.Toast; import com.mikepenz.materialdrawer.util.KeyboardUtil; import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; +import org.sufficientlysecure.keychain.livedata.GenericLiveData; +import org.sufficientlysecure.keychain.livedata.PgpKeyGenerationLiveData; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.ui.MainActivity; @@ -89,13 +94,18 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - RemoteSelectIdViewModel viewModel = - ViewModelProviders.of(this).get(RemoteSelectIdViewModel.class); - - presenter = new RemoteSelectIdentityKeyPresenter(getBaseContext(), viewModel, this); + presenter = new RemoteSelectIdentityKeyPresenter(getBaseContext(), this); KeyboardUtil.hideKeyboard(this); + RemoteSelectIdViewModel viewModel = ViewModelProviders.of(this).get(RemoteSelectIdViewModel.class); + + Intent intent = getIntent(); + viewModel.rawUserId = intent.getStringExtra(EXTRA_USER_ID); + viewModel.packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); + viewModel.packageSignature = intent.getByteArrayExtra(EXTRA_PACKAGE_SIGNATURE); + viewModel.clientHasAutocryptSetupMsg = intent.getBooleanExtra(EXTRA_SHOW_AUTOCRYPT_HINT, false); + if (savedInstanceState == null) { RemoteSelectIdentityKeyDialogFragment frag = new RemoteSelectIdentityKeyDialogFragment(); frag.show(getSupportFragmentManager(), "requestKeyDialog"); @@ -106,13 +116,45 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { protected void onStart() { super.onStart(); - Intent intent = getIntent(); - String userId = intent.getStringExtra(EXTRA_USER_ID); - String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); - byte[] packageSignature = intent.getByteArrayExtra(EXTRA_PACKAGE_SIGNATURE); - boolean showAutocryptHint = intent.getBooleanExtra(EXTRA_SHOW_AUTOCRYPT_HINT, false); + RemoteSelectIdViewModel viewModel = ViewModelProviders.of(this).get(RemoteSelectIdViewModel.class); + presenter.setupFromViewModel(viewModel); + } + + public static class RemoteSelectIdViewModel extends ViewModel { + public String packageName; + public byte[] packageSignature; + public String rawUserId; + public boolean clientHasAutocryptSetupMsg; + + public List filteredKeyInfo; + + private LiveData> keyInfo; + private PgpKeyGenerationLiveData keyGenerationData; + private boolean listAllKeys; + + public LiveData> getSecretUnifiedKeyInfo(Context context) { + if (keyInfo == null) { + KeyRepository keyRepository = KeyRepository.create(context); + keyInfo = new GenericLiveData<>(context, null, keyRepository::getAllUnifiedKeyInfoWithSecret); + } + return keyInfo; + } + + public PgpKeyGenerationLiveData getKeyGenerationLiveData(Context context) { + if (keyGenerationData == null) { + keyGenerationData = new PgpKeyGenerationLiveData(context); + } + return keyGenerationData; + } + + public boolean isListAllKeys() { + return listAllKeys; + } + + public void setListAllKeys(boolean listAllKeys) { + this.listAllKeys = listAllKeys; + } - presenter.setupFromIntentData(packageName, packageSignature, userId, showAutocryptHint); } public static class RemoteSelectIdentityKeyDialogFragment extends DialogFragment { @@ -135,7 +177,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); + Activity activity = requireActivity(); ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); @@ -177,7 +219,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - presenter = ((RemoteSelectIdKeyActivity) getActivity()).presenter; + presenter = ((RemoteSelectIdKeyActivity) requireActivity()).presenter; presenter.setView(mvpView); } @@ -203,7 +245,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { @NonNull private RemoteSelectIdentityKeyView createMvpView(final ViewGroup rootView, LayoutInflater layoutInflater) { // final ImageView iconClientApp = rootView.findViewById(R.id.icon_client_app); - final KeyChoiceAdapter keyChoiceAdapter = new KeyChoiceAdapter(layoutInflater, getResources()); + final KeyChoiceAdapter keyChoiceAdapter = new KeyChoiceAdapter(layoutInflater); final TextView titleText = rootView.findViewById(R.id.text_title_select_key); final TextView addressText = rootView.findViewById(R.id.text_user_id); final TextView autocryptHint = rootView.findViewById(R.id.key_import_autocrypt_hint); @@ -309,7 +351,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { } @Override - public void setKeyListData(List data) { + public void setKeyListData(List data) { keyChoiceAdapter.setData(data); } @@ -405,19 +447,18 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { private static class KeyChoiceAdapter extends Adapter { private final LayoutInflater layoutInflater; - private final Resources resources; - private List data; + private List data; private Drawable iconUnselected; private Drawable iconSelected; private Integer activeItem; - KeyChoiceAdapter(LayoutInflater layoutInflater, Resources resources) { + KeyChoiceAdapter(LayoutInflater layoutInflater) { this.layoutInflater = layoutInflater; - this.resources = resources; } + @NonNull @Override - public KeyChoiceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public KeyChoiceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View keyChoiceItemView = layoutInflater.inflate(R.layout.api_select_identity_item, parent, false); return new KeyChoiceViewHolder(keyChoiceItemView); } @@ -428,8 +469,8 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { } @Override - public void onBindViewHolder(KeyChoiceViewHolder holder, int position) { - KeyInfo keyInfo = data.get(position); + public void onBindViewHolder(@NonNull KeyChoiceViewHolder holder, int position) { + UnifiedKeyInfo keyInfo = data.get(position); boolean hasActiveItem = activeItem != null; boolean isActiveItem = hasActiveItem && position == activeItem; @@ -444,7 +485,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { return data != null ? data.size() : 0; } - public void setData(List data) { + public void setData(List data) { this.data = data; notifyDataSetChanged(); } @@ -469,11 +510,11 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { vIcon = itemView.findViewById(R.id.key_list_item_icon); } - void bind(KeyInfo keyInfo, Drawable selectionIcon) { + void bind(UnifiedKeyInfo keyInfo, Drawable selectionIcon) { Context context = vCreation.getContext(); - String email = keyInfo.getEmail(); - String name = keyInfo.getName(); + String email = keyInfo.email(); + String name = keyInfo.name(); if (email != null) { vName.setText(context.getString(R.string.use_key, email)); } else if (name != null) { @@ -482,7 +523,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity { vName.setText(context.getString(R.string.use_key_no_name)); } - String dateTime = DateUtils.formatDateTime(context, keyInfo.getCreationDate(), + String dateTime = DateUtils.formatDateTime(context, keyInfo.creation(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH); vCreation.setText(context.getString(R.string.label_key_created, dateTime)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdViewModel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdViewModel.java deleted file mode 100644 index d287129fb..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdViewModel.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.sufficientlysecure.keychain.remote.ui.dialog; - - -import android.arch.lifecycle.ViewModel; -import android.content.Context; - -import org.sufficientlysecure.keychain.livedata.KeyInfoLiveData; -import org.sufficientlysecure.keychain.livedata.PgpKeyGenerationLiveData; - - -public class RemoteSelectIdViewModel extends ViewModel { - - private KeyInfoLiveData keyInfo; - private PgpKeyGenerationLiveData keyGenerationData; - private boolean listAllKeys; - - public KeyInfoLiveData getKeyInfo(Context context) { - if (keyInfo == null) { - keyInfo = new KeyInfoLiveData(context, context.getContentResolver()); - } - return keyInfo; - } - - public PgpKeyGenerationLiveData getKeyGenerationLiveData(Context context) { - if (keyGenerationData == null) { - keyGenerationData = new PgpKeyGenerationLiveData(context); - } - return keyGenerationData; - } - - public boolean isListAllKeys() { - return listAllKeys; - } - - public void setListAllKeys(boolean listAllKeys) { - this.listAllKeys = listAllKeys; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdentityKeyPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdentityKeyPresenter.java index b9856367e..460546e70 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdentityKeyPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/dialog/RemoteSelectIdentityKeyPresenter.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.remote.ui.dialog; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import android.arch.lifecycle.LifecycleOwner; @@ -27,19 +28,18 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; -import android.net.Uri; +import android.text.TextUtils; import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils.UserId; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo; -import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector; import org.sufficientlysecure.keychain.model.ApiApp; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.provider.ApiAppDao; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdKeyActivity.RemoteSelectIdViewModel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import timber.log.Timber; @@ -47,12 +47,12 @@ import timber.log.Timber; class RemoteSelectIdentityKeyPresenter { private final PackageManager packageManager; + private LifecycleOwner lifecycleOwner; private final Context context; - private final RemoteSelectIdViewModel viewModel; - private RemoteSelectIdentityKeyView view; - private List keyInfoData; + private RemoteSelectIdViewModel viewModel; + private List keyInfoData; private UserId userId; private long selectedMasterKeyId; @@ -61,41 +61,35 @@ class RemoteSelectIdentityKeyPresenter { private ApiApp apiApp; - RemoteSelectIdentityKeyPresenter(Context context, RemoteSelectIdViewModel viewModel, LifecycleOwner lifecycleOwner) { + RemoteSelectIdentityKeyPresenter(Context context, LifecycleOwner lifecycleOwner) { this.context = context; - this.viewModel = viewModel; + this.lifecycleOwner = lifecycleOwner; this.apiAppDao = ApiAppDao.getInstance(context); packageManager = context.getPackageManager(); - - viewModel.getKeyGenerationLiveData(context).observe(lifecycleOwner, this::onChangeKeyGeneration); - viewModel.getKeyInfo(context).observe(lifecycleOwner, this::onChangeKeyInfoData); } public void setView(RemoteSelectIdentityKeyView view) { this.view = view; } - void setupFromIntentData(String packageName, byte[] packageSignature, String rawUserId, boolean clientHasAutocryptSetupMsg) { + void setupFromViewModel(RemoteSelectIdViewModel viewModel) { + this.viewModel = viewModel; + try { - setPackageInfo(packageName, packageSignature); + setPackageInfo(viewModel.packageName, viewModel.packageSignature); } catch (NameNotFoundException e) { Timber.e(e, "Unable to find info of calling app!"); view.finishAsCancelled(); return; } - this.userId = OpenPgpUtils.splitUserId(rawUserId); + this.userId = OpenPgpUtils.splitUserId(viewModel.rawUserId); view.setAddressText(userId.email); - view.setShowAutocryptHint(clientHasAutocryptSetupMsg); + view.setShowAutocryptHint(viewModel.clientHasAutocryptSetupMsg); - loadKeyInfo(); - } - - private void loadKeyInfo() { - Uri listedKeyRingUri = viewModel.isListAllKeys() ? - KeyRings.buildUnifiedKeyRingsUri() : KeyRings.buildUnifiedKeyRingsFindByUserIdUri(userId.email); - viewModel.getKeyInfo(context).setKeySelector(KeySelector.createOnlySecret(listedKeyRingUri, null)); + viewModel.getKeyGenerationLiveData(context).observe(lifecycleOwner, this::onChangeKeyGeneration); + viewModel.getSecretUnifiedKeyInfo(context).observe(lifecycleOwner, this::onChangeKeyInfoData); } private void setPackageInfo(String packageName, byte[] packageSignature) throws NameNotFoundException { @@ -108,22 +102,41 @@ class RemoteSelectIdentityKeyPresenter { view.setTitleClientIconAndName(appIcon, appLabel); } - private void onChangeKeyInfoData(List data) { + private void onChangeKeyInfoData(List data) { + if (data == null) { + return; + } keyInfoData = data; goToSelectLayout(); } private void goToSelectLayout() { - if (keyInfoData == null) { + List filteredKeyInfoData = + viewModel.isListAllKeys() || TextUtils.isEmpty(userId.email) ? keyInfoData : getFilteredKeyInfo(); + + if (filteredKeyInfoData == null) { view.showLayoutEmpty(); - } else if (keyInfoData.isEmpty()) { + } else if (filteredKeyInfoData.isEmpty()) { view.showLayoutSelectNoKeys(); } else { - view.setKeyListData(keyInfoData); + view.setKeyListData(filteredKeyInfoData); view.showLayoutSelectKeyList(); } } + private List getFilteredKeyInfo() { + if (viewModel.filteredKeyInfo == null) { + viewModel.filteredKeyInfo = new ArrayList<>(); + for (UnifiedKeyInfo unifiedKeyInfo : keyInfoData) { + String emailSearchList = unifiedKeyInfo.user_id_list(); + if (emailSearchList == null || emailSearchList.contains(userId.email)) { + viewModel.filteredKeyInfo.add(unifiedKeyInfo); + } + } + } + return viewModel.filteredKeyInfo; + } + private void onChangeKeyGeneration(PgpEditKeyResult pgpEditKeyResult) { if (pgpEditKeyResult == null) { return; @@ -171,7 +184,7 @@ class RemoteSelectIdentityKeyPresenter { } void onKeyItemClick(int position) { - selectedMasterKeyId = keyInfoData.get(position).getMasterKeyId(); + selectedMasterKeyId = keyInfoData.get(position).master_key_id(); view.highlightKey(position); } @@ -222,8 +235,7 @@ class RemoteSelectIdentityKeyPresenter { public void onClickMenuListAllKeys() { viewModel.setListAllKeys(!viewModel.isListAllKeys()); - loadKeyInfo(); - view.showLayoutSelectKeyList(); + goToSelectLayout(); } public void onClickGoToOpenKeychain() { @@ -246,7 +258,7 @@ class RemoteSelectIdentityKeyPresenter { void showLayoutGenerateOk(); void showLayoutGenerateSave(); - void setKeyListData(List data); + void setKeyListData(List data); void highlightKey(int position); diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq index 4653b3ded..bdb260e54 100644 --- a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq @@ -23,8 +23,9 @@ CREATE TABLE IF NOT EXISTS keys ( keyrings_public(master_key_id) ON DELETE CASCADE ); -selectAllUnifiedKeyInfo: -SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, certs.verified, +unifiedKeyView: +CREATE VIEW unifiedKeyView AS + SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, certs.verified, (EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate_int, (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0 )) AS has_any_secret_int, (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0 )) AS has_auth_key_int, @@ -36,23 +37,25 @@ SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packet LEFT JOIN certs ON ( keys.master_key_id = certs.master_key_id AND certs.verified = 1 ) LEFT JOIN autocrypt_peers AS aTI ON ( aTI.master_key_id = keys.master_key_id ) WHERE keys.rank = 0 - GROUP BY keys.master_key_id - ORDER BY has_secret DESC, user_packets.name COLLATE NOCASE ASC; + GROUP BY keys.master_key_id; + +selectAllUnifiedKeyInfo: +SELECT * FROM unifiedKeyView + ORDER BY has_any_secret_int DESC, name COLLATE NOCASE ASC, creation DESC; selectUnifiedKeyInfoByMasterKeyId: -SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, certs.verified, - (EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate_int, - (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0 )) AS has_any_secret_int, - (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0 )) AS has_auth_key_int, - (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0 )) AS has_encrypt_key_int, - GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv, - GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list - FROM keys - INNER JOIN user_packets ON ( keys.master_key_id = user_packets.master_key_id AND user_packets.type IS NULL ) - LEFT JOIN certs ON ( keys.master_key_id = certs.master_key_id AND certs.verified = 1 ) - LEFT JOIN autocrypt_peers AS aTI ON ( aTI.master_key_id = keys.master_key_id ) - WHERE keys.rank = 0 AND keys.master_key_id = ? - GROUP BY keys.master_key_id; +SELECT * FROM unifiedKeyView + WHERE is_revoked = 0 AND master_key_id = ?; + +selectUnifiedKeyInfoSearchMailAddress: +SELECT * FROM unifiedKeyView + WHERE email LIKE ? + ORDER BY creation DESC; + +selectAllUnifiedKeyInfoWithSecret: +SELECT * FROM unifiedKeyView + WHERE has_any_secret_int = 1 + ORDER BY creation DESC; selectSubkeysByMasterKeyId: SELECT *