simplify ViewKeyFragment
This commit is contained in:
@@ -25,10 +25,10 @@ import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -52,28 +52,28 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
private final Context context;
|
||||
private final LayoutInflater layoutInflater;
|
||||
private final boolean isSecret;
|
||||
private final IdentityClickListener identityClickListener;
|
||||
|
||||
private List<IdentityInfo> data;
|
||||
private boolean isSecret;
|
||||
|
||||
|
||||
public IdentityAdapter(Context context, boolean isSecret, IdentityClickListener identityClickListener) {
|
||||
public IdentityAdapter(Context context, IdentityClickListener identityClickListener) {
|
||||
super();
|
||||
this.layoutInflater = LayoutInflater.from(context);
|
||||
this.context = context;
|
||||
this.isSecret = isSecret;
|
||||
this.identityClickListener = identityClickListener;
|
||||
}
|
||||
|
||||
public void setData(List<IdentityInfo> data) {
|
||||
public void setData(List<IdentityInfo> data, boolean isSecret) {
|
||||
this.data = data;
|
||||
this.isSecret = isSecret;
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
IdentityInfo info = data.get(position);
|
||||
|
||||
int viewType = getItemViewType(position);
|
||||
@@ -90,8 +90,9 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
if (viewType == VIEW_TYPE_USER_ID) {
|
||||
return new UserIdViewHolder(
|
||||
layoutInflater.inflate(R.layout.view_key_identity_user_id, parent, false), identityClickListener);
|
||||
@@ -144,12 +145,9 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
vTitle = view.findViewById(R.id.linked_id_title);
|
||||
vComment = view.findViewById(R.id.linked_id_comment);
|
||||
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (identityClickListener != null) {
|
||||
identityClickListener.onClickIdentity(getAdapterPosition());
|
||||
}
|
||||
view.setOnClickListener(v -> {
|
||||
if (identityClickListener != null) {
|
||||
identityClickListener.onClickIdentity(getAdapterPosition());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -213,19 +211,8 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
vIcon = view.findViewById(R.id.trust_id_app_icon);
|
||||
vMore = view.findViewById(R.id.user_id_item_more);
|
||||
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
identityClickListener.onClickIdentity(getAdapterPosition());
|
||||
}
|
||||
});
|
||||
|
||||
vMore.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
identityClickListener.onClickIdentityMore(getAdapterPosition(), v);
|
||||
}
|
||||
});
|
||||
view.setOnClickListener(v -> identityClickListener.onClickIdentity(getAdapterPosition()));
|
||||
vMore.setOnClickListener(v -> identityClickListener.onClickIdentityMore(getAdapterPosition(), v));
|
||||
}
|
||||
|
||||
public void bind(AutocryptPeerInfo info) {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.sufficientlysecure.keychain.ui.keyview;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Transformations;
|
||||
import android.arch.lifecycle.ViewModel;
|
||||
import android.content.Context;
|
||||
|
||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
||||
import org.sufficientlysecure.keychain.provider.KeyMetadataDao;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeySubkeyStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactDao;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactDao.SystemContactInfo;
|
||||
|
||||
|
||||
public class KeyFragmentViewModel extends ViewModel {
|
||||
private LiveData<List<IdentityInfo>> identityInfo;
|
||||
private LiveData<KeySubkeyStatus> subkeyStatus;
|
||||
private LiveData<SystemContactInfo> systemContactInfo;
|
||||
private LiveData<KeyMetadata> keyserverStatus;
|
||||
|
||||
LiveData<List<IdentityInfo>> getIdentityInfo(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData,
|
||||
boolean showLinkedIds) {
|
||||
if (identityInfo == null) {
|
||||
IdentityDao identityDao = IdentityDao.getInstance(context);
|
||||
identityInfo = Transformations.switchMap(unifiedKeyInfoLiveData,
|
||||
(unifiedKeyInfo) -> new GenericLiveData<>(context, null,
|
||||
() -> identityDao.getIdentityInfos(unifiedKeyInfo.master_key_id(), showLinkedIds)));
|
||||
}
|
||||
return identityInfo;
|
||||
}
|
||||
|
||||
LiveData<KeySubkeyStatus> getSubkeyStatus(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
|
||||
if (subkeyStatus == null) {
|
||||
SubkeyStatusDao subkeyStatusDao = SubkeyStatusDao.getInstance(context);
|
||||
subkeyStatus = Transformations.switchMap(unifiedKeyInfoLiveData,
|
||||
(unifiedKeyInfo) -> new GenericLiveData<>(context, null,
|
||||
() -> subkeyStatusDao.getSubkeyStatus(unifiedKeyInfo.master_key_id())));
|
||||
}
|
||||
return subkeyStatus;
|
||||
}
|
||||
|
||||
LiveData<SystemContactInfo> getSystemContactInfo(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
|
||||
if (systemContactInfo == null) {
|
||||
SystemContactDao systemContactDao = SystemContactDao.getInstance(context);
|
||||
systemContactInfo = Transformations.switchMap(unifiedKeyInfoLiveData,
|
||||
(unifiedKeyInfo) -> new GenericLiveData<>(context, null,
|
||||
() -> systemContactDao.getSystemContactInfo(unifiedKeyInfo.master_key_id(),
|
||||
unifiedKeyInfo.has_any_secret())));
|
||||
}
|
||||
return systemContactInfo;
|
||||
}
|
||||
|
||||
LiveData<KeyMetadata> getKeyserverStatus(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
|
||||
if (keyserverStatus == null) {
|
||||
KeyMetadataDao keyMetadataDao = KeyMetadataDao.create(context);
|
||||
keyserverStatus = Transformations.switchMap(unifiedKeyInfoLiveData,
|
||||
(unifiedKeyInfo) -> new GenericLiveData<>(context, null,
|
||||
() -> keyMetadataDao.getKeyMetadata(unifiedKeyInfo.master_key_id())));
|
||||
}
|
||||
return keyserverStatus;
|
||||
}
|
||||
}
|
||||
@@ -313,7 +313,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
|
||||
}
|
||||
if (unifiedKeyInfoLiveData == null) {
|
||||
KeyRepository keyRepository = KeyRepository.create(context);
|
||||
unifiedKeyInfoLiveData = new GenericLiveData<>(context, null,
|
||||
unifiedKeyInfoLiveData = new GenericLiveData<>(context, KeyRings.buildGenericKeyRingUri(masterKeyId),
|
||||
() -> keyRepository.getUnifiedKeyInfo(masterKeyId));
|
||||
}
|
||||
return unifiedKeyInfoLiveData;
|
||||
|
||||
@@ -21,11 +21,13 @@ 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.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
@@ -42,35 +44,43 @@ import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
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.ViewKeyActivity.ViewKeyViewModel;
|
||||
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.SubkeyStatusDao.KeyHealthStatus;
|
||||
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;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyStatusList.KeyDisplayStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyserverStatusView;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView;
|
||||
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class ViewKeyFragment extends Fragment implements ViewKeyMvpView, OnMenuItemClickListener {
|
||||
public class ViewKeyFragment extends Fragment implements OnMenuItemClickListener {
|
||||
private IdentitiesCardView identitiesCardView;
|
||||
private IdentitiesPresenter identitiesPresenter;
|
||||
private SystemContactCardView systemContactCard;
|
||||
private KeyHealthView keyStatusHealth;
|
||||
private KeyserverStatusView keyserverStatusView;
|
||||
|
||||
SystemContactCardView systemContactCard;
|
||||
SystemContactPresenter systemContactPresenter;
|
||||
|
||||
KeyHealthView keyStatusHealth;
|
||||
KeyserverStatusView keyStatusKeyserver;
|
||||
|
||||
KeyHealthPresenter keyHealthPresenter;
|
||||
KeyserverStatusPresenter keyserverStatusPresenter;
|
||||
IdentityAdapter identitiesAdapter;
|
||||
|
||||
private Integer displayedContextMenuPosition;
|
||||
private UnifiedKeyInfo unifiedKeyInfo;
|
||||
private KeySubkeyStatus subkeyStatus;
|
||||
private boolean showingExpandedInfo;
|
||||
|
||||
public static ViewKeyFragment newInstance() {
|
||||
return new ViewKeyFragment();
|
||||
@@ -83,74 +93,233 @@ public class ViewKeyFragment extends Fragment implements ViewKeyMvpView, OnMenuI
|
||||
identitiesCardView = view.findViewById(R.id.card_identities);
|
||||
systemContactCard = view.findViewById(R.id.linked_system_contact_card);
|
||||
keyStatusHealth = view.findViewById(R.id.key_status_health);
|
||||
keyStatusKeyserver = view.findViewById(R.id.key_status_keyserver);
|
||||
keyserverStatusView = view.findViewById(R.id.key_status_keyserver);
|
||||
|
||||
identitiesAdapter = new IdentityAdapter(requireContext(), new IdentityClickListener() {
|
||||
@Override
|
||||
public void onClickIdentity(int position) {
|
||||
showIdentityInfo(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClickIdentityMore(int position, View anchor) {
|
||||
showIdentityContextMenu(position, anchor);
|
||||
}
|
||||
});
|
||||
identitiesCardView.setIdentitiesAdapter(identitiesAdapter);
|
||||
|
||||
keyStatusHealth.setOnHealthClickListener((v) -> onKeyHealthClick());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public static class KeyFragmentViewModel extends ViewModel {
|
||||
private LiveData<List<IdentityInfo>> identityInfo;
|
||||
private LiveData<KeySubkeyStatus> subkeyStatus;
|
||||
private LiveData<SystemContactInfo> systemContactInfo;
|
||||
private LiveData<KeyMetadata> 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<KeyMetadata> getKeyserverStatus(KeyserverStatusPresenter keyserverStatusPresenter) {
|
||||
if (keyserverStatus == null) {
|
||||
keyserverStatus = keyserverStatusPresenter.getLiveDataInstance();
|
||||
}
|
||||
return keyserverStatus;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
Context context = requireContext();
|
||||
|
||||
ViewKeyViewModel viewKeyViewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyViewModel.class);
|
||||
viewKeyViewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyInfo);
|
||||
LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData = viewKeyViewModel.getUnifiedKeyInfoLiveData(requireContext());
|
||||
|
||||
unifiedKeyInfoLiveData.observe(this, this::onLoadUnifiedKeyInfo);
|
||||
|
||||
KeyFragmentViewModel model = ViewModelProviders.of(this).get(KeyFragmentViewModel.class);
|
||||
|
||||
boolean showLinkedIds = Preferences.getPreferences(context).getExperimentalEnableLinkedIdentities();
|
||||
model.getIdentityInfo(context, unifiedKeyInfoLiveData, showLinkedIds).observe(this, this::onLoadIdentityInfo);
|
||||
model.getKeyserverStatus(context, unifiedKeyInfoLiveData).observe(this, this::onLoadKeyMetadata);
|
||||
model.getSystemContactInfo(context, unifiedKeyInfoLiveData).observe(this, this::onLoadSystemContact);
|
||||
model.getSubkeyStatus(context, unifiedKeyInfoLiveData).observe(this, this::onLoadSubkeyStatus);
|
||||
}
|
||||
|
||||
private void onLoadSubkeyStatus(KeySubkeyStatus subkeyStatus) {
|
||||
if (subkeyStatus == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.subkeyStatus = subkeyStatus;
|
||||
|
||||
KeyHealthStatus keyHealthStatus = subkeyStatus.keyHealthStatus;
|
||||
|
||||
boolean isInsecure = keyHealthStatus == KeyHealthStatus.INSECURE;
|
||||
boolean isExpired = keyHealthStatus == KeyHealthStatus.EXPIRED;
|
||||
if (isInsecure) {
|
||||
boolean primaryKeySecurityProblem = subkeyStatus.keyCertify.mSecurityProblem != null;
|
||||
if (primaryKeySecurityProblem) {
|
||||
keyStatusHealth.setKeyStatus(keyHealthStatus);
|
||||
keyStatusHealth.setPrimarySecurityProblem(subkeyStatus.keyCertify.mSecurityProblem);
|
||||
keyStatusHealth.setShowExpander(false);
|
||||
} else {
|
||||
keyStatusHealth.setKeyStatus(keyHealthStatus);
|
||||
keyStatusHealth.setShowExpander(false);
|
||||
displayExpandedInfo(false);
|
||||
}
|
||||
} else if (isExpired) {
|
||||
keyStatusHealth.setKeyStatus(keyHealthStatus);
|
||||
keyStatusHealth.setPrimaryExpiryDate(subkeyStatus.keyCertify.mExpiry);
|
||||
keyStatusHealth.setShowExpander(false);
|
||||
keyStatusHealth.hideExpandedInfo();
|
||||
} else {
|
||||
keyStatusHealth.setKeyStatus(keyHealthStatus);
|
||||
keyStatusHealth.setShowExpander(keyHealthStatus != KeyHealthStatus.REVOKED);
|
||||
keyStatusHealth.hideExpandedInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private void displayExpandedInfo(boolean displayAll) {
|
||||
SubKeyItem keyCertify = subkeyStatus.keyCertify;
|
||||
SubKeyItem keySign = subkeyStatus.keysSign.isEmpty() ? null : subkeyStatus.keysSign.get(0);
|
||||
SubKeyItem keyEncrypt = subkeyStatus.keysEncrypt.isEmpty() ? null : subkeyStatus.keysEncrypt.get(0);
|
||||
|
||||
KeyDisplayStatus certDisplayStatus = getKeyDisplayStatus(keyCertify);
|
||||
KeyDisplayStatus signDisplayStatus = getKeyDisplayStatus(keySign);
|
||||
KeyDisplayStatus encryptDisplayStatus = getKeyDisplayStatus(keyEncrypt);
|
||||
|
||||
if (!displayAll) {
|
||||
if (certDisplayStatus == KeyDisplayStatus.OK) {
|
||||
certDisplayStatus = null;
|
||||
}
|
||||
if (certDisplayStatus == KeyDisplayStatus.INSECURE) {
|
||||
signDisplayStatus = null;
|
||||
encryptDisplayStatus = null;
|
||||
}
|
||||
if (signDisplayStatus == KeyDisplayStatus.OK) {
|
||||
signDisplayStatus = null;
|
||||
}
|
||||
if (encryptDisplayStatus == KeyDisplayStatus.OK) {
|
||||
encryptDisplayStatus = null;
|
||||
}
|
||||
}
|
||||
|
||||
keyStatusHealth.showExpandedState(certDisplayStatus, signDisplayStatus, encryptDisplayStatus);
|
||||
}
|
||||
|
||||
private void onKeyHealthClick() {
|
||||
if (showingExpandedInfo) {
|
||||
showingExpandedInfo = false;
|
||||
keyStatusHealth.hideExpandedInfo();
|
||||
} else {
|
||||
showingExpandedInfo = true;
|
||||
displayExpandedInfo(true);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyDisplayStatus getKeyDisplayStatus(SubKeyItem subKeyItem) {
|
||||
if (subKeyItem == null) {
|
||||
return KeyDisplayStatus.UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (subKeyItem.mIsRevoked) {
|
||||
return KeyDisplayStatus.REVOKED;
|
||||
}
|
||||
if (subKeyItem.mIsExpired) {
|
||||
return KeyDisplayStatus.EXPIRED;
|
||||
}
|
||||
if (subKeyItem.mSecurityProblem != null) {
|
||||
return KeyDisplayStatus.INSECURE;
|
||||
}
|
||||
if (subKeyItem.mSecretKeyType == SecretKeyType.GNU_DUMMY) {
|
||||
return KeyDisplayStatus.STRIPPED;
|
||||
}
|
||||
if (subKeyItem.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD) {
|
||||
return KeyDisplayStatus.DIVERT;
|
||||
}
|
||||
|
||||
return KeyDisplayStatus.OK;
|
||||
}
|
||||
|
||||
private void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
|
||||
KeyFragmentViewModel model = ViewModelProviders.of(this).get(KeyFragmentViewModel.class);
|
||||
if (unifiedKeyInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
identitiesPresenter = new IdentitiesPresenter(
|
||||
getContext(), identitiesCardView, this, unifiedKeyInfo.master_key_id(), unifiedKeyInfo.has_any_secret());
|
||||
model.getIdentityInfo(identitiesPresenter).observe(this, identitiesPresenter);
|
||||
Context context = requireContext();
|
||||
|
||||
systemContactPresenter = new SystemContactPresenter(
|
||||
getContext(), systemContactCard, unifiedKeyInfo.master_key_id(), unifiedKeyInfo.has_any_secret());
|
||||
model.getSystemContactInfo(systemContactPresenter).observe(this, systemContactPresenter);
|
||||
this.unifiedKeyInfo = unifiedKeyInfo;
|
||||
|
||||
keyHealthPresenter = new KeyHealthPresenter(getContext(), keyStatusHealth, unifiedKeyInfo.master_key_id());
|
||||
model.getSubkeyStatus(keyHealthPresenter).observe(this, keyHealthPresenter);
|
||||
|
||||
keyserverStatusPresenter = new KeyserverStatusPresenter(
|
||||
getContext(), keyStatusKeyserver, unifiedKeyInfo.master_key_id(), unifiedKeyInfo.has_any_secret());
|
||||
model.getKeyserverStatus(keyserverStatusPresenter).observe(this, keyserverStatusPresenter);
|
||||
boolean showLinkedIds = Preferences.getPreferences(context).getExperimentalEnableLinkedIdentities();
|
||||
boolean isSecret = unifiedKeyInfo.has_any_secret();
|
||||
identitiesCardView.setAddLinkedIdButtonVisible(showLinkedIds && isSecret);
|
||||
identitiesCardView.setIdentitiesCardListener((v) -> addLinkedIdentity());
|
||||
}
|
||||
|
||||
private void showIdentityInfo(final int position) {
|
||||
IdentityInfo info = identitiesAdapter.getInfo(position);
|
||||
if (info instanceof LinkedIdInfo) {
|
||||
showLinkedId((LinkedIdInfo) info);
|
||||
} else if (info instanceof UserIdInfo) {
|
||||
showUserIdInfo((UserIdInfo) info);
|
||||
} else if (info instanceof AutocryptPeerInfo) {
|
||||
Intent autocryptPeerIntent = ((AutocryptPeerInfo) info).getAutocryptPeerIntent();
|
||||
if (autocryptPeerIntent != null) {
|
||||
startActivity(autocryptPeerIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showIdentityContextMenu(int position, View anchor) {
|
||||
showContextMenu(position, anchor);
|
||||
}
|
||||
|
||||
private void showLinkedId(final LinkedIdInfo info) {
|
||||
LinkedIdViewFragment frag = LinkedIdViewFragment.newInstance(info.getMasterKeyId(), info.getRank(), unifiedKeyInfo.has_any_secret());
|
||||
|
||||
switchToFragment(frag, "linked_id");
|
||||
}
|
||||
|
||||
private void showUserIdInfo(UserIdInfo info) {
|
||||
if (!unifiedKeyInfo.has_any_secret()) {
|
||||
UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, info.isVerified());
|
||||
showDialogFragment(dialogFragment, "userIdInfoDialog");
|
||||
}
|
||||
}
|
||||
|
||||
private void addLinkedIdentity() {
|
||||
Intent intent = new Intent(requireContext(), LinkedIdWizard.class);
|
||||
intent.setData(KeyRings.buildUnifiedKeyRingUri(unifiedKeyInfo.master_key_id()));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
public void onClickForgetIdentity(int position) {
|
||||
AutocryptPeerInfo info = (AutocryptPeerInfo) identitiesAdapter.getInfo(position);
|
||||
if (info == null) {
|
||||
Timber.e("got a 'forget' click on a bad trust id");
|
||||
return;
|
||||
}
|
||||
|
||||
AutocryptPeerDao.getInstance(requireContext()).deleteByIdentifier(info.getPackageName(), info.getIdentity());
|
||||
}
|
||||
|
||||
private void onLoadIdentityInfo(List<IdentityInfo> identityInfos) {
|
||||
identitiesAdapter.setData(identityInfos, unifiedKeyInfo.has_any_secret());
|
||||
}
|
||||
|
||||
private void onLoadSystemContact(SystemContactInfo systemContactInfo) {
|
||||
if (systemContactInfo == null) {
|
||||
systemContactCard.hideLinkedSystemContact();
|
||||
return;
|
||||
}
|
||||
|
||||
systemContactCard.showLinkedSystemContact(systemContactInfo.contactName, systemContactInfo.contactPicture);
|
||||
systemContactCard.setSystemContactClickListener((v) -> launchAndroidContactActivity(systemContactInfo.contactId));
|
||||
}
|
||||
|
||||
private void onLoadKeyMetadata(KeyMetadata keyMetadata) {
|
||||
if (keyMetadata == null) {
|
||||
keyserverStatusView.setDisplayStatusUnknown();
|
||||
} else if (keyMetadata.hasBeenUpdated()) {
|
||||
if (keyMetadata.isPublished()) {
|
||||
keyserverStatusView.setDisplayStatusPublished();
|
||||
} else {
|
||||
keyserverStatusView.setDisplayStatusNotPublished();
|
||||
}
|
||||
keyserverStatusView.setLastUpdated(keyMetadata.last_updated());
|
||||
} else {
|
||||
keyserverStatusView.setDisplayStatusUnknown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void switchToFragment(final Fragment frag, final String backStackName) {
|
||||
new Handler().post(() -> requireFragmentManager().beginTransaction()
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
@@ -170,18 +339,11 @@ public class ViewKeyFragment extends Fragment implements ViewKeyMvpView, OnMenuI
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startActivityAndShowResultSnackbar(Intent intent) {
|
||||
startActivityForResult(intent, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDialogFragment(final DialogFragment dialogFragment, final String tag) {
|
||||
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(
|
||||
() -> dialogFragment.show(requireFragmentManager(), tag));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showContextMenu(int position, View anchor) {
|
||||
displayedContextMenuPosition = position;
|
||||
|
||||
@@ -202,10 +364,17 @@ public class ViewKeyFragment extends Fragment implements ViewKeyMvpView, OnMenuI
|
||||
case R.id.autocrypt_forget:
|
||||
int position = displayedContextMenuPosition;
|
||||
displayedContextMenuPosition = null;
|
||||
identitiesPresenter.onClickForgetIdentity(position);
|
||||
onClickForgetIdentity(position);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void launchAndroidContactActivity(long contactId) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactId));
|
||||
intent.setData(uri);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class IdentityDao {
|
||||
this.autocryptPeerDao = autocryptPeerDao;
|
||||
}
|
||||
|
||||
List<IdentityInfo> getIdentityInfos(long masterKeyId, boolean showLinkedIds) {
|
||||
public List<IdentityInfo> getIdentityInfos(long masterKeyId, boolean showLinkedIds) {
|
||||
ArrayList<IdentityInfo> identities = new ArrayList<>();
|
||||
|
||||
if (showLinkedIds) {
|
||||
@@ -95,11 +95,11 @@ public class IdentityDao {
|
||||
if (associatedUserIdInfo != null) {
|
||||
int position = identities.indexOf(associatedUserIdInfo);
|
||||
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
||||
.create(associatedUserIdInfo, autocryptId, packageName, drawable, autocryptPeerIntent);
|
||||
.create(masterKeyId, associatedUserIdInfo, autocryptId, packageName, drawable, autocryptPeerIntent);
|
||||
identities.set(position, autocryptPeerInfo);
|
||||
} else {
|
||||
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
||||
.create(autocryptId, packageName, drawable, autocryptPeerIntent);
|
||||
.create(masterKeyId, autocryptId, packageName, drawable, autocryptPeerIntent);
|
||||
identities.add(autocryptPeerInfo);
|
||||
}
|
||||
}
|
||||
@@ -163,7 +163,7 @@ public class IdentityDao {
|
||||
try {
|
||||
UriAttribute uriAttribute = LinkedAttribute.fromAttributeData(userAttribute.attribute_data());
|
||||
if (uriAttribute instanceof LinkedAttribute) {
|
||||
return LinkedIdInfo.create(userAttribute.rank(),
|
||||
return LinkedIdInfo.create(userAttribute.master_key_id(), userAttribute.rank(),
|
||||
userAttribute.isVerified(), userAttribute.is_primary(), (LinkedAttribute) uriAttribute);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -180,7 +180,7 @@ public class IdentityDao {
|
||||
|
||||
if (userId.name() != null || userId.email() != null) {
|
||||
IdentityInfo identityInfo = UserIdInfo.create(
|
||||
userId.rank(), userId.isVerified(), userId.is_primary(), userId.name(), userId.email(), userId.comment());
|
||||
userId.master_key_id(), userId.rank(), userId.isVerified(), userId.is_primary(), userId.name(), userId.email(), userId.comment());
|
||||
identities.add(identityInfo);
|
||||
}
|
||||
}
|
||||
@@ -188,6 +188,7 @@ public class IdentityDao {
|
||||
}
|
||||
|
||||
public interface IdentityInfo {
|
||||
long getMasterKeyId();
|
||||
int getRank();
|
||||
boolean isVerified();
|
||||
boolean isPrimary();
|
||||
@@ -195,6 +196,7 @@ public class IdentityDao {
|
||||
|
||||
@AutoValue
|
||||
public abstract static class UserIdInfo implements IdentityInfo {
|
||||
public abstract long getMasterKeyId();
|
||||
public abstract int getRank();
|
||||
public abstract boolean isVerified();
|
||||
public abstract boolean isPrimary();
|
||||
@@ -206,27 +208,29 @@ public class IdentityDao {
|
||||
@Nullable
|
||||
public abstract String getComment();
|
||||
|
||||
static UserIdInfo create(int rank, boolean isVerified, boolean isPrimary, String name, String email,
|
||||
static UserIdInfo create(long masterKeyId, int rank, boolean isVerified, boolean isPrimary, String name, String email,
|
||||
String comment) {
|
||||
return new AutoValue_IdentityDao_UserIdInfo(rank, isVerified, isPrimary, name, email, comment);
|
||||
return new AutoValue_IdentityDao_UserIdInfo(masterKeyId, rank, isVerified, isPrimary, name, email, comment);
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
public abstract static class LinkedIdInfo implements IdentityInfo {
|
||||
public abstract long getMasterKeyId();
|
||||
public abstract int getRank();
|
||||
public abstract boolean isVerified();
|
||||
public abstract boolean isPrimary();
|
||||
|
||||
public abstract LinkedAttribute getLinkedAttribute();
|
||||
|
||||
static LinkedIdInfo create(int rank, boolean isVerified, boolean isPrimary, LinkedAttribute linkedAttribute) {
|
||||
return new AutoValue_IdentityDao_LinkedIdInfo(rank, isVerified, isPrimary, linkedAttribute);
|
||||
static LinkedIdInfo create(long masterKeyId, int rank, boolean isVerified, boolean isPrimary, LinkedAttribute linkedAttribute) {
|
||||
return new AutoValue_IdentityDao_LinkedIdInfo(masterKeyId, rank, isVerified, isPrimary, linkedAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
public abstract static class AutocryptPeerInfo implements IdentityInfo {
|
||||
public abstract long getMasterKeyId();
|
||||
public abstract int getRank();
|
||||
public abstract boolean isVerified();
|
||||
public abstract boolean isPrimary();
|
||||
@@ -240,15 +244,14 @@ public class IdentityDao {
|
||||
@Nullable
|
||||
public abstract Intent getAutocryptPeerIntent();
|
||||
|
||||
static AutocryptPeerInfo create(UserIdInfo userIdInfo, String autocryptPeer, String packageName,
|
||||
static AutocryptPeerInfo create(long masterKeyId, UserIdInfo userIdInfo, String autocryptPeer, String packageName,
|
||||
Drawable appIcon, Intent autocryptPeerIntent) {
|
||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(userIdInfo.getRank(), userIdInfo.isVerified(),
|
||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, userIdInfo.getRank(), userIdInfo.isVerified(),
|
||||
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent);
|
||||
}
|
||||
|
||||
static AutocryptPeerInfo create(String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(
|
||||
0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
||||
static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId,0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public class SubkeyStatusDao {
|
||||
this.keyRepository = keyRepository;
|
||||
}
|
||||
|
||||
KeySubkeyStatus getSubkeyStatus(long masterKeyId, Comparator<SubKeyItem> comparator) {
|
||||
public KeySubkeyStatus getSubkeyStatus(long masterKeyId) {
|
||||
SubKeyItem keyCertify = null;
|
||||
ArrayList<SubKeyItem> keysSign = new ArrayList<>();
|
||||
ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>();
|
||||
@@ -73,10 +73,89 @@ public class SubkeyStatusDao {
|
||||
return null;
|
||||
}
|
||||
|
||||
Collections.sort(keysSign, comparator);
|
||||
Collections.sort(keysEncrypt, comparator);
|
||||
Collections.sort(keysSign, SUBKEY_COMPARATOR);
|
||||
Collections.sort(keysEncrypt, SUBKEY_COMPARATOR);
|
||||
|
||||
return new KeySubkeyStatus(keyCertify, keysSign, keysEncrypt);
|
||||
KeyHealthStatus keyHealthStatus = determineKeyHealthStatus(keyCertify, keysSign, keysEncrypt);
|
||||
|
||||
return new KeySubkeyStatus(keyCertify, keysSign, keysEncrypt, keyHealthStatus);
|
||||
}
|
||||
|
||||
private KeyHealthStatus determineKeyHealthStatus(SubKeyItem keyCertify,
|
||||
ArrayList<SubKeyItem> keysSign,
|
||||
ArrayList<SubKeyItem> keysEncrypt) {
|
||||
if (keyCertify.mIsRevoked) {
|
||||
return KeyHealthStatus.REVOKED;
|
||||
}
|
||||
|
||||
if (keyCertify.mIsExpired) {
|
||||
return KeyHealthStatus.EXPIRED;
|
||||
}
|
||||
|
||||
if (keyCertify.mSecurityProblem != null) {
|
||||
return KeyHealthStatus.INSECURE;
|
||||
}
|
||||
|
||||
if (!keysSign.isEmpty() && keysEncrypt.isEmpty()) {
|
||||
SubKeyItem keySign = keysSign.get(0);
|
||||
if (!keySign.isValid()) {
|
||||
return KeyHealthStatus.BROKEN;
|
||||
}
|
||||
|
||||
if (keySign.mSecurityProblem != null) {
|
||||
return KeyHealthStatus.INSECURE;
|
||||
}
|
||||
|
||||
return KeyHealthStatus.SIGN_ONLY;
|
||||
}
|
||||
|
||||
if (keysSign.isEmpty() || keysEncrypt.isEmpty()) {
|
||||
return KeyHealthStatus.BROKEN;
|
||||
}
|
||||
|
||||
SubKeyItem keySign = keysSign.get(0);
|
||||
SubKeyItem keyEncrypt = keysEncrypt.get(0);
|
||||
|
||||
if (keySign.mSecurityProblem != null && keySign.isValid()
|
||||
|| keyEncrypt.mSecurityProblem != null && keyEncrypt.isValid()) {
|
||||
return KeyHealthStatus.INSECURE;
|
||||
}
|
||||
|
||||
if (!keySign.isValid() || !keyEncrypt.isValid()) {
|
||||
return KeyHealthStatus.BROKEN;
|
||||
}
|
||||
|
||||
if (keyCertify.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
&& keySign.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
&& keyEncrypt.mSecretKeyType == SecretKeyType.GNU_DUMMY) {
|
||||
return KeyHealthStatus.STRIPPED;
|
||||
}
|
||||
|
||||
if (keyCertify.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD
|
||||
&& keySign.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD
|
||||
&& keyEncrypt.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD) {
|
||||
return KeyHealthStatus.DIVERT;
|
||||
}
|
||||
|
||||
boolean containsDivertKeys = keyCertify.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD ||
|
||||
keySign.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD ||
|
||||
keyEncrypt.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD;
|
||||
if (containsDivertKeys) {
|
||||
return KeyHealthStatus.DIVERT_PARTIAL;
|
||||
}
|
||||
|
||||
boolean containsStrippedKeys = keyCertify.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
|| keySign.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
|| keyEncrypt.mSecretKeyType == SecretKeyType.GNU_DUMMY;
|
||||
if (containsStrippedKeys) {
|
||||
return KeyHealthStatus.PARTIAL_STRIPPED;
|
||||
}
|
||||
|
||||
return KeyHealthStatus.OK;
|
||||
}
|
||||
|
||||
public enum KeyHealthStatus {
|
||||
OK, DIVERT, DIVERT_PARTIAL, REVOKED, EXPIRED, INSECURE, SIGN_ONLY, STRIPPED, PARTIAL_STRIPPED, BROKEN
|
||||
}
|
||||
|
||||
public static class KeySubkeyStatus {
|
||||
@@ -84,11 +163,14 @@ public class SubkeyStatusDao {
|
||||
public final SubKeyItem keyCertify;
|
||||
public final List<SubKeyItem> keysSign;
|
||||
public final List<SubKeyItem> keysEncrypt;
|
||||
public final KeyHealthStatus keyHealthStatus;
|
||||
|
||||
KeySubkeyStatus(@NonNull SubKeyItem keyCertify, List<SubKeyItem> keysSign, List<SubKeyItem> keysEncrypt) {
|
||||
KeySubkeyStatus(@NonNull SubKeyItem keyCertify, List<SubKeyItem> keysSign, List<SubKeyItem> keysEncrypt,
|
||||
KeyHealthStatus keyHealthStatus) {
|
||||
this.keyCertify = keyCertify;
|
||||
this.keysSign = keysSign;
|
||||
this.keysEncrypt = keysEncrypt;
|
||||
this.keyHealthStatus = keyHealthStatus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +213,24 @@ public class SubkeyStatusDao {
|
||||
return !mIsRevoked && !mIsExpired;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Comparator<SubKeyItem> SUBKEY_COMPARATOR = (one, two) -> {
|
||||
if (one == two) {
|
||||
return 0;
|
||||
}
|
||||
// if one is valid and the other isn't, the valid one always comes first
|
||||
if (one.isValid() ^ two.isValid()) {
|
||||
return one.isValid() ? -1 : 1;
|
||||
}
|
||||
// compare usability, if one is "more usable" than the other, that one comes first
|
||||
int usability = one.mSecretKeyType.compareUsability(two.mSecretKeyType);
|
||||
if (usability != 0) {
|
||||
return usability;
|
||||
}
|
||||
if ((one.mSecurityProblem == null) ^ (two.mSecurityProblem == null)) {
|
||||
return one.mSecurityProblem == null ? -1 : 1;
|
||||
}
|
||||
// otherwise, the newer one comes first
|
||||
return one.newerThan(two) ? -1 : 1;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class SystemContactDao {
|
||||
this.contentResolver = contentResolver;
|
||||
}
|
||||
|
||||
SystemContactInfo getSystemContactInfo(long masterKeyId, boolean isSecret) {
|
||||
public 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!");
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
package org.sufficientlysecure.keychain.ui.keyview.loader;
|
||||
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
||||
import org.sufficientlysecure.keychain.provider.KeyMetadataDao;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||
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<KeyMetadata> {
|
||||
private final KeyMetadataDao keyMetadataDao;
|
||||
|
||||
private final long masterKeyId;
|
||||
|
||||
public KeyserverStatusLiveData(Context context, long masterKeyId) {
|
||||
super(context, KeyRings.buildGenericKeyRingUri(masterKeyId));
|
||||
|
||||
this.keyMetadataDao = KeyMetadataDao.create(context);
|
||||
this.masterKeyId = masterKeyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyMetadata asyncLoadData() {
|
||||
return keyMetadataDao.getKeyMetadata(masterKeyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Schürmann & Breitmoser GbR
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
|
||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
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.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 Observer<List<IdentityInfo>> {
|
||||
private final Context context;
|
||||
private final IdentitiesMvpView view;
|
||||
private final ViewKeyMvpView viewKeyMvpView;
|
||||
|
||||
private final IdentityAdapter identitiesAdapter;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
private final boolean showLinkedIds;
|
||||
private AutocryptPeerDao autocryptPeerDao;
|
||||
|
||||
public IdentitiesPresenter(Context context, IdentitiesMvpView view, ViewKeyMvpView viewKeyMvpView,
|
||||
long masterKeyId, boolean isSecret) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
this.viewKeyMvpView = viewKeyMvpView;
|
||||
this.autocryptPeerDao = AutocryptPeerDao.getInstance(context);
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
|
||||
showLinkedIds = Preferences.getPreferences(context).getExperimentalEnableLinkedIdentities();
|
||||
|
||||
identitiesAdapter = new IdentityAdapter(context, isSecret, new IdentityClickListener() {
|
||||
@Override
|
||||
public void onClickIdentity(int position) {
|
||||
showIdentityInfo(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClickIdentityMore(int position, View anchor) {
|
||||
showIdentityContextMenu(position, anchor);
|
||||
|
||||
}
|
||||
});
|
||||
view.setIdentitiesAdapter(identitiesAdapter);
|
||||
|
||||
view.setAddLinkedIdButtonVisible(showLinkedIds && isSecret);
|
||||
|
||||
view.setIdentitiesCardListener(() -> addLinkedIdentity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(@Nullable List<IdentityInfo> identityInfos) {
|
||||
identitiesAdapter.setData(identityInfos);
|
||||
}
|
||||
|
||||
private void showIdentityInfo(final int position) {
|
||||
IdentityInfo info = identitiesAdapter.getInfo(position);
|
||||
if (info instanceof LinkedIdInfo) {
|
||||
showLinkedId((LinkedIdInfo) info);
|
||||
} else if (info instanceof UserIdInfo) {
|
||||
showUserIdInfo((UserIdInfo) info);
|
||||
} else if (info instanceof AutocryptPeerInfo) {
|
||||
Intent autocryptPeerIntent = ((AutocryptPeerInfo) info).getAutocryptPeerIntent();
|
||||
if (autocryptPeerIntent != null) {
|
||||
viewKeyMvpView.startActivity(autocryptPeerIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showIdentityContextMenu(int position, View anchor) {
|
||||
viewKeyMvpView.showContextMenu(position, anchor);
|
||||
}
|
||||
|
||||
private void showLinkedId(final LinkedIdInfo info) {
|
||||
LinkedIdViewFragment frag = LinkedIdViewFragment.newInstance(masterKeyId, info.getRank(), isSecret);
|
||||
|
||||
viewKeyMvpView.switchToFragment(frag, "linked_id");
|
||||
}
|
||||
|
||||
private void showUserIdInfo(UserIdInfo info) {
|
||||
if (!isSecret) {
|
||||
UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, info.isVerified());
|
||||
viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog");
|
||||
}
|
||||
}
|
||||
|
||||
private void addLinkedIdentity() {
|
||||
Intent intent = new Intent(context, LinkedIdWizard.class);
|
||||
intent.setData(KeyRings.buildUnifiedKeyRingUri(masterKeyId));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public void onClickForgetIdentity(int position) {
|
||||
AutocryptPeerInfo info = (AutocryptPeerInfo) identitiesAdapter.getInfo(position);
|
||||
if (info == null) {
|
||||
Timber.e("got a 'forget' click on a bad trust id");
|
||||
return;
|
||||
}
|
||||
|
||||
autocryptPeerDao.deleteByIdentifier(info.getPackageName(), info.getIdentity());
|
||||
}
|
||||
|
||||
public LiveData<List<IdentityInfo>> getLiveDataInstance() {
|
||||
return new IdentityLiveData(context, masterKeyId, showLinkedIds);
|
||||
}
|
||||
|
||||
public interface IdentitiesMvpView {
|
||||
void setIdentitiesAdapter(IdentityAdapter userIdsAdapter);
|
||||
void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener);
|
||||
void setAddLinkedIdButtonVisible(boolean showLinkedIds);
|
||||
}
|
||||
|
||||
public interface IdentitiesCardListener {
|
||||
void onClickAddIdentity();
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Schürmann & Breitmoser GbR
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
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;
|
||||
|
||||
|
||||
public class KeyHealthPresenter implements Observer<KeySubkeyStatus> {
|
||||
private static final Comparator<SubKeyItem> SUBKEY_COMPARATOR = new Comparator<SubKeyItem>() {
|
||||
@Override
|
||||
public int compare(SubKeyItem one, SubKeyItem two) {
|
||||
// if one is valid and the other isn't, the valid one always comes first
|
||||
if (one.isValid() ^ two.isValid()) {
|
||||
return one.isValid() ? -1 : 1;
|
||||
}
|
||||
// compare usability, if one is "more usable" than the other, that one comes first
|
||||
int usability = one.mSecretKeyType.compareUsability(two.mSecretKeyType);
|
||||
if (usability != 0) {
|
||||
return usability;
|
||||
}
|
||||
if ((one.mSecurityProblem == null) ^ (two.mSecurityProblem == null)) {
|
||||
return one.mSecurityProblem == null ? -1 : 1;
|
||||
}
|
||||
// otherwise, the newer one comes first
|
||||
return one.newerThan(two) ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
private final Context context;
|
||||
private final KeyHealthMvpView view;
|
||||
private final long masterKeyId;
|
||||
|
||||
private KeySubkeyStatus subkeyStatus;
|
||||
private boolean showingExpandedInfo;
|
||||
|
||||
|
||||
public KeyHealthPresenter(Context context, KeyHealthMvpView view, long masterKeyId) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
this.masterKeyId = masterKeyId;
|
||||
|
||||
view.setOnHealthClickListener(new KeyHealthClickListener() {
|
||||
@Override
|
||||
public void onKeyHealthClick() {
|
||||
KeyHealthPresenter.this.onKeyHealthClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(@Nullable KeySubkeyStatus subkeyStatus) {
|
||||
this.subkeyStatus = subkeyStatus;
|
||||
if (subkeyStatus == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
KeyHealthStatus keyHealthStatus = determineKeyHealthStatus(subkeyStatus);
|
||||
|
||||
boolean isInsecure = keyHealthStatus == KeyHealthStatus.INSECURE;
|
||||
boolean isExpired = keyHealthStatus == KeyHealthStatus.EXPIRED;
|
||||
if (isInsecure) {
|
||||
boolean primaryKeySecurityProblem = subkeyStatus.keyCertify.mSecurityProblem != null;
|
||||
if (primaryKeySecurityProblem) {
|
||||
view.setKeyStatus(keyHealthStatus);
|
||||
view.setPrimarySecurityProblem(subkeyStatus.keyCertify.mSecurityProblem);
|
||||
view.setShowExpander(false);
|
||||
} else {
|
||||
view.setKeyStatus(keyHealthStatus);
|
||||
view.setShowExpander(false);
|
||||
displayExpandedInfo(false);
|
||||
}
|
||||
} else if (isExpired) {
|
||||
view.setKeyStatus(keyHealthStatus);
|
||||
view.setPrimaryExpiryDate(subkeyStatus.keyCertify.mExpiry);
|
||||
view.setShowExpander(false);
|
||||
view.hideExpandedInfo();
|
||||
} else {
|
||||
view.setKeyStatus(keyHealthStatus);
|
||||
view.setShowExpander(keyHealthStatus != KeyHealthStatus.REVOKED);
|
||||
view.hideExpandedInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private KeyHealthStatus determineKeyHealthStatus(KeySubkeyStatus subkeyStatus) {
|
||||
SubKeyItem keyCertify = subkeyStatus.keyCertify;
|
||||
if (keyCertify.mIsRevoked) {
|
||||
return KeyHealthStatus.REVOKED;
|
||||
}
|
||||
|
||||
if (keyCertify.mIsExpired) {
|
||||
return KeyHealthStatus.EXPIRED;
|
||||
}
|
||||
|
||||
if (keyCertify.mSecurityProblem != null) {
|
||||
return KeyHealthStatus.INSECURE;
|
||||
}
|
||||
|
||||
if (!subkeyStatus.keysSign.isEmpty() && subkeyStatus.keysEncrypt.isEmpty()) {
|
||||
SubKeyItem keySign = subkeyStatus.keysSign.get(0);
|
||||
if (!keySign.isValid()) {
|
||||
return KeyHealthStatus.BROKEN;
|
||||
}
|
||||
|
||||
if (keySign.mSecurityProblem != null) {
|
||||
return KeyHealthStatus.INSECURE;
|
||||
}
|
||||
|
||||
return KeyHealthStatus.SIGN_ONLY;
|
||||
}
|
||||
|
||||
if (subkeyStatus.keysSign.isEmpty() || subkeyStatus.keysEncrypt.isEmpty()) {
|
||||
return KeyHealthStatus.BROKEN;
|
||||
}
|
||||
|
||||
SubKeyItem keySign = subkeyStatus.keysSign.get(0);
|
||||
SubKeyItem keyEncrypt = subkeyStatus.keysEncrypt.get(0);
|
||||
|
||||
if (keySign.mSecurityProblem != null && keySign.isValid()
|
||||
|| keyEncrypt.mSecurityProblem != null && keyEncrypt.isValid()) {
|
||||
return KeyHealthStatus.INSECURE;
|
||||
}
|
||||
|
||||
if (!keySign.isValid() || !keyEncrypt.isValid()) {
|
||||
return KeyHealthStatus.BROKEN;
|
||||
}
|
||||
|
||||
if (keyCertify.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
&& keySign.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
&& keyEncrypt.mSecretKeyType == SecretKeyType.GNU_DUMMY) {
|
||||
return KeyHealthStatus.STRIPPED;
|
||||
}
|
||||
|
||||
if (keyCertify.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD
|
||||
&& keySign.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD
|
||||
&& keyEncrypt.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD) {
|
||||
return KeyHealthStatus.DIVERT;
|
||||
}
|
||||
|
||||
boolean containsDivertKeys = keyCertify.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD ||
|
||||
keySign.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD ||
|
||||
keyEncrypt.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD;
|
||||
if (containsDivertKeys) {
|
||||
return KeyHealthStatus.DIVERT_PARTIAL;
|
||||
}
|
||||
|
||||
boolean containsStrippedKeys = keyCertify.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
|| keySign.mSecretKeyType == SecretKeyType.GNU_DUMMY
|
||||
|| keyEncrypt.mSecretKeyType == SecretKeyType.GNU_DUMMY;
|
||||
if (containsStrippedKeys) {
|
||||
return KeyHealthStatus.PARTIAL_STRIPPED;
|
||||
}
|
||||
|
||||
return KeyHealthStatus.OK;
|
||||
}
|
||||
|
||||
private void onKeyHealthClick() {
|
||||
if (showingExpandedInfo) {
|
||||
showingExpandedInfo = false;
|
||||
view.hideExpandedInfo();
|
||||
} else {
|
||||
showingExpandedInfo = true;
|
||||
displayExpandedInfo(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void displayExpandedInfo(boolean displayAll) {
|
||||
SubKeyItem keyCertify = subkeyStatus.keyCertify;
|
||||
SubKeyItem keySign = subkeyStatus.keysSign.isEmpty() ? null : subkeyStatus.keysSign.get(0);
|
||||
SubKeyItem keyEncrypt = subkeyStatus.keysEncrypt.isEmpty() ? null : subkeyStatus.keysEncrypt.get(0);
|
||||
|
||||
KeyDisplayStatus certDisplayStatus = getKeyDisplayStatus(keyCertify);
|
||||
KeyDisplayStatus signDisplayStatus = getKeyDisplayStatus(keySign);
|
||||
KeyDisplayStatus encryptDisplayStatus = getKeyDisplayStatus(keyEncrypt);
|
||||
|
||||
if (!displayAll) {
|
||||
if (certDisplayStatus == KeyDisplayStatus.OK) {
|
||||
certDisplayStatus = null;
|
||||
}
|
||||
if (certDisplayStatus == KeyDisplayStatus.INSECURE) {
|
||||
signDisplayStatus = null;
|
||||
encryptDisplayStatus = null;
|
||||
}
|
||||
if (signDisplayStatus == KeyDisplayStatus.OK) {
|
||||
signDisplayStatus = null;
|
||||
}
|
||||
if (encryptDisplayStatus == KeyDisplayStatus.OK) {
|
||||
encryptDisplayStatus = null;
|
||||
}
|
||||
}
|
||||
|
||||
view.showExpandedState(certDisplayStatus, signDisplayStatus, encryptDisplayStatus);
|
||||
}
|
||||
|
||||
private KeyDisplayStatus getKeyDisplayStatus(SubKeyItem subKeyItem) {
|
||||
if (subKeyItem == null) {
|
||||
return KeyDisplayStatus.UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (subKeyItem.mIsRevoked) {
|
||||
return KeyDisplayStatus.REVOKED;
|
||||
}
|
||||
if (subKeyItem.mIsExpired) {
|
||||
return KeyDisplayStatus.EXPIRED;
|
||||
}
|
||||
if (subKeyItem.mSecurityProblem != null) {
|
||||
return KeyDisplayStatus.INSECURE;
|
||||
}
|
||||
if (subKeyItem.mSecretKeyType == SecretKeyType.GNU_DUMMY) {
|
||||
return KeyDisplayStatus.STRIPPED;
|
||||
}
|
||||
if (subKeyItem.mSecretKeyType == SecretKeyType.DIVERT_TO_CARD) {
|
||||
return KeyDisplayStatus.DIVERT;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
public interface KeyHealthMvpView {
|
||||
void setKeyStatus(KeyHealthStatus keyHealthStatus);
|
||||
void setPrimarySecurityProblem(KeySecurityProblem securityProblem);
|
||||
void setPrimaryExpiryDate(Date expiry);
|
||||
|
||||
void setShowExpander(boolean showExpander);
|
||||
void showExpandedState(KeyDisplayStatus certifyStatus, KeyDisplayStatus signStatus,
|
||||
KeyDisplayStatus encryptStatus);
|
||||
void hideExpandedInfo();
|
||||
|
||||
void setOnHealthClickListener(KeyHealthClickListener keyHealthClickListener);
|
||||
|
||||
}
|
||||
|
||||
public interface KeyStatusMvpView {
|
||||
void setCertifyStatus(KeyDisplayStatus unavailable);
|
||||
void setSignStatus(KeyDisplayStatus signStatus);
|
||||
void setDecryptStatus(KeyDisplayStatus encryptStatus);
|
||||
}
|
||||
|
||||
public interface KeyHealthClickListener {
|
||||
void onKeyHealthClick();
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Schürmann & Breitmoser GbR
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.ViewKeyLiveData.KeyserverStatusLiveData;
|
||||
|
||||
|
||||
public class KeyserverStatusPresenter implements Observer<KeyMetadata> {
|
||||
private final Context context;
|
||||
private final KeyserverStatusMvpView view;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
|
||||
|
||||
public KeyserverStatusPresenter(Context context, KeyserverStatusMvpView view, long masterKeyId,
|
||||
boolean isSecret) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
}
|
||||
|
||||
public LiveData<KeyMetadata> getLiveDataInstance() {
|
||||
return new KeyserverStatusLiveData(context, masterKeyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(@Nullable KeyMetadata keyserverStatus) {
|
||||
if (keyserverStatus == null) {
|
||||
view.setDisplayStatusUnknown();
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyserverStatus.hasBeenUpdated()) {
|
||||
if (keyserverStatus.isPublished()) {
|
||||
view.setDisplayStatusPublished();
|
||||
} else {
|
||||
view.setDisplayStatusNotPublished();
|
||||
}
|
||||
view.setLastUpdated(keyserverStatus.last_updated());
|
||||
} else {
|
||||
view.setDisplayStatusUnknown();
|
||||
}
|
||||
}
|
||||
|
||||
public interface KeyserverStatusMvpView {
|
||||
void setDisplayStatusPublished();
|
||||
void setDisplayStatusNotPublished();
|
||||
void setLastUpdated(Date lastUpdated);
|
||||
void setDisplayStatusUnknown();
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Schürmann & Breitmoser GbR
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.Observer;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SystemContactDao.SystemContactInfo;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.ViewKeyLiveData.SystemContactInfoLiveData;
|
||||
|
||||
|
||||
public class SystemContactPresenter implements Observer<SystemContactInfo> {
|
||||
private final Context context;
|
||||
private final SystemContactMvpView view;
|
||||
|
||||
private final long masterKeyId;
|
||||
private final boolean isSecret;
|
||||
|
||||
private long contactId;
|
||||
|
||||
|
||||
public SystemContactPresenter(Context context, SystemContactMvpView view, long masterKeyId, boolean isSecret) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isSecret = isSecret;
|
||||
|
||||
view.setSystemContactClickListener(SystemContactPresenter.this::onSystemContactClick);
|
||||
}
|
||||
|
||||
public LiveData<SystemContactInfo> getLiveDataInstance() {
|
||||
return new SystemContactInfoLiveData(context, masterKeyId, isSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(@Nullable SystemContactInfo systemContactInfo) {
|
||||
if (systemContactInfo == null) {
|
||||
view.hideLinkedSystemContact();
|
||||
return;
|
||||
}
|
||||
|
||||
this.contactId = systemContactInfo.contactId;
|
||||
view.showLinkedSystemContact(systemContactInfo.contactName, systemContactInfo.contactPicture);
|
||||
}
|
||||
|
||||
private void onSystemContactClick() {
|
||||
launchAndroidContactActivity(contactId, context);
|
||||
}
|
||||
|
||||
public interface SystemContactMvpView {
|
||||
void setSystemContactClickListener(SystemContactClickListener systemContactClickListener);
|
||||
|
||||
void showLinkedSystemContact(String contactName, Bitmap picture);
|
||||
void hideLinkedSystemContact();
|
||||
}
|
||||
|
||||
public interface SystemContactClickListener {
|
||||
void onSystemContactClick();
|
||||
}
|
||||
|
||||
private static void launchAndroidContactActivity(long contactId, Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactId));
|
||||
intent.setData(uri);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
@@ -29,15 +29,12 @@ import android.widget.Button;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesCardListener;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesMvpView;
|
||||
import org.sufficientlysecure.keychain.ui.util.recyclerview.DividerItemDecoration;
|
||||
|
||||
|
||||
public class IdentitiesCardView extends CardView implements IdentitiesMvpView {
|
||||
public class IdentitiesCardView extends CardView {
|
||||
private final RecyclerView vIdentities;
|
||||
|
||||
private IdentitiesCardListener identitiesCardListener;
|
||||
private final Button linkedIdsAddButton;
|
||||
|
||||
public IdentitiesCardView(Context context, AttributeSet attrs) {
|
||||
@@ -50,24 +47,16 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView {
|
||||
vIdentities.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL_LIST, false));
|
||||
|
||||
linkedIdsAddButton = view.findViewById(R.id.view_key_card_linked_ids_add);
|
||||
linkedIdsAddButton.setOnClickListener(v -> {
|
||||
if (identitiesCardListener != null) {
|
||||
identitiesCardListener.onClickAddIdentity();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentitiesAdapter(IdentityAdapter identityAdapter) {
|
||||
vIdentities.setAdapter(identityAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener) {
|
||||
this.identitiesCardListener = identitiesCardListener;
|
||||
public void setIdentitiesCardListener(OnClickListener identitiesCardListener) {
|
||||
linkedIdsAddButton.setOnClickListener(identitiesCardListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddLinkedIdButtonVisible(boolean show) {
|
||||
linkedIdsAddButton.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@@ -39,14 +39,12 @@ import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureBitStrength;
|
||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
|
||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.NotWhitelistedCurve;
|
||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.UnidentifiedKeyProblem;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter.KeyHealthClickListener;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter.KeyHealthMvpView;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter.KeyHealthStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeyHealthStatus;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyStatusList.KeyDisplayStatus;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
|
||||
|
||||
public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnClickListener {
|
||||
public class KeyHealthView extends LinearLayout implements OnClickListener {
|
||||
private final View vLayout;
|
||||
private final TextView vTitle, vSubtitle;
|
||||
private final ImageView vIcon;
|
||||
@@ -59,7 +57,7 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
||||
private final View vExpiryLayout;
|
||||
private final TextView vExpiryText;
|
||||
|
||||
private KeyHealthClickListener keyHealthClickListener;
|
||||
private OnClickListener keyHealthClickListener;
|
||||
|
||||
public KeyHealthView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -125,7 +123,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeyStatus(KeyHealthStatus keyHealthStatus) {
|
||||
switch (keyHealthStatus) {
|
||||
case OK:
|
||||
@@ -161,7 +158,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimarySecurityProblem(KeySecurityProblem securityProblem) {
|
||||
if (securityProblem == null) {
|
||||
vInsecureLayout.setVisibility(View.GONE);
|
||||
@@ -190,7 +186,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryExpiryDate(Date expiry) {
|
||||
if (expiry == null) {
|
||||
vExpiryLayout.setVisibility(View.GONE);
|
||||
@@ -205,23 +200,20 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (keyHealthClickListener != null) {
|
||||
keyHealthClickListener.onKeyHealthClick();
|
||||
keyHealthClickListener.onClick(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnHealthClickListener(KeyHealthClickListener keyHealthClickListener) {
|
||||
public void setOnHealthClickListener(OnClickListener keyHealthClickListener) {
|
||||
this.keyHealthClickListener = keyHealthClickListener;
|
||||
vLayout.setClickable(keyHealthClickListener != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowExpander(boolean showExpander) {
|
||||
vLayout.setClickable(showExpander);
|
||||
vExpander.setVisibility(showExpander ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showExpandedState(KeyDisplayStatus certifyStatus, KeyDisplayStatus signStatus,
|
||||
KeyDisplayStatus encryptStatus) {
|
||||
if (certifyStatus == null && signStatus == null && encryptStatus == null) {
|
||||
@@ -240,7 +232,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideExpandedInfo() {
|
||||
showExpandedState(null, null, null);
|
||||
}
|
||||
|
||||
@@ -30,10 +30,9 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter.KeyStatusMvpView;
|
||||
|
||||
|
||||
public class KeyStatusList extends LinearLayout implements KeyStatusMvpView {
|
||||
public class KeyStatusList extends LinearLayout {
|
||||
private final TextView vCertText, vSignText, vDecryptText;
|
||||
private final ImageView vCertIcon, vSignIcon, vDecryptIcon;
|
||||
private final View vCertToken, vSignToken, vDecryptToken;
|
||||
@@ -107,7 +106,6 @@ public class KeyStatusList extends LinearLayout implements KeyStatusMvpView {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCertifyStatus(KeyDisplayStatus keyDisplayStatus) {
|
||||
if (keyDisplayStatus == null) {
|
||||
vCertifyLayout.setVisibility(View.GONE);
|
||||
@@ -121,7 +119,6 @@ public class KeyStatusList extends LinearLayout implements KeyStatusMvpView {
|
||||
vCertifyLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSignStatus(KeyDisplayStatus keyDisplayStatus) {
|
||||
if (keyDisplayStatus == null) {
|
||||
vSignLayout.setVisibility(View.GONE);
|
||||
@@ -134,7 +131,6 @@ public class KeyStatusList extends LinearLayout implements KeyStatusMvpView {
|
||||
vSignLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDecryptStatus(KeyDisplayStatus keyDisplayStatus) {
|
||||
if (keyDisplayStatus == null) {
|
||||
vDecryptLayout.setVisibility(View.GONE);
|
||||
|
||||
@@ -34,10 +34,9 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter.KeyserverStatusMvpView;
|
||||
|
||||
|
||||
public class KeyserverStatusView extends FrameLayout implements KeyserverStatusMvpView {
|
||||
public class KeyserverStatusView extends FrameLayout {
|
||||
private final View vLayout;
|
||||
private final TextView vTitle;
|
||||
private final TextView vSubtitle;
|
||||
@@ -75,23 +74,19 @@ public class KeyserverStatusView extends FrameLayout implements KeyserverStatusM
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayStatusPublished() {
|
||||
setDisplayStatus(KeyserverDisplayStatus.PUBLISHED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayStatusNotPublished() {
|
||||
setDisplayStatus(KeyserverDisplayStatus.NOT_PUBLISHED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayStatusUnknown() {
|
||||
setDisplayStatus(KeyserverDisplayStatus.UNKNOWN);
|
||||
vSubtitle.setText(R.string.keyserver_last_updated_never);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastUpdated(Date lastUpdated) {
|
||||
String lastUpdatedText = DateFormat.getMediumDateFormat(getContext()).format(lastUpdated);
|
||||
vSubtitle.setText(getResources().getString(R.string.keyserver_last_updated, lastUpdatedText));
|
||||
|
||||
@@ -24,23 +24,18 @@ import android.support.v7.widget.CardView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter.SystemContactClickListener;
|
||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter.SystemContactMvpView;
|
||||
|
||||
|
||||
public class SystemContactCardView extends CardView implements SystemContactMvpView, OnClickListener {
|
||||
public class SystemContactCardView extends CardView {
|
||||
private LinearLayout vSystemContactLayout;
|
||||
private ImageView vSystemContactPicture;
|
||||
private TextView vSystemContactName;
|
||||
|
||||
private SystemContactClickListener systemContactClickListener;
|
||||
|
||||
public SystemContactCardView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
@@ -49,28 +44,16 @@ public class SystemContactCardView extends CardView implements SystemContactMvpV
|
||||
vSystemContactLayout = view.findViewById(R.id.system_contact_layout);
|
||||
vSystemContactName = view.findViewById(R.id.system_contact_name);
|
||||
vSystemContactPicture = view.findViewById(R.id.system_contact_picture);
|
||||
|
||||
vSystemContactLayout.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (systemContactClickListener != null) {
|
||||
systemContactClickListener.onSystemContactClick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemContactClickListener(SystemContactClickListener systemContactClickListener) {
|
||||
this.systemContactClickListener = systemContactClickListener;
|
||||
vSystemContactLayout.setClickable(systemContactClickListener != null);
|
||||
public void setSystemContactClickListener(OnClickListener onClickListener) {
|
||||
vSystemContactLayout.setOnClickListener(onClickListener);
|
||||
}
|
||||
|
||||
public void hideLinkedSystemContact() {
|
||||
setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showLinkedSystemContact(String contactName, Bitmap picture) {
|
||||
vSystemContactName.setText(contactName);
|
||||
if (picture != null) {
|
||||
|
||||
Reference in New Issue
Block a user