Use LiveData in favor of ContentLoader for ViewKeyFragment

This commit is contained in:
Vincent Breitmoser
2018-03-25 15:09:41 +02:00
parent 700e06dcb9
commit 10d3ca814c
11 changed files with 291 additions and 340 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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();

View File

@@ -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() {