Merge pull request #2348 from open-keychain/live-data
Use LiveData in favor of ContentLoader in ViewKeyFragment
This commit is contained in:
@@ -72,10 +72,11 @@ public class AutocryptPeerDataAccessObject {
|
||||
|
||||
private final SimpleContentResolverInterface queryInterface;
|
||||
private final String packageName;
|
||||
|
||||
private final DatabaseNotifyManager databaseNotifyManager;
|
||||
|
||||
public AutocryptPeerDataAccessObject(Context context, String packageName) {
|
||||
this.packageName = packageName;
|
||||
this.databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
queryInterface = new SimpleContentResolverInterface() {
|
||||
@@ -102,9 +103,11 @@ public class AutocryptPeerDataAccessObject {
|
||||
};
|
||||
}
|
||||
|
||||
public AutocryptPeerDataAccessObject(SimpleContentResolverInterface queryInterface, String packageName) {
|
||||
public AutocryptPeerDataAccessObject(SimpleContentResolverInterface queryInterface, String packageName,
|
||||
DatabaseNotifyManager databaseNotifyManager) {
|
||||
this.queryInterface = queryInterface;
|
||||
this.packageName = packageName;
|
||||
this.databaseNotifyManager = databaseNotifyManager;
|
||||
}
|
||||
|
||||
public Long getMasterKeyIdForAutocryptPeer(String autocryptId) {
|
||||
@@ -190,6 +193,7 @@ public class AutocryptPeerDataAccessObject {
|
||||
cv.put(ApiAutocryptPeer.IS_MUTUAL, isMutual ? 1 : 0);
|
||||
queryInterface
|
||||
.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
||||
databaseNotifyManager.notifyAutocryptUpdate(autocryptId, masterKeyId);
|
||||
}
|
||||
|
||||
public void updateKeyGossipFromAutocrypt(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||
@@ -211,10 +215,13 @@ public class AutocryptPeerDataAccessObject {
|
||||
cv.put(ApiAutocryptPeer.GOSSIP_ORIGIN, origin);
|
||||
queryInterface
|
||||
.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
||||
databaseNotifyManager.notifyAutocryptUpdate(autocryptId, masterKeyId);
|
||||
}
|
||||
|
||||
public void delete(String autocryptId) {
|
||||
Long masterKeyId = getMasterKeyIdForAutocryptPeer(autocryptId);
|
||||
queryInterface.delete(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), null, null);
|
||||
databaseNotifyManager.notifyAutocryptDelete(autocryptId, masterKeyId);
|
||||
}
|
||||
|
||||
public List<AutocryptRecommendationResult> determineAutocryptRecommendations(String... autocryptIds) {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.sufficientlysecure.keychain.provider;
|
||||
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
|
||||
|
||||
public class DatabaseNotifyManager {
|
||||
private ContentResolver contentResolver;
|
||||
|
||||
public static DatabaseNotifyManager create(Context context) {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
return new DatabaseNotifyManager(contentResolver);
|
||||
}
|
||||
|
||||
private DatabaseNotifyManager(ContentResolver contentResolver) {
|
||||
this.contentResolver = contentResolver;
|
||||
}
|
||||
|
||||
public void notifyKeyChange(long masterKeyId) {
|
||||
Uri uri = KeyRings.buildGenericKeyRingUri(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
public void notifyAutocryptDelete(String autocryptId, Long masterKeyId) {
|
||||
Uri uri = KeyRings.buildGenericKeyRingUri(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
public void notifyAutocryptUpdate(String autocryptId, long masterKeyId) {
|
||||
Uri uri = KeyRings.buildGenericKeyRingUri(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
public void notifyKeyserverStatusChange(long masterKeyId) {
|
||||
Uri uri = KeyRings.buildGenericKeyRingUri(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public class KeyRepository {
|
||||
public static final int FIELD_TYPE_STRING = 4;
|
||||
public static final int FIELD_TYPE_BLOB = 5;
|
||||
|
||||
final ContentResolver mContentResolver;
|
||||
final ContentResolver contentResolver;
|
||||
final LocalPublicKeyStorage mLocalPublicKeyStorage;
|
||||
OperationLog mLog;
|
||||
int mIndent;
|
||||
@@ -71,7 +71,7 @@ public class KeyRepository {
|
||||
|
||||
KeyRepository(ContentResolver contentResolver, LocalPublicKeyStorage localPublicKeyStorage,
|
||||
OperationLog log, int indent) {
|
||||
mContentResolver = contentResolver;
|
||||
this.contentResolver = contentResolver;
|
||||
mLocalPublicKeyStorage = localPublicKeyStorage;
|
||||
mIndent = indent;
|
||||
mLog = log;
|
||||
@@ -121,7 +121,7 @@ public class KeyRepository {
|
||||
|
||||
private HashMap<String, Object> getGenericData(Uri uri, String[] proj, int[] types, String selection)
|
||||
throws NotFoundException {
|
||||
Cursor cursor = mContentResolver.query(uri, proj, selection, null, null);
|
||||
Cursor cursor = contentResolver.query(uri, proj, selection, null, null);
|
||||
|
||||
try {
|
||||
HashMap<String, Object> result = new HashMap<>(proj.length);
|
||||
@@ -184,7 +184,7 @@ public class KeyRepository {
|
||||
}
|
||||
|
||||
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(Uri queryUri) throws NotFoundException {
|
||||
Cursor cursor = mContentResolver.query(queryUri,
|
||||
Cursor cursor = contentResolver.query(queryUri,
|
||||
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.VERIFIED }, null, null, null);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
@@ -208,7 +208,7 @@ public class KeyRepository {
|
||||
}
|
||||
|
||||
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(Uri queryUri) throws NotFoundException {
|
||||
Cursor cursor = mContentResolver.query(queryUri,
|
||||
Cursor cursor = contentResolver.query(queryUri,
|
||||
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.VERIFIED, KeyRings.HAS_ANY_SECRET }, null, null, null);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
@@ -232,7 +232,7 @@ public class KeyRepository {
|
||||
}
|
||||
|
||||
public ArrayList<String> getConfirmedUserIds(long masterKeyId) throws NotFoundException {
|
||||
Cursor cursor = mContentResolver.query(UserPackets.buildUserIdsUri(masterKeyId),
|
||||
Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId),
|
||||
new String[]{UserPackets.USER_ID}, UserPackets.VERIFIED + " = " + Certs.VERIFIED_SECRET, null, null
|
||||
);
|
||||
if (cursor == null) {
|
||||
@@ -276,12 +276,12 @@ public class KeyRepository {
|
||||
}
|
||||
|
||||
public ContentResolver getContentResolver() {
|
||||
return mContentResolver;
|
||||
return contentResolver;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Long getLastUpdateTime(long masterKeyId) {
|
||||
Cursor lastUpdatedCursor = mContentResolver.query(
|
||||
Cursor lastUpdatedCursor = contentResolver.query(
|
||||
UpdatedKeys.CONTENT_URI,
|
||||
new String[] { UpdatedKeys.LAST_UPDATED },
|
||||
UpdatedKeys.MASTER_KEY_ID + " = ?",
|
||||
|
||||
@@ -83,32 +83,38 @@ import timber.log.Timber;
|
||||
public class KeyWritableRepository extends KeyRepository {
|
||||
private static final int MAX_CACHED_KEY_SIZE = 1024 * 50;
|
||||
|
||||
private final Context mContext;
|
||||
private final Context context;
|
||||
private final LastUpdateInteractor lastUpdateInteractor;
|
||||
private DatabaseNotifyManager databaseNotifyManager;
|
||||
|
||||
public static KeyWritableRepository create(Context context) {
|
||||
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
|
||||
LastUpdateInteractor lastUpdateInteractor = LastUpdateInteractor.create(context);
|
||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
|
||||
return new KeyWritableRepository(context, localPublicKeyStorage, lastUpdateInteractor);
|
||||
return new KeyWritableRepository(context, localPublicKeyStorage, lastUpdateInteractor,
|
||||
databaseNotifyManager);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
KeyWritableRepository(Context context, LocalPublicKeyStorage localPublicKeyStorage,
|
||||
LastUpdateInteractor lastUpdateInteractor) {
|
||||
this(context, localPublicKeyStorage, lastUpdateInteractor, new OperationLog(), 0);
|
||||
LastUpdateInteractor lastUpdateInteractor, DatabaseNotifyManager databaseNotifyManager) {
|
||||
this(context, localPublicKeyStorage, lastUpdateInteractor, new OperationLog(), 0,
|
||||
databaseNotifyManager);
|
||||
}
|
||||
|
||||
private KeyWritableRepository(Context context, LocalPublicKeyStorage localPublicKeyStorage,
|
||||
LastUpdateInteractor lastUpdateInteractor, OperationLog log, int indent) {
|
||||
LastUpdateInteractor lastUpdateInteractor, OperationLog log, int indent,
|
||||
DatabaseNotifyManager databaseNotifyManager) {
|
||||
super(context.getContentResolver(), localPublicKeyStorage, log, indent);
|
||||
|
||||
mContext = context;
|
||||
this.context = context;
|
||||
this.databaseNotifyManager = databaseNotifyManager;
|
||||
this.lastUpdateInteractor = lastUpdateInteractor;
|
||||
}
|
||||
|
||||
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
|
||||
Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
|
||||
Cursor cursor = contentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
|
||||
KeyRings.MASTER_KEY_ID,
|
||||
// we pick from cache only information that is not easily available from keyrings
|
||||
KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED
|
||||
@@ -530,7 +536,7 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
|
||||
try {
|
||||
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
|
||||
int deleted = mContentResolver.delete(
|
||||
int deleted = contentResolver.delete(
|
||||
KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null);
|
||||
if (deleted > 0) {
|
||||
log(LogType.MSG_IP_DELETE_OLD_OK);
|
||||
@@ -540,7 +546,8 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
}
|
||||
|
||||
log(LogType.MSG_IP_APPLY_BATCH);
|
||||
mContentResolver.applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
|
||||
contentResolver.applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
|
||||
databaseNotifyManager.notifyKeyChange(masterKeyId);
|
||||
|
||||
log(LogType.MSG_IP_SUCCESS);
|
||||
return result;
|
||||
@@ -603,7 +610,7 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
|
||||
// insert new version of this keyRing
|
||||
Uri uri = KeyRingData.buildSecretKeyRingUri(masterKeyId);
|
||||
return mContentResolver.insert(uri, values);
|
||||
return contentResolver.insert(uri, values);
|
||||
}
|
||||
|
||||
public boolean deleteKeyRing(long masterKeyId) {
|
||||
@@ -613,8 +620,11 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
Timber.e(e, "Could not delete file!");
|
||||
return false;
|
||||
}
|
||||
mContentResolver.delete(ApiAutocryptPeer.buildByMasterKeyId(masterKeyId),null, null);
|
||||
int deletedRows = mContentResolver.delete(KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null);
|
||||
contentResolver.delete(ApiAutocryptPeer.buildByMasterKeyId(masterKeyId),null, null);
|
||||
int deletedRows = contentResolver.delete(KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null);
|
||||
|
||||
databaseNotifyManager.notifyKeyChange(masterKeyId);
|
||||
|
||||
return deletedRows > 0;
|
||||
}
|
||||
|
||||
@@ -690,7 +700,7 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
// first, mark all keys as not available
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Keys.HAS_SECRET, SecretKeyType.GNU_DUMMY.getNum());
|
||||
mContentResolver.update(uri, values, null, null);
|
||||
contentResolver.update(uri, values, null, null);
|
||||
|
||||
// then, mark exactly the keys we have available
|
||||
log(LogType.MSG_IS_IMPORTING_SUBKEYS);
|
||||
@@ -699,7 +709,7 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
long id = sub.getKeyId();
|
||||
SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive();
|
||||
values.put(Keys.HAS_SECRET, mode.getNum());
|
||||
int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?",
|
||||
int upd = contentResolver.update(uri, values, Keys.KEY_ID + " = ?",
|
||||
new String[]{Long.toString(id)});
|
||||
if (upd == 1) {
|
||||
switch (mode) {
|
||||
@@ -1030,11 +1040,11 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
log.add(LogType.MSG_TRUST, 0);
|
||||
|
||||
Cursor cursor;
|
||||
Preferences preferences = Preferences.getPreferences(mContext);
|
||||
Preferences preferences = Preferences.getPreferences(context);
|
||||
boolean isTrustDbInitialized = preferences.isKeySignaturesTableInitialized();
|
||||
if (!isTrustDbInitialized) {
|
||||
log.add(LogType.MSG_TRUST_INITIALIZE, 1);
|
||||
cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(),
|
||||
cursor = contentResolver.query(KeyRings.buildUnifiedKeyRingsUri(),
|
||||
new String[] { KeyRings.MASTER_KEY_ID }, null, null, null);
|
||||
} else {
|
||||
String[] signerMasterKeyIdStrings = new String[signerMasterKeyIds.size()];
|
||||
@@ -1044,7 +1054,7 @@ public class KeyWritableRepository extends KeyRepository {
|
||||
signerMasterKeyIdStrings[i++] = Long.toString(masterKeyId);
|
||||
}
|
||||
|
||||
cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsFilterBySigner(),
|
||||
cursor = contentResolver.query(KeyRings.buildUnifiedKeyRingsFilterBySigner(),
|
||||
new String[] { KeyRings.MASTER_KEY_ID }, null, signerMasterKeyIdStrings, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||
import org.sufficientlysecure.keychain.util.DatabaseUtil;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static android.database.DatabaseUtils.dumpCursorToString;
|
||||
@@ -101,7 +102,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
|
||||
String authority = KeychainContract.CONTENT_AUTHORITY;
|
||||
|
||||
/**
|
||||
/*
|
||||
* list key_rings
|
||||
*
|
||||
* <pre>
|
||||
@@ -124,7 +125,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
+ "/" + KeychainContract.PATH_USER_IDS,
|
||||
KEY_RINGS_USER_IDS);
|
||||
|
||||
/**
|
||||
/*
|
||||
* find by criteria other than master key id
|
||||
*
|
||||
* key_rings/find/email/_
|
||||
@@ -144,7 +145,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
+ KeychainContract.PATH_FILTER + "/" + KeychainContract.PATH_BY_SIGNER,
|
||||
KEY_RINGS_FILTER_BY_SIGNER);
|
||||
|
||||
/**
|
||||
/*
|
||||
* list key_ring specifics
|
||||
*
|
||||
* <pre>
|
||||
@@ -189,7 +190,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
+ KeychainContract.PATH_CERTS + "/*/*",
|
||||
KEY_RING_CERTS_SPECIFIC);
|
||||
|
||||
/**
|
||||
/*
|
||||
* API apps
|
||||
*
|
||||
* <pre>
|
||||
@@ -205,7 +206,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
|
||||
+ KeychainContract.PATH_ALLOWED_KEYS, API_ALLOWED_KEYS);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Trust Identity access
|
||||
*
|
||||
* <pre>
|
||||
@@ -221,7 +222,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
KeychainContract.PATH_BY_PACKAGE_NAME + "/*/*", AUTOCRYPT_PEERS_BY_PACKAGE_NAME_AND_TRUST_ID);
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* to access table containing last updated dates of keys
|
||||
*/
|
||||
matcher.addURI(authority, KeychainContract.BASE_UPDATED_KEYS, UPDATED_KEYS);
|
||||
@@ -835,7 +836,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
|
||||
SQLiteDatabase db = getDb().getReadableDatabase();
|
||||
|
||||
Cursor cursor = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
|
||||
Cursor cursor = qb.query(db, projection, selection, selectionArgs, groupBy, null, orderBy);
|
||||
if (cursor != null) {
|
||||
// Tell the cursor what uri to watch, so it knows when its source data changes
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
@@ -849,27 +850,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
|
||||
if (Constants.DEBUG && Constants.DEBUG_EXPLAIN_QUERIES) {
|
||||
String rawQuery = qb.buildQuery(projection, selection, groupBy, having, orderBy, null);
|
||||
Cursor explainCursor = db.rawQuery("EXPLAIN QUERY PLAN " + rawQuery, selectionArgs);
|
||||
|
||||
// this is a debugging feature, we can be a little careless
|
||||
explainCursor.moveToFirst();
|
||||
|
||||
StringBuilder line = new StringBuilder();
|
||||
for (int i = 0; i < explainCursor.getColumnCount(); i++) {
|
||||
line.append(explainCursor.getColumnName(i)).append(", ");
|
||||
}
|
||||
Timber.d(line.toString());
|
||||
|
||||
while (!explainCursor.isAfterLast()) {
|
||||
line = new StringBuilder();
|
||||
for (int i = 0; i < explainCursor.getColumnCount(); i++) {
|
||||
line.append(explainCursor.getString(i)).append(", ");
|
||||
}
|
||||
Timber.d(line.toString());
|
||||
explainCursor.moveToNext();
|
||||
}
|
||||
|
||||
explainCursor.close();
|
||||
DatabaseUtil.explainQuery(db, rawQuery);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
@@ -966,9 +947,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
rowUri = uri;
|
||||
}
|
||||
|
||||
// notify of changes in db
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
|
||||
} catch (SQLiteConstraintException e) {
|
||||
Timber.d(e, "Constraint exception on insert! Entry already existing?");
|
||||
}
|
||||
@@ -1003,7 +981,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
}
|
||||
// corresponding keys and userIds are deleted by ON DELETE CASCADE
|
||||
count = db.delete(Tables.KEY_RINGS_PUBLIC, selection, selectionArgs);
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1)), null);
|
||||
break;
|
||||
}
|
||||
case KEY_RING_SECRET: {
|
||||
@@ -1013,7 +990,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
selection += " AND (" + additionalSelection + ")";
|
||||
}
|
||||
count = db.delete(Tables.KEY_RINGS_SECRET, selection, selectionArgs);
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1)), null);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1024,20 +1000,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
String selection = ApiAutocryptPeer.PACKAGE_NAME + " = ? AND " + ApiAutocryptPeer.IDENTIFIER + " = ?";
|
||||
selectionArgs = new String[] { packageName, autocryptPeer };
|
||||
|
||||
Cursor cursor = db.query(Tables.API_AUTOCRYPT_PEERS, new String[] { ApiAutocryptPeer.MASTER_KEY_ID },
|
||||
selection, selectionArgs, null, null, null);
|
||||
Long masterKeyId = null;
|
||||
if (cursor != null && cursor.moveToNext() && !cursor.isNull(0)) {
|
||||
masterKeyId = cursor.getLong(0);
|
||||
}
|
||||
|
||||
count = db.delete(Tables.API_AUTOCRYPT_PEERS, selection, selectionArgs);
|
||||
|
||||
if (masterKeyId != null) {
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(masterKeyId), null);
|
||||
}
|
||||
contentResolver.notifyChange(
|
||||
ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptPeer), null);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1047,7 +1010,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
selection += " AND (" + additionalSelection + ")";
|
||||
}
|
||||
count = db.delete(Tables.API_AUTOCRYPT_PEERS, selection, selectionArgs);
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(uri.getLastPathSegment()), null);
|
||||
break;
|
||||
|
||||
case API_APPS_BY_PACKAGE_NAME: {
|
||||
@@ -1076,7 +1038,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
Timber.v("update(uri=" + uri + ", values=" + values.toString() + ")");
|
||||
|
||||
final SQLiteDatabase db = getDb().getWritableDatabase();
|
||||
ContentResolver contentResolver = getContext().getContentResolver();
|
||||
|
||||
int count = 0;
|
||||
try {
|
||||
@@ -1127,25 +1088,12 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||
db.insertOrThrow(Tables.API_AUTOCRYPT_PEERS, null, values);
|
||||
}
|
||||
|
||||
Long masterKeyId = values.getAsLong(ApiAutocryptPeer.MASTER_KEY_ID);
|
||||
if (masterKeyId != null) {
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(masterKeyId), null);
|
||||
}
|
||||
Long gossipMasterKeyId = values.getAsLong(ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID);
|
||||
if (gossipMasterKeyId != null && !gossipMasterKeyId.equals(masterKeyId)) {
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(gossipMasterKeyId), null);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new UnsupportedOperationException("Unknown uri: " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
// notify of changes in db
|
||||
contentResolver.notifyChange(uri, null);
|
||||
|
||||
} catch (SQLiteConstraintException e) {
|
||||
Timber.d(e, "Constraint exception on update! Entry already existing?");
|
||||
}
|
||||
|
||||
@@ -15,14 +15,16 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys;
|
||||
|
||||
public class LastUpdateInteractor {
|
||||
private final ContentResolver contentResolver;
|
||||
private final DatabaseNotifyManager databaseNotifyManager;
|
||||
|
||||
|
||||
public static LastUpdateInteractor create(Context context) {
|
||||
return new LastUpdateInteractor(context.getContentResolver());
|
||||
return new LastUpdateInteractor(context.getContentResolver(), DatabaseNotifyManager.create(context));
|
||||
}
|
||||
|
||||
private LastUpdateInteractor(ContentResolver contentResolver) {
|
||||
private LastUpdateInteractor(ContentResolver contentResolver, DatabaseNotifyManager databaseNotifyManager) {
|
||||
this.contentResolver = contentResolver;
|
||||
this.databaseNotifyManager = databaseNotifyManager;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -69,6 +71,8 @@ public class LastUpdateInteractor {
|
||||
|
||||
// this will actually update/replace, doing the right thing™ for seenOnKeyservers value
|
||||
// see `KeychainProvider.insert()`
|
||||
return contentResolver.insert(UpdatedKeys.CONTENT_URI, values);
|
||||
Uri insert = contentResolver.insert(UpdatedKeys.CONTENT_URI, values);
|
||||
databaseNotifyManager.notifyKeyserverStatusChange(masterKeyId);
|
||||
return insert;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.List;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
@@ -40,6 +41,7 @@ import org.sufficientlysecure.keychain.provider.ApiDataAccessObject;
|
||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDataAccessObject;
|
||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDataAccessObject.AutocryptRecommendationResult;
|
||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDataAccessObject.AutocryptState;
|
||||
import org.sufficientlysecure.keychain.provider.DatabaseNotifyManager;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
@@ -72,6 +74,7 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
||||
private UriMatcher uriMatcher;
|
||||
private ApiPermissionHelper apiPermissionHelper;
|
||||
private KeychainProvider internalKeychainProvider;
|
||||
private DatabaseNotifyManager databaseNotifyManager;
|
||||
|
||||
|
||||
/**
|
||||
@@ -103,9 +106,15 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
||||
public boolean onCreate() {
|
||||
uriMatcher = buildUriMatcher();
|
||||
|
||||
Context context = getContext();
|
||||
if (context == null) {
|
||||
throw new NullPointerException("Context can't be null during onCreate!");
|
||||
}
|
||||
|
||||
internalKeychainProvider = new KeychainProvider();
|
||||
internalKeychainProvider.attachInfo(getContext(), null);
|
||||
apiPermissionHelper = new ApiPermissionHelper(getContext(), new ApiDataAccessObject(internalKeychainProvider));
|
||||
internalKeychainProvider.attachInfo(context, null);
|
||||
apiPermissionHelper = new ApiPermissionHelper(context, new ApiDataAccessObject(internalKeychainProvider));
|
||||
databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -270,7 +279,8 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
||||
}
|
||||
if (!isWildcardSelector && queriesAutocryptResult) {
|
||||
AutocryptPeerDataAccessObject autocryptPeerDao =
|
||||
new AutocryptPeerDataAccessObject(internalKeychainProvider, callingPackageName);
|
||||
new AutocryptPeerDataAccessObject(internalKeychainProvider, callingPackageName,
|
||||
databaseNotifyManager);
|
||||
fillTempTableWithAutocryptRecommendations(db, autocryptPeerDao, selectionArgs);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@ import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.AutocryptPeerInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.LinkedIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.UserIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.AutocryptPeerInfo;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
package org.sufficientlysecure.keychain.ui.keyview;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.ViewModel;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -36,6 +41,10 @@ import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.ui.base.LoaderFragment;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusDao.KeyserverStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeySubkeyStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactDao.SystemContactInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter;
|
||||
@@ -53,11 +62,6 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView, O
|
||||
|
||||
boolean mIsSecret = false;
|
||||
|
||||
private static final int LOADER_IDENTITIES = 1;
|
||||
private static final int LOADER_ID_LINKED_CONTACT = 2;
|
||||
private static final int LOADER_ID_SUBKEY_STATUS = 3;
|
||||
private static final int LOADER_ID_KEYSERVER_STATUS = 4;
|
||||
|
||||
private IdentitiesCardView identitiesCardView;
|
||||
private IdentitiesPresenter identitiesPresenter;
|
||||
|
||||
@@ -100,6 +104,41 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView, O
|
||||
return root;
|
||||
}
|
||||
|
||||
public static class KeyFragmentViewModel extends ViewModel {
|
||||
private LiveData<List<IdentityInfo>> identityInfo;
|
||||
private LiveData<KeySubkeyStatus> subkeyStatus;
|
||||
private LiveData<SystemContactInfo> systemContactInfo;
|
||||
private LiveData<KeyserverStatus> keyserverStatus;
|
||||
|
||||
LiveData<List<IdentityInfo>> getIdentityInfo(IdentitiesPresenter identitiesPresenter) {
|
||||
if (identityInfo == null) {
|
||||
identityInfo = identitiesPresenter.getLiveDataInstance();
|
||||
}
|
||||
return identityInfo;
|
||||
}
|
||||
|
||||
LiveData<KeySubkeyStatus> getSubkeyStatus(KeyHealthPresenter keyHealthPresenter) {
|
||||
if (subkeyStatus == null) {
|
||||
subkeyStatus = keyHealthPresenter.getLiveDataInstance();
|
||||
}
|
||||
return subkeyStatus;
|
||||
}
|
||||
|
||||
LiveData<SystemContactInfo> getSystemContactInfo(SystemContactPresenter systemContactPresenter) {
|
||||
if (systemContactInfo == null) {
|
||||
systemContactInfo = systemContactPresenter.getLiveDataInstance();
|
||||
}
|
||||
return systemContactInfo;
|
||||
}
|
||||
|
||||
LiveData<KeyserverStatus> getKeyserverStatus(KeyserverStatusPresenter keyserverStatusPresenter) {
|
||||
if (keyserverStatus == null) {
|
||||
keyserverStatus = keyserverStatusPresenter.getLiveDataInstance();
|
||||
}
|
||||
return keyserverStatus;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
@@ -107,21 +146,22 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView, O
|
||||
long masterKeyId = getArguments().getLong(ARG_MASTER_KEY_ID);
|
||||
mIsSecret = getArguments().getBoolean(ARG_IS_SECRET);
|
||||
|
||||
KeyFragmentViewModel model = ViewModelProviders.of(this).get(KeyFragmentViewModel.class);
|
||||
|
||||
identitiesPresenter = new IdentitiesPresenter(
|
||||
getContext(), identitiesCardView, this, LOADER_IDENTITIES, masterKeyId, mIsSecret);
|
||||
identitiesPresenter.startLoader(getLoaderManager());
|
||||
getContext(), identitiesCardView, this, masterKeyId, mIsSecret);
|
||||
model.getIdentityInfo(identitiesPresenter).observe(this, identitiesPresenter);
|
||||
|
||||
systemContactPresenter = new SystemContactPresenter(
|
||||
getContext(), systemContactCard, LOADER_ID_LINKED_CONTACT, masterKeyId, mIsSecret);
|
||||
systemContactPresenter.startLoader(getLoaderManager());
|
||||
getContext(), systemContactCard, masterKeyId, mIsSecret);
|
||||
model.getSystemContactInfo(systemContactPresenter).observe(this, systemContactPresenter);
|
||||
|
||||
keyHealthPresenter = new KeyHealthPresenter(
|
||||
getContext(), keyStatusHealth, LOADER_ID_SUBKEY_STATUS, masterKeyId, mIsSecret);
|
||||
keyHealthPresenter.startLoader(getLoaderManager());
|
||||
keyHealthPresenter = new KeyHealthPresenter(getContext(), keyStatusHealth, masterKeyId);
|
||||
model.getSubkeyStatus(keyHealthPresenter).observe(this, keyHealthPresenter);
|
||||
|
||||
keyserverStatusPresenter = new KeyserverStatusPresenter(
|
||||
getContext(), keyStatusKeyserver, LOADER_ID_KEYSERVER_STATUS, masterKeyId, mIsSecret);
|
||||
keyserverStatusPresenter.startLoader(getLoaderManager());
|
||||
getContext(), keyStatusKeyserver, masterKeyId, mIsSecret);
|
||||
model.getKeyserverStatus(keyserverStatusPresenter).observe(this, keyserverStatusPresenter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,11 +26,11 @@ import java.util.List;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
@@ -38,14 +38,12 @@ import org.sufficientlysecure.keychain.linked.LinkedAttribute;
|
||||
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAutocryptPeer;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
public class IdentityDao {
|
||||
private static final String[] USER_PACKETS_PROJECTION = new String[]{
|
||||
UserPackets._ID,
|
||||
UserPackets.TYPE,
|
||||
@@ -84,41 +82,34 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
|
||||
private final ContentResolver contentResolver;
|
||||
private final PackageIconGetter packageIconGetter;
|
||||
private final long masterKeyId;
|
||||
private final boolean showLinkedIds;
|
||||
private final PackageManager packageManager;
|
||||
|
||||
private List<IdentityInfo> cachedResult;
|
||||
|
||||
private ForceLoadContentObserver identityObserver;
|
||||
|
||||
|
||||
public IdentityLoader(Context context, ContentResolver contentResolver, long masterKeyId, boolean showLinkedIds) {
|
||||
super(context);
|
||||
|
||||
this.contentResolver = contentResolver;
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.showLinkedIds = showLinkedIds;
|
||||
|
||||
this.identityObserver = new ForceLoadContentObserver();
|
||||
this.packageIconGetter = PackageIconGetter.getInstance(context);
|
||||
|
||||
this.identityObserver = new ForceLoadContentObserver();
|
||||
static IdentityDao getInstance(Context context) {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageIconGetter iconGetter = PackageIconGetter.getInstance(context);
|
||||
return new IdentityDao(contentResolver, packageManager, iconGetter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IdentityInfo> loadInBackground() {
|
||||
private IdentityDao(ContentResolver contentResolver, PackageManager packageManager, PackageIconGetter iconGetter) {
|
||||
this.packageManager = packageManager;
|
||||
this.contentResolver = contentResolver;
|
||||
this.packageIconGetter = iconGetter;
|
||||
}
|
||||
|
||||
List<IdentityInfo> getIdentityInfos(long masterKeyId, boolean showLinkedIds) {
|
||||
ArrayList<IdentityInfo> identities = new ArrayList<>();
|
||||
|
||||
if (showLinkedIds) {
|
||||
loadLinkedIds(identities);
|
||||
loadLinkedIds(identities, masterKeyId);
|
||||
}
|
||||
loadUserIds(identities);
|
||||
correlateOrAddAutocryptPeers(identities);
|
||||
loadUserIds(identities, masterKeyId);
|
||||
correlateOrAddAutocryptPeers(identities, masterKeyId);
|
||||
|
||||
return Collections.unmodifiableList(identities);
|
||||
}
|
||||
|
||||
private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities) {
|
||||
private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities, long masterKeyId) {
|
||||
Cursor cursor = contentResolver.query(ApiAutocryptPeer.buildByMasterKeyId(masterKeyId),
|
||||
AUTOCRYPT_PEER_PROJECTION, null, null, null);
|
||||
if (cursor == null) {
|
||||
@@ -158,7 +149,7 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_ID, autocryptPeer);
|
||||
|
||||
List<ResolveInfo> resolveInfos = getContext().getPackageManager().queryIntentActivities(intent, 0);
|
||||
List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);
|
||||
if (resolveInfos != null && !resolveInfos.isEmpty()) {
|
||||
return intent;
|
||||
} else {
|
||||
@@ -178,7 +169,7 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void loadLinkedIds(ArrayList<IdentityInfo> identities) {
|
||||
private void loadLinkedIds(ArrayList<IdentityInfo> identities, long masterKeyId) {
|
||||
Cursor cursor = contentResolver.query(UserPackets.buildLinkedIdsUri(masterKeyId),
|
||||
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
||||
if (cursor == null) {
|
||||
@@ -208,7 +199,7 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadUserIds(ArrayList<IdentityInfo> identities) {
|
||||
private void loadUserIds(ArrayList<IdentityInfo> identities, long masterKeyId) {
|
||||
Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId),
|
||||
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
||||
if (cursor == null) {
|
||||
@@ -236,36 +227,6 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(List<IdentityInfo> keySubkeyStatus) {
|
||||
cachedResult = keySubkeyStatus;
|
||||
|
||||
if (isStarted()) {
|
||||
super.deliverResult(keySubkeyStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (cachedResult != null) {
|
||||
deliverResult(cachedResult);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || cachedResult == null) {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
getContext().getContentResolver().registerContentObserver(
|
||||
KeyRings.buildGenericKeyRingUri(masterKeyId), true, identityObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAbandon() {
|
||||
super.onAbandon();
|
||||
|
||||
getContext().getContentResolver().unregisterContentObserver(identityObserver);
|
||||
}
|
||||
|
||||
public interface IdentityInfo {
|
||||
int getRank();
|
||||
int getVerified();
|
||||
@@ -287,7 +248,7 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
|
||||
static UserIdInfo create(int rank, int verified, boolean isPrimary, String name, String email,
|
||||
String comment) {
|
||||
return new AutoValue_IdentityLoader_UserIdInfo(rank, verified, isPrimary, name, email, comment);
|
||||
return new AutoValue_IdentityDao_UserIdInfo(rank, verified, isPrimary, name, email, comment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +261,7 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
public abstract UriAttribute getUriAttribute();
|
||||
|
||||
static LinkedIdInfo create(int rank, int verified, boolean isPrimary, UriAttribute uriAttribute) {
|
||||
return new AutoValue_IdentityLoader_LinkedIdInfo(rank, verified, isPrimary, uriAttribute);
|
||||
return new AutoValue_IdentityDao_LinkedIdInfo(rank, verified, isPrimary, uriAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,12 +282,12 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
||||
|
||||
static AutocryptPeerInfo create(UserIdInfo userIdInfo, String autocryptPeer, String packageName,
|
||||
Drawable appIcon, Intent autocryptPeerIntent) {
|
||||
return new AutoValue_IdentityLoader_AutocryptPeerInfo(userIdInfo.getRank(), userIdInfo.getVerified(),
|
||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(userIdInfo.getRank(), userIdInfo.getVerified(),
|
||||
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent);
|
||||
}
|
||||
|
||||
static AutocryptPeerInfo create(String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
||||
return new AutoValue_IdentityLoader_AutocryptPeerInfo(
|
||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(
|
||||
0, Certs.VERIFIED_SELF, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
||||
}
|
||||
}
|
||||
@@ -23,17 +23,12 @@ import java.util.Date;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.util.Log;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusLoader.KeyserverStatus;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class KeyserverStatusLoader extends AsyncTaskLoader<KeyserverStatus> {
|
||||
public class KeyserverStatusDao {
|
||||
public static final String[] PROJECTION = new String[] {
|
||||
UpdatedKeys.LAST_UPDATED,
|
||||
UpdatedKeys.SEEN_ON_KEYSERVERS
|
||||
@@ -43,23 +38,17 @@ public class KeyserverStatusLoader extends AsyncTaskLoader<KeyserverStatus> {
|
||||
|
||||
|
||||
private final ContentResolver contentResolver;
|
||||
private final long masterKeyId;
|
||||
|
||||
private KeyserverStatus cachedResult;
|
||||
|
||||
private ForceLoadContentObserver keyserverStatusObserver;
|
||||
|
||||
public KeyserverStatusLoader(Context context, ContentResolver contentResolver, long masterKeyId) {
|
||||
super(context);
|
||||
|
||||
this.contentResolver = contentResolver;
|
||||
this.masterKeyId = masterKeyId;
|
||||
|
||||
this.keyserverStatusObserver = new ForceLoadContentObserver();
|
||||
public static KeyserverStatusDao getInstance(Context context) {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
return new KeyserverStatusDao(contentResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyserverStatus loadInBackground() {
|
||||
private KeyserverStatusDao(ContentResolver contentResolver) {
|
||||
this.contentResolver = contentResolver;
|
||||
}
|
||||
|
||||
public KeyserverStatus getKeyserverStatus(long masterKeyId) {
|
||||
Cursor cursor = contentResolver.query(UpdatedKeys.CONTENT_URI, PROJECTION,
|
||||
UpdatedKeys.MASTER_KEY_ID + " = ?", new String[] { Long.toString(masterKeyId) }, null);
|
||||
if (cursor == null) {
|
||||
@@ -85,36 +74,6 @@ public class KeyserverStatusLoader extends AsyncTaskLoader<KeyserverStatus> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(KeyserverStatus keySubkeyStatus) {
|
||||
cachedResult = keySubkeyStatus;
|
||||
|
||||
if (isStarted()) {
|
||||
super.deliverResult(keySubkeyStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (cachedResult != null) {
|
||||
deliverResult(cachedResult);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || cachedResult == null) {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
getContext().getContentResolver().registerContentObserver(
|
||||
KeyRings.buildGenericKeyRingUri(masterKeyId), true, keyserverStatusObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAbandon() {
|
||||
super.onAbandon();
|
||||
|
||||
getContext().getContentResolver().unregisterContentObserver(keyserverStatusObserver);
|
||||
}
|
||||
|
||||
public static class KeyserverStatus {
|
||||
private final long masterKeyId;
|
||||
private final boolean isPublished;
|
||||
@@ -28,19 +28,15 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.util.Log;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
|
||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusLoader.KeySubkeyStatus;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
|
||||
public class SubkeyStatusDao {
|
||||
public static final String[] PROJECTION = new String[] {
|
||||
Keys.KEY_ID,
|
||||
Keys.CREATION,
|
||||
@@ -68,23 +64,18 @@ public class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
|
||||
|
||||
|
||||
private final ContentResolver contentResolver;
|
||||
private final long masterKeyId;
|
||||
private final Comparator<SubKeyItem> comparator;
|
||||
|
||||
private KeySubkeyStatus cachedResult;
|
||||
|
||||
|
||||
public SubkeyStatusLoader(Context context, ContentResolver contentResolver, long masterKeyId,
|
||||
Comparator<SubKeyItem> comparator) {
|
||||
super(context);
|
||||
|
||||
this.contentResolver = contentResolver;
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.comparator = comparator;
|
||||
public static SubkeyStatusDao getInstance(Context context) {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
return new SubkeyStatusDao(contentResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeySubkeyStatus loadInBackground() {
|
||||
private SubkeyStatusDao(ContentResolver contentResolver) {
|
||||
this.contentResolver = contentResolver;
|
||||
}
|
||||
|
||||
KeySubkeyStatus getSubkeyStatus(long masterKeyId, Comparator<SubKeyItem> comparator) {
|
||||
Cursor cursor = contentResolver.query(Keys.buildKeysUri(masterKeyId), PROJECTION, null, null, null);
|
||||
if (cursor == null) {
|
||||
Timber.e("Error loading key items!");
|
||||
@@ -111,7 +102,10 @@ public class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
|
||||
}
|
||||
|
||||
if (keyCertify == null) {
|
||||
throw new IllegalStateException("Certification key must be set at this point, it's a bug otherwise!");
|
||||
if (!keysSign.isEmpty() || !keysEncrypt.isEmpty()) {
|
||||
throw new IllegalStateException("Certification key can't be missing for a key that hasn't been deleted!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Collections.sort(keysSign, comparator);
|
||||
@@ -123,26 +117,6 @@ public class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(KeySubkeyStatus keySubkeyStatus) {
|
||||
cachedResult = keySubkeyStatus;
|
||||
|
||||
if (isStarted()) {
|
||||
super.deliverResult(keySubkeyStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (cachedResult != null) {
|
||||
deliverResult(cachedResult);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || cachedResult == null) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeySubkeyStatus {
|
||||
@NonNull
|
||||
public final SubKeyItem keyCertify;
|
||||
@@ -20,22 +20,22 @@ package org.sufficientlysecure.keychain.ui.keyview.loader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.util.Log;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactInfoLoader.SystemContactInfo;
|
||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class SystemContactInfoLoader extends AsyncTaskLoader<SystemContactInfo> {
|
||||
public class SystemContactDao {
|
||||
private static final String[] PROJECTION = {
|
||||
ContactsContract.RawContacts.CONTACT_ID
|
||||
};
|
||||
@@ -43,23 +43,30 @@ public class SystemContactInfoLoader extends AsyncTaskLoader<SystemContactInfo>
|
||||
private static final String CONTACT_NOT_DELETED = "0";
|
||||
|
||||
|
||||
private final Context context;
|
||||
private final ContentResolver contentResolver;
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
|
||||
private SystemContactInfo cachedResult;
|
||||
private final ContactHelper contactHelper;
|
||||
|
||||
|
||||
public SystemContactInfoLoader(Context context, ContentResolver contentResolver, long masterKeyId, boolean isSecret) {
|
||||
super(context);
|
||||
|
||||
this.contentResolver = contentResolver;
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
public static SystemContactDao getInstance(Context context) {
|
||||
ContactHelper contactHelper = new ContactHelper(context);
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
return new SystemContactDao(context, contactHelper, contentResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemContactInfo loadInBackground() {
|
||||
private SystemContactDao(Context context, ContactHelper contactHelper, ContentResolver contentResolver) {
|
||||
this.context = context;
|
||||
this.contactHelper = contactHelper;
|
||||
this.contentResolver = contentResolver;
|
||||
}
|
||||
|
||||
SystemContactInfo getSystemContactInfo(long masterKeyId, boolean isSecret) {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
|
||||
== PackageManager.PERMISSION_DENIED) {
|
||||
Timber.w(Constants.TAG, "loading linked system contact not possible READ_CONTACTS permission denied!");
|
||||
return null;
|
||||
}
|
||||
|
||||
Uri baseUri = isSecret ? ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI :
|
||||
ContactsContract.RawContacts.CONTENT_URI;
|
||||
Cursor cursor = contentResolver.query(baseUri, PROJECTION,
|
||||
@@ -87,8 +94,6 @@ public class SystemContactInfoLoader extends AsyncTaskLoader<SystemContactInfo>
|
||||
return null;
|
||||
}
|
||||
|
||||
ContactHelper contactHelper = new ContactHelper(getContext());
|
||||
|
||||
String contactName = null;
|
||||
if (isSecret) { //all secret keys are linked to "me" profile in contacts
|
||||
List<String> mainProfileNames = contactHelper.getMainProfileContactName();
|
||||
@@ -116,26 +121,6 @@ public class SystemContactInfoLoader extends AsyncTaskLoader<SystemContactInfo>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(SystemContactInfo systemContactInfo) {
|
||||
cachedResult = systemContactInfo;
|
||||
|
||||
if (isStarted()) {
|
||||
super.deliverResult(systemContactInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (cachedResult != null) {
|
||||
deliverResult(cachedResult);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || cachedResult == null) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SystemContactInfo {
|
||||
final long masterKeyId;
|
||||
public final long contactId;
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.sufficientlysecure.keychain.ui.keyview.loader;
|
||||
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusDao.KeyserverStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeySubkeyStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.SubKeyItem;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactDao.SystemContactInfo;
|
||||
|
||||
|
||||
public class ViewKeyLiveData {
|
||||
public static class IdentityLiveData extends AsyncTaskLiveData<List<IdentityInfo>> {
|
||||
private final IdentityDao identityDao;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean showLinkedIds;
|
||||
|
||||
public IdentityLiveData(Context context, long masterKeyId, boolean showLinkedIds) {
|
||||
super(context, KeyRings.buildGenericKeyRingUri(masterKeyId));
|
||||
|
||||
this.identityDao = IdentityDao.getInstance(context);
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.showLinkedIds = showLinkedIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IdentityInfo> asyncLoadData() {
|
||||
return identityDao.getIdentityInfos(masterKeyId, showLinkedIds);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SubkeyStatusLiveData extends AsyncTaskLiveData<KeySubkeyStatus> {
|
||||
private final SubkeyStatusDao subkeyStatusDao;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final Comparator<SubKeyItem> comparator;
|
||||
|
||||
public SubkeyStatusLiveData(Context context, long masterKeyId, Comparator<SubKeyItem> comparator) {
|
||||
super(context, KeyRings.buildGenericKeyRingUri(masterKeyId));
|
||||
|
||||
this.subkeyStatusDao = SubkeyStatusDao.getInstance(context);
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeySubkeyStatus asyncLoadData() {
|
||||
return subkeyStatusDao.getSubkeyStatus(masterKeyId, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SystemContactInfoLiveData extends AsyncTaskLiveData<SystemContactInfo> {
|
||||
private final SystemContactDao systemContactDao;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
|
||||
public SystemContactInfoLiveData(Context context, long masterKeyId, boolean isSecret) {
|
||||
super(context, null);
|
||||
|
||||
this.systemContactDao = SystemContactDao.getInstance(context);
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemContactInfo asyncLoadData() {
|
||||
return systemContactDao.getSystemContactInfo(masterKeyId, isSecret);
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeyserverStatusLiveData extends AsyncTaskLiveData<KeyserverStatus> {
|
||||
private final KeyserverStatusDao keyserverStatusDao;
|
||||
|
||||
private final long masterKeyId;
|
||||
|
||||
public KeyserverStatusLiveData(Context context, long masterKeyId) {
|
||||
super(context, KeyRings.buildGenericKeyRingUri(masterKeyId));
|
||||
|
||||
this.keyserverStatusDao = KeyserverStatusDao.getInstance(context);
|
||||
this.masterKeyId = masterKeyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyserverStatus asyncLoadData() {
|
||||
return keyserverStatusDao.getKeyserverStatus(masterKeyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,12 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
|
||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDataAccessObject;
|
||||
@@ -37,21 +36,20 @@ import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.IdentityClickListener;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.AutocryptPeerInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.AutocryptPeerInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.LinkedIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.UserIdInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.ViewKeyLiveData.IdentityLiveData;
|
||||
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>> {
|
||||
public class IdentitiesPresenter implements Observer<List<IdentityInfo>> {
|
||||
private final Context context;
|
||||
private final IdentitiesMvpView view;
|
||||
private final ViewKeyMvpView viewKeyMvpView;
|
||||
private final int loaderId;
|
||||
|
||||
private final IdentityAdapter identitiesAdapter;
|
||||
|
||||
@@ -60,11 +58,10 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
||||
private final boolean showLinkedIds;
|
||||
|
||||
public IdentitiesPresenter(Context context, IdentitiesMvpView view, ViewKeyMvpView viewKeyMvpView,
|
||||
int loaderId, long masterKeyId, boolean isSecret) {
|
||||
long masterKeyId, boolean isSecret) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
this.viewKeyMvpView = viewKeyMvpView;
|
||||
this.loaderId = loaderId;
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
@@ -90,24 +87,10 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
||||
view.setIdentitiesCardListener(() -> addLinkedIdentity());
|
||||
}
|
||||
|
||||
public void startLoader(LoaderManager loaderManager) {
|
||||
loaderManager.restartLoader(loaderId, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<List<IdentityInfo>> onCreateLoader(int id, Bundle args) {
|
||||
return new IdentityLoader(context, context.getContentResolver(), masterKeyId, showLinkedIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<List<IdentityInfo>> loader, List<IdentityInfo> data) {
|
||||
public void onChanged(@Nullable List<IdentityInfo> identityInfos) {
|
||||
viewKeyMvpView.setContentShown(true, false);
|
||||
identitiesAdapter.setData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader loader) {
|
||||
identitiesAdapter.setData(null);
|
||||
identitiesAdapter.setData(identityInfos);
|
||||
}
|
||||
|
||||
private void showIdentityInfo(final int position) {
|
||||
@@ -168,6 +151,10 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
||||
autocryptPeerDao.delete(info.getIdentity());
|
||||
}
|
||||
|
||||
public LiveData<List<IdentityInfo>> getLiveDataInstance() {
|
||||
return new IdentityLiveData(context, masterKeyId, showLinkedIds);
|
||||
}
|
||||
|
||||
public interface IdentitiesMvpView {
|
||||
void setIdentitiesAdapter(IdentityAdapter userIdsAdapter);
|
||||
void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener);
|
||||
|
||||
@@ -21,21 +21,21 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
||||
import android.app.Application;
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeySubkeyStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.SubKeyItem;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.ViewKeyLiveData.SubkeyStatusLiveData;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyStatusList.KeyDisplayStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusLoader;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusLoader.KeySubkeyStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusLoader.SubKeyItem;
|
||||
|
||||
|
||||
public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
|
||||
public class KeyHealthPresenter implements Observer<KeySubkeyStatus> {
|
||||
private static final Comparator<SubKeyItem> SUBKEY_COMPARATOR = new Comparator<SubKeyItem>() {
|
||||
@Override
|
||||
public int compare(SubKeyItem one, SubKeyItem two) {
|
||||
@@ -58,22 +58,16 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
|
||||
|
||||
private final Context context;
|
||||
private final KeyHealthMvpView view;
|
||||
private final int loaderId;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
|
||||
private KeySubkeyStatus subkeyStatus;
|
||||
private boolean showingExpandedInfo;
|
||||
|
||||
|
||||
public KeyHealthPresenter(Context context, KeyHealthMvpView view, int loaderId, long masterKeyId, boolean isSecret) {
|
||||
public KeyHealthPresenter(Context context, KeyHealthMvpView view, long masterKeyId) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
this.loaderId = loaderId;
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
|
||||
view.setOnHealthClickListener(new KeyHealthClickListener() {
|
||||
@Override
|
||||
@@ -83,18 +77,12 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
|
||||
});
|
||||
}
|
||||
|
||||
public void startLoader(LoaderManager loaderManager) {
|
||||
loaderManager.restartLoader(loaderId, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<KeySubkeyStatus> onCreateLoader(int id, Bundle args) {
|
||||
return new SubkeyStatusLoader(context, context.getContentResolver(), masterKeyId, SUBKEY_COMPARATOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<KeySubkeyStatus> loader, KeySubkeyStatus subkeyStatus) {
|
||||
public void onChanged(@Nullable KeySubkeyStatus subkeyStatus) {
|
||||
this.subkeyStatus = subkeyStatus;
|
||||
if (subkeyStatus == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
KeyHealthStatus keyHealthStatus = determineKeyHealthStatus(subkeyStatus);
|
||||
|
||||
@@ -195,11 +183,6 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
|
||||
return KeyHealthStatus.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader loader) {
|
||||
|
||||
}
|
||||
|
||||
private void onKeyHealthClick() {
|
||||
if (showingExpandedInfo) {
|
||||
showingExpandedInfo = false;
|
||||
@@ -262,6 +245,10 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
|
||||
return KeyDisplayStatus.OK;
|
||||
}
|
||||
|
||||
public LiveData<KeySubkeyStatus> getLiveDataInstance() {
|
||||
return new SubkeyStatusLiveData(context, masterKeyId, SUBKEY_COMPARATOR);
|
||||
}
|
||||
|
||||
public enum KeyHealthStatus {
|
||||
OK, DIVERT, DIVERT_PARTIAL, REVOKED, EXPIRED, INSECURE, SIGN_ONLY, STRIPPED, PARTIAL_STRIPPED, BROKEN
|
||||
}
|
||||
|
||||
@@ -20,46 +20,43 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusLoader;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusLoader.KeyserverStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusDao.KeyserverStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.ViewKeyLiveData.KeyserverStatusLiveData;
|
||||
|
||||
|
||||
public class KeyserverStatusPresenter implements LoaderCallbacks<KeyserverStatus> {
|
||||
public class KeyserverStatusPresenter implements Observer<KeyserverStatus> {
|
||||
private final Context context;
|
||||
private final KeyserverStatusMvpView view;
|
||||
private final int loaderId;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
|
||||
|
||||
public KeyserverStatusPresenter(Context context, KeyserverStatusMvpView view, int loaderId, long masterKeyId,
|
||||
public KeyserverStatusPresenter(Context context, KeyserverStatusMvpView view, long masterKeyId,
|
||||
boolean isSecret) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
this.loaderId = loaderId;
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
}
|
||||
|
||||
public void startLoader(LoaderManager loaderManager) {
|
||||
loaderManager.restartLoader(loaderId, null, this);
|
||||
public LiveData<KeyserverStatus> getLiveDataInstance() {
|
||||
return new KeyserverStatusLiveData(context, masterKeyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<KeyserverStatus> onCreateLoader(int id, Bundle args) {
|
||||
return new KeyserverStatusLoader(context, context.getContentResolver(), masterKeyId);
|
||||
}
|
||||
public void onChanged(@Nullable KeyserverStatus keyserverStatus) {
|
||||
if (keyserverStatus == null) {
|
||||
view.setDisplayStatusUnknown();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<KeyserverStatus> loader, KeyserverStatus keyserverStatus) {
|
||||
if (keyserverStatus.hasBeenUpdated()) {
|
||||
if (keyserverStatus.isPublished()) {
|
||||
view.setDisplayStatusPublished();
|
||||
@@ -72,11 +69,6 @@ public class KeyserverStatusPresenter implements LoaderCallbacks<KeyserverStatus
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader loader) {
|
||||
|
||||
}
|
||||
|
||||
public interface KeyserverStatusMvpView {
|
||||
void setDisplayStatusPublished();
|
||||
void setDisplayStatusNotPublished();
|
||||
|
||||
@@ -18,28 +18,22 @@
|
||||
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactInfoLoader;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactInfoLoader.SystemContactInfo;
|
||||
import timber.log.Timber;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactDao.SystemContactInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.ViewKeyLiveData.SystemContactInfoLiveData;
|
||||
|
||||
|
||||
public class SystemContactPresenter implements LoaderCallbacks<SystemContactInfo> {
|
||||
public class SystemContactPresenter implements Observer<SystemContactInfo> {
|
||||
private final Context context;
|
||||
private final SystemContactMvpView view;
|
||||
private final int loaderId;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
@@ -47,55 +41,29 @@ public class SystemContactPresenter implements LoaderCallbacks<SystemContactInfo
|
||||
private long contactId;
|
||||
|
||||
|
||||
public SystemContactPresenter(Context context, SystemContactMvpView view, int loaderId, long masterKeyId, boolean isSecret) {
|
||||
public SystemContactPresenter(Context context, SystemContactMvpView view, long masterKeyId, boolean isSecret) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
this.loaderId = loaderId;
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
|
||||
view.setSystemContactClickListener(new SystemContactClickListener() {
|
||||
@Override
|
||||
public void onSystemContactClick() {
|
||||
SystemContactPresenter.this.onSystemContactClick();
|
||||
}
|
||||
});
|
||||
view.setSystemContactClickListener(SystemContactPresenter.this::onSystemContactClick);
|
||||
}
|
||||
|
||||
public void startLoader(LoaderManager loaderManager) {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
|
||||
== PackageManager.PERMISSION_DENIED) {
|
||||
Timber.w("loading linked system contact not possible READ_CONTACTS permission denied!");
|
||||
public LiveData<SystemContactInfo> getLiveDataInstance() {
|
||||
return new SystemContactInfoLiveData(context, masterKeyId, isSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(@Nullable SystemContactInfo systemContactInfo) {
|
||||
if (systemContactInfo == null) {
|
||||
view.hideLinkedSystemContact();
|
||||
return;
|
||||
}
|
||||
|
||||
Bundle linkedContactData = new Bundle();
|
||||
|
||||
// initialises loader for contact query so we can listen to any updates
|
||||
loaderManager.restartLoader(loaderId, linkedContactData, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<SystemContactInfo> onCreateLoader(int id, Bundle args) {
|
||||
return new SystemContactInfoLoader(context, context.getContentResolver(), masterKeyId, isSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<SystemContactInfo> loader, SystemContactInfo data) {
|
||||
if (data == null) {
|
||||
view.hideLinkedSystemContact();
|
||||
return;
|
||||
}
|
||||
|
||||
this.contactId = data.contactId;
|
||||
view.showLinkedSystemContact(data.contactName, data.contactPicture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader loader) {
|
||||
|
||||
this.contactId = systemContactInfo.contactId;
|
||||
view.showLinkedSystemContact(systemContactInfo.contactName, systemContactInfo.contactPicture);
|
||||
}
|
||||
|
||||
private void onSystemContactClick() {
|
||||
|
||||
@@ -17,8 +17,13 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
/**
|
||||
* Shamelessly copied from android.database.DatabaseUtils
|
||||
*/
|
||||
@@ -50,4 +55,28 @@ public class DatabaseUtil {
|
||||
System.arraycopy(newValues, 0, result, originalValues.length, newValues.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void explainQuery(SQLiteDatabase db, String sql) {
|
||||
Cursor explainCursor = db.rawQuery("EXPLAIN QUERY PLAN " + sql, new String[0]);
|
||||
|
||||
// this is a debugging feature, we can be a little careless
|
||||
explainCursor.moveToFirst();
|
||||
|
||||
StringBuilder line = new StringBuilder();
|
||||
for (int i = 0; i < explainCursor.getColumnCount(); i++) {
|
||||
line.append(explainCursor.getColumnName(i)).append(", ");
|
||||
}
|
||||
Timber.d(line.toString());
|
||||
|
||||
while (!explainCursor.isAfterLast()) {
|
||||
line = new StringBuilder();
|
||||
for (int i = 0; i < explainCursor.getColumnCount(); i++) {
|
||||
line.append(explainCursor.getString(i)).append(", ");
|
||||
}
|
||||
Timber.d(line.toString());
|
||||
explainCursor.moveToNext();
|
||||
}
|
||||
|
||||
explainCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class DatabaseUtils {
|
||||
public static void explainQuery(SQLiteDatabase db, String sql) {
|
||||
Cursor explainCursor = db.rawQuery("EXPLAIN QUERY PLAN " + sql, new String[0]);
|
||||
|
||||
// this is a debugging feature, we can be a little careless
|
||||
explainCursor.moveToFirst();
|
||||
|
||||
StringBuilder line = new StringBuilder();
|
||||
for (int i = 0; i < explainCursor.getColumnCount(); i++) {
|
||||
line.append(explainCursor.getColumnName(i)).append(", ");
|
||||
}
|
||||
Timber.d(line.toString());
|
||||
|
||||
while (!explainCursor.isAfterLast()) {
|
||||
line = new StringBuilder();
|
||||
for (int i = 0; i < explainCursor.getColumnCount(); i++) {
|
||||
line.append(explainCursor.getString(i)).append(", ");
|
||||
}
|
||||
Timber.d(line.toString());
|
||||
explainCursor.moveToNext();
|
||||
}
|
||||
|
||||
explainCursor.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user