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.AxolotlService.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.OnNewKeysAvailable;
 24import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 25import eu.siacs.conversations.xmpp.jid.Jid;
 26
 27public class TrustKeysActivity extends XmppActivity implements OnNewKeysAvailable {
 28	private Jid accountJid;
 29	private Jid contactJid;
 30	private boolean hasOtherTrustedKeys = false;
 31	private boolean hasPendingFetches = false;
 32
 33	private Contact contact;
 34	private TextView ownKeysTitle;
 35	private LinearLayout ownKeys;
 36	private LinearLayout ownKeysCard;
 37	private TextView foreignKeysTitle;
 38	private LinearLayout foreignKeys;
 39	private LinearLayout foreignKeysCard;
 40	private Button mSaveButton;
 41	private Button mCancelButton;
 42
 43	private final Map<IdentityKey, Boolean> ownKeysToTrust = new HashMap<>();
 44	private final Map<IdentityKey, Boolean> foreignKeysToTrust = new HashMap<>();
 45
 46	private final OnClickListener mSaveButtonListener = new OnClickListener() {
 47		@Override
 48		public void onClick(View v) {
 49			commitTrusts();
 50			Intent data = new Intent();
 51			data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID));
 52			setResult(RESULT_OK, data);
 53			finish();
 54		}
 55	};
 56
 57	private final OnClickListener mCancelButtonListener = new OnClickListener() {
 58		@Override
 59		public void onClick(View v) {
 60			setResult(RESULT_CANCELED);
 61			finish();
 62		}
 63	};
 64
 65	@Override
 66	protected void refreshUiReal() {
 67		invalidateOptionsMenu();
 68		populateView();
 69	}
 70
 71	@Override
 72	protected String getShareableUri() {
 73		if (contact != null) {
 74			return contact.getShareableUri();
 75		} else {
 76			return "";
 77		}
 78	}
 79
 80	@Override
 81	protected void onCreate(final Bundle savedInstanceState) {
 82		super.onCreate(savedInstanceState);
 83		setContentView(R.layout.activity_trust_keys);
 84		try {
 85			this.accountJid = Jid.fromString(getIntent().getExtras().getString("account"));
 86		} catch (final InvalidJidException ignored) {
 87		}
 88		try {
 89			this.contactJid = Jid.fromString(getIntent().getExtras().getString("contact"));
 90		} catch (final InvalidJidException ignored) {
 91		}
 92
 93		ownKeysTitle = (TextView) findViewById(R.id.own_keys_title);
 94		ownKeys = (LinearLayout) findViewById(R.id.own_keys_details);
 95		ownKeysCard = (LinearLayout) findViewById(R.id.own_keys_card);
 96		foreignKeysTitle = (TextView) findViewById(R.id.foreign_keys_title);
 97		foreignKeys = (LinearLayout) findViewById(R.id.foreign_keys_details);
 98		foreignKeysCard = (LinearLayout) findViewById(R.id.foreign_keys_card);
 99		mCancelButton = (Button) findViewById(R.id.cancel_button);
100		mCancelButton.setOnClickListener(mCancelButtonListener);
101		mSaveButton = (Button) findViewById(R.id.save_button);
102		mSaveButton.setOnClickListener(mSaveButtonListener);
103
104
105		if (getActionBar() != null) {
106			getActionBar().setHomeButtonEnabled(true);
107			getActionBar().setDisplayHomeAsUpEnabled(true);
108		}
109	}
110
111	private void populateView() {
112		setTitle(getString(R.string.trust_keys));
113		ownKeys.removeAllViews();
114		foreignKeys.removeAllViews();
115		boolean hasOwnKeys = false;
116		boolean hasForeignKeys = false;
117		for(final IdentityKey identityKey : ownKeysToTrust.keySet()) {
118			hasOwnKeys = true;
119			addFingerprintRowWithListeners(ownKeys, contact.getAccount(), identityKey,
120					Trust.fromBoolean(ownKeysToTrust.get(identityKey)), false,
121					new CompoundButton.OnCheckedChangeListener() {
122						@Override
123						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
124							ownKeysToTrust.put(identityKey, isChecked);
125							refreshUi();
126							xmppConnectionService.updateAccountUi();
127							xmppConnectionService.updateConversationUi();
128						}
129					},
130					null
131			);
132		}
133		for(final IdentityKey identityKey : foreignKeysToTrust.keySet()) {
134			hasForeignKeys = true;
135			addFingerprintRowWithListeners(foreignKeys, contact.getAccount(), identityKey,
136					Trust.fromBoolean(foreignKeysToTrust.get(identityKey)), false,
137					new CompoundButton.OnCheckedChangeListener() {
138						@Override
139						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
140							foreignKeysToTrust.put(identityKey, isChecked);
141							refreshUi();
142							xmppConnectionService.updateAccountUi();
143							xmppConnectionService.updateConversationUi();
144						}
145					},
146					null
147			);
148		}
149
150		if(hasOwnKeys) {
151			ownKeysTitle.setText(accountJid.toString());
152			ownKeysCard.setVisibility(View.VISIBLE);
153		}
154		if(hasForeignKeys) {
155			foreignKeysTitle.setText(contactJid.toString());
156			foreignKeysCard.setVisibility(View.VISIBLE);
157		}
158		if(hasPendingFetches) {
159			setFetching();
160			lock();
161		} else {
162			if (!hasOtherTrustedKeys && !foreignKeysToTrust.values().contains(true)){
163				lock();
164			} else {
165				unlock();
166			}
167			setDone();
168		}
169	}
170
171	private void getFingerprints(final Account account) {
172		Set<IdentityKey> ownKeysSet = account.getAxolotlService().getPendingKeys();
173		for(final IdentityKey identityKey : ownKeysSet) {
174			if(!ownKeysToTrust.containsKey(identityKey)) {
175				ownKeysToTrust.put(identityKey, false);
176			}
177		}
178		Set<IdentityKey> foreignKeysSet = account.getAxolotlService().getPendingKeys(contact);
179		for(final IdentityKey identityKey : foreignKeysSet) {
180			if(!foreignKeysToTrust.containsKey(identityKey)) {
181				foreignKeysToTrust.put(identityKey, false);
182			}
183		}
184	}
185
186	@Override
187	public void onBackendConnected() {
188		if ((accountJid != null) && (contactJid != null)) {
189			final Account account = xmppConnectionService
190				.findAccountByJid(accountJid);
191			if (account == null) {
192				return;
193			}
194			this.contact = account.getRoster().getContact(contactJid);
195			ownKeysToTrust.clear();
196			foreignKeysToTrust.clear();
197			getFingerprints(account);
198
199			if(account.getAxolotlService().getNumTrustedKeys(contact) > 0) {
200				hasOtherTrustedKeys = true;
201			}
202			Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, false);
203			if(account.getAxolotlService().hasPendingKeyFetches(conversation)) {
204				hasPendingFetches = true;
205			}
206
207			populateView();
208		}
209	}
210
211	@Override
212	public void onNewKeysAvailable() {
213		runOnUiThread(new Runnable() {
214			@Override
215			public void run() {
216				final Account account = xmppConnectionService
217						.findAccountByJid(accountJid);
218				hasPendingFetches = false;
219				getFingerprints(account);
220				refreshUi();
221			}
222		});
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}