TrustKeysActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.content.Intent;
  4import android.os.Bundle;
  5import android.view.View;
  6import android.view.View.OnClickListener;
  7import android.widget.Button;
  8import android.widget.CompoundButton;
  9import android.widget.LinearLayout;
 10import android.widget.TextView;
 11
 12import org.whispersystems.libaxolotl.IdentityKey;
 13
 14import java.util.HashMap;
 15import java.util.Map;
 16import java.util.Set;
 17
 18import eu.siacs.conversations.R;
 19import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore.Trust;
 20import eu.siacs.conversations.entities.Account;
 21import eu.siacs.conversations.entities.Contact;
 22import eu.siacs.conversations.entities.Conversation;
 23import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
 24import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 25import eu.siacs.conversations.xmpp.jid.Jid;
 26
 27public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated {
 28	private Jid accountJid;
 29	private Jid contactJid;
 30	private boolean hasOtherTrustedKeys = false;
 31	private boolean hasPendingFetches = false;
 32	private boolean hasNoTrustedKeys = true;
 33
 34	private Contact contact;
 35	private TextView ownKeysTitle;
 36	private LinearLayout ownKeys;
 37	private LinearLayout ownKeysCard;
 38	private TextView foreignKeysTitle;
 39	private LinearLayout foreignKeys;
 40	private LinearLayout foreignKeysCard;
 41	private Button mSaveButton;
 42	private Button mCancelButton;
 43
 44	private final Map<IdentityKey, Boolean> ownKeysToTrust = new HashMap<>();
 45	private final Map<IdentityKey, Boolean> foreignKeysToTrust = new HashMap<>();
 46
 47	private final OnClickListener mSaveButtonListener = new OnClickListener() {
 48		@Override
 49		public void onClick(View v) {
 50			commitTrusts();
 51			Intent data = new Intent();
 52			data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID));
 53			setResult(RESULT_OK, data);
 54			finish();
 55		}
 56	};
 57
 58	private final OnClickListener mCancelButtonListener = new OnClickListener() {
 59		@Override
 60		public void onClick(View v) {
 61			setResult(RESULT_CANCELED);
 62			finish();
 63		}
 64	};
 65
 66	@Override
 67	protected void refreshUiReal() {
 68		invalidateOptionsMenu();
 69		populateView();
 70	}
 71
 72	@Override
 73	protected String getShareableUri() {
 74		if (contact != null) {
 75			return contact.getShareableUri();
 76		} else {
 77			return "";
 78		}
 79	}
 80
 81	@Override
 82	protected void onCreate(final Bundle savedInstanceState) {
 83		super.onCreate(savedInstanceState);
 84		setContentView(R.layout.activity_trust_keys);
 85		try {
 86			this.accountJid = Jid.fromString(getIntent().getExtras().getString("account"));
 87		} catch (final InvalidJidException ignored) {
 88		}
 89		try {
 90			this.contactJid = Jid.fromString(getIntent().getExtras().getString("contact"));
 91		} catch (final InvalidJidException ignored) {
 92		}
 93		hasNoTrustedKeys = getIntent().getBooleanExtra("has_no_trusted", false);
 94
 95		ownKeysTitle = (TextView) findViewById(R.id.own_keys_title);
 96		ownKeys = (LinearLayout) findViewById(R.id.own_keys_details);
 97		ownKeysCard = (LinearLayout) findViewById(R.id.own_keys_card);
 98		foreignKeysTitle = (TextView) findViewById(R.id.foreign_keys_title);
 99		foreignKeys = (LinearLayout) findViewById(R.id.foreign_keys_details);
100		foreignKeysCard = (LinearLayout) findViewById(R.id.foreign_keys_card);
101		mCancelButton = (Button) findViewById(R.id.cancel_button);
102		mCancelButton.setOnClickListener(mCancelButtonListener);
103		mSaveButton = (Button) findViewById(R.id.save_button);
104		mSaveButton.setOnClickListener(mSaveButtonListener);
105
106
107		if (getActionBar() != null) {
108			getActionBar().setHomeButtonEnabled(true);
109			getActionBar().setDisplayHomeAsUpEnabled(true);
110		}
111	}
112
113	private void populateView() {
114		setTitle(getString(R.string.trust_keys));
115		ownKeys.removeAllViews();
116		foreignKeys.removeAllViews();
117		boolean hasOwnKeys = false;
118		boolean hasForeignKeys = false;
119		for(final IdentityKey identityKey : ownKeysToTrust.keySet()) {
120			hasOwnKeys = true;
121			addFingerprintRowWithListeners(ownKeys, contact.getAccount(), identityKey, false,
122					Trust.fromBoolean(ownKeysToTrust.get(identityKey)), false,
123					new CompoundButton.OnCheckedChangeListener() {
124						@Override
125						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
126							ownKeysToTrust.put(identityKey, isChecked);
127							refreshUi();
128							xmppConnectionService.updateAccountUi();
129							xmppConnectionService.updateConversationUi();
130						}
131					},
132					null
133			);
134		}
135		for(final IdentityKey identityKey : foreignKeysToTrust.keySet()) {
136			hasForeignKeys = true;
137			addFingerprintRowWithListeners(foreignKeys, contact.getAccount(), identityKey, false,
138					Trust.fromBoolean(foreignKeysToTrust.get(identityKey)), false,
139					new CompoundButton.OnCheckedChangeListener() {
140						@Override
141						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
142							foreignKeysToTrust.put(identityKey, isChecked);
143							refreshUi();
144							xmppConnectionService.updateAccountUi();
145							xmppConnectionService.updateConversationUi();
146						}
147					},
148					null
149			);
150		}
151
152		if(hasOwnKeys) {
153			ownKeysTitle.setText(accountJid.toString());
154			ownKeysCard.setVisibility(View.VISIBLE);
155		}
156		if(hasForeignKeys) {
157			foreignKeysTitle.setText(contactJid.toString());
158			foreignKeysCard.setVisibility(View.VISIBLE);
159		}
160		if(hasPendingFetches) {
161			setFetching();
162			lock();
163		} else {
164			if (!hasOtherTrustedKeys && !foreignKeysToTrust.values().contains(true)){
165				lock();
166			} else {
167				unlock();
168			}
169			setDone();
170		}
171	}
172
173	private void getFingerprints(final Account account) {
174		Set<IdentityKey> ownKeysSet = account.getAxolotlService().getKeysWithTrust(Trust.UNDECIDED);
175		Set<IdentityKey> foreignKeysSet = account.getAxolotlService().getKeysWithTrust(Trust.UNDECIDED, contact);
176		if (hasNoTrustedKeys) {
177			ownKeysSet.addAll(account.getAxolotlService().getKeysWithTrust(Trust.UNTRUSTED));
178			foreignKeysSet.addAll(account.getAxolotlService().getKeysWithTrust(Trust.UNTRUSTED, contact));
179		}
180		for(final IdentityKey identityKey : ownKeysSet) {
181			if(!ownKeysToTrust.containsKey(identityKey)) {
182				ownKeysToTrust.put(identityKey, false);
183			}
184		}
185		for(final IdentityKey identityKey : foreignKeysSet) {
186			if(!foreignKeysToTrust.containsKey(identityKey)) {
187				foreignKeysToTrust.put(identityKey, false);
188			}
189		}
190	}
191
192	@Override
193	public void onBackendConnected() {
194		if ((accountJid != null) && (contactJid != null)) {
195			final Account account = xmppConnectionService
196				.findAccountByJid(accountJid);
197			if (account == null) {
198				return;
199			}
200			this.contact = account.getRoster().getContact(contactJid);
201			ownKeysToTrust.clear();
202			foreignKeysToTrust.clear();
203			getFingerprints(account);
204
205			if(account.getAxolotlService().getNumTrustedKeys(contact) > 0) {
206				hasOtherTrustedKeys = true;
207			}
208			Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, false);
209			if(account.getAxolotlService().hasPendingKeyFetches(conversation)) {
210				hasPendingFetches = true;
211			}
212
213			populateView();
214		}
215	}
216
217	@Override
218	public void onKeyStatusUpdated() {
219		final Account account = xmppConnectionService.findAccountByJid(accountJid);
220		hasPendingFetches = false;
221		getFingerprints(account);
222		refreshUi();
223	}
224
225	private void commitTrusts() {
226		for(IdentityKey identityKey:ownKeysToTrust.keySet()) {
227			contact.getAccount().getAxolotlService().setFingerprintTrust(
228					identityKey.getFingerprint().replaceAll("\\s", ""),
229					Trust.fromBoolean(ownKeysToTrust.get(identityKey)));
230		}
231		for(IdentityKey identityKey:foreignKeysToTrust.keySet()) {
232			contact.getAccount().getAxolotlService().setFingerprintTrust(
233					identityKey.getFingerprint().replaceAll("\\s", ""),
234					Trust.fromBoolean(foreignKeysToTrust.get(identityKey)));
235		}
236	}
237
238	private void unlock() {
239		mSaveButton.setEnabled(true);
240		mSaveButton.setTextColor(getPrimaryTextColor());
241	}
242
243	private void lock() {
244		mSaveButton.setEnabled(false);
245		mSaveButton.setTextColor(getSecondaryTextColor());
246	}
247
248	private void setDone() {
249		mSaveButton.setText(getString(R.string.done));
250	}
251
252	private void setFetching() {
253		mSaveButton.setText(getString(R.string.fetching_keys));
254	}
255}