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