EditAccountActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.app.AlertDialog;
  4import android.app.AlertDialog.Builder;
  5import android.app.PendingIntent;
  6import android.content.DialogInterface;
  7import android.content.Intent;
  8import android.content.res.Configuration;
  9import android.graphics.Bitmap;
 10import android.os.Bundle;
 11import android.security.KeyChain;
 12import android.security.KeyChainAliasCallback;
 13import android.text.Editable;
 14import android.text.TextWatcher;
 15import android.view.Menu;
 16import android.view.MenuItem;
 17import android.view.View;
 18import android.view.View.OnClickListener;
 19import android.widget.AutoCompleteTextView;
 20import android.widget.Button;
 21import android.widget.CheckBox;
 22import android.widget.CompoundButton;
 23import android.widget.CompoundButton.OnCheckedChangeListener;
 24import android.widget.EditText;
 25import android.widget.ImageButton;
 26import android.widget.ImageView;
 27import android.widget.LinearLayout;
 28import android.widget.RelativeLayout;
 29import android.widget.TableLayout;
 30import android.widget.TextView;
 31import android.widget.Toast;
 32
 33import java.util.Set;
 34
 35import eu.siacs.conversations.Config;
 36import eu.siacs.conversations.R;
 37import eu.siacs.conversations.crypto.axolotl.AxolotlService;
 38import eu.siacs.conversations.entities.Account;
 39import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested;
 40import eu.siacs.conversations.services.XmppConnectionService;
 41import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
 42import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 43import eu.siacs.conversations.utils.CryptoHelper;
 44import eu.siacs.conversations.utils.UIHelper;
 45import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
 46import eu.siacs.conversations.xmpp.XmppConnection.Features;
 47import eu.siacs.conversations.xmpp.forms.Data;
 48import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 49import eu.siacs.conversations.xmpp.jid.Jid;
 50import eu.siacs.conversations.xmpp.pep.Avatar;
 51
 52public class EditAccountActivity extends XmppActivity implements OnAccountUpdate,
 53		OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast {
 54
 55	private LinearLayout mMainLayout;
 56	private AutoCompleteTextView mAccountJid;
 57	private EditText mPassword;
 58	private EditText mPasswordConfirm;
 59	private CheckBox mRegisterNew;
 60	private Button mCancelButton;
 61	private Button mSaveButton;
 62	private TableLayout mMoreTable;
 63
 64	private LinearLayout mStats;
 65	private TextView mServerInfoSm;
 66	private TextView mServerInfoRosterVersion;
 67	private TextView mServerInfoCarbons;
 68	private TextView mServerInfoMam;
 69	private TextView mServerInfoCSI;
 70	private TextView mServerInfoBlocking;
 71	private TextView mServerInfoPep;
 72	private TextView mServerInfoHttpUpload;
 73	private TextView mSessionEst;
 74	private TextView mOtrFingerprint;
 75	private TextView mAxolotlFingerprint;
 76	private TextView mAccountJidLabel;
 77	private ImageView mAvatar;
 78	private RelativeLayout mOtrFingerprintBox;
 79	private RelativeLayout mAxolotlFingerprintBox;
 80	private ImageButton mOtrFingerprintToClipboardButton;
 81	private ImageButton mAxolotlFingerprintToClipboardButton;
 82	private ImageButton mRegenerateAxolotlKeyButton;
 83	private LinearLayout keys;
 84	private LinearLayout keysCard;
 85	private LinearLayout mNamePort;
 86	private EditText mHostname;
 87	private EditText mPort;
 88	private AlertDialog mCaptchaDialog = null;
 89
 90	private Jid jidToEdit;
 91	private boolean mInitMode = false;
 92	private boolean mUseTor = false;
 93	private Account mAccount;
 94	private String messageFingerprint;
 95
 96	private boolean mFetchingAvatar = false;
 97
 98	private final OnClickListener mSaveButtonClickListener = new OnClickListener() {
 99
100		@Override
101		public void onClick(final View v) {
102			if (mInitMode && mAccount != null) {
103				mAccount.setOption(Account.OPTION_DISABLED, false);
104			}
105			if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !accountInfoEdited()) {
106				mAccount.setOption(Account.OPTION_DISABLED, false);
107				xmppConnectionService.updateAccount(mAccount);
108				return;
109			}
110			final boolean registerNewAccount = mRegisterNew.isChecked() && !Config.DISALLOW_REGISTRATION_IN_UI;
111			if (Config.DOMAIN_LOCK != null && mAccountJid.getText().toString().contains("@")) {
112				mAccountJid.setError(getString(R.string.invalid_username));
113				mAccountJid.requestFocus();
114				return;
115			}
116			final Jid jid;
117			try {
118				if (Config.DOMAIN_LOCK != null) {
119					jid = Jid.fromParts(mAccountJid.getText().toString(), Config.DOMAIN_LOCK, null);
120				} else {
121					jid = Jid.fromString(mAccountJid.getText().toString());
122				}
123			} catch (final InvalidJidException e) {
124				if (Config.DOMAIN_LOCK != null) {
125					mAccountJid.setError(getString(R.string.invalid_username));
126				} else {
127					mAccountJid.setError(getString(R.string.invalid_jid));
128				}
129				mAccountJid.requestFocus();
130				return;
131			}
132			String hostname = null;
133			int numericPort = 5222;
134			if (mUseTor) {
135				hostname = mHostname.getText().toString();
136				final String port = mPort.getText().toString();
137				if (hostname.contains(" ")) {
138					mHostname.setError(getString(R.string.not_valid_hostname));
139					mHostname.requestFocus();
140					return;
141				}
142				try {
143					numericPort = Integer.parseInt(port);
144					if (numericPort < 0 || numericPort > 65535) {
145						mPort.setError(getString(R.string.not_a_valid_port));
146						mPort.requestFocus();
147						return;
148					}
149
150				} catch (NumberFormatException e) {
151					mPort.setError(getString(R.string.not_a_valid_port));
152					mPort.requestFocus();
153					return;
154				}
155			}
156
157			if (jid.isDomainJid()) {
158				if (Config.DOMAIN_LOCK != null) {
159					mAccountJid.setError(getString(R.string.invalid_username));
160				} else {
161					mAccountJid.setError(getString(R.string.invalid_jid));
162				}
163				mAccountJid.requestFocus();
164				return;
165			}
166			final String password = mPassword.getText().toString();
167			final String passwordConfirm = mPasswordConfirm.getText().toString();
168			if (registerNewAccount) {
169				if (!password.equals(passwordConfirm)) {
170					mPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
171					mPasswordConfirm.requestFocus();
172					return;
173				}
174			}
175			if (mAccount != null) {
176				mAccount.setJid(jid);
177				mAccount.setPort(numericPort);
178				mAccount.setHostname(hostname);
179				mAccountJid.setError(null);
180				mPasswordConfirm.setError(null);
181				mAccount.setPassword(password);
182				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
183				xmppConnectionService.updateAccount(mAccount);
184			} else {
185				if (xmppConnectionService.findAccountByJid(jid) != null) {
186					mAccountJid.setError(getString(R.string.account_already_exists));
187					mAccountJid.requestFocus();
188					return;
189				}
190				mAccount = new Account(jid.toBareJid(), password);
191				mAccount.setPort(numericPort);
192				mAccount.setHostname(hostname);
193				mAccount.setOption(Account.OPTION_USETLS, true);
194				mAccount.setOption(Account.OPTION_USECOMPRESSION, true);
195				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
196				xmppConnectionService.createAccount(mAccount);
197			}
198			mHostname.setError(null);
199			mPort.setError(null);
200			if (!mAccount.isOptionSet(Account.OPTION_DISABLED)
201					&& !registerNewAccount
202					&& !mInitMode) {
203				finish();
204			} else {
205				updateSaveButton();
206				updateAccountInformation(true);
207			}
208
209		}
210	};
211	private final OnClickListener mCancelButtonClickListener = new OnClickListener() {
212
213		@Override
214		public void onClick(final View v) {
215			finish();
216		}
217	};
218
219	public void refreshUiReal() {
220		invalidateOptionsMenu();
221		if (mAccount != null
222				&& mAccount.getStatus() != Account.State.ONLINE
223				&& mFetchingAvatar) {
224			startActivity(new Intent(getApplicationContext(),
225					ManageAccountActivity.class));
226			finish();
227		} else if (mInitMode && mAccount != null && mAccount.getStatus() == Account.State.ONLINE) {
228			if (!mFetchingAvatar) {
229				mFetchingAvatar = true;
230				xmppConnectionService.checkForAvatar(mAccount, mAvatarFetchCallback);
231			}
232		} else {
233			updateSaveButton();
234		}
235		if (mAccount != null) {
236			updateAccountInformation(false);
237		}
238	}
239
240	@Override
241	public void onAccountUpdate() {
242		refreshUi();
243	}
244
245	private final UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
246
247		@Override
248		public void userInputRequried(final PendingIntent pi, final Avatar avatar) {
249			finishInitialSetup(avatar);
250		}
251
252		@Override
253		public void success(final Avatar avatar) {
254			finishInitialSetup(avatar);
255		}
256
257		@Override
258		public void error(final int errorCode, final Avatar avatar) {
259			finishInitialSetup(avatar);
260		}
261	};
262	private final TextWatcher mTextWatcher = new TextWatcher() {
263
264		@Override
265		public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
266			updateSaveButton();
267		}
268
269		@Override
270		public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
271		}
272
273		@Override
274		public void afterTextChanged(final Editable s) {
275
276		}
277	};
278
279	private final OnClickListener mAvatarClickListener = new OnClickListener() {
280		@Override
281		public void onClick(final View view) {
282			if (mAccount != null) {
283				final Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
284				intent.putExtra("account", mAccount.getJid().toBareJid().toString());
285				startActivity(intent);
286			}
287		}
288	};
289
290	protected void finishInitialSetup(final Avatar avatar) {
291		runOnUiThread(new Runnable() {
292
293			@Override
294			public void run() {
295				final Intent intent;
296				if (avatar != null) {
297					intent = new Intent(getApplicationContext(),
298							StartConversationActivity.class);
299					if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
300						intent.putExtra("init", true);
301					}
302				} else {
303					intent = new Intent(getApplicationContext(),
304							PublishProfilePictureActivity.class);
305					intent.putExtra("account", mAccount.getJid().toBareJid().toString());
306					intent.putExtra("setup", true);
307				}
308				startActivity(intent);
309				finish();
310			}
311		});
312	}
313
314	protected void updateSaveButton() {
315		if (accountInfoEdited() && !mInitMode) {
316			this.mSaveButton.setText(R.string.save);
317			this.mSaveButton.setEnabled(true);
318			this.mSaveButton.setTextColor(getPrimaryTextColor());
319		} else if (mAccount != null && (mAccount.getStatus() == Account.State.CONNECTING || mFetchingAvatar)) {
320			this.mSaveButton.setEnabled(false);
321			this.mSaveButton.setTextColor(getSecondaryTextColor());
322			this.mSaveButton.setText(R.string.account_status_connecting);
323		} else if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !mInitMode) {
324			this.mSaveButton.setEnabled(true);
325			this.mSaveButton.setTextColor(getPrimaryTextColor());
326			this.mSaveButton.setText(R.string.enable);
327		} else {
328			this.mSaveButton.setEnabled(true);
329			this.mSaveButton.setTextColor(getPrimaryTextColor());
330			if (!mInitMode) {
331				if (mAccount != null && mAccount.isOnlineAndConnected()) {
332					this.mSaveButton.setText(R.string.save);
333					if (!accountInfoEdited()) {
334						this.mSaveButton.setEnabled(false);
335						this.mSaveButton.setTextColor(getSecondaryTextColor());
336					}
337				} else {
338					this.mSaveButton.setText(R.string.connect);
339				}
340			} else {
341				this.mSaveButton.setText(R.string.next);
342			}
343		}
344	}
345
346	protected boolean accountInfoEdited() {
347		if (this.mAccount == null) {
348			return false;
349		}
350		final String unmodified;
351		if (Config.DOMAIN_LOCK != null) {
352			unmodified = this.mAccount.getJid().getLocalpart();
353		} else {
354			unmodified = this.mAccount.getJid().toBareJid().toString();
355		}
356		return !unmodified.equals(this.mAccountJid.getText().toString()) ||
357				!this.mAccount.getPassword().equals(this.mPassword.getText().toString()) ||
358				!this.mAccount.getHostname().equals(this.mHostname.getText().toString()) ||
359				!String.valueOf(this.mAccount.getPort()).equals(this.mPort.getText().toString());
360	}
361
362	@Override
363	protected String getShareableUri() {
364		if (mAccount != null) {
365			return mAccount.getShareableUri();
366		} else {
367			return "";
368		}
369	}
370
371	@Override
372	protected void onCreate(final Bundle savedInstanceState) {
373		super.onCreate(savedInstanceState);
374		setContentView(R.layout.activity_edit_account);
375		this.mMainLayout = (LinearLayout) findViewById(R.id.account_main_layout);
376		this.mAccountJid = (AutoCompleteTextView) findViewById(R.id.account_jid);
377		this.mAccountJid.addTextChangedListener(this.mTextWatcher);
378		this.mAccountJidLabel = (TextView) findViewById(R.id.account_jid_label);
379		if (Config.DOMAIN_LOCK != null) {
380			this.mAccountJidLabel.setText(R.string.username);
381			this.mAccountJid.setHint(R.string.username_hint);
382		}
383		this.mPassword = (EditText) findViewById(R.id.account_password);
384		this.mPassword.addTextChangedListener(this.mTextWatcher);
385		this.mPasswordConfirm = (EditText) findViewById(R.id.account_password_confirm);
386		this.mAvatar = (ImageView) findViewById(R.id.avater);
387		this.mAvatar.setOnClickListener(this.mAvatarClickListener);
388		this.mRegisterNew = (CheckBox) findViewById(R.id.account_register_new);
389		this.mStats = (LinearLayout) findViewById(R.id.stats);
390		this.mSessionEst = (TextView) findViewById(R.id.session_est);
391		this.mServerInfoRosterVersion = (TextView) findViewById(R.id.server_info_roster_version);
392		this.mServerInfoCarbons = (TextView) findViewById(R.id.server_info_carbons);
393		this.mServerInfoMam = (TextView) findViewById(R.id.server_info_mam);
394		this.mServerInfoCSI = (TextView) findViewById(R.id.server_info_csi);
395		this.mServerInfoBlocking = (TextView) findViewById(R.id.server_info_blocking);
396		this.mServerInfoSm = (TextView) findViewById(R.id.server_info_sm);
397		this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep);
398		this.mServerInfoHttpUpload = (TextView) findViewById(R.id.server_info_http_upload);
399		this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint);
400		this.mOtrFingerprintBox = (RelativeLayout) findViewById(R.id.otr_fingerprint_box);
401		this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard);
402		this.mAxolotlFingerprint = (TextView) findViewById(R.id.axolotl_fingerprint);
403		this.mAxolotlFingerprintBox = (RelativeLayout) findViewById(R.id.axolotl_fingerprint_box);
404		this.mAxolotlFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_axolotl_to_clipboard);
405		this.mRegenerateAxolotlKeyButton = (ImageButton) findViewById(R.id.action_regenerate_axolotl_key);
406		this.keysCard = (LinearLayout) findViewById(R.id.other_device_keys_card);
407		this.keys = (LinearLayout) findViewById(R.id.other_device_keys);
408		this.mNamePort = (LinearLayout) findViewById(R.id.name_port);
409		this.mHostname = (EditText) findViewById(R.id.hostname);
410		this.mHostname.addTextChangedListener(mTextWatcher);
411		this.mPort = (EditText) findViewById(R.id.port);
412		this.mPort.setText("5222");
413		this.mPort.addTextChangedListener(mTextWatcher);
414		this.mSaveButton = (Button) findViewById(R.id.save_button);
415		this.mCancelButton = (Button) findViewById(R.id.cancel_button);
416		this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener);
417		this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener);
418		this.mMoreTable = (TableLayout) findViewById(R.id.server_info_more);
419		final OnCheckedChangeListener OnCheckedShowConfirmPassword = new OnCheckedChangeListener() {
420			@Override
421			public void onCheckedChanged(final CompoundButton buttonView,
422										 final boolean isChecked) {
423				if (isChecked) {
424					mPasswordConfirm.setVisibility(View.VISIBLE);
425				} else {
426					mPasswordConfirm.setVisibility(View.GONE);
427				}
428				updateSaveButton();
429			}
430		};
431		this.mRegisterNew.setOnCheckedChangeListener(OnCheckedShowConfirmPassword);
432		if (Config.DISALLOW_REGISTRATION_IN_UI) {
433			this.mRegisterNew.setVisibility(View.GONE);
434		}
435	}
436
437	@Override
438	public boolean onCreateOptionsMenu(final Menu menu) {
439		super.onCreateOptionsMenu(menu);
440		getMenuInflater().inflate(R.menu.editaccount, menu);
441		final MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code);
442		final MenuItem showBlocklist = menu.findItem(R.id.action_show_block_list);
443		final MenuItem showMoreInfo = menu.findItem(R.id.action_server_info_show_more);
444		final MenuItem changePassword = menu.findItem(R.id.action_change_password_on_server);
445		final MenuItem clearDevices = menu.findItem(R.id.action_clear_devices);
446		final MenuItem renewCertificate = menu.findItem(R.id.action_renew_certificate);
447
448		renewCertificate.setVisible(mAccount != null && mAccount.getPrivateKeyAlias() != null);
449
450		if (mAccount != null && mAccount.isOnlineAndConnected()) {
451			if (!mAccount.getXmppConnection().getFeatures().blocking()) {
452				showBlocklist.setVisible(false);
453			}
454			if (!mAccount.getXmppConnection().getFeatures().register()) {
455				changePassword.setVisible(false);
456			}
457			Set<Integer> otherDevices = mAccount.getAxolotlService().getOwnDeviceIds();
458			if (otherDevices == null || otherDevices.isEmpty()) {
459				clearDevices.setVisible(false);
460			}
461		} else {
462			showQrCode.setVisible(false);
463			showBlocklist.setVisible(false);
464			showMoreInfo.setVisible(false);
465			changePassword.setVisible(false);
466			clearDevices.setVisible(false);
467		}
468		return true;
469	}
470
471	@Override
472	protected void onStart() {
473		super.onStart();
474		if (getIntent() != null) {
475			try {
476				this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid"));
477			} catch (final InvalidJidException | NullPointerException ignored) {
478				this.jidToEdit = null;
479			}
480			this.mInitMode = getIntent().getBooleanExtra("init", false) || this.jidToEdit == null;
481			this.messageFingerprint = getIntent().getStringExtra("fingerprint");
482			if (!mInitMode) {
483				this.mRegisterNew.setVisibility(View.GONE);
484				if (getActionBar() != null) {
485					getActionBar().setTitle(getString(R.string.account_details));
486				}
487			} else {
488				this.mAvatar.setVisibility(View.GONE);
489				if (getActionBar() != null) {
490					getActionBar().setTitle(R.string.action_add_account);
491				}
492			}
493		}
494		this.mUseTor = Config.FORCE_ORBOT || getPreferences().getBoolean("use_tor", false);
495		this.mNamePort.setVisibility(mUseTor ? View.VISIBLE : View.GONE);
496	}
497
498	@Override
499	protected void onBackendConnected() {
500		if (this.jidToEdit != null) {
501			this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit);
502			if (this.mAccount != null) {
503				if (this.mAccount.getPrivateKeyAlias() != null) {
504					this.mPassword.setHint(R.string.authenticate_with_certificate);
505					if (this.mInitMode) {
506						this.mPassword.requestFocus();
507					}
508				}
509				updateAccountInformation(true);
510			}
511		} else if (this.xmppConnectionService.getAccounts().size() == 0) {
512			if (getActionBar() != null) {
513				getActionBar().setDisplayHomeAsUpEnabled(false);
514				getActionBar().setDisplayShowHomeEnabled(false);
515				getActionBar().setHomeButtonEnabled(false);
516			}
517			this.mCancelButton.setEnabled(false);
518			this.mCancelButton.setTextColor(getSecondaryTextColor());
519		}
520		if (Config.DOMAIN_LOCK == null) {
521			final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
522					android.R.layout.simple_list_item_1,
523					xmppConnectionService.getKnownHosts());
524			this.mAccountJid.setAdapter(mKnownHostsAdapter);
525		}
526		updateSaveButton();
527		invalidateOptionsMenu();
528	}
529
530	@Override
531	public boolean onOptionsItemSelected(final MenuItem item) {
532		switch (item.getItemId()) {
533			case R.id.action_show_block_list:
534				final Intent showBlocklistIntent = new Intent(this, BlocklistActivity.class);
535				showBlocklistIntent.putExtra("account", mAccount.getJid().toString());
536				startActivity(showBlocklistIntent);
537				break;
538			case R.id.action_server_info_show_more:
539				mMoreTable.setVisibility(item.isChecked() ? View.GONE : View.VISIBLE);
540				item.setChecked(!item.isChecked());
541				break;
542			case R.id.action_change_password_on_server:
543				final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
544				changePasswordIntent.putExtra("account", mAccount.getJid().toString());
545				startActivity(changePasswordIntent);
546				break;
547			case R.id.action_clear_devices:
548				showWipePepDialog();
549				break;
550			case R.id.action_renew_certificate:
551				renewCertificate();
552				break;
553		}
554		return super.onOptionsItemSelected(item);
555	}
556
557	private void renewCertificate() {
558		KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
559	}
560
561	@Override
562	public void alias(String alias) {
563		if (alias != null) {
564			xmppConnectionService.updateKeyInAccount(mAccount, alias);
565		}
566	}
567
568	private void updateAccountInformation(boolean init) {
569		if (init) {
570			this.mAccountJid.getEditableText().clear();
571			if (Config.DOMAIN_LOCK != null) {
572				this.mAccountJid.getEditableText().append(this.mAccount.getJid().getLocalpart());
573			} else {
574				this.mAccountJid.getEditableText().append(this.mAccount.getJid().toBareJid().toString());
575			}
576			this.mPassword.setText(this.mAccount.getPassword());
577			this.mHostname.setText("");
578			this.mHostname.getEditableText().append(this.mAccount.getHostname());
579			this.mPort.setText("");
580			this.mPort.getEditableText().append(String.valueOf(this.mAccount.getPort()));
581			this.mNamePort.setVisibility(mUseTor ? View.VISIBLE : View.GONE);
582
583		}
584		if (!mInitMode) {
585			this.mAvatar.setVisibility(View.VISIBLE);
586			this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72)));
587		}
588		if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) {
589			this.mRegisterNew.setVisibility(View.VISIBLE);
590			this.mRegisterNew.setChecked(true);
591			this.mPasswordConfirm.setText(this.mAccount.getPassword());
592		} else {
593			this.mRegisterNew.setVisibility(View.GONE);
594			this.mRegisterNew.setChecked(false);
595		}
596		if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) {
597			this.mStats.setVisibility(View.VISIBLE);
598			this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(this, this.mAccount.getXmppConnection()
599					.getLastSessionEstablished()));
600			Features features = this.mAccount.getXmppConnection().getFeatures();
601			if (features.rosterVersioning()) {
602				this.mServerInfoRosterVersion.setText(R.string.server_info_available);
603			} else {
604				this.mServerInfoRosterVersion.setText(R.string.server_info_unavailable);
605			}
606			if (features.carbons()) {
607				this.mServerInfoCarbons.setText(R.string.server_info_available);
608			} else {
609				this.mServerInfoCarbons
610						.setText(R.string.server_info_unavailable);
611			}
612			if (features.mam()) {
613				this.mServerInfoMam.setText(R.string.server_info_available);
614			} else {
615				this.mServerInfoMam.setText(R.string.server_info_unavailable);
616			}
617			if (features.csi()) {
618				this.mServerInfoCSI.setText(R.string.server_info_available);
619			} else {
620				this.mServerInfoCSI.setText(R.string.server_info_unavailable);
621			}
622			if (features.blocking()) {
623				this.mServerInfoBlocking.setText(R.string.server_info_available);
624			} else {
625				this.mServerInfoBlocking.setText(R.string.server_info_unavailable);
626			}
627			if (features.sm()) {
628				this.mServerInfoSm.setText(R.string.server_info_available);
629			} else {
630				this.mServerInfoSm.setText(R.string.server_info_unavailable);
631			}
632			if (features.pep()) {
633				AxolotlService axolotlService = this.mAccount.getAxolotlService();
634				if (axolotlService != null && axolotlService.isPepBroken()) {
635					this.mServerInfoPep.setText(R.string.server_info_broken);
636				} else {
637					this.mServerInfoPep.setText(R.string.server_info_available);
638				}
639			} else {
640				this.mServerInfoPep.setText(R.string.server_info_unavailable);
641			}
642			if (features.httpUpload()) {
643				this.mServerInfoHttpUpload.setText(R.string.server_info_available);
644			} else {
645				this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable);
646			}
647			final String otrFingerprint = this.mAccount.getOtrFingerprint();
648			if (otrFingerprint != null) {
649				this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
650				this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(otrFingerprint));
651				this.mOtrFingerprintToClipboardButton
652						.setVisibility(View.VISIBLE);
653				this.mOtrFingerprintToClipboardButton
654						.setOnClickListener(new View.OnClickListener() {
655
656							@Override
657							public void onClick(final View v) {
658
659								if (copyTextToClipboard(otrFingerprint, R.string.otr_fingerprint)) {
660									Toast.makeText(
661											EditAccountActivity.this,
662											R.string.toast_message_otr_fingerprint,
663											Toast.LENGTH_SHORT).show();
664								}
665							}
666						});
667			} else {
668				this.mOtrFingerprintBox.setVisibility(View.GONE);
669			}
670			final String axolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint();
671			if (axolotlFingerprint != null) {
672				this.mAxolotlFingerprintBox.setVisibility(View.VISIBLE);
673				this.mAxolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(axolotlFingerprint));
674				this.mAxolotlFingerprintToClipboardButton
675						.setVisibility(View.VISIBLE);
676				this.mAxolotlFingerprintToClipboardButton
677						.setOnClickListener(new View.OnClickListener() {
678
679							@Override
680							public void onClick(final View v) {
681
682								if (copyTextToClipboard(axolotlFingerprint, R.string.omemo_fingerprint)) {
683									Toast.makeText(
684											EditAccountActivity.this,
685											R.string.toast_message_omemo_fingerprint,
686											Toast.LENGTH_SHORT).show();
687								}
688							}
689						});
690				if (Config.SHOW_REGENERATE_AXOLOTL_KEYS_BUTTON) {
691					this.mRegenerateAxolotlKeyButton
692							.setVisibility(View.VISIBLE);
693					this.mRegenerateAxolotlKeyButton
694							.setOnClickListener(new View.OnClickListener() {
695
696								@Override
697								public void onClick(final View v) {
698									showRegenerateAxolotlKeyDialog();
699								}
700							});
701				}
702			} else {
703				this.mAxolotlFingerprintBox.setVisibility(View.GONE);
704			}
705			final String ownFingerprint = mAccount.getAxolotlService().getOwnFingerprint();
706			boolean hasKeys = false;
707			keys.removeAllViews();
708			for (final String fingerprint : mAccount.getAxolotlService().getFingerprintsForOwnSessions()) {
709				if (ownFingerprint.equals(fingerprint)) {
710					continue;
711				}
712				boolean highlight = fingerprint.equals(messageFingerprint);
713				hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight, null);
714			}
715			if (hasKeys) {
716				keysCard.setVisibility(View.VISIBLE);
717			} else {
718				keysCard.setVisibility(View.GONE);
719			}
720		} else {
721			if (this.mAccount.errorStatus()) {
722				this.mAccountJid.setError(getString(this.mAccount.getStatus().getReadableId()));
723				if (init || !accountInfoEdited()) {
724					this.mAccountJid.requestFocus();
725				}
726			} else {
727				this.mAccountJid.setError(null);
728			}
729			this.mStats.setVisibility(View.GONE);
730		}
731	}
732
733	public void showRegenerateAxolotlKeyDialog() {
734		Builder builder = new Builder(this);
735		builder.setTitle("Regenerate Key");
736		builder.setIconAttribute(android.R.attr.alertDialogIcon);
737		builder.setMessage("Are you sure you want to regenerate your Identity Key? (This will also wipe all established sessions and contact Identity Keys)");
738		builder.setNegativeButton(getString(R.string.cancel), null);
739		builder.setPositiveButton("Yes",
740				new DialogInterface.OnClickListener() {
741					@Override
742					public void onClick(DialogInterface dialog, int which) {
743						mAccount.getAxolotlService().regenerateKeys(false);
744					}
745				});
746		builder.create().show();
747	}
748
749	public void showWipePepDialog() {
750		Builder builder = new Builder(this);
751		builder.setTitle(getString(R.string.clear_other_devices));
752		builder.setIconAttribute(android.R.attr.alertDialogIcon);
753		builder.setMessage(getString(R.string.clear_other_devices_desc));
754		builder.setNegativeButton(getString(R.string.cancel), null);
755		builder.setPositiveButton(getString(R.string.accept),
756				new DialogInterface.OnClickListener() {
757					@Override
758					public void onClick(DialogInterface dialog, int which) {
759						mAccount.getAxolotlService().wipeOtherPepDevices();
760					}
761				});
762		builder.create().show();
763	}
764
765	@Override
766	public void onKeyStatusUpdated(AxolotlService.FetchStatus report) {
767		refreshUi();
768	}
769
770	@Override
771	public void onCaptchaRequested(final Account account, final String id, final Data data,
772								   final Bitmap captcha) {
773		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
774		final ImageView view = new ImageView(this);
775		final LinearLayout layout = new LinearLayout(this);
776		final EditText input = new EditText(this);
777
778		view.setImageBitmap(captcha);
779		view.setScaleType(ImageView.ScaleType.FIT_CENTER);
780
781		input.setHint(getString(R.string.captcha_hint));
782
783		layout.setOrientation(LinearLayout.VERTICAL);
784		layout.addView(view);
785		layout.addView(input);
786
787		builder.setTitle(getString(R.string.captcha_required));
788		builder.setView(layout);
789
790		builder.setPositiveButton(getString(R.string.ok),
791				new DialogInterface.OnClickListener() {
792					@Override
793					public void onClick(DialogInterface dialog, int which) {
794						String rc = input.getText().toString();
795						data.put("username", account.getUsername());
796						data.put("password", account.getPassword());
797						data.put("ocr", rc);
798						data.submit();
799
800						if (xmppConnectionServiceBound) {
801							xmppConnectionService.sendCreateAccountWithCaptchaPacket(
802									account, id, data);
803						}
804					}
805				});
806		builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
807			@Override
808			public void onClick(DialogInterface dialog, int which) {
809				if (xmppConnectionService != null) {
810					xmppConnectionService.sendCreateAccountWithCaptchaPacket(account, null, null);
811				}
812			}
813		});
814
815		builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
816			@Override
817			public void onCancel(DialogInterface dialog) {
818				if (xmppConnectionService != null) {
819					xmppConnectionService.sendCreateAccountWithCaptchaPacket(account, null, null);
820				}
821			}
822		});
823
824		runOnUiThread(new Runnable() {
825			@Override
826			public void run() {
827				if ((mCaptchaDialog != null) && mCaptchaDialog.isShowing()) {
828					mCaptchaDialog.dismiss();
829				}
830				mCaptchaDialog = builder.create();
831				mCaptchaDialog.show();
832			}
833		});
834	}
835
836	public void onShowErrorToast(final int resId) {
837		runOnUiThread(new Runnable() {
838			@Override
839			public void run() {
840				Toast.makeText(EditAccountActivity.this, resId, Toast.LENGTH_SHORT).show();
841			}
842		});
843	}
844}