simplify ViewKeyFragment
This commit is contained in:
@@ -25,10 +25,10 @@ import android.content.Context;
|
|||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -52,28 +52,28 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final LayoutInflater layoutInflater;
|
private final LayoutInflater layoutInflater;
|
||||||
private final boolean isSecret;
|
|
||||||
private final IdentityClickListener identityClickListener;
|
private final IdentityClickListener identityClickListener;
|
||||||
|
|
||||||
private List<IdentityInfo> data;
|
private List<IdentityInfo> data;
|
||||||
|
private boolean isSecret;
|
||||||
|
|
||||||
|
|
||||||
public IdentityAdapter(Context context, boolean isSecret, IdentityClickListener identityClickListener) {
|
public IdentityAdapter(Context context, IdentityClickListener identityClickListener) {
|
||||||
super();
|
super();
|
||||||
this.layoutInflater = LayoutInflater.from(context);
|
this.layoutInflater = LayoutInflater.from(context);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.isSecret = isSecret;
|
|
||||||
this.identityClickListener = identityClickListener;
|
this.identityClickListener = identityClickListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(List<IdentityInfo> data) {
|
public void setData(List<IdentityInfo> data, boolean isSecret) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
this.isSecret = isSecret;
|
||||||
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
IdentityInfo info = data.get(position);
|
IdentityInfo info = data.get(position);
|
||||||
|
|
||||||
int viewType = getItemViewType(position);
|
int viewType = getItemViewType(position);
|
||||||
@@ -90,8 +90,9 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
if (viewType == VIEW_TYPE_USER_ID) {
|
if (viewType == VIEW_TYPE_USER_ID) {
|
||||||
return new UserIdViewHolder(
|
return new UserIdViewHolder(
|
||||||
layoutInflater.inflate(R.layout.view_key_identity_user_id, parent, false), identityClickListener);
|
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);
|
vTitle = view.findViewById(R.id.linked_id_title);
|
||||||
vComment = view.findViewById(R.id.linked_id_comment);
|
vComment = view.findViewById(R.id.linked_id_comment);
|
||||||
|
|
||||||
view.setOnClickListener(new OnClickListener() {
|
view.setOnClickListener(v -> {
|
||||||
@Override
|
if (identityClickListener != null) {
|
||||||
public void onClick(View v) {
|
identityClickListener.onClickIdentity(getAdapterPosition());
|
||||||
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);
|
vIcon = view.findViewById(R.id.trust_id_app_icon);
|
||||||
vMore = view.findViewById(R.id.user_id_item_more);
|
vMore = view.findViewById(R.id.user_id_item_more);
|
||||||
|
|
||||||
view.setOnClickListener(new OnClickListener() {
|
view.setOnClickListener(v -> identityClickListener.onClickIdentity(getAdapterPosition()));
|
||||||
@Override
|
vMore.setOnClickListener(v -> identityClickListener.onClickIdentityMore(getAdapterPosition(), v));
|
||||||
public void onClick(View v) {
|
|
||||||
identityClickListener.onClickIdentity(getAdapterPosition());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
vMore.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
identityClickListener.onClickIdentityMore(getAdapterPosition(), v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bind(AutocryptPeerInfo info) {
|
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) {
|
if (unifiedKeyInfoLiveData == null) {
|
||||||
KeyRepository keyRepository = KeyRepository.create(context);
|
KeyRepository keyRepository = KeyRepository.create(context);
|
||||||
unifiedKeyInfoLiveData = new GenericLiveData<>(context, null,
|
unifiedKeyInfoLiveData = new GenericLiveData<>(context, KeyRings.buildGenericKeyRingUri(masterKeyId),
|
||||||
() -> keyRepository.getUnifiedKeyInfo(masterKeyId));
|
() -> keyRepository.getUnifiedKeyInfo(masterKeyId));
|
||||||
}
|
}
|
||||||
return unifiedKeyInfoLiveData;
|
return unifiedKeyInfoLiveData;
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ package org.sufficientlysecure.keychain.ui.keyview;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.arch.lifecycle.LiveData;
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.arch.lifecycle.ViewModel;
|
|
||||||
import android.arch.lifecycle.ViewModelProviders;
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.provider.ContactsContract;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.support.v4.app.Fragment;
|
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.KeyMetadata;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
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.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.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.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.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.IdentitiesCardView;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView;
|
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.KeyserverStatusView;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView;
|
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 IdentitiesCardView identitiesCardView;
|
||||||
private IdentitiesPresenter identitiesPresenter;
|
private SystemContactCardView systemContactCard;
|
||||||
|
private KeyHealthView keyStatusHealth;
|
||||||
|
private KeyserverStatusView keyserverStatusView;
|
||||||
|
|
||||||
SystemContactCardView systemContactCard;
|
IdentityAdapter identitiesAdapter;
|
||||||
SystemContactPresenter systemContactPresenter;
|
|
||||||
|
|
||||||
KeyHealthView keyStatusHealth;
|
|
||||||
KeyserverStatusView keyStatusKeyserver;
|
|
||||||
|
|
||||||
KeyHealthPresenter keyHealthPresenter;
|
|
||||||
KeyserverStatusPresenter keyserverStatusPresenter;
|
|
||||||
|
|
||||||
private Integer displayedContextMenuPosition;
|
private Integer displayedContextMenuPosition;
|
||||||
|
private UnifiedKeyInfo unifiedKeyInfo;
|
||||||
|
private KeySubkeyStatus subkeyStatus;
|
||||||
|
private boolean showingExpandedInfo;
|
||||||
|
|
||||||
public static ViewKeyFragment newInstance() {
|
public static ViewKeyFragment newInstance() {
|
||||||
return new ViewKeyFragment();
|
return new ViewKeyFragment();
|
||||||
@@ -83,74 +93,233 @@ public class ViewKeyFragment extends Fragment implements ViewKeyMvpView, OnMenuI
|
|||||||
identitiesCardView = view.findViewById(R.id.card_identities);
|
identitiesCardView = view.findViewById(R.id.card_identities);
|
||||||
systemContactCard = view.findViewById(R.id.linked_system_contact_card);
|
systemContactCard = view.findViewById(R.id.linked_system_contact_card);
|
||||||
keyStatusHealth = view.findViewById(R.id.key_status_health);
|
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;
|
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
|
@Override
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
|
Context context = requireContext();
|
||||||
|
|
||||||
ViewKeyViewModel viewKeyViewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyViewModel.class);
|
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) {
|
private void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
|
||||||
KeyFragmentViewModel model = ViewModelProviders.of(this).get(KeyFragmentViewModel.class);
|
if (unifiedKeyInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
identitiesPresenter = new IdentitiesPresenter(
|
Context context = requireContext();
|
||||||
getContext(), identitiesCardView, this, unifiedKeyInfo.master_key_id(), unifiedKeyInfo.has_any_secret());
|
|
||||||
model.getIdentityInfo(identitiesPresenter).observe(this, identitiesPresenter);
|
|
||||||
|
|
||||||
systemContactPresenter = new SystemContactPresenter(
|
this.unifiedKeyInfo = unifiedKeyInfo;
|
||||||
getContext(), systemContactCard, unifiedKeyInfo.master_key_id(), unifiedKeyInfo.has_any_secret());
|
|
||||||
model.getSystemContactInfo(systemContactPresenter).observe(this, systemContactPresenter);
|
|
||||||
|
|
||||||
keyHealthPresenter = new KeyHealthPresenter(getContext(), keyStatusHealth, unifiedKeyInfo.master_key_id());
|
boolean showLinkedIds = Preferences.getPreferences(context).getExperimentalEnableLinkedIdentities();
|
||||||
model.getSubkeyStatus(keyHealthPresenter).observe(this, keyHealthPresenter);
|
boolean isSecret = unifiedKeyInfo.has_any_secret();
|
||||||
|
identitiesCardView.setAddLinkedIdButtonVisible(showLinkedIds && isSecret);
|
||||||
keyserverStatusPresenter = new KeyserverStatusPresenter(
|
identitiesCardView.setIdentitiesCardListener((v) -> addLinkedIdentity());
|
||||||
getContext(), keyStatusKeyserver, unifiedKeyInfo.master_key_id(), unifiedKeyInfo.has_any_secret());
|
}
|
||||||
model.getKeyserverStatus(keyserverStatusPresenter).observe(this, keyserverStatusPresenter);
|
|
||||||
|
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) {
|
public void switchToFragment(final Fragment frag, final String backStackName) {
|
||||||
new Handler().post(() -> requireFragmentManager().beginTransaction()
|
new Handler().post(() -> requireFragmentManager().beginTransaction()
|
||||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
.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) {
|
public void showDialogFragment(final DialogFragment dialogFragment, final String tag) {
|
||||||
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(
|
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(
|
||||||
() -> dialogFragment.show(requireFragmentManager(), tag));
|
() -> dialogFragment.show(requireFragmentManager(), tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showContextMenu(int position, View anchor) {
|
public void showContextMenu(int position, View anchor) {
|
||||||
displayedContextMenuPosition = position;
|
displayedContextMenuPosition = position;
|
||||||
|
|
||||||
@@ -202,10 +364,17 @@ public class ViewKeyFragment extends Fragment implements ViewKeyMvpView, OnMenuI
|
|||||||
case R.id.autocrypt_forget:
|
case R.id.autocrypt_forget:
|
||||||
int position = displayedContextMenuPosition;
|
int position = displayedContextMenuPosition;
|
||||||
displayedContextMenuPosition = null;
|
displayedContextMenuPosition = null;
|
||||||
identitiesPresenter.onClickForgetIdentity(position);
|
onClickForgetIdentity(position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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;
|
this.autocryptPeerDao = autocryptPeerDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IdentityInfo> getIdentityInfos(long masterKeyId, boolean showLinkedIds) {
|
public List<IdentityInfo> getIdentityInfos(long masterKeyId, boolean showLinkedIds) {
|
||||||
ArrayList<IdentityInfo> identities = new ArrayList<>();
|
ArrayList<IdentityInfo> identities = new ArrayList<>();
|
||||||
|
|
||||||
if (showLinkedIds) {
|
if (showLinkedIds) {
|
||||||
@@ -95,11 +95,11 @@ public class IdentityDao {
|
|||||||
if (associatedUserIdInfo != null) {
|
if (associatedUserIdInfo != null) {
|
||||||
int position = identities.indexOf(associatedUserIdInfo);
|
int position = identities.indexOf(associatedUserIdInfo);
|
||||||
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
||||||
.create(associatedUserIdInfo, autocryptId, packageName, drawable, autocryptPeerIntent);
|
.create(masterKeyId, associatedUserIdInfo, autocryptId, packageName, drawable, autocryptPeerIntent);
|
||||||
identities.set(position, autocryptPeerInfo);
|
identities.set(position, autocryptPeerInfo);
|
||||||
} else {
|
} else {
|
||||||
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
||||||
.create(autocryptId, packageName, drawable, autocryptPeerIntent);
|
.create(masterKeyId, autocryptId, packageName, drawable, autocryptPeerIntent);
|
||||||
identities.add(autocryptPeerInfo);
|
identities.add(autocryptPeerInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ public class IdentityDao {
|
|||||||
try {
|
try {
|
||||||
UriAttribute uriAttribute = LinkedAttribute.fromAttributeData(userAttribute.attribute_data());
|
UriAttribute uriAttribute = LinkedAttribute.fromAttributeData(userAttribute.attribute_data());
|
||||||
if (uriAttribute instanceof LinkedAttribute) {
|
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);
|
userAttribute.isVerified(), userAttribute.is_primary(), (LinkedAttribute) uriAttribute);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -180,7 +180,7 @@ public class IdentityDao {
|
|||||||
|
|
||||||
if (userId.name() != null || userId.email() != null) {
|
if (userId.name() != null || userId.email() != null) {
|
||||||
IdentityInfo identityInfo = UserIdInfo.create(
|
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);
|
identities.add(identityInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,6 +188,7 @@ public class IdentityDao {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public interface IdentityInfo {
|
public interface IdentityInfo {
|
||||||
|
long getMasterKeyId();
|
||||||
int getRank();
|
int getRank();
|
||||||
boolean isVerified();
|
boolean isVerified();
|
||||||
boolean isPrimary();
|
boolean isPrimary();
|
||||||
@@ -195,6 +196,7 @@ public class IdentityDao {
|
|||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class UserIdInfo implements IdentityInfo {
|
public abstract static class UserIdInfo implements IdentityInfo {
|
||||||
|
public abstract long getMasterKeyId();
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
public abstract boolean isVerified();
|
public abstract boolean isVerified();
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
@@ -206,27 +208,29 @@ public class IdentityDao {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public abstract String getComment();
|
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) {
|
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
|
@AutoValue
|
||||||
public abstract static class LinkedIdInfo implements IdentityInfo {
|
public abstract static class LinkedIdInfo implements IdentityInfo {
|
||||||
|
public abstract long getMasterKeyId();
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
public abstract boolean isVerified();
|
public abstract boolean isVerified();
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
public abstract LinkedAttribute getLinkedAttribute();
|
public abstract LinkedAttribute getLinkedAttribute();
|
||||||
|
|
||||||
static LinkedIdInfo create(int rank, boolean isVerified, boolean isPrimary, LinkedAttribute linkedAttribute) {
|
static LinkedIdInfo create(long masterKeyId, int rank, boolean isVerified, boolean isPrimary, LinkedAttribute linkedAttribute) {
|
||||||
return new AutoValue_IdentityDao_LinkedIdInfo(rank, isVerified, isPrimary, linkedAttribute);
|
return new AutoValue_IdentityDao_LinkedIdInfo(masterKeyId, rank, isVerified, isPrimary, linkedAttribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class AutocryptPeerInfo implements IdentityInfo {
|
public abstract static class AutocryptPeerInfo implements IdentityInfo {
|
||||||
|
public abstract long getMasterKeyId();
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
public abstract boolean isVerified();
|
public abstract boolean isVerified();
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
@@ -240,15 +244,14 @@ public class IdentityDao {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public abstract Intent getAutocryptPeerIntent();
|
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) {
|
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);
|
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AutocryptPeerInfo create(String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
||||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(
|
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId,0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
||||||
0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class SubkeyStatusDao {
|
|||||||
this.keyRepository = keyRepository;
|
this.keyRepository = keyRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeySubkeyStatus getSubkeyStatus(long masterKeyId, Comparator<SubKeyItem> comparator) {
|
public KeySubkeyStatus getSubkeyStatus(long masterKeyId) {
|
||||||
SubKeyItem keyCertify = null;
|
SubKeyItem keyCertify = null;
|
||||||
ArrayList<SubKeyItem> keysSign = new ArrayList<>();
|
ArrayList<SubKeyItem> keysSign = new ArrayList<>();
|
||||||
ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>();
|
ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>();
|
||||||
@@ -73,10 +73,89 @@ public class SubkeyStatusDao {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(keysSign, comparator);
|
Collections.sort(keysSign, SUBKEY_COMPARATOR);
|
||||||
Collections.sort(keysEncrypt, 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 {
|
public static class KeySubkeyStatus {
|
||||||
@@ -84,11 +163,14 @@ public class SubkeyStatusDao {
|
|||||||
public final SubKeyItem keyCertify;
|
public final SubKeyItem keyCertify;
|
||||||
public final List<SubKeyItem> keysSign;
|
public final List<SubKeyItem> keysSign;
|
||||||
public final List<SubKeyItem> keysEncrypt;
|
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.keyCertify = keyCertify;
|
||||||
this.keysSign = keysSign;
|
this.keysSign = keysSign;
|
||||||
this.keysEncrypt = keysEncrypt;
|
this.keysEncrypt = keysEncrypt;
|
||||||
|
this.keyHealthStatus = keyHealthStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,4 +213,24 @@ public class SubkeyStatusDao {
|
|||||||
return !mIsRevoked && !mIsExpired;
|
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;
|
this.contentResolver = contentResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemContactInfo getSystemContactInfo(long masterKeyId, boolean isSecret) {
|
public SystemContactInfo getSystemContactInfo(long masterKeyId, boolean isSecret) {
|
||||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
|
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
|
||||||
== PackageManager.PERMISSION_DENIED) {
|
== PackageManager.PERMISSION_DENIED) {
|
||||||
Timber.w(Constants.TAG, "loading linked system contact not possible READ_CONTACTS 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.R;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
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;
|
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 final RecyclerView vIdentities;
|
||||||
|
|
||||||
private IdentitiesCardListener identitiesCardListener;
|
|
||||||
private final Button linkedIdsAddButton;
|
private final Button linkedIdsAddButton;
|
||||||
|
|
||||||
public IdentitiesCardView(Context context, AttributeSet attrs) {
|
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));
|
vIdentities.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL_LIST, false));
|
||||||
|
|
||||||
linkedIdsAddButton = view.findViewById(R.id.view_key_card_linked_ids_add);
|
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) {
|
public void setIdentitiesAdapter(IdentityAdapter identityAdapter) {
|
||||||
vIdentities.setAdapter(identityAdapter);
|
vIdentities.setAdapter(identityAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setIdentitiesCardListener(OnClickListener identitiesCardListener) {
|
||||||
public void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener) {
|
linkedIdsAddButton.setOnClickListener(identitiesCardListener);
|
||||||
this.identitiesCardListener = identitiesCardListener;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAddLinkedIdButtonVisible(boolean show) {
|
public void setAddLinkedIdButtonVisible(boolean show) {
|
||||||
linkedIdsAddButton.setVisibility(show ? View.VISIBLE : View.GONE);
|
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.KeySecurityProblem;
|
||||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.NotWhitelistedCurve;
|
import org.sufficientlysecure.keychain.pgp.SecurityProblem.NotWhitelistedCurve;
|
||||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.UnidentifiedKeyProblem;
|
import org.sufficientlysecure.keychain.pgp.SecurityProblem.UnidentifiedKeyProblem;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter.KeyHealthClickListener;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeyHealthStatus;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter.KeyHealthMvpView;
|
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter.KeyHealthStatus;
|
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyStatusList.KeyDisplayStatus;
|
import org.sufficientlysecure.keychain.ui.keyview.view.KeyStatusList.KeyDisplayStatus;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
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 View vLayout;
|
||||||
private final TextView vTitle, vSubtitle;
|
private final TextView vTitle, vSubtitle;
|
||||||
private final ImageView vIcon;
|
private final ImageView vIcon;
|
||||||
@@ -59,7 +57,7 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
|||||||
private final View vExpiryLayout;
|
private final View vExpiryLayout;
|
||||||
private final TextView vExpiryText;
|
private final TextView vExpiryText;
|
||||||
|
|
||||||
private KeyHealthClickListener keyHealthClickListener;
|
private OnClickListener keyHealthClickListener;
|
||||||
|
|
||||||
public KeyHealthView(Context context, AttributeSet attrs) {
|
public KeyHealthView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@@ -125,7 +123,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setKeyStatus(KeyHealthStatus keyHealthStatus) {
|
public void setKeyStatus(KeyHealthStatus keyHealthStatus) {
|
||||||
switch (keyHealthStatus) {
|
switch (keyHealthStatus) {
|
||||||
case OK:
|
case OK:
|
||||||
@@ -161,7 +158,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPrimarySecurityProblem(KeySecurityProblem securityProblem) {
|
public void setPrimarySecurityProblem(KeySecurityProblem securityProblem) {
|
||||||
if (securityProblem == null) {
|
if (securityProblem == null) {
|
||||||
vInsecureLayout.setVisibility(View.GONE);
|
vInsecureLayout.setVisibility(View.GONE);
|
||||||
@@ -190,7 +186,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPrimaryExpiryDate(Date expiry) {
|
public void setPrimaryExpiryDate(Date expiry) {
|
||||||
if (expiry == null) {
|
if (expiry == null) {
|
||||||
vExpiryLayout.setVisibility(View.GONE);
|
vExpiryLayout.setVisibility(View.GONE);
|
||||||
@@ -205,23 +200,20 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if (keyHealthClickListener != null) {
|
if (keyHealthClickListener != null) {
|
||||||
keyHealthClickListener.onKeyHealthClick();
|
keyHealthClickListener.onClick(view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setOnHealthClickListener(OnClickListener keyHealthClickListener) {
|
||||||
public void setOnHealthClickListener(KeyHealthClickListener keyHealthClickListener) {
|
|
||||||
this.keyHealthClickListener = keyHealthClickListener;
|
this.keyHealthClickListener = keyHealthClickListener;
|
||||||
vLayout.setClickable(keyHealthClickListener != null);
|
vLayout.setClickable(keyHealthClickListener != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setShowExpander(boolean showExpander) {
|
public void setShowExpander(boolean showExpander) {
|
||||||
vLayout.setClickable(showExpander);
|
vLayout.setClickable(showExpander);
|
||||||
vExpander.setVisibility(showExpander ? View.VISIBLE : View.GONE);
|
vExpander.setVisibility(showExpander ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showExpandedState(KeyDisplayStatus certifyStatus, KeyDisplayStatus signStatus,
|
public void showExpandedState(KeyDisplayStatus certifyStatus, KeyDisplayStatus signStatus,
|
||||||
KeyDisplayStatus encryptStatus) {
|
KeyDisplayStatus encryptStatus) {
|
||||||
if (certifyStatus == null && signStatus == null && encryptStatus == null) {
|
if (certifyStatus == null && signStatus == null && encryptStatus == null) {
|
||||||
@@ -240,7 +232,6 @@ public class KeyHealthView extends LinearLayout implements KeyHealthMvpView, OnC
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void hideExpandedInfo() {
|
public void hideExpandedInfo() {
|
||||||
showExpandedState(null, null, null);
|
showExpandedState(null, null, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,9 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
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 TextView vCertText, vSignText, vDecryptText;
|
||||||
private final ImageView vCertIcon, vSignIcon, vDecryptIcon;
|
private final ImageView vCertIcon, vSignIcon, vDecryptIcon;
|
||||||
private final View vCertToken, vSignToken, vDecryptToken;
|
private final View vCertToken, vSignToken, vDecryptToken;
|
||||||
@@ -107,7 +106,6 @@ public class KeyStatusList extends LinearLayout implements KeyStatusMvpView {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCertifyStatus(KeyDisplayStatus keyDisplayStatus) {
|
public void setCertifyStatus(KeyDisplayStatus keyDisplayStatus) {
|
||||||
if (keyDisplayStatus == null) {
|
if (keyDisplayStatus == null) {
|
||||||
vCertifyLayout.setVisibility(View.GONE);
|
vCertifyLayout.setVisibility(View.GONE);
|
||||||
@@ -121,7 +119,6 @@ public class KeyStatusList extends LinearLayout implements KeyStatusMvpView {
|
|||||||
vCertifyLayout.setVisibility(View.VISIBLE);
|
vCertifyLayout.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSignStatus(KeyDisplayStatus keyDisplayStatus) {
|
public void setSignStatus(KeyDisplayStatus keyDisplayStatus) {
|
||||||
if (keyDisplayStatus == null) {
|
if (keyDisplayStatus == null) {
|
||||||
vSignLayout.setVisibility(View.GONE);
|
vSignLayout.setVisibility(View.GONE);
|
||||||
@@ -134,7 +131,6 @@ public class KeyStatusList extends LinearLayout implements KeyStatusMvpView {
|
|||||||
vSignLayout.setVisibility(View.VISIBLE);
|
vSignLayout.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDecryptStatus(KeyDisplayStatus keyDisplayStatus) {
|
public void setDecryptStatus(KeyDisplayStatus keyDisplayStatus) {
|
||||||
if (keyDisplayStatus == null) {
|
if (keyDisplayStatus == null) {
|
||||||
vDecryptLayout.setVisibility(View.GONE);
|
vDecryptLayout.setVisibility(View.GONE);
|
||||||
|
|||||||
@@ -34,10 +34,9 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
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 View vLayout;
|
||||||
private final TextView vTitle;
|
private final TextView vTitle;
|
||||||
private final TextView vSubtitle;
|
private final TextView vSubtitle;
|
||||||
@@ -75,23 +74,19 @@ public class KeyserverStatusView extends FrameLayout implements KeyserverStatusM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDisplayStatusPublished() {
|
public void setDisplayStatusPublished() {
|
||||||
setDisplayStatus(KeyserverDisplayStatus.PUBLISHED);
|
setDisplayStatus(KeyserverDisplayStatus.PUBLISHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDisplayStatusNotPublished() {
|
public void setDisplayStatusNotPublished() {
|
||||||
setDisplayStatus(KeyserverDisplayStatus.NOT_PUBLISHED);
|
setDisplayStatus(KeyserverDisplayStatus.NOT_PUBLISHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDisplayStatusUnknown() {
|
public void setDisplayStatusUnknown() {
|
||||||
setDisplayStatus(KeyserverDisplayStatus.UNKNOWN);
|
setDisplayStatus(KeyserverDisplayStatus.UNKNOWN);
|
||||||
vSubtitle.setText(R.string.keyserver_last_updated_never);
|
vSubtitle.setText(R.string.keyserver_last_updated_never);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLastUpdated(Date lastUpdated) {
|
public void setLastUpdated(Date lastUpdated) {
|
||||||
String lastUpdatedText = DateFormat.getMediumDateFormat(getContext()).format(lastUpdated);
|
String lastUpdatedText = DateFormat.getMediumDateFormat(getContext()).format(lastUpdated);
|
||||||
vSubtitle.setText(getResources().getString(R.string.keyserver_last_updated, lastUpdatedText));
|
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.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
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 LinearLayout vSystemContactLayout;
|
||||||
private ImageView vSystemContactPicture;
|
private ImageView vSystemContactPicture;
|
||||||
private TextView vSystemContactName;
|
private TextView vSystemContactName;
|
||||||
|
|
||||||
private SystemContactClickListener systemContactClickListener;
|
|
||||||
|
|
||||||
public SystemContactCardView(Context context, AttributeSet attrs) {
|
public SystemContactCardView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
@@ -49,28 +44,16 @@ public class SystemContactCardView extends CardView implements SystemContactMvpV
|
|||||||
vSystemContactLayout = view.findViewById(R.id.system_contact_layout);
|
vSystemContactLayout = view.findViewById(R.id.system_contact_layout);
|
||||||
vSystemContactName = view.findViewById(R.id.system_contact_name);
|
vSystemContactName = view.findViewById(R.id.system_contact_name);
|
||||||
vSystemContactPicture = view.findViewById(R.id.system_contact_picture);
|
vSystemContactPicture = view.findViewById(R.id.system_contact_picture);
|
||||||
|
|
||||||
vSystemContactLayout.setOnClickListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setSystemContactClickListener(OnClickListener onClickListener) {
|
||||||
public void onClick(View view) {
|
vSystemContactLayout.setOnClickListener(onClickListener);
|
||||||
if (systemContactClickListener != null) {
|
|
||||||
systemContactClickListener.onSystemContactClick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSystemContactClickListener(SystemContactClickListener systemContactClickListener) {
|
|
||||||
this.systemContactClickListener = systemContactClickListener;
|
|
||||||
vSystemContactLayout.setClickable(systemContactClickListener != null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hideLinkedSystemContact() {
|
public void hideLinkedSystemContact() {
|
||||||
setVisibility(View.GONE);
|
setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showLinkedSystemContact(String contactName, Bitmap picture) {
|
public void showLinkedSystemContact(String contactName, Bitmap picture) {
|
||||||
vSystemContactName.setText(contactName);
|
vSystemContactName.setText(contactName);
|
||||||
if (picture != null) {
|
if (picture != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user