diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java index b02b61b5c..f3bb61d51 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java @@ -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; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java index 27c04e1ae..b1e675583 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java @@ -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> identityInfo; + private LiveData subkeyStatus; + private LiveData systemContactInfo; + private LiveData keyserverStatus; + + LiveData> getIdentityInfo(IdentitiesPresenter identitiesPresenter) { + if (identityInfo == null) { + identityInfo = identitiesPresenter.getLiveDataInstance(); + } + return identityInfo; + } + + LiveData getSubkeyStatus(KeyHealthPresenter keyHealthPresenter) { + if (subkeyStatus == null) { + subkeyStatus = keyHealthPresenter.getLiveDataInstance(); + } + return subkeyStatus; + } + + LiveData getSystemContactInfo(SystemContactPresenter systemContactPresenter) { + if (systemContactInfo == null) { + systemContactInfo = systemContactPresenter.getLiveDataInstance(); + } + return systemContactInfo; + } + + LiveData 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 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityDao.java similarity index 80% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityDao.java index bafd1e74b..8a3458a51 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityDao.java @@ -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> { +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> { private final ContentResolver contentResolver; private final PackageIconGetter packageIconGetter; - private final long masterKeyId; - private final boolean showLinkedIds; + private final PackageManager packageManager; - private List 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 loadInBackground() { + private IdentityDao(ContentResolver contentResolver, PackageManager packageManager, PackageIconGetter iconGetter) { + this.packageManager = packageManager; + this.contentResolver = contentResolver; + this.packageIconGetter = iconGetter; + } + + List getIdentityInfos(long masterKeyId, boolean showLinkedIds) { ArrayList 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 identities) { + private void correlateOrAddAutocryptPeers(ArrayList 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> { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_ID, autocryptPeer); - List resolveInfos = getContext().getPackageManager().queryIntentActivities(intent, 0); + List resolveInfos = packageManager.queryIntentActivities(intent, 0); if (resolveInfos != null && !resolveInfos.isEmpty()) { return intent; } else { @@ -178,7 +169,7 @@ public class IdentityLoader extends AsyncTaskLoader> { return null; } - private void loadLinkedIds(ArrayList identities) { + private void loadLinkedIds(ArrayList 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> { } } - private void loadUserIds(ArrayList identities) { + private void loadUserIds(ArrayList 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> { } } - @Override - public void deliverResult(List keySubkeyStatus) { - cachedResult = keySubkeyStatus; - - if (isStarted()) { - super.deliverResult(keySubkeyStatus); - } - } - - @Override - protected void onStartLoading() { - if (cachedResult != null) { - deliverResult(cachedResult); - } - - if (takeContentChanged() || cachedResult == null) { - forceLoad(); - } - - 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> { 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> { 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> { 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); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java index 5f643ee1c..16e6828c6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java @@ -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 { +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 { 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 { } } - @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; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SubkeyStatusLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SubkeyStatusDao.java similarity index 81% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SubkeyStatusLoader.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SubkeyStatusDao.java index 82816d05d..8caf8b261 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SubkeyStatusLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SubkeyStatusDao.java @@ -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 { +public class SubkeyStatusDao { public static final String[] PROJECTION = new String[] { Keys.KEY_ID, Keys.CREATION, @@ -68,23 +64,18 @@ public class SubkeyStatusLoader extends AsyncTaskLoader { private final ContentResolver contentResolver; - private final long masterKeyId; - private final Comparator comparator; - - private KeySubkeyStatus cachedResult; - public SubkeyStatusLoader(Context context, ContentResolver contentResolver, long masterKeyId, - Comparator 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 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 { } 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 { } } - @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; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SystemContactInfoLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SystemContactDao.java similarity index 76% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SystemContactInfoLoader.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SystemContactDao.java index cfbe51f73..e666920c4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SystemContactInfoLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/SystemContactDao.java @@ -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 { +public class SystemContactDao { private static final String[] PROJECTION = { ContactsContract.RawContacts.CONTACT_ID }; @@ -43,23 +43,30 @@ public class SystemContactInfoLoader extends AsyncTaskLoader 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 return null; } - ContactHelper contactHelper = new ContactHelper(getContext()); - String contactName = null; if (isSecret) { //all secret keys are linked to "me" profile in contacts List mainProfileNames = contactHelper.getMainProfileContactName(); @@ -116,26 +121,6 @@ public class SystemContactInfoLoader extends AsyncTaskLoader } } - @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; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/ViewKeyLiveData.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/ViewKeyLiveData.java new file mode 100644 index 000000000..c9bb64dd9 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/ViewKeyLiveData.java @@ -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> { + 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 asyncLoadData() { + return identityDao.getIdentityInfos(masterKeyId, showLinkedIds); + } + } + + public static class SubkeyStatusLiveData extends AsyncTaskLiveData { + private final SubkeyStatusDao subkeyStatusDao; + + private final long masterKeyId; + private final Comparator comparator; + + public SubkeyStatusLiveData(Context context, long masterKeyId, Comparator 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 { + 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 { + 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); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java index de4cf3e1e..28cd69b5b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java @@ -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> { +public class IdentitiesPresenter implements Observer> { 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> 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> view.setIdentitiesCardListener(() -> addLinkedIdentity()); } - public void startLoader(LoaderManager loaderManager) { - loaderManager.restartLoader(loaderId, null, this); - } - @Override - public Loader> onCreateLoader(int id, Bundle args) { - return new IdentityLoader(context, context.getContentResolver(), masterKeyId, showLinkedIds); - } - - @Override - public void onLoadFinished(Loader> loader, List data) { + public void onChanged(@Nullable List 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> autocryptPeerDao.delete(info.getIdentity()); } + public LiveData> getLiveDataInstance() { + return new IdentityLiveData(context, masterKeyId, showLinkedIds); + } + public interface IdentitiesMvpView { void setIdentitiesAdapter(IdentityAdapter userIdsAdapter); void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyHealthPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyHealthPresenter.java index a8bb68552..3a9e11d63 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyHealthPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyHealthPresenter.java @@ -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 { +public class KeyHealthPresenter implements Observer { private static final Comparator SUBKEY_COMPARATOR = new Comparator() { @Override public int compare(SubKeyItem one, SubKeyItem two) { @@ -58,22 +58,16 @@ public class KeyHealthPresenter implements LoaderCallbacks { 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 { }); } - public void startLoader(LoaderManager loaderManager) { - loaderManager.restartLoader(loaderId, null, this); - } - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new SubkeyStatusLoader(context, context.getContentResolver(), masterKeyId, SUBKEY_COMPARATOR); - } - - @Override - public void onLoadFinished(Loader 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 { 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 { return KeyDisplayStatus.OK; } + public LiveData getLiveDataInstance() { + return new SubkeyStatusLiveData(context, masterKeyId, SUBKEY_COMPARATOR); + } + public enum KeyHealthStatus { OK, DIVERT, DIVERT_PARTIAL, REVOKED, EXPIRED, INSECURE, SIGN_ONLY, STRIPPED, PARTIAL_STRIPPED, BROKEN } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java index 112144db6..76e63f15e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java @@ -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 { +public class KeyserverStatusPresenter implements Observer { 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 getLiveDataInstance() { + return new KeyserverStatusLiveData(context, masterKeyId); } @Override - public Loader 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 loader, KeyserverStatus keyserverStatus) { if (keyserverStatus.hasBeenUpdated()) { if (keyserverStatus.isPublished()) { view.setDisplayStatusPublished(); @@ -72,11 +69,6 @@ public class KeyserverStatusPresenter implements LoaderCallbacks { +public class SystemContactPresenter implements Observer { 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 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 onCreateLoader(int id, Bundle args) { - return new SystemContactInfoLoader(context, context.getContentResolver(), masterKeyId, isSecret); - } - - @Override - public void onLoadFinished(Loader 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() {