extract findByUserId and findByEmail usage from KeychainProvider
This commit is contained in:
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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<KeyInfo> loadKeyInfo(KeySelector keySelector) {
|
|
||||||
ArrayList<KeyInfo> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<List<KeyInfo>> {
|
|
||||||
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<KeyInfo> asyncLoadData() {
|
|
||||||
if (keySelector == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return keyInfoInteractor.loadKeyInfo(keySelector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,8 +15,8 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
|||||||
public abstract class SubKey implements KeysModel {
|
public abstract class SubKey implements KeysModel {
|
||||||
public static final Factory<SubKey> FACTORY =
|
public static final Factory<SubKey> FACTORY =
|
||||||
new Factory<>(AutoValue_SubKey::new, CustomColumnAdapters.SECRET_KEY_TYPE_ADAPTER);
|
new Factory<>(AutoValue_SubKey::new, CustomColumnAdapters.SECRET_KEY_TYPE_ADAPTER);
|
||||||
public static final SelectAllUnifiedKeyInfoMapper<UnifiedKeyInfo> UNIFIED_KEY_INFO_MAPPER =
|
public static final UnifiedKeyViewMapper<UnifiedKeyInfo> UNIFIED_KEY_INFO_MAPPER =
|
||||||
FACTORY.selectAllUnifiedKeyInfoMapper(AutoValue_SubKey_UnifiedKeyInfo::new);
|
FACTORY.selectUnifiedKeyInfoByMasterKeyIdMapper(AutoValue_SubKey_UnifiedKeyInfo::new);
|
||||||
public static Mapper<SubKey> SUBKEY_MAPPER = new Mapper<>(FACTORY);
|
public static Mapper<SubKey> SUBKEY_MAPPER = new Mapper<>(FACTORY);
|
||||||
public static RowMapper<SecretKeyType> SKT_MAPPER = FACTORY.selectSecretKeyTypeMapper();
|
public static RowMapper<SecretKeyType> SKT_MAPPER = FACTORY.selectSecretKeyTypeMapper();
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ public abstract class SubKey implements KeysModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public static abstract class UnifiedKeyInfo implements SelectAllUnifiedKeyInfoModel {
|
public static abstract class UnifiedKeyInfo implements KeysModel.UnifiedKeyViewModel {
|
||||||
private List<String> autocryptPackageNames;
|
private List<String> autocryptPackageNames;
|
||||||
|
|
||||||
public boolean is_expired() {
|
public boolean is_expired() {
|
||||||
|
|||||||
@@ -264,11 +264,21 @@ public class KeyRepository extends AbstractDao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
|
||||||
|
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%');
|
||||||
|
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||||
|
}
|
||||||
|
|
||||||
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
|
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo();
|
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo();
|
||||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() {
|
||||||
|
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret();
|
||||||
|
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||||
|
}
|
||||||
|
|
||||||
public List<UserId> getUserIds(long... masterKeyIds) {
|
public List<UserId> getUserIds(long... masterKeyIds) {
|
||||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds);
|
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds);
|
||||||
return mapAllRows(query, UserPacket.USER_ID_MAPPER::map);
|
return mapAllRows(query, UserPacket.USER_ID_MAPPER::map);
|
||||||
|
|||||||
@@ -100,9 +100,7 @@ public class KeychainContract {
|
|||||||
public static final String PATH_UNIFIED = "unified";
|
public static final String PATH_UNIFIED = "unified";
|
||||||
|
|
||||||
public static final String PATH_FIND = "find";
|
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_SUBKEY = "subkey";
|
||||||
public static final String PATH_BY_USER_ID = "user_id";
|
|
||||||
|
|
||||||
public static final String PATH_PUBLIC = "public";
|
public static final String PATH_PUBLIC = "public";
|
||||||
public static final String PATH_USER_IDS = "user_ids";
|
public static final String PATH_USER_IDS = "user_ids";
|
||||||
@@ -140,16 +138,6 @@ public class KeychainContract {
|
|||||||
.appendPath(PATH_UNIFIED).build();
|
.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) {
|
public static Uri buildUnifiedKeyRingsFindBySubkeyUri(long subkey) {
|
||||||
return CONTENT_URI.buildUpon().appendPath(PATH_FIND)
|
return CONTENT_URI.buildUpon().appendPath(PATH_FIND)
|
||||||
.appendPath(PATH_BY_SUBKEY).appendPath(Long.toString(subkey)).build();
|
.appendPath(PATH_BY_SUBKEY).appendPath(Long.toString(subkey)).build();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.KeyMetadataModel;
|
import org.sufficientlysecure.keychain.KeyMetadataModel;
|
||||||
import org.sufficientlysecure.keychain.KeyRingsPublicModel;
|
import org.sufficientlysecure.keychain.KeyRingsPublicModel;
|
||||||
import org.sufficientlysecure.keychain.KeySignaturesModel;
|
import org.sufficientlysecure.keychain.KeySignaturesModel;
|
||||||
|
import org.sufficientlysecure.keychain.KeysModel;
|
||||||
import org.sufficientlysecure.keychain.UserPacketsModel;
|
import org.sufficientlysecure.keychain.UserPacketsModel;
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
import org.sufficientlysecure.keychain.model.ApiApp;
|
||||||
import org.sufficientlysecure.keychain.model.Certification;
|
import org.sufficientlysecure.keychain.model.Certification;
|
||||||
@@ -65,7 +66,7 @@ import timber.log.Timber;
|
|||||||
*/
|
*/
|
||||||
public class KeychainDatabase {
|
public class KeychainDatabase {
|
||||||
private static final String DATABASE_NAME = "openkeychain.db";
|
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 final SupportSQLiteOpenHelper supportSQLiteOpenHelper;
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
@@ -205,6 +206,7 @@ public class KeychainDatabase {
|
|||||||
db.execSQL(CREATE_OVERRIDDEN_WARNINGS);
|
db.execSQL(CREATE_OVERRIDDEN_WARNINGS);
|
||||||
db.execSQL(AutocryptPeersModel.CREATE_TABLE);
|
db.execSQL(AutocryptPeersModel.CREATE_TABLE);
|
||||||
db.execSQL(ApiAppsModel.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 keys_by_rank ON keys (" + KeysColumns.RANK + ", " + KeysColumns.MASTER_KEY_ID + ");");
|
||||||
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsColumns.RANK + ", "
|
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);
|
migrateUpdatedKeysToKeyMetadataTable(db);
|
||||||
}
|
|
||||||
|
|
||||||
case 27: {
|
case 27:
|
||||||
renameApiAutocryptPeersTable(db);
|
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 {
|
private void migrateSecretKeysFromDbToLocalStorage(SupportSQLiteDatabase db) throws IOException {
|
||||||
LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context);
|
LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context);
|
||||||
Cursor cursor = db.query("SELECT master_key_id, key_ring_data FROM keyrings_secret");
|
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) {
|
private void migrateUpdatedKeysToKeyMetadataTable(SupportSQLiteDatabase db) {
|
||||||
try {
|
try {
|
||||||
db.execSQL("ALTER TABLE updated_keys RENAME TO key_metadata;");
|
db.execSQL("ALTER TABLE updated_keys RENAME TO key_metadata;");
|
||||||
db.execSQL("UPDATE key_metadata SET last_updated = last_updated * 1000;");
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
if (Constants.DEBUG) {
|
if (Constants.DEBUG) {
|
||||||
Timber.e(e, "Ignoring migration exception, this probably happened before");
|
Timber.e(e, "Ignoring migration exception, this probably happened before");
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import android.content.ContentProvider;
|
|||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.DatabaseUtils;
|
|
||||||
import android.database.sqlite.SQLiteConstraintException;
|
import android.database.sqlite.SQLiteConstraintException;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
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_PUBLIC = 203;
|
||||||
private static final int KEY_RING_CERTS = 205;
|
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_SUBKEY = 401;
|
||||||
private static final int KEY_RINGS_FIND_BY_USER_ID = 402;
|
|
||||||
|
|
||||||
private static final int KEY_SIGNATURES = 700;
|
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
|
* find by criteria other than master key id
|
||||||
*
|
*
|
||||||
* key_rings/find/email/_
|
|
||||||
* key_rings/find/subkey/_
|
* 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 + "/"
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
|
||||||
+ KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*",
|
+ KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*",
|
||||||
KEY_RINGS_FIND_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
|
* list key_ring specifics
|
||||||
@@ -185,9 +175,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
|||||||
switch (match) {
|
switch (match) {
|
||||||
case KEY_RING_UNIFIED:
|
case KEY_RING_UNIFIED:
|
||||||
case KEY_RINGS_UNIFIED:
|
case KEY_RINGS_UNIFIED:
|
||||||
case KEY_RINGS_FIND_BY_EMAIL:
|
case KEY_RINGS_FIND_BY_SUBKEY: {
|
||||||
case KEY_RINGS_FIND_BY_SUBKEY:
|
|
||||||
case KEY_RINGS_FIND_BY_USER_ID: {
|
|
||||||
HashMap<String, String> projectionMap = new HashMap<>();
|
HashMap<String, String> projectionMap = new HashMap<>();
|
||||||
projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
|
projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
|
||||||
projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_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;
|
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)) {
|
if (TextUtils.isEmpty(sortOrder)) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.remote;
|
package org.sufficientlysecure.keychain.remote;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
@@ -25,7 +26,6 @@ import android.content.Intent;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.pgp.DecryptVerifySecurityProblem;
|
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.RemoteBackupActivity;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.RemoteDisplayTransferCodeActivity;
|
import org.sufficientlysecure.keychain.remote.ui.RemoteDisplayTransferCodeActivity;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.RemoteErrorActivity;
|
import org.sufficientlysecure.keychain.remote.ui.RemoteErrorActivity;
|
||||||
|
|||||||
@@ -207,9 +207,9 @@ class SecurityProblemPresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onClickViewKey() {
|
void onClickViewKey() {
|
||||||
Intent viewKeyIntent = new Intent(context, ViewKeyActivity.class);
|
Intent intent = new Intent(context, ViewKeyActivity.class);
|
||||||
viewKeyIntent.setData(KeyRings.buildGenericKeyRingUri(viewKeyMasterKeyId));
|
intent.putExtra(ViewKeyActivity.EXTRA_MASTER_KEY_ID, viewKeyMasterKeyId);
|
||||||
context.startActivity(viewKeyIntent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onClickOverride() {
|
void onClickOverride() {
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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<List<KeyInfo>> {
|
|
||||||
private final KeySelector keySelector;
|
|
||||||
|
|
||||||
private List<KeyInfo> cachedResult;
|
|
||||||
private KeyInfoInteractor keyInfoInteractor;
|
|
||||||
|
|
||||||
KeyInfoLoader(Context context, ContentResolver contentResolver, KeySelector keySelector) {
|
|
||||||
super(context);
|
|
||||||
|
|
||||||
this.keySelector = keySelector;
|
|
||||||
this.keyInfoInteractor = new KeyInfoInteractor(contentResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<KeyInfo> loadInBackground() {
|
|
||||||
return keyInfoInteractor.loadKeyInfo(keySelector);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deliverResult(List<KeyInfo> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,6 +23,9 @@ import java.util.List;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
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.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -42,7 +45,6 @@ import android.text.format.DateUtils;
|
|||||||
import android.view.ContextThemeWrapper;
|
import android.view.ContextThemeWrapper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -50,8 +52,10 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
||||||
import org.sufficientlysecure.keychain.R;
|
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.remote.ui.RemoteSecurityTokenOperationActivity;
|
||||||
import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicatePresenter.RemoteDeduplicateView;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicatePresenter.RemoteDeduplicateView;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
||||||
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
|
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_PACKAGE_NAME = "package_name";
|
||||||
public static final String EXTRA_DUPLICATE_EMAILS = "duplicate_emails";
|
public static final String EXTRA_DUPLICATE_EMAILS = "duplicate_emails";
|
||||||
|
|
||||||
public static final int LOADER_ID_KEYS = 0;
|
|
||||||
|
|
||||||
|
|
||||||
private RemoteDeduplicatePresenter presenter;
|
private RemoteDeduplicatePresenter presenter;
|
||||||
|
|
||||||
@@ -73,7 +75,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
presenter = new RemoteDeduplicatePresenter(getBaseContext(), LOADER_ID_KEYS);
|
presenter = new RemoteDeduplicatePresenter(getBaseContext(), this);
|
||||||
|
|
||||||
KeyboardUtil.hideKeyboard(this);
|
KeyboardUtil.hideKeyboard(this);
|
||||||
|
|
||||||
@@ -92,8 +94,43 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
String duplicateAddress = dupAddresses.get(0);
|
String duplicateAddress = dupAddresses.get(0);
|
||||||
String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
|
String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
|
||||||
|
|
||||||
presenter.setupFromIntentData(packageName, duplicateAddress);
|
DeduplicateViewModel viewModel = ViewModelProviders.of(this).get(DeduplicateViewModel.class);
|
||||||
presenter.startLoaders(getSupportLoaderManager());
|
viewModel.setDuplicateAddress(duplicateAddress);
|
||||||
|
viewModel.setPackageName(packageName);
|
||||||
|
|
||||||
|
presenter.setupFromViewModel(viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DeduplicateViewModel extends ViewModel {
|
||||||
|
private String duplicateAddress;
|
||||||
|
private LiveData<List<UnifiedKeyInfo>> keyInfoLiveData;
|
||||||
|
private String packageName;
|
||||||
|
|
||||||
|
public LiveData<List<UnifiedKeyInfo>> 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 {
|
public static class RemoteDeduplicateDialogFragment extends DialogFragment {
|
||||||
@@ -107,7 +144,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final Activity activity = getActivity();
|
Activity activity = requireActivity();
|
||||||
|
|
||||||
ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
|
ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
|
||||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
|
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
|
||||||
@@ -135,7 +172,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
presenter = ((RemoteDeduplicateActivity) getActivity()).presenter;
|
presenter = ((RemoteDeduplicateActivity) requireActivity()).presenter;
|
||||||
presenter.setView(mvpView);
|
presenter.setView(mvpView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +239,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setKeyListData(List<KeyInfo> data) {
|
public void setKeyListData(List<UnifiedKeyInfo> data) {
|
||||||
keyChoiceAdapter.setData(data);
|
keyChoiceAdapter.setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,34 +256,17 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupListenersForPresenter() {
|
private void setupListenersForPresenter() {
|
||||||
buttonSelect.setOnClickListener(new OnClickListener() {
|
buttonSelect.setOnClickListener(view -> presenter.onClickSelect());
|
||||||
@Override
|
buttonCancel.setOnClickListener(view -> presenter.onClickCancel());
|
||||||
public void onClick(View view) {
|
|
||||||
presenter.onClickSelect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonCancel.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
presenter.onClickCancel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
keyChoiceList.addOnItemTouchListener(new RecyclerItemClickListener(getContext(),
|
keyChoiceList.addOnItemTouchListener(new RecyclerItemClickListener(getContext(),
|
||||||
new RecyclerItemClickListener.OnItemClickListener() {
|
(view, position) -> presenter.onKeyItemClick(position)));
|
||||||
@Override
|
|
||||||
public void onItemClick(View view, int position) {
|
|
||||||
presenter.onKeyItemClick(position);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class KeyChoiceAdapter extends Adapter<KeyChoiceViewHolder> {
|
private static class KeyChoiceAdapter extends Adapter<KeyChoiceViewHolder> {
|
||||||
private final LayoutInflater layoutInflater;
|
private final LayoutInflater layoutInflater;
|
||||||
private final Resources resources;
|
private final Resources resources;
|
||||||
private List<KeyInfo> data;
|
private List<UnifiedKeyInfo> data;
|
||||||
private Drawable iconUnselected;
|
private Drawable iconUnselected;
|
||||||
private Drawable iconSelected;
|
private Drawable iconSelected;
|
||||||
private Integer activeItem;
|
private Integer activeItem;
|
||||||
@@ -256,15 +276,16 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
this.resources = resources;
|
this.resources = resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@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);
|
View keyChoiceItemView = layoutInflater.inflate(R.layout.duplicate_key_item, parent, false);
|
||||||
return new KeyChoiceViewHolder(keyChoiceItemView);
|
return new KeyChoiceViewHolder(keyChoiceItemView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(KeyChoiceViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull KeyChoiceViewHolder holder, int position) {
|
||||||
KeyInfo keyInfo = data.get(position);
|
UnifiedKeyInfo keyInfo = data.get(position);
|
||||||
Drawable icon = (activeItem != null && position == activeItem) ? iconSelected : iconUnselected;
|
Drawable icon = (activeItem != null && position == activeItem) ? iconSelected : iconUnselected;
|
||||||
holder.bind(keyInfo, icon);
|
holder.bind(keyInfo, icon);
|
||||||
}
|
}
|
||||||
@@ -274,7 +295,7 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
return data != null ? data.size() : 0;
|
return data != null ? data.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(List<KeyInfo> data) {
|
public void setData(List<UnifiedKeyInfo> data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@@ -319,11 +340,11 @@ public class RemoteDeduplicateActivity extends FragmentActivity {
|
|||||||
vIcon = itemView.findViewById(R.id.key_list_item_icon);
|
vIcon = itemView.findViewById(R.id.key_list_item_icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind(KeyInfo keyInfo, Drawable selectionIcon) {
|
void bind(UnifiedKeyInfo keyInfo, Drawable selectionIcon) {
|
||||||
vName.setText(keyInfo.getName());
|
vName.setText(keyInfo.name());
|
||||||
|
|
||||||
Context context = vCreation.getContext();
|
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_DATE | DateUtils.FORMAT_SHOW_TIME |
|
||||||
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH);
|
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH);
|
||||||
vCreation.setText(context.getString(R.string.label_key_created, dateTime));
|
vCreation.setText(context.getString(R.string.label_key_created, dateTime));
|
||||||
|
|||||||
@@ -20,62 +20,59 @@ package org.sufficientlysecure.keychain.remote.ui.dialog;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.graphics.drawable.Drawable;
|
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.model.SubKey.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
|
||||||
import org.sufficientlysecure.keychain.remote.AutocryptInteractor;
|
import org.sufficientlysecure.keychain.remote.AutocryptInteractor;
|
||||||
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicateActivity.DeduplicateViewModel;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
class RemoteDeduplicatePresenter implements LoaderCallbacks<List<KeyInfo>> {
|
class RemoteDeduplicatePresenter {
|
||||||
private final PackageManager packageManager;
|
private final PackageManager packageManager;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final int loaderId;
|
private final LifecycleOwner lifecycleOwner;
|
||||||
|
|
||||||
|
|
||||||
private AutocryptInteractor autocryptInteractor;
|
private AutocryptInteractor autocryptInteractor;
|
||||||
private String duplicateAddress;
|
|
||||||
|
|
||||||
|
private DeduplicateViewModel viewModel;
|
||||||
private RemoteDeduplicateView view;
|
private RemoteDeduplicateView view;
|
||||||
private Integer selectedItem;
|
private Integer selectedItem;
|
||||||
private List<KeyInfo> keyInfoData;
|
private List<UnifiedKeyInfo> keyInfoData;
|
||||||
|
|
||||||
|
|
||||||
RemoteDeduplicatePresenter(Context context, int loaderId) {
|
RemoteDeduplicatePresenter(Context context, LifecycleOwner lifecycleOwner) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.lifecycleOwner = lifecycleOwner;
|
||||||
|
|
||||||
packageManager = context.getPackageManager();
|
packageManager = context.getPackageManager();
|
||||||
|
|
||||||
this.loaderId = loaderId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setView(RemoteDeduplicateView view) {
|
public void setView(RemoteDeduplicateView view) {
|
||||||
this.view = 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 {
|
try {
|
||||||
setPackageInfo(packageName);
|
setPackageInfo(viewModel.getPackageName());
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
Timber.e("Unable to find info of calling app!");
|
Timber.e("Unable to find info of calling app!");
|
||||||
view.finishAsCancelled();
|
view.finishAsCancelled();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.autocryptInteractor = AutocryptInteractor.getInstance(context, packageName);
|
view.setAddressText(viewModel.getDuplicateAddress());
|
||||||
|
|
||||||
this.duplicateAddress = duplicateAddress;
|
viewModel.getKeyInfoLiveData(context).observe(lifecycleOwner, this::onLoadKeyInfos);
|
||||||
view.setAddressText(duplicateAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPackageInfo(String packageName) throws NameNotFoundException {
|
private void setPackageInfo(String packageName) throws NameNotFoundException {
|
||||||
@@ -85,31 +82,11 @@ class RemoteDeduplicatePresenter implements LoaderCallbacks<List<KeyInfo>> {
|
|||||||
view.setTitleClientIcon(appIcon);
|
view.setTitleClientIcon(appIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startLoaders(LoaderManager loaderManager) {
|
private void onLoadKeyInfos(List<UnifiedKeyInfo> data) {
|
||||||
loaderManager.restartLoader(loaderId, null, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Loader<List<KeyInfo>> 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<List<KeyInfo>> loader, List<KeyInfo> data) {
|
|
||||||
this.keyInfoData = data;
|
this.keyInfoData = data;
|
||||||
view.setKeyListData(data);
|
view.setKeyListData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoaderReset(Loader loader) {
|
|
||||||
if (view != null) {
|
|
||||||
view.setKeyListData(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onClickSelect() {
|
void onClickSelect() {
|
||||||
if (keyInfoData == null) {
|
if (keyInfoData == null) {
|
||||||
Timber.e("got click on select with no data…?");
|
Timber.e("got click on select with no data…?");
|
||||||
@@ -120,8 +97,8 @@ class RemoteDeduplicatePresenter implements LoaderCallbacks<List<KeyInfo>> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long masterKeyId = keyInfoData.get(selectedItem).getMasterKeyId();
|
long masterKeyId = keyInfoData.get(selectedItem).master_key_id();
|
||||||
autocryptInteractor.updateKeyGossipFromDedup(duplicateAddress, masterKeyId);
|
autocryptInteractor.updateKeyGossipFromDedup(viewModel.getDuplicateAddress(), masterKeyId);
|
||||||
|
|
||||||
view.finish();
|
view.finish();
|
||||||
}
|
}
|
||||||
@@ -151,7 +128,7 @@ class RemoteDeduplicatePresenter implements LoaderCallbacks<List<KeyInfo>> {
|
|||||||
void setAddressText(String text);
|
void setAddressText(String text);
|
||||||
void setTitleClientIcon(Drawable drawable);
|
void setTitleClientIcon(Drawable drawable);
|
||||||
|
|
||||||
void setKeyListData(List<KeyInfo> data);
|
void setKeyListData(List<UnifiedKeyInfo> data);
|
||||||
void setActiveItem(Integer position);
|
void setActiveItem(Integer position);
|
||||||
void setEnableSelectButton(boolean enabled);
|
void setEnableSelectButton(boolean enabled);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import java.util.List;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
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.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -42,7 +45,6 @@ import android.text.format.DateUtils;
|
|||||||
import android.view.ContextThemeWrapper;
|
import android.view.ContextThemeWrapper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -51,8 +53,10 @@ import android.widget.TextView;
|
|||||||
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
||||||
import org.openintents.ssh.authentication.SshAuthenticationApi;
|
import org.openintents.ssh.authentication.SshAuthenticationApi;
|
||||||
import org.sufficientlysecure.keychain.R;
|
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.ApiAppDao;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
|
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
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 class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
||||||
public static final String EXTRA_PACKAGE_NAME = "package_name";
|
public static final String EXTRA_PACKAGE_NAME = "package_name";
|
||||||
|
|
||||||
public static final int LOADER_ID_KEYS = 0;
|
|
||||||
|
|
||||||
|
|
||||||
private RemoteSelectAuthenticationKeyPresenter presenter;
|
private RemoteSelectAuthenticationKeyPresenter presenter;
|
||||||
private String packageName;
|
private String packageName;
|
||||||
@@ -75,7 +77,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
presenter = new RemoteSelectAuthenticationKeyPresenter(getBaseContext(), LOADER_ID_KEYS);
|
presenter = new RemoteSelectAuthenticationKeyPresenter(getBaseContext(), this);
|
||||||
|
|
||||||
KeyboardUtil.hideKeyboard(this);
|
KeyboardUtil.hideKeyboard(this);
|
||||||
|
|
||||||
@@ -92,8 +94,33 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
|
packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
|
||||||
|
|
||||||
presenter.setupFromIntentData(packageName);
|
SelectAuthKeyViewModel viewModel = ViewModelProviders.of(this).get(SelectAuthKeyViewModel.class);
|
||||||
presenter.startLoaders(getSupportLoaderManager());
|
viewModel.setPackageName(packageName);
|
||||||
|
|
||||||
|
presenter.setupFromViewModel(viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SelectAuthKeyViewModel extends ViewModel {
|
||||||
|
private LiveData<List<UnifiedKeyInfo>> keyInfoLiveData;
|
||||||
|
private String packageName;
|
||||||
|
|
||||||
|
public LiveData<List<UnifiedKeyInfo>> 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) {
|
private void onKeySelected(long masterKeyId) {
|
||||||
@@ -121,7 +148,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final Activity activity = getActivity();
|
Activity activity = requireActivity();
|
||||||
|
|
||||||
ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
|
ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
|
||||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
|
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
|
||||||
@@ -149,7 +176,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
presenter = ((RemoteSelectAuthenticationKeyActivity) getActivity()).presenter;
|
presenter = ((RemoteSelectAuthenticationKeyActivity) requireActivity()).presenter;
|
||||||
presenter.setView(mvpView);
|
presenter.setView(mvpView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +234,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setKeyListData(List<KeyInfo> data) {
|
public void setKeyListData(List<UnifiedKeyInfo> data) {
|
||||||
keyChoiceAdapter.setData(data);
|
keyChoiceAdapter.setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,34 +251,17 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupListenersForPresenter() {
|
private void setupListenersForPresenter() {
|
||||||
buttonSelect.setOnClickListener(new OnClickListener() {
|
buttonSelect.setOnClickListener(view -> presenter.onClickSelect());
|
||||||
@Override
|
buttonCancel.setOnClickListener(view -> presenter.onClickCancel());
|
||||||
public void onClick(View view) {
|
|
||||||
presenter.onClickSelect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonCancel.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
presenter.onClickCancel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
keyChoiceList.addOnItemTouchListener(new RecyclerItemClickListener(getContext(),
|
keyChoiceList.addOnItemTouchListener(new RecyclerItemClickListener(getContext(),
|
||||||
new RecyclerItemClickListener.OnItemClickListener() {
|
(view, position) -> presenter.onKeyItemClick(position)));
|
||||||
@Override
|
|
||||||
public void onItemClick(View view, int position) {
|
|
||||||
presenter.onKeyItemClick(position);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class KeyChoiceAdapter extends Adapter<KeyChoiceViewHolder> {
|
private static class KeyChoiceAdapter extends Adapter<KeyChoiceViewHolder> {
|
||||||
private final LayoutInflater layoutInflater;
|
private final LayoutInflater layoutInflater;
|
||||||
private final Resources resources;
|
private final Resources resources;
|
||||||
private List<KeyInfo> data;
|
private List<UnifiedKeyInfo> data;
|
||||||
private Drawable iconUnselected;
|
private Drawable iconUnselected;
|
||||||
private Drawable iconSelected;
|
private Drawable iconSelected;
|
||||||
private Integer activeItem;
|
private Integer activeItem;
|
||||||
@@ -261,15 +271,16 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
this.resources = resources;
|
this.resources = resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@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);
|
View keyChoiceItemView = layoutInflater.inflate(R.layout.authentication_key_item, parent, false);
|
||||||
return new KeyChoiceViewHolder(keyChoiceItemView);
|
return new KeyChoiceViewHolder(keyChoiceItemView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(KeyChoiceViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull KeyChoiceViewHolder holder, int position) {
|
||||||
KeyInfo keyInfo = data.get(position);
|
UnifiedKeyInfo keyInfo = data.get(position);
|
||||||
Drawable icon = (activeItem != null && position == activeItem) ? iconSelected : iconUnselected;
|
Drawable icon = (activeItem != null && position == activeItem) ? iconSelected : iconUnselected;
|
||||||
holder.bind(keyInfo, icon);
|
holder.bind(keyInfo, icon);
|
||||||
}
|
}
|
||||||
@@ -279,7 +290,7 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
return data != null ? data.size() : 0;
|
return data != null ? data.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(List<KeyInfo> data) {
|
public void setData(List<UnifiedKeyInfo> data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@@ -324,11 +335,11 @@ public class RemoteSelectAuthenticationKeyActivity extends FragmentActivity {
|
|||||||
vIcon = itemView.findViewById(R.id.key_list_item_icon);
|
vIcon = itemView.findViewById(R.id.key_list_item_icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind(KeyInfo keyInfo, Drawable selectionIcon) {
|
void bind(UnifiedKeyInfo keyInfo, Drawable selectionIcon) {
|
||||||
vName.setText(keyInfo.getName());
|
vName.setText(keyInfo.name());
|
||||||
|
|
||||||
Context context = vCreation.getContext();
|
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_DATE | DateUtils.FORMAT_SHOW_TIME |
|
||||||
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH);
|
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH);
|
||||||
vCreation.setText(context.getString(R.string.label_key_created, dateTime));
|
vCreation.setText(context.getString(R.string.label_key_created, dateTime));
|
||||||
|
|||||||
@@ -20,52 +20,49 @@ package org.sufficientlysecure.keychain.remote.ui.dialog;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.graphics.drawable.Drawable;
|
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.model.SubKey.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyActivity.SelectAuthKeyViewModel;
|
||||||
import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector;
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
class RemoteSelectAuthenticationKeyPresenter implements LoaderCallbacks<List<KeyInfo>> {
|
class RemoteSelectAuthenticationKeyPresenter {
|
||||||
private final PackageManager packageManager;
|
private final PackageManager packageManager;
|
||||||
|
private final LifecycleOwner lifecycleOwner;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final int loaderId;
|
|
||||||
|
|
||||||
|
|
||||||
private RemoteSelectAuthenticationKeyView view;
|
private RemoteSelectAuthenticationKeyView view;
|
||||||
private Integer selectedItem;
|
private Integer selectedItem;
|
||||||
private List<KeyInfo> keyInfoData;
|
private List<UnifiedKeyInfo> keyInfoData;
|
||||||
|
|
||||||
|
|
||||||
RemoteSelectAuthenticationKeyPresenter(Context context, int loaderId) {
|
RemoteSelectAuthenticationKeyPresenter(Context context, LifecycleOwner lifecycleOwner) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.lifecycleOwner = lifecycleOwner;
|
||||||
|
|
||||||
packageManager = context.getPackageManager();
|
packageManager = context.getPackageManager();
|
||||||
|
|
||||||
this.loaderId = loaderId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setView(RemoteSelectAuthenticationKeyView view) {
|
public void setView(RemoteSelectAuthenticationKeyView view) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupFromIntentData(String packageName) {
|
void setupFromViewModel(SelectAuthKeyViewModel viewModel) {
|
||||||
try {
|
try {
|
||||||
setPackageInfo(packageName);
|
setPackageInfo(viewModel.getPackageName());
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
Timber.e("Unable to find info of calling app!");
|
Timber.e("Unable to find info of calling app!");
|
||||||
view.finishAsCancelled();
|
view.finishAsCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.getKeyInfoLiveData(context).observe(lifecycleOwner, this::onLoadKeyInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPackageInfo(String packageName) throws NameNotFoundException {
|
private void setPackageInfo(String packageName) throws NameNotFoundException {
|
||||||
@@ -75,31 +72,11 @@ class RemoteSelectAuthenticationKeyPresenter implements LoaderCallbacks<List<Key
|
|||||||
view.setTitleClientIcon(appIcon);
|
view.setTitleClientIcon(appIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startLoaders(LoaderManager loaderManager) {
|
private void onLoadKeyInfos(List<UnifiedKeyInfo> data) {
|
||||||
loaderManager.restartLoader(loaderId, null, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Loader<List<KeyInfo>> 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<List<KeyInfo>> loader, List<KeyInfo> data) {
|
|
||||||
this.keyInfoData = data;
|
this.keyInfoData = data;
|
||||||
view.setKeyListData(data);
|
view.setKeyListData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoaderReset(Loader loader) {
|
|
||||||
if (view != null) {
|
|
||||||
view.setKeyListData(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onClickSelect() {
|
void onClickSelect() {
|
||||||
if (keyInfoData == null) {
|
if (keyInfoData == null) {
|
||||||
Timber.e("got click on select with no data…?");
|
Timber.e("got click on select with no data…?");
|
||||||
@@ -110,7 +87,7 @@ class RemoteSelectAuthenticationKeyPresenter implements LoaderCallbacks<List<Key
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long masterKeyId = keyInfoData.get(selectedItem).getMasterKeyId();
|
long masterKeyId = keyInfoData.get(selectedItem).master_key_id();
|
||||||
view.finish(masterKeyId);
|
view.finish(masterKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +115,7 @@ class RemoteSelectAuthenticationKeyPresenter implements LoaderCallbacks<List<Key
|
|||||||
|
|
||||||
void setTitleClientIcon(Drawable drawable);
|
void setTitleClientIcon(Drawable drawable);
|
||||||
|
|
||||||
void setKeyListData(List<KeyInfo> data);
|
void setKeyListData(List<UnifiedKeyInfo> data);
|
||||||
void setActiveItem(Integer position);
|
void setActiveItem(Integer position);
|
||||||
void setEnableSelectButton(boolean enabled);
|
void setEnableSelectButton(boolean enabled);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import java.util.List;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.ViewModel;
|
||||||
import android.arch.lifecycle.ViewModelProviders;
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@@ -58,8 +60,11 @@ import android.widget.Toast;
|
|||||||
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.sufficientlysecure.keychain.R;
|
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.operations.results.ImportKeyResult;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView;
|
||||||
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.MainActivity;
|
import org.sufficientlysecure.keychain.ui.MainActivity;
|
||||||
@@ -89,13 +94,18 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
RemoteSelectIdViewModel viewModel =
|
presenter = new RemoteSelectIdentityKeyPresenter(getBaseContext(), this);
|
||||||
ViewModelProviders.of(this).get(RemoteSelectIdViewModel.class);
|
|
||||||
|
|
||||||
presenter = new RemoteSelectIdentityKeyPresenter(getBaseContext(), viewModel, this);
|
|
||||||
|
|
||||||
KeyboardUtil.hideKeyboard(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) {
|
if (savedInstanceState == null) {
|
||||||
RemoteSelectIdentityKeyDialogFragment frag = new RemoteSelectIdentityKeyDialogFragment();
|
RemoteSelectIdentityKeyDialogFragment frag = new RemoteSelectIdentityKeyDialogFragment();
|
||||||
frag.show(getSupportFragmentManager(), "requestKeyDialog");
|
frag.show(getSupportFragmentManager(), "requestKeyDialog");
|
||||||
@@ -106,13 +116,45 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
Intent intent = getIntent();
|
RemoteSelectIdViewModel viewModel = ViewModelProviders.of(this).get(RemoteSelectIdViewModel.class);
|
||||||
String userId = intent.getStringExtra(EXTRA_USER_ID);
|
presenter.setupFromViewModel(viewModel);
|
||||||
String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
|
}
|
||||||
byte[] packageSignature = intent.getByteArrayExtra(EXTRA_PACKAGE_SIGNATURE);
|
|
||||||
boolean showAutocryptHint = intent.getBooleanExtra(EXTRA_SHOW_AUTOCRYPT_HINT, false);
|
public static class RemoteSelectIdViewModel extends ViewModel {
|
||||||
|
public String packageName;
|
||||||
|
public byte[] packageSignature;
|
||||||
|
public String rawUserId;
|
||||||
|
public boolean clientHasAutocryptSetupMsg;
|
||||||
|
|
||||||
|
public List<UnifiedKeyInfo> filteredKeyInfo;
|
||||||
|
|
||||||
|
private LiveData<List<UnifiedKeyInfo>> keyInfo;
|
||||||
|
private PgpKeyGenerationLiveData keyGenerationData;
|
||||||
|
private boolean listAllKeys;
|
||||||
|
|
||||||
|
public LiveData<List<UnifiedKeyInfo>> 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 {
|
public static class RemoteSelectIdentityKeyDialogFragment extends DialogFragment {
|
||||||
@@ -135,7 +177,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final Activity activity = getActivity();
|
Activity activity = requireActivity();
|
||||||
|
|
||||||
ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
|
ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
|
||||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
|
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
|
||||||
@@ -177,7 +219,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
presenter = ((RemoteSelectIdKeyActivity) getActivity()).presenter;
|
presenter = ((RemoteSelectIdKeyActivity) requireActivity()).presenter;
|
||||||
presenter.setView(mvpView);
|
presenter.setView(mvpView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +245,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private RemoteSelectIdentityKeyView createMvpView(final ViewGroup rootView, LayoutInflater layoutInflater) {
|
private RemoteSelectIdentityKeyView createMvpView(final ViewGroup rootView, LayoutInflater layoutInflater) {
|
||||||
// final ImageView iconClientApp = rootView.findViewById(R.id.icon_client_app);
|
// 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 titleText = rootView.findViewById(R.id.text_title_select_key);
|
||||||
final TextView addressText = rootView.findViewById(R.id.text_user_id);
|
final TextView addressText = rootView.findViewById(R.id.text_user_id);
|
||||||
final TextView autocryptHint = rootView.findViewById(R.id.key_import_autocrypt_hint);
|
final TextView autocryptHint = rootView.findViewById(R.id.key_import_autocrypt_hint);
|
||||||
@@ -309,7 +351,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setKeyListData(List<KeyInfo> data) {
|
public void setKeyListData(List<UnifiedKeyInfo> data) {
|
||||||
keyChoiceAdapter.setData(data);
|
keyChoiceAdapter.setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,19 +447,18 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
|
|
||||||
private static class KeyChoiceAdapter extends Adapter<KeyChoiceViewHolder> {
|
private static class KeyChoiceAdapter extends Adapter<KeyChoiceViewHolder> {
|
||||||
private final LayoutInflater layoutInflater;
|
private final LayoutInflater layoutInflater;
|
||||||
private final Resources resources;
|
private List<UnifiedKeyInfo> data;
|
||||||
private List<KeyInfo> data;
|
|
||||||
private Drawable iconUnselected;
|
private Drawable iconUnselected;
|
||||||
private Drawable iconSelected;
|
private Drawable iconSelected;
|
||||||
private Integer activeItem;
|
private Integer activeItem;
|
||||||
|
|
||||||
KeyChoiceAdapter(LayoutInflater layoutInflater, Resources resources) {
|
KeyChoiceAdapter(LayoutInflater layoutInflater) {
|
||||||
this.layoutInflater = layoutInflater;
|
this.layoutInflater = layoutInflater;
|
||||||
this.resources = resources;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@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);
|
View keyChoiceItemView = layoutInflater.inflate(R.layout.api_select_identity_item, parent, false);
|
||||||
return new KeyChoiceViewHolder(keyChoiceItemView);
|
return new KeyChoiceViewHolder(keyChoiceItemView);
|
||||||
}
|
}
|
||||||
@@ -428,8 +469,8 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(KeyChoiceViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull KeyChoiceViewHolder holder, int position) {
|
||||||
KeyInfo keyInfo = data.get(position);
|
UnifiedKeyInfo keyInfo = data.get(position);
|
||||||
boolean hasActiveItem = activeItem != null;
|
boolean hasActiveItem = activeItem != null;
|
||||||
boolean isActiveItem = hasActiveItem && position == activeItem;
|
boolean isActiveItem = hasActiveItem && position == activeItem;
|
||||||
|
|
||||||
@@ -444,7 +485,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
return data != null ? data.size() : 0;
|
return data != null ? data.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(List<KeyInfo> data) {
|
public void setData(List<UnifiedKeyInfo> data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@@ -469,11 +510,11 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
vIcon = itemView.findViewById(R.id.key_list_item_icon);
|
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();
|
Context context = vCreation.getContext();
|
||||||
|
|
||||||
String email = keyInfo.getEmail();
|
String email = keyInfo.email();
|
||||||
String name = keyInfo.getName();
|
String name = keyInfo.name();
|
||||||
if (email != null) {
|
if (email != null) {
|
||||||
vName.setText(context.getString(R.string.use_key, email));
|
vName.setText(context.getString(R.string.use_key, email));
|
||||||
} else if (name != null) {
|
} else if (name != null) {
|
||||||
@@ -482,7 +523,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
|
|||||||
vName.setText(context.getString(R.string.use_key_no_name));
|
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_DATE | DateUtils.FORMAT_SHOW_TIME |
|
||||||
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH);
|
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH);
|
||||||
vCreation.setText(context.getString(R.string.label_key_created, dateTime));
|
vCreation.setText(context.getString(R.string.label_key_created, dateTime));
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.remote.ui.dialog;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.arch.lifecycle.LifecycleOwner;
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
@@ -27,19 +28,18 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.graphics.drawable.Drawable;
|
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;
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
|
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
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.ApiApp;
|
||||||
|
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
import org.sufficientlysecure.keychain.provider.ApiAppDao;
|
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.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
@@ -47,12 +47,12 @@ import timber.log.Timber;
|
|||||||
|
|
||||||
class RemoteSelectIdentityKeyPresenter {
|
class RemoteSelectIdentityKeyPresenter {
|
||||||
private final PackageManager packageManager;
|
private final PackageManager packageManager;
|
||||||
|
private LifecycleOwner lifecycleOwner;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final RemoteSelectIdViewModel viewModel;
|
|
||||||
|
|
||||||
|
|
||||||
private RemoteSelectIdentityKeyView view;
|
private RemoteSelectIdentityKeyView view;
|
||||||
private List<KeyInfo> keyInfoData;
|
private RemoteSelectIdViewModel viewModel;
|
||||||
|
private List<UnifiedKeyInfo> keyInfoData;
|
||||||
|
|
||||||
private UserId userId;
|
private UserId userId;
|
||||||
private long selectedMasterKeyId;
|
private long selectedMasterKeyId;
|
||||||
@@ -61,41 +61,35 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
private ApiApp apiApp;
|
private ApiApp apiApp;
|
||||||
|
|
||||||
|
|
||||||
RemoteSelectIdentityKeyPresenter(Context context, RemoteSelectIdViewModel viewModel, LifecycleOwner lifecycleOwner) {
|
RemoteSelectIdentityKeyPresenter(Context context, LifecycleOwner lifecycleOwner) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.viewModel = viewModel;
|
this.lifecycleOwner = lifecycleOwner;
|
||||||
this.apiAppDao = ApiAppDao.getInstance(context);
|
this.apiAppDao = ApiAppDao.getInstance(context);
|
||||||
|
|
||||||
packageManager = context.getPackageManager();
|
packageManager = context.getPackageManager();
|
||||||
|
|
||||||
viewModel.getKeyGenerationLiveData(context).observe(lifecycleOwner, this::onChangeKeyGeneration);
|
|
||||||
viewModel.getKeyInfo(context).observe(lifecycleOwner, this::onChangeKeyInfoData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setView(RemoteSelectIdentityKeyView view) {
|
public void setView(RemoteSelectIdentityKeyView view) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupFromIntentData(String packageName, byte[] packageSignature, String rawUserId, boolean clientHasAutocryptSetupMsg) {
|
void setupFromViewModel(RemoteSelectIdViewModel viewModel) {
|
||||||
|
this.viewModel = viewModel;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setPackageInfo(packageName, packageSignature);
|
setPackageInfo(viewModel.packageName, viewModel.packageSignature);
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
Timber.e(e, "Unable to find info of calling app!");
|
Timber.e(e, "Unable to find info of calling app!");
|
||||||
view.finishAsCancelled();
|
view.finishAsCancelled();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userId = OpenPgpUtils.splitUserId(rawUserId);
|
this.userId = OpenPgpUtils.splitUserId(viewModel.rawUserId);
|
||||||
view.setAddressText(userId.email);
|
view.setAddressText(userId.email);
|
||||||
view.setShowAutocryptHint(clientHasAutocryptSetupMsg);
|
view.setShowAutocryptHint(viewModel.clientHasAutocryptSetupMsg);
|
||||||
|
|
||||||
loadKeyInfo();
|
viewModel.getKeyGenerationLiveData(context).observe(lifecycleOwner, this::onChangeKeyGeneration);
|
||||||
}
|
viewModel.getSecretUnifiedKeyInfo(context).observe(lifecycleOwner, this::onChangeKeyInfoData);
|
||||||
|
|
||||||
private void loadKeyInfo() {
|
|
||||||
Uri listedKeyRingUri = viewModel.isListAllKeys() ?
|
|
||||||
KeyRings.buildUnifiedKeyRingsUri() : KeyRings.buildUnifiedKeyRingsFindByUserIdUri(userId.email);
|
|
||||||
viewModel.getKeyInfo(context).setKeySelector(KeySelector.createOnlySecret(listedKeyRingUri, null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPackageInfo(String packageName, byte[] packageSignature) throws NameNotFoundException {
|
private void setPackageInfo(String packageName, byte[] packageSignature) throws NameNotFoundException {
|
||||||
@@ -108,22 +102,41 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
view.setTitleClientIconAndName(appIcon, appLabel);
|
view.setTitleClientIconAndName(appIcon, appLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onChangeKeyInfoData(List<KeyInfo> data) {
|
private void onChangeKeyInfoData(List<UnifiedKeyInfo> data) {
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
keyInfoData = data;
|
keyInfoData = data;
|
||||||
goToSelectLayout();
|
goToSelectLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void goToSelectLayout() {
|
private void goToSelectLayout() {
|
||||||
if (keyInfoData == null) {
|
List<UnifiedKeyInfo> filteredKeyInfoData =
|
||||||
|
viewModel.isListAllKeys() || TextUtils.isEmpty(userId.email) ? keyInfoData : getFilteredKeyInfo();
|
||||||
|
|
||||||
|
if (filteredKeyInfoData == null) {
|
||||||
view.showLayoutEmpty();
|
view.showLayoutEmpty();
|
||||||
} else if (keyInfoData.isEmpty()) {
|
} else if (filteredKeyInfoData.isEmpty()) {
|
||||||
view.showLayoutSelectNoKeys();
|
view.showLayoutSelectNoKeys();
|
||||||
} else {
|
} else {
|
||||||
view.setKeyListData(keyInfoData);
|
view.setKeyListData(filteredKeyInfoData);
|
||||||
view.showLayoutSelectKeyList();
|
view.showLayoutSelectKeyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<UnifiedKeyInfo> 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) {
|
private void onChangeKeyGeneration(PgpEditKeyResult pgpEditKeyResult) {
|
||||||
if (pgpEditKeyResult == null) {
|
if (pgpEditKeyResult == null) {
|
||||||
return;
|
return;
|
||||||
@@ -171,7 +184,7 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onKeyItemClick(int position) {
|
void onKeyItemClick(int position) {
|
||||||
selectedMasterKeyId = keyInfoData.get(position).getMasterKeyId();
|
selectedMasterKeyId = keyInfoData.get(position).master_key_id();
|
||||||
view.highlightKey(position);
|
view.highlightKey(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,8 +235,7 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
|
|
||||||
public void onClickMenuListAllKeys() {
|
public void onClickMenuListAllKeys() {
|
||||||
viewModel.setListAllKeys(!viewModel.isListAllKeys());
|
viewModel.setListAllKeys(!viewModel.isListAllKeys());
|
||||||
loadKeyInfo();
|
goToSelectLayout();
|
||||||
view.showLayoutSelectKeyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClickGoToOpenKeychain() {
|
public void onClickGoToOpenKeychain() {
|
||||||
@@ -246,7 +258,7 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
void showLayoutGenerateOk();
|
void showLayoutGenerateOk();
|
||||||
void showLayoutGenerateSave();
|
void showLayoutGenerateSave();
|
||||||
|
|
||||||
void setKeyListData(List<KeyInfo> data);
|
void setKeyListData(List<UnifiedKeyInfo> data);
|
||||||
|
|
||||||
void highlightKey(int position);
|
void highlightKey(int position);
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ CREATE TABLE IF NOT EXISTS keys (
|
|||||||
keyrings_public(master_key_id) ON DELETE CASCADE
|
keyrings_public(master_key_id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
selectAllUnifiedKeyInfo:
|
unifiedKeyView:
|
||||||
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,
|
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 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.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_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 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 )
|
LEFT JOIN autocrypt_peers AS aTI ON ( aTI.master_key_id = keys.master_key_id )
|
||||||
WHERE keys.rank = 0
|
WHERE keys.rank = 0
|
||||||
GROUP BY keys.master_key_id
|
GROUP BY keys.master_key_id;
|
||||||
ORDER BY has_secret DESC, user_packets.name COLLATE NOCASE ASC;
|
|
||||||
|
selectAllUnifiedKeyInfo:
|
||||||
|
SELECT * FROM unifiedKeyView
|
||||||
|
ORDER BY has_any_secret_int DESC, name COLLATE NOCASE ASC, creation DESC;
|
||||||
|
|
||||||
selectUnifiedKeyInfoByMasterKeyId:
|
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,
|
SELECT * FROM unifiedKeyView
|
||||||
(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,
|
WHERE is_revoked = 0 AND master_key_id = ?;
|
||||||
(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,
|
selectUnifiedKeyInfoSearchMailAddress:
|
||||||
(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,
|
SELECT * FROM unifiedKeyView
|
||||||
GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv,
|
WHERE email LIKE ?
|
||||||
GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list
|
ORDER BY creation DESC;
|
||||||
FROM keys
|
|
||||||
INNER JOIN user_packets ON ( keys.master_key_id = user_packets.master_key_id AND user_packets.type IS NULL )
|
selectAllUnifiedKeyInfoWithSecret:
|
||||||
LEFT JOIN certs ON ( keys.master_key_id = certs.master_key_id AND certs.verified = 1 )
|
SELECT * FROM unifiedKeyView
|
||||||
LEFT JOIN autocrypt_peers AS aTI ON ( aTI.master_key_id = keys.master_key_id )
|
WHERE has_any_secret_int = 1
|
||||||
WHERE keys.rank = 0 AND keys.master_key_id = ?
|
ORDER BY creation DESC;
|
||||||
GROUP BY keys.master_key_id;
|
|
||||||
|
|
||||||
selectSubkeysByMasterKeyId:
|
selectSubkeysByMasterKeyId:
|
||||||
SELECT *
|
SELECT *
|
||||||
|
|||||||
Reference in New Issue
Block a user