refactor omemo fingerprint UI code
54
art/ic_verified_fingerprint.svg
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="ic_verified_fingerprint.svg">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1156"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.9166667"
|
||||
inkscape:cx="-3.3559322"
|
||||
inkscape:cy="24"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="20"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" />
|
||||
<path
|
||||
d="M24 2L6 10v12c0 11.11 7.67 21.47 18 24 10.33-2.53 18-12.89 18-24V10L24 2zm-4 32l-8-8 2.83-2.83L20 28.34l13.17-13.17L36 18 20 34z"
|
||||
id="path4"
|
||||
style="fill:#259b24;fill-opacity:0.627451" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -50,6 +50,7 @@ images = {
|
||||
'ic_notifications_off_white80.svg' => ['ic_notifications_off_white80', 24],
|
||||
'ic_notifications_paused_white80.svg' => ['ic_notifications_paused_white80', 24],
|
||||
'ic_notifications_white80.svg' => ['ic_notifications_white80', 24],
|
||||
'ic_verified_fingerprint.svg' => ['ic_verified_fingerprint', 36],
|
||||
'md_switch_thumb_disable.svg' => ['switch_thumb_disable', 48],
|
||||
'md_switch_thumb_off_normal.svg' => ['switch_thumb_off_normal', 48],
|
||||
'md_switch_thumb_off_pressed.svg' => ['switch_thumb_off_pressed', 48],
|
||||
@ -57,7 +58,7 @@ images = {
|
||||
'md_switch_thumb_on_pressed.svg' => ['switch_thumb_on_pressed', 48],
|
||||
'message_bubble_received.svg' => ['message_bubble_received.9', 0],
|
||||
'message_bubble_received_grey.svg' => ['message_bubble_received_grey.9', 0],
|
||||
'message_bubble_received_dark.svg' => ['message_bubble_received_dark.9', 0],
|
||||
'message_bubble_received_dark.svg' => ['message_bubble_received_dark.9', 0],
|
||||
'message_bubble_received_warning.svg' => ['message_bubble_received_warning.9', 0],
|
||||
'message_bubble_received_white.svg' => ['message_bubble_received_white.9', 0],
|
||||
'message_bubble_sent.svg' => ['message_bubble_sent.9', 0],
|
||||
|
237
src/main/java/eu/siacs/conversations/OmemoActivity.java
Normal file
@ -0,0 +1,237 @@
|
||||
package eu.siacs.conversations;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.ui.XmppActivity;
|
||||
import eu.siacs.conversations.ui.widget.Switch;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
|
||||
|
||||
public abstract class OmemoActivity extends XmppActivity {
|
||||
|
||||
private Account mSelectedAccount;
|
||||
private String mSelectedFingerprint;
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu,v,menuInfo);
|
||||
Object account = v.getTag(R.id.TAG_ACCOUNT);
|
||||
Object fingerprint = v.getTag(R.id.TAG_FINGERPRINT);
|
||||
if (account != null && fingerprint != null && account instanceof Account && fingerprint instanceof String) {
|
||||
getMenuInflater().inflate(R.menu.omemo_key_context, menu);
|
||||
this.mSelectedAccount = (Account) account;
|
||||
this.mSelectedFingerprint = (String) fingerprint;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.purge_omemo_key:
|
||||
showPurgeKeyDialog(mSelectedAccount,mSelectedFingerprint);
|
||||
break;
|
||||
case R.id.copy_omemo_key:
|
||||
copyOmemoFingerprint(mSelectedFingerprint);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void copyOmemoFingerprint(String fingerprint) {
|
||||
if (copyTextToClipboard(CryptoHelper.prettifyFingerprint(fingerprint.substring(2)), R.string.omemo_fingerprint)) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
R.string.toast_message_omemo_fingerprint,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean addFingerprintRow(LinearLayout keys, final Account account, final String fingerprint, boolean highlight) {
|
||||
final FingerprintStatus status = account.getAxolotlService().getFingerprintTrust(fingerprint);
|
||||
return status != null && addFingerprintRowWithListeners(keys, account, fingerprint, highlight, status, true, true, new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
account.getAxolotlService().setFingerprintTrust(fingerprint, FingerprintStatus.createActive(isChecked));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected boolean addFingerprintRowWithListeners(LinearLayout keys, final Account account,
|
||||
final String fingerprint,
|
||||
boolean highlight,
|
||||
FingerprintStatus status,
|
||||
boolean showTag,
|
||||
boolean undecidedNeedEnablement,
|
||||
CompoundButton.OnCheckedChangeListener
|
||||
onCheckedChangeListener) {
|
||||
if (status.isCompromised()) {
|
||||
return false;
|
||||
}
|
||||
View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false);
|
||||
TextView key = (TextView) view.findViewById(R.id.key);
|
||||
TextView keyType = (TextView) view.findViewById(R.id.key_type);
|
||||
if (Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509) {
|
||||
View.OnClickListener listener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showX509Certificate(account,fingerprint);
|
||||
}
|
||||
};
|
||||
key.setOnClickListener(listener);
|
||||
keyType.setOnClickListener(listener);
|
||||
}
|
||||
Switch trustToggle = (Switch) view.findViewById(R.id.tgl_trust);
|
||||
ImageView verifiedFingerprintSymbol = (ImageView) view.findViewById(R.id.verified_fingerprint);
|
||||
trustToggle.setVisibility(View.VISIBLE);
|
||||
registerForContextMenu(view);
|
||||
view.setTag(R.id.TAG_ACCOUNT,account);
|
||||
view.setTag(R.id.TAG_FINGERPRINT,fingerprint);
|
||||
boolean x509 = Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509;
|
||||
final View.OnClickListener toast;
|
||||
trustToggle.setChecked(status.isTrusted(), false);
|
||||
|
||||
if (status.isActive()){
|
||||
key.setTextColor(getPrimaryTextColor());
|
||||
keyType.setTextColor(getSecondaryTextColor());
|
||||
if (status.isVerified()) {
|
||||
verifiedFingerprintSymbol.setVisibility(View.VISIBLE);
|
||||
trustToggle.setVisibility(View.GONE);
|
||||
verifiedFingerprintSymbol.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
replaceToast(getString(R.string.this_device_has_been_verified), false);
|
||||
}
|
||||
});
|
||||
toast = null;
|
||||
} else {
|
||||
verifiedFingerprintSymbol.setVisibility(View.GONE);
|
||||
trustToggle.setVisibility(View.VISIBLE);
|
||||
trustToggle.setOnCheckedChangeListener(onCheckedChangeListener);
|
||||
if (status.getTrust() == FingerprintStatus.Trust.UNDECIDED && undecidedNeedEnablement) {
|
||||
trustToggle.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(false));
|
||||
v.setEnabled(true);
|
||||
v.setOnClickListener(null);
|
||||
}
|
||||
});
|
||||
trustToggle.setEnabled(false);
|
||||
} else {
|
||||
trustToggle.setOnClickListener(null);
|
||||
trustToggle.setEnabled(true);
|
||||
}
|
||||
toast = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
hideToast();
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
key.setTextColor(getTertiaryTextColor());
|
||||
keyType.setTextColor(getTertiaryTextColor());
|
||||
toast = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
replaceToast(getString(R.string.this_device_is_no_longer_in_use), false);
|
||||
}
|
||||
};
|
||||
if (status.isVerified()) {
|
||||
trustToggle.setVisibility(View.GONE);
|
||||
verifiedFingerprintSymbol.setVisibility(View.VISIBLE);
|
||||
verifiedFingerprintSymbol.setOnClickListener(toast);
|
||||
} else {
|
||||
trustToggle.setVisibility(View.VISIBLE);
|
||||
verifiedFingerprintSymbol.setVisibility(View.GONE);
|
||||
trustToggle.setOnClickListener(null);
|
||||
trustToggle.setEnabled(false);
|
||||
trustToggle.setOnClickListener(toast);
|
||||
}
|
||||
}
|
||||
|
||||
view.setOnClickListener(toast);
|
||||
key.setOnClickListener(toast);
|
||||
keyType.setOnClickListener(toast);
|
||||
if (showTag) {
|
||||
keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
|
||||
} else {
|
||||
keyType.setVisibility(View.GONE);
|
||||
}
|
||||
if (highlight) {
|
||||
keyType.setTextColor(getResources().getColor(R.color.accent));
|
||||
keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message));
|
||||
} else {
|
||||
keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
|
||||
}
|
||||
|
||||
key.setText(CryptoHelper.prettifyFingerprint(fingerprint.substring(2)));
|
||||
|
||||
keys.addView(view);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void showPurgeKeyDialog(final Account account, final String fingerprint) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(getString(R.string.purge_key));
|
||||
builder.setIconAttribute(android.R.attr.alertDialogIcon);
|
||||
builder.setMessage(getString(R.string.purge_key_desc_part1)
|
||||
+ "\n\n" + CryptoHelper.prettifyFingerprint(fingerprint.substring(2))
|
||||
+ "\n\n" + getString(R.string.purge_key_desc_part2));
|
||||
builder.setNegativeButton(getString(R.string.cancel), null);
|
||||
builder.setPositiveButton(getString(R.string.purge_key),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
account.getAxolotlService().purgeKey(fingerprint);
|
||||
refreshUi();
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void showX509Certificate(Account account, String fingerprint) {
|
||||
X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint);
|
||||
if (x509Certificate != null) {
|
||||
showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate));
|
||||
} else {
|
||||
Toast.makeText(this,R.string.certificate_not_found, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void showCertificateInformationDialog(Bundle bundle) {
|
||||
View view = getLayoutInflater().inflate(R.layout.certificate_information, null);
|
||||
final String not_available = getString(R.string.certicate_info_not_available);
|
||||
TextView subject_cn = (TextView) view.findViewById(R.id.subject_cn);
|
||||
TextView subject_o = (TextView) view.findViewById(R.id.subject_o);
|
||||
TextView issuer_cn = (TextView) view.findViewById(R.id.issuer_cn);
|
||||
TextView issuer_o = (TextView) view.findViewById(R.id.issuer_o);
|
||||
TextView sha1 = (TextView) view.findViewById(R.id.sha1);
|
||||
|
||||
subject_cn.setText(bundle.getString("subject_cn", not_available));
|
||||
subject_o.setText(bundle.getString("subject_o", not_available));
|
||||
issuer_cn.setText(bundle.getString("issuer_cn", not_available));
|
||||
issuer_o.setText(bundle.getString("issuer_o", not_available));
|
||||
sha1.setText(bundle.getString("sha1", not_available));
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.certificate_information);
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
builder.create().show();
|
||||
}
|
||||
}
|
@ -36,15 +36,14 @@ import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.OmemoActivity;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.PgpEngine;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
||||
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Contact;
|
||||
import eu.siacs.conversations.entities.ListItem;
|
||||
import eu.siacs.conversations.entities.Presence;
|
||||
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
|
||||
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
@ -55,7 +54,7 @@ import eu.siacs.conversations.xmpp.XmppConnection;
|
||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
|
||||
public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated {
|
||||
public class ContactDetailsActivity extends OmemoActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated {
|
||||
public static final String ACTION_VIEW_CONTACT = "view_contact";
|
||||
|
||||
private Contact contact;
|
||||
@ -448,12 +447,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||
if (Config.supportOmemo()) {
|
||||
for (final String fingerprint : contact.getAccount().getAxolotlService().getFingerprintsForContact(contact)) {
|
||||
boolean highlight = fingerprint.equals(messageFingerprint);
|
||||
hasKeys |= addFingerprintRow(keys, contact.getAccount(), fingerprint, highlight, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onOmemoKeyClicked(contact.getAccount(), fingerprint);
|
||||
}
|
||||
});
|
||||
hasKeys |= addFingerprintRow(keys, contact.getAccount(), fingerprint, highlight);
|
||||
}
|
||||
}
|
||||
if (Config.supportOpenPgp() && contact.getPgpKeyId() != 0) {
|
||||
@ -509,40 +503,6 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||
}
|
||||
}
|
||||
|
||||
private void onOmemoKeyClicked(Account account, String fingerprint) {
|
||||
FingerprintStatus status = account.getAxolotlService().getFingerprintTrust(fingerprint);
|
||||
if (Config.X509_VERIFICATION && status != null && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509) {
|
||||
X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint);
|
||||
if (x509Certificate != null) {
|
||||
showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate));
|
||||
} else {
|
||||
Toast.makeText(this,R.string.certificate_not_found, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showCertificateInformationDialog(Bundle bundle) {
|
||||
View view = getLayoutInflater().inflate(R.layout.certificate_information, null);
|
||||
final String not_available = getString(R.string.certicate_info_not_available);
|
||||
TextView subject_cn = (TextView) view.findViewById(R.id.subject_cn);
|
||||
TextView subject_o = (TextView) view.findViewById(R.id.subject_o);
|
||||
TextView issuer_cn = (TextView) view.findViewById(R.id.issuer_cn);
|
||||
TextView issuer_o = (TextView) view.findViewById(R.id.issuer_o);
|
||||
TextView sha1 = (TextView) view.findViewById(R.id.sha1);
|
||||
|
||||
subject_cn.setText(bundle.getString("subject_cn", not_available));
|
||||
subject_o.setText(bundle.getString("subject_o", not_available));
|
||||
issuer_cn.setText(bundle.getString("issuer_cn", not_available));
|
||||
issuer_o.setText(bundle.getString("issuer_o", not_available));
|
||||
sha1.setText(bundle.getString("sha1", not_available));
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.certificate_information);
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
protected void confirmToDeleteFingerprint(final String fingerprint) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.delete_fingerprint);
|
||||
@ -563,7 +523,6 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackendConnected() {
|
||||
if ((accountJid != null) && (contactJid != null)) {
|
||||
Account account = xmppConnectionService
|
||||
|
@ -41,6 +41,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.OmemoActivity;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
@ -59,7 +60,7 @@ import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
import eu.siacs.conversations.xmpp.pep.Avatar;
|
||||
|
||||
public class EditAccountActivity extends XmppActivity implements OnAccountUpdate,
|
||||
public class EditAccountActivity extends OmemoActivity implements OnAccountUpdate,
|
||||
OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnMamPreferencesFetched {
|
||||
|
||||
private static final int REQUEST_DATA_SAVER = 0x37af244;
|
||||
@ -635,7 +636,6 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||
super.onSaveInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBackendConnected() {
|
||||
boolean init = true;
|
||||
if (mSavedInstanceAccount != null) {
|
||||
@ -884,13 +884,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
|
||||
if (copyTextToClipboard(ownAxolotlFingerprint.substring(2), R.string.omemo_fingerprint)) {
|
||||
Toast.makeText(
|
||||
EditAccountActivity.this,
|
||||
R.string.toast_message_omemo_fingerprint,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
copyOmemoFingerprint(ownAxolotlFingerprint);
|
||||
}
|
||||
});
|
||||
if (Config.SHOW_REGENERATE_AXOLOTL_KEYS_BUTTON) {
|
||||
@ -915,7 +909,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||
continue;
|
||||
}
|
||||
boolean highlight = fingerprint.equals(messageFingerprint);
|
||||
hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight, null);
|
||||
hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight);
|
||||
}
|
||||
if (hasKeys && Config.supportOmemo()) {
|
||||
keysCard.setVisibility(View.VISIBLE);
|
||||
|
@ -18,6 +18,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import eu.siacs.conversations.OmemoActivity;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
||||
@ -28,7 +29,7 @@ import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
|
||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
|
||||
public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated {
|
||||
public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdated {
|
||||
private List<Jid> contactJids;
|
||||
|
||||
private Account mAccount;
|
||||
@ -109,16 +110,14 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||
for(final String fingerprint : ownKeysToTrust.keySet()) {
|
||||
hasOwnKeys = true;
|
||||
addFingerprintRowWithListeners(ownKeys, mAccount, fingerprint, false,
|
||||
FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint)), false,
|
||||
FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint)), false, false,
|
||||
new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
ownKeysToTrust.put(fingerprint, isChecked);
|
||||
// own fingerprints have no impact on locked status.
|
||||
}
|
||||
},
|
||||
null,
|
||||
null
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -134,16 +133,14 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||
final Map<String, Boolean> fingerprints = entry.getValue();
|
||||
for (final String fingerprint : fingerprints.keySet()) {
|
||||
addFingerprintRowWithListeners(keysContainer, mAccount, fingerprint, false,
|
||||
FingerprintStatus.createActive(fingerprints.get(fingerprint)), false,
|
||||
FingerprintStatus.createActive(fingerprints.get(fingerprint)), false, false,
|
||||
new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
fingerprints.put(fingerprint, isChecked);
|
||||
lockOrUnlockAsNeeded();
|
||||
}
|
||||
},
|
||||
null,
|
||||
null
|
||||
}
|
||||
);
|
||||
}
|
||||
if (fingerprints.size() == 0) {
|
||||
@ -212,7 +209,6 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
|
||||
return ownKeysSet.size() + foreignKeysToTrust.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackendConnected() {
|
||||
Intent intent = getIntent();
|
||||
this.mAccount = extractAccount(intent);
|
||||
|
@ -49,11 +49,8 @@ import android.util.Pair;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
@ -69,7 +66,6 @@ import java.io.FileNotFoundException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -78,20 +74,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
||||
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Contact;
|
||||
import eu.siacs.conversations.entities.Conversation;
|
||||
import eu.siacs.conversations.entities.Message;
|
||||
import eu.siacs.conversations.entities.MucOptions;
|
||||
import eu.siacs.conversations.entities.Presence;
|
||||
import eu.siacs.conversations.entities.Presences;
|
||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
||||
import eu.siacs.conversations.services.AvatarService;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
|
||||
import eu.siacs.conversations.ui.widget.Switch;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
import eu.siacs.conversations.utils.ExceptionHelper;
|
||||
import eu.siacs.conversations.utils.UIHelper;
|
||||
@ -780,132 +771,6 @@ public abstract class XmppActivity extends Activity {
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
protected boolean addFingerprintRow(LinearLayout keys, final Account account, final String fingerprint, boolean highlight, View.OnClickListener onKeyClickedListener) {
|
||||
final FingerprintStatus status = account.getAxolotlService().getFingerprintTrust(fingerprint);
|
||||
if (status == null) {
|
||||
return false;
|
||||
}
|
||||
return addFingerprintRowWithListeners(keys, account, fingerprint, highlight, status, true,
|
||||
new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(isChecked));
|
||||
}
|
||||
},
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(false));
|
||||
v.setEnabled(true);
|
||||
}
|
||||
},
|
||||
onKeyClickedListener
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
protected boolean addFingerprintRowWithListeners(LinearLayout keys, final Account account,
|
||||
final String fingerprint,
|
||||
boolean highlight,
|
||||
FingerprintStatus status,
|
||||
boolean showTag,
|
||||
CompoundButton.OnCheckedChangeListener
|
||||
onCheckedChangeListener,
|
||||
View.OnClickListener onClickListener,
|
||||
View.OnClickListener onKeyClickedListener) {
|
||||
if (status.isCompromised()) {
|
||||
return false;
|
||||
}
|
||||
View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false);
|
||||
TextView key = (TextView) view.findViewById(R.id.key);
|
||||
key.setOnClickListener(onKeyClickedListener);
|
||||
TextView keyType = (TextView) view.findViewById(R.id.key_type);
|
||||
keyType.setOnClickListener(onKeyClickedListener);
|
||||
Switch trustToggle = (Switch) view.findViewById(R.id.tgl_trust);
|
||||
trustToggle.setVisibility(View.VISIBLE);
|
||||
final View.OnLongClickListener purge = new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
showPurgeKeyDialog(account, fingerprint);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
view.setOnLongClickListener(purge);
|
||||
key.setOnLongClickListener(purge);
|
||||
keyType.setOnLongClickListener(purge);
|
||||
boolean x509 = Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509;
|
||||
final View.OnClickListener toast;
|
||||
trustToggle.setChecked(status.isTrusted(), false);
|
||||
if (status.isActive()) {
|
||||
key.setTextColor(getPrimaryTextColor());
|
||||
keyType.setTextColor(getSecondaryTextColor());
|
||||
trustToggle.setOnCheckedChangeListener(onCheckedChangeListener);
|
||||
if (status.getTrust() == FingerprintStatus.Trust.UNDECIDED) {
|
||||
trustToggle.setOnClickListener(onClickListener);
|
||||
trustToggle.setEnabled(false);
|
||||
} else {
|
||||
trustToggle.setOnClickListener(null);
|
||||
trustToggle.setEnabled(true);
|
||||
}
|
||||
toast = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
hideToast();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
key.setTextColor(getTertiaryTextColor());
|
||||
keyType.setTextColor(getTertiaryTextColor());
|
||||
trustToggle.setOnClickListener(null);
|
||||
trustToggle.setEnabled(false);
|
||||
toast = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
replaceToast(getString(R.string.this_device_is_no_longer_in_use), false);
|
||||
}
|
||||
};
|
||||
trustToggle.setOnClickListener(toast);
|
||||
}
|
||||
view.setOnClickListener(toast);
|
||||
key.setOnClickListener(toast);
|
||||
keyType.setOnClickListener(toast);
|
||||
if (showTag) {
|
||||
keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
|
||||
} else {
|
||||
keyType.setVisibility(View.GONE);
|
||||
}
|
||||
if (highlight) {
|
||||
keyType.setTextColor(getResources().getColor(R.color.accent));
|
||||
keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message));
|
||||
} else {
|
||||
keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
|
||||
}
|
||||
|
||||
key.setText(CryptoHelper.prettifyFingerprint(fingerprint.substring(2)));
|
||||
|
||||
keys.addView(view);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void showPurgeKeyDialog(final Account account, final String fingerprint) {
|
||||
Builder builder = new Builder(this);
|
||||
builder.setTitle(getString(R.string.purge_key));
|
||||
builder.setIconAttribute(android.R.attr.alertDialogIcon);
|
||||
builder.setMessage(getString(R.string.purge_key_desc_part1)
|
||||
+ "\n\n" + CryptoHelper.prettifyFingerprint(fingerprint.substring(2))
|
||||
+ "\n\n" + getString(R.string.purge_key_desc_part2));
|
||||
builder.setNegativeButton(getString(R.string.cancel), null);
|
||||
builder.setPositiveButton(getString(R.string.purge_key),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
account.getAxolotlService().purgeKey(fingerprint);
|
||||
refreshUi();
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public boolean hasStoragePermission(int requestCode) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
|
BIN
src/main/res/drawable-hdpi/ic_verified_fingerprint.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 765 B After Width: | Height: | Size: 765 B |
Before Width: | Height: | Size: 779 B After Width: | Height: | Size: 779 B |
Before Width: | Height: | Size: 750 B After Width: | Height: | Size: 750 B |
Before Width: | Height: | Size: 757 B After Width: | Height: | Size: 757 B |
Before Width: | Height: | Size: 779 B After Width: | Height: | Size: 779 B |
Before Width: | Height: | Size: 687 B After Width: | Height: | Size: 687 B |
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 707 B |
BIN
src/main/res/drawable-mdpi/ic_verified_fingerprint.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 594 B After Width: | Height: | Size: 594 B |
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 595 B After Width: | Height: | Size: 595 B |
Before Width: | Height: | Size: 598 B After Width: | Height: | Size: 598 B |
Before Width: | Height: | Size: 610 B After Width: | Height: | Size: 610 B |
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 558 B |
Before Width: | Height: | Size: 568 B After Width: | Height: | Size: 568 B |
BIN
src/main/res/drawable-xhdpi/ic_verified_fingerprint.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 929 B After Width: | Height: | Size: 929 B |
Before Width: | Height: | Size: 928 B After Width: | Height: | Size: 928 B |
Before Width: | Height: | Size: 915 B After Width: | Height: | Size: 915 B |
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 921 B |
Before Width: | Height: | Size: 935 B After Width: | Height: | Size: 935 B |
Before Width: | Height: | Size: 857 B After Width: | Height: | Size: 857 B |
Before Width: | Height: | Size: 842 B After Width: | Height: | Size: 842 B |
BIN
src/main/res/drawable-xxhdpi/ic_verified_fingerprint.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
src/main/res/drawable-xxxhdpi/ic_verified_fingerprint.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@ -1,37 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_height="match_parent"
|
||||
android:longClickable="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/key_data"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
android:paddingTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/key"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/color_text_primary"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toLeftOf="@+id/tgl_trust"
|
||||
android:layout_toLeftOf="@+id/action_container"
|
||||
android:fontFamily="monospace"
|
||||
android:textColor="?attr/color_text_primary"
|
||||
android:textSize="?attr/TextSizeBody"
|
||||
android:typeface="monospace"
|
||||
android:fontFamily="monospace"/>
|
||||
android:longClickable="true"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/key_type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/color_text_secondary"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/key"
|
||||
android:maxLines="1"
|
||||
android:textSize="?attr/TextSizeInfo"/>
|
||||
android:textColor="?attr/color_text_secondary"
|
||||
android:textSize="?attr/TextSizeInfo"
|
||||
android:longClickable="true"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/key_trust"
|
||||
@ -39,32 +42,46 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_below="@+id/key"
|
||||
android:visibility="gone"
|
||||
android:textColor="?attr/color_text_secondary"
|
||||
android:textSize="?attr/TextSizeInfo"/>
|
||||
android:textSize="?attr/TextSizeInfo"
|
||||
android:visibility="gone"
|
||||
android:longClickable="true"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/action_container"
|
||||
android:layout_width="96dp"
|
||||
android:layout_marginRight="-32dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true">
|
||||
<ImageButton
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/button_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="?attr/icon_alpha"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:padding="@dimen/image_button_padding"
|
||||
android:src="?attr/icon_remove"
|
||||
android:layout_marginRight="16dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_toRightOf="@+id/key"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:padding="@dimen/image_button_padding"
|
||||
android:alpha="?attr/icon_alpha"
|
||||
android:src="?attr/icon_remove"
|
||||
android:visibility="gone" />
|
||||
<ImageView
|
||||
android:visibility="gone"
|
||||
android:id="@+id/verified_fingerprint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginRight="16dp"
|
||||
android:src="@drawable/ic_verified_fingerprint" />
|
||||
|
||||
|
||||
<eu.siacs.conversations.ui.widget.Switch
|
||||
android:id="@+id/tgl_trust"
|
||||
android:visibility="invisible"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/MD"/>
|
||||
<eu.siacs.conversations.ui.widget.Switch
|
||||
android:id="@+id/tgl_trust"
|
||||
style="@style/MD"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
9
src/main/res/menu/omemo_key_context.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/purge_omemo_key"
|
||||
android:title="@string/purge_key"/>
|
||||
<item
|
||||
android:id="@+id/copy_omemo_key"
|
||||
android:title="@string/copy_fingerprint"/>
|
||||
</menu>
|
5
src/main/res/values/ids.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<item type="id" name="TAG_ACCOUNT"/>
|
||||
<item type="id" name="TAG_FINGERPRINT"/>
|
||||
</resources>
|
@ -699,4 +699,7 @@
|
||||
<string name="data_saver_enabled">Data saver enabled</string>
|
||||
<string name="data_saver_enabled_explained">Your operating system is restricting Conversations from accessing the Internet when in background. To receive notifications of new messages you should allow Conversations unrestricted access when Data saver is on.\nConversations will still make an effort to save data when possible.</string>
|
||||
<string name="device_does_not_support_data_saver">Your device does not support disabling Data saver for Conversations.</string>
|
||||
<string name="error_unable_to_create_temporary_file">Unable to create temporary file</string>
|
||||
<string name="this_device_has_been_verified">This device has been verified</string>
|
||||
<string name="copy_fingerprint">Copy fingerprint</string>
|
||||
</resources>
|
||||
|