EditAccountActivity.java

   1package eu.siacs.conversations.ui;
   2
   3import android.app.ActionBar;
   4import android.app.AlertDialog;
   5import android.app.AlertDialog.Builder;
   6import android.app.PendingIntent;
   7import android.content.ActivityNotFoundException;
   8import android.content.DialogInterface;
   9import android.content.Intent;
  10import android.content.SharedPreferences;
  11import android.graphics.Bitmap;
  12import android.net.Uri;
  13import android.os.Bundle;
  14import android.provider.Settings;
  15import android.security.KeyChain;
  16import android.security.KeyChainAliasCallback;
  17import android.text.Editable;
  18import android.text.TextWatcher;
  19import android.view.Menu;
  20import android.view.MenuItem;
  21import android.view.View;
  22import android.view.View.OnClickListener;
  23import android.widget.AutoCompleteTextView;
  24import android.widget.Button;
  25import android.widget.CheckBox;
  26import android.widget.CompoundButton;
  27import android.widget.CompoundButton.OnCheckedChangeListener;
  28import android.widget.EditText;
  29import android.widget.ImageButton;
  30import android.widget.ImageView;
  31import android.widget.LinearLayout;
  32import android.widget.RelativeLayout;
  33import android.widget.TableLayout;
  34import android.widget.TableRow;
  35import android.widget.TextView;
  36import android.widget.Toast;
  37
  38import java.util.Arrays;
  39import java.util.List;
  40import java.util.Set;
  41import java.util.concurrent.atomic.AtomicInteger;
  42
  43import eu.siacs.conversations.Config;
  44import eu.siacs.conversations.OmemoActivity;
  45import eu.siacs.conversations.R;
  46import eu.siacs.conversations.crypto.axolotl.AxolotlService;
  47import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
  48import eu.siacs.conversations.entities.Account;
  49import eu.siacs.conversations.services.BarcodeProvider;
  50import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested;
  51import eu.siacs.conversations.services.XmppConnectionService;
  52import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
  53import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
  54import eu.siacs.conversations.utils.CryptoHelper;
  55import eu.siacs.conversations.utils.UIHelper;
  56import eu.siacs.conversations.utils.XmppUri;
  57import eu.siacs.conversations.xml.Element;
  58import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
  59import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
  60import eu.siacs.conversations.xmpp.XmppConnection;
  61import eu.siacs.conversations.xmpp.XmppConnection.Features;
  62import eu.siacs.conversations.xmpp.forms.Data;
  63import eu.siacs.conversations.xmpp.jid.InvalidJidException;
  64import eu.siacs.conversations.xmpp.jid.Jid;
  65import eu.siacs.conversations.xmpp.pep.Avatar;
  66
  67public class EditAccountActivity extends OmemoActivity implements OnAccountUpdate, OnUpdateBlocklist,
  68		OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnMamPreferencesFetched {
  69
  70	private static final int REQUEST_DATA_SAVER = 0x37af244;
  71	private AutoCompleteTextView mAccountJid;
  72	private EditText mPassword;
  73	private EditText mPasswordConfirm;
  74	private CheckBox mRegisterNew;
  75	private Button mCancelButton;
  76	private Button mSaveButton;
  77	private Button mDisableOsOptimizationsButton;
  78	private TextView mDisableOsOptimizationsHeadline;
  79	private TextView getmDisableOsOptimizationsBody;
  80	private TableLayout mMoreTable;
  81
  82	private LinearLayout mStats;
  83	private RelativeLayout mOsOptimizations;
  84	private TextView mServerInfoSm;
  85	private TextView mServerInfoRosterVersion;
  86	private TextView mServerInfoCarbons;
  87	private TextView mServerInfoMam;
  88	private TextView mServerInfoCSI;
  89	private TextView mServerInfoBlocking;
  90	private TextView mServerInfoPep;
  91	private TextView mServerInfoHttpUpload;
  92	private TextView mServerInfoPush;
  93	private TextView mSessionEst;
  94	private TextView mOtrFingerprint;
  95	private TextView mAxolotlFingerprint;
  96	private TextView mOwnFingerprintDesc;
  97	private TextView mAccountJidLabel;
  98	private ImageView mAvatar;
  99	private RelativeLayout mOtrFingerprintBox;
 100	private RelativeLayout mAxolotlFingerprintBox;
 101	private ImageButton mOtrFingerprintToClipboardButton;
 102	private ImageButton mAxolotlFingerprintToClipboardButton;
 103	private ImageButton mRegenerateAxolotlKeyButton;
 104	private LinearLayout keys;
 105	private LinearLayout keysCard;
 106	private LinearLayout mNamePort;
 107	private EditText mHostname;
 108	private EditText mPort;
 109	private AlertDialog mCaptchaDialog = null;
 110
 111	private Jid jidToEdit;
 112	private boolean mInitMode = false;
 113	private boolean mUsernameMode = Config.DOMAIN_LOCK != null;
 114	private boolean mShowOptions = false;
 115	private Account mAccount;
 116	private String messageFingerprint;
 117
 118	private boolean mFetchingAvatar = false;
 119
 120	private final OnClickListener mSaveButtonClickListener = new OnClickListener() {
 121
 122		@Override
 123		public void onClick(final View v) {
 124			final String password = mPassword.getText().toString();
 125			final String passwordConfirm = mPasswordConfirm.getText().toString();
 126
 127			if (!mInitMode && passwordChangedInMagicCreateMode()) {
 128				gotoChangePassword(password);
 129				return;
 130			}
 131			if (mInitMode && mAccount != null) {
 132				mAccount.setOption(Account.OPTION_DISABLED, false);
 133			}
 134			if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !accountInfoEdited()) {
 135				mAccount.setOption(Account.OPTION_DISABLED, false);
 136				if (!xmppConnectionService.updateAccount(mAccount)) {
 137					Toast.makeText(EditAccountActivity.this,R.string.unable_to_update_account,Toast.LENGTH_SHORT).show();
 138				}
 139				return;
 140			}
 141			final boolean registerNewAccount = mRegisterNew.isChecked() && !Config.DISALLOW_REGISTRATION_IN_UI;
 142			if (mUsernameMode && mAccountJid.getText().toString().contains("@")) {
 143				mAccountJid.setError(getString(R.string.invalid_username));
 144				mAccountJid.requestFocus();
 145				return;
 146			}
 147			final Jid jid;
 148			try {
 149				if (mUsernameMode) {
 150					jid = Jid.fromParts(mAccountJid.getText().toString(), getUserModeDomain(), null);
 151				} else {
 152					jid = Jid.fromString(mAccountJid.getText().toString());
 153				}
 154			} catch (final InvalidJidException e) {
 155				if (mUsernameMode) {
 156					mAccountJid.setError(getString(R.string.invalid_username));
 157				} else {
 158					mAccountJid.setError(getString(R.string.invalid_jid));
 159				}
 160				mAccountJid.requestFocus();
 161				return;
 162			}
 163			String hostname = null;
 164			int numericPort = 5222;
 165			if (mShowOptions) {
 166				hostname = mHostname.getText().toString().replaceAll("\\s","");
 167				final String port = mPort.getText().toString().replaceAll("\\s","");
 168				if (hostname.contains(" ")) {
 169					mHostname.setError(getString(R.string.not_valid_hostname));
 170					mHostname.requestFocus();
 171					return;
 172				}
 173				try {
 174					numericPort = Integer.parseInt(port);
 175					if (numericPort < 0 || numericPort > 65535) {
 176						mPort.setError(getString(R.string.not_a_valid_port));
 177						mPort.requestFocus();
 178						return;
 179					}
 180
 181				} catch (NumberFormatException e) {
 182					mPort.setError(getString(R.string.not_a_valid_port));
 183					mPort.requestFocus();
 184					return;
 185				}
 186			}
 187
 188			if (jid.isDomainJid()) {
 189				if (mUsernameMode) {
 190					mAccountJid.setError(getString(R.string.invalid_username));
 191				} else {
 192					mAccountJid.setError(getString(R.string.invalid_jid));
 193				}
 194				mAccountJid.requestFocus();
 195				return;
 196			}
 197			if (registerNewAccount) {
 198				if (!password.equals(passwordConfirm)) {
 199					mPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
 200					mPasswordConfirm.requestFocus();
 201					return;
 202				}
 203			}
 204			if (mAccount != null) {
 205				if (mInitMode && mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
 206					mAccount.setOption(Account.OPTION_MAGIC_CREATE, mAccount.getPassword().contains(password));
 207				}
 208				mAccount.setJid(jid);
 209				mAccount.setPort(numericPort);
 210				mAccount.setHostname(hostname);
 211				mAccountJid.setError(null);
 212				mPasswordConfirm.setError(null);
 213				mAccount.setPassword(password);
 214				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
 215				if (!xmppConnectionService.updateAccount(mAccount)) {
 216					Toast.makeText(EditAccountActivity.this,R.string.unable_to_update_account,Toast.LENGTH_SHORT).show();
 217					return;
 218				}
 219			} else {
 220				if (xmppConnectionService.findAccountByJid(jid) != null) {
 221					mAccountJid.setError(getString(R.string.account_already_exists));
 222					mAccountJid.requestFocus();
 223					return;
 224				}
 225				mAccount = new Account(jid.toBareJid(), password);
 226				mAccount.setPort(numericPort);
 227				mAccount.setHostname(hostname);
 228				mAccount.setOption(Account.OPTION_USETLS, true);
 229				mAccount.setOption(Account.OPTION_USECOMPRESSION, true);
 230				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
 231				xmppConnectionService.createAccount(mAccount);
 232			}
 233			mHostname.setError(null);
 234			mPort.setError(null);
 235			if (!mAccount.isOptionSet(Account.OPTION_DISABLED)
 236					&& !registerNewAccount
 237					&& !mInitMode) {
 238				finish();
 239			} else {
 240				updateSaveButton();
 241				updateAccountInformation(true);
 242			}
 243
 244		}
 245	};
 246	private final OnClickListener mCancelButtonClickListener = new OnClickListener() {
 247
 248		@Override
 249		public void onClick(final View v) {
 250			deleteMagicCreatedAccountAndReturnIfNecessary();
 251			finish();
 252		}
 253	};
 254	private Toast mFetchingMamPrefsToast;
 255	private TableRow mPushRow;
 256	private String mSavedInstanceAccount;
 257	private boolean mSavedInstanceInit = false;
 258	private Button mClearDevicesButton;
 259
 260	public void refreshUiReal() {
 261		invalidateOptionsMenu();
 262		if (mAccount != null
 263				&& mAccount.getStatus() != Account.State.ONLINE
 264				&& mFetchingAvatar) {
 265			startActivity(new Intent(getApplicationContext(),
 266					ManageAccountActivity.class));
 267			finish();
 268		} else if (mInitMode && mAccount != null && mAccount.getStatus() == Account.State.ONLINE) {
 269			if (!mFetchingAvatar) {
 270				mFetchingAvatar = true;
 271				xmppConnectionService.checkForAvatar(mAccount, mAvatarFetchCallback);
 272			}
 273		}
 274		if (mAccount != null) {
 275			updateAccountInformation(false);
 276		}
 277		updateSaveButton();
 278	}
 279
 280	@Override
 281	public boolean onNavigateUp() {
 282		deleteMagicCreatedAccountAndReturnIfNecessary();
 283		return super.onNavigateUp();
 284	}
 285
 286	@Override
 287	public void onBackPressed() {
 288		deleteMagicCreatedAccountAndReturnIfNecessary();
 289		super.onBackPressed();
 290	}
 291
 292	private void deleteMagicCreatedAccountAndReturnIfNecessary() {
 293		if (Config.MAGIC_CREATE_DOMAIN != null
 294				&& mAccount != null
 295				&& mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)
 296				&& mAccount.isOptionSet(Account.OPTION_REGISTER)
 297				&& xmppConnectionService.getAccounts().size() == 1) {
 298			xmppConnectionService.deleteAccount(mAccount);
 299			startActivity(new Intent(EditAccountActivity.this, WelcomeActivity.class));
 300		}
 301	}
 302
 303	@Override
 304	public void onAccountUpdate() {
 305		refreshUi();
 306	}
 307
 308	private final UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
 309
 310		@Override
 311		public void userInputRequried(final PendingIntent pi, final Avatar avatar) {
 312			finishInitialSetup(avatar);
 313		}
 314
 315		@Override
 316		public void success(final Avatar avatar) {
 317			finishInitialSetup(avatar);
 318		}
 319
 320		@Override
 321		public void error(final int errorCode, final Avatar avatar) {
 322			finishInitialSetup(avatar);
 323		}
 324	};
 325	private final TextWatcher mTextWatcher = new TextWatcher() {
 326
 327		@Override
 328		public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
 329			updateSaveButton();
 330		}
 331
 332		@Override
 333		public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
 334		}
 335
 336		@Override
 337		public void afterTextChanged(final Editable s) {
 338
 339		}
 340	};
 341
 342	private final OnClickListener mAvatarClickListener = new OnClickListener() {
 343		@Override
 344		public void onClick(final View view) {
 345			if (mAccount != null) {
 346				final Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
 347				intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toBareJid().toString());
 348				startActivity(intent);
 349			}
 350		}
 351	};
 352
 353	protected void finishInitialSetup(final Avatar avatar) {
 354		runOnUiThread(new Runnable() {
 355
 356			@Override
 357			public void run() {
 358				final Intent intent;
 359				final XmppConnection connection = mAccount.getXmppConnection();
 360				final boolean wasFirstAccount = xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1;
 361				if (avatar != null || (connection != null && !connection.getFeatures().pep())) {
 362					intent = new Intent(getApplicationContext(), StartConversationActivity.class);
 363					if (wasFirstAccount) {
 364						intent.putExtra("init", true);
 365					}
 366				} else {
 367					intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
 368					intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toBareJid().toString());
 369					intent.putExtra("setup", true);
 370				}
 371				if (wasFirstAccount) {
 372					intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
 373				}
 374				startActivity(intent);
 375				finish();
 376			}
 377		});
 378	}
 379
 380	@Override
 381	public void onActivityResult(int requestCode, int resultCode, Intent data) {
 382		super.onActivityResult(requestCode, resultCode, data);
 383		if (requestCode == REQUEST_BATTERY_OP || requestCode == REQUEST_DATA_SAVER) {
 384			updateAccountInformation(mAccount == null);
 385		}
 386	}
 387
 388	@Override
 389	protected void processFingerprintVerification(XmppUri uri) {
 390		if (mAccount != null && mAccount.getJid().toBareJid().equals(uri.getJid()) && uri.hasFingerprints()) {
 391			if (xmppConnectionService.verifyFingerprints(mAccount,uri.getFingerprints())) {
 392				Toast.makeText(this,R.string.verified_fingerprints,Toast.LENGTH_SHORT).show();
 393			}
 394		} else {
 395			Toast.makeText(this,R.string.invalid_barcode,Toast.LENGTH_SHORT).show();
 396		}
 397	}
 398
 399	protected void updateSaveButton() {
 400		boolean accountInfoEdited = accountInfoEdited();
 401
 402		if (!mInitMode && passwordChangedInMagicCreateMode()) {
 403			this.mSaveButton.setText(R.string.change_password);
 404			this.mSaveButton.setEnabled(true);
 405			this.mSaveButton.setTextColor(getPrimaryTextColor());
 406		} else if (accountInfoEdited && !mInitMode) {
 407			this.mSaveButton.setText(R.string.save);
 408			this.mSaveButton.setEnabled(true);
 409			this.mSaveButton.setTextColor(getPrimaryTextColor());
 410		} else if (mAccount != null
 411				&& (mAccount.getStatus() == Account.State.CONNECTING || mAccount.getStatus() == Account.State.REGISTRATION_SUCCESSFUL|| mFetchingAvatar)) {
 412			this.mSaveButton.setEnabled(false);
 413			this.mSaveButton.setTextColor(getSecondaryTextColor());
 414			this.mSaveButton.setText(R.string.account_status_connecting);
 415		} else if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !mInitMode) {
 416			this.mSaveButton.setEnabled(true);
 417			this.mSaveButton.setTextColor(getPrimaryTextColor());
 418			this.mSaveButton.setText(R.string.enable);
 419		} else {
 420			this.mSaveButton.setEnabled(true);
 421			this.mSaveButton.setTextColor(getPrimaryTextColor());
 422			if (!mInitMode) {
 423				if (mAccount != null && mAccount.isOnlineAndConnected()) {
 424					this.mSaveButton.setText(R.string.save);
 425					if (!accountInfoEdited) {
 426						this.mSaveButton.setEnabled(false);
 427						this.mSaveButton.setTextColor(getSecondaryTextColor());
 428					}
 429				} else {
 430					this.mSaveButton.setText(R.string.connect);
 431				}
 432			} else {
 433				this.mSaveButton.setText(R.string.next);
 434			}
 435		}
 436	}
 437
 438	protected boolean accountInfoEdited() {
 439		if (this.mAccount == null) {
 440			return false;
 441		}
 442		return jidEdited() ||
 443				!this.mAccount.getPassword().equals(this.mPassword.getText().toString()) ||
 444				!this.mAccount.getHostname().equals(this.mHostname.getText().toString()) ||
 445				!String.valueOf(this.mAccount.getPort()).equals(this.mPort.getText().toString());
 446	}
 447
 448	protected boolean jidEdited() {
 449		final String unmodified;
 450		if (mUsernameMode) {
 451			unmodified = this.mAccount.getJid().getLocalpart();
 452		} else {
 453			unmodified = this.mAccount.getJid().toBareJid().toString();
 454		}
 455		return !unmodified.equals(this.mAccountJid.getText().toString());
 456	}
 457
 458	protected boolean passwordChangedInMagicCreateMode() {
 459		return mAccount != null
 460				&& mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)
 461				&& !this.mAccount.getPassword().equals(this.mPassword.getText().toString())
 462				&& !this.jidEdited()
 463				&& mAccount.isOnlineAndConnected();
 464	}
 465
 466	@Override
 467	protected String getShareableUri() {
 468		if (mAccount != null) {
 469			return mAccount.getShareableUri();
 470		} else {
 471			return "";
 472		}
 473	}
 474
 475	@Override
 476	protected void onCreate(final Bundle savedInstanceState) {
 477		super.onCreate(savedInstanceState);
 478		if (savedInstanceState != null) {
 479			this.mSavedInstanceAccount = savedInstanceState.getString("account");
 480			this.mSavedInstanceInit = savedInstanceState.getBoolean("initMode", false);
 481		}
 482		setContentView(R.layout.activity_edit_account);
 483		this.mAccountJid = (AutoCompleteTextView) findViewById(R.id.account_jid);
 484		this.mAccountJid.addTextChangedListener(this.mTextWatcher);
 485		this.mAccountJidLabel = (TextView) findViewById(R.id.account_jid_label);
 486		this.mPassword = (EditText) findViewById(R.id.account_password);
 487		this.mPassword.addTextChangedListener(this.mTextWatcher);
 488		this.mPasswordConfirm = (EditText) findViewById(R.id.account_password_confirm);
 489		this.mAvatar = (ImageView) findViewById(R.id.avater);
 490		this.mAvatar.setOnClickListener(this.mAvatarClickListener);
 491		this.mRegisterNew = (CheckBox) findViewById(R.id.account_register_new);
 492		this.mStats = (LinearLayout) findViewById(R.id.stats);
 493		this.mOsOptimizations = (RelativeLayout) findViewById(R.id.os_optimization);
 494		this.mDisableOsOptimizationsButton = (Button) findViewById(R.id.os_optimization_disable);
 495		this.mDisableOsOptimizationsHeadline = (TextView) findViewById(R.id.os_optimization_headline);
 496		this.getmDisableOsOptimizationsBody = (TextView) findViewById(R.id.os_optimization_body);
 497		this.mSessionEst = (TextView) findViewById(R.id.session_est);
 498		this.mServerInfoRosterVersion = (TextView) findViewById(R.id.server_info_roster_version);
 499		this.mServerInfoCarbons = (TextView) findViewById(R.id.server_info_carbons);
 500		this.mServerInfoMam = (TextView) findViewById(R.id.server_info_mam);
 501		this.mServerInfoCSI = (TextView) findViewById(R.id.server_info_csi);
 502		this.mServerInfoBlocking = (TextView) findViewById(R.id.server_info_blocking);
 503		this.mServerInfoSm = (TextView) findViewById(R.id.server_info_sm);
 504		this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep);
 505		this.mServerInfoHttpUpload = (TextView) findViewById(R.id.server_info_http_upload);
 506		this.mPushRow = (TableRow) findViewById(R.id.push_row);
 507		this.mServerInfoPush = (TextView) findViewById(R.id.server_info_push);
 508		this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint);
 509		this.mOtrFingerprintBox = (RelativeLayout) findViewById(R.id.otr_fingerprint_box);
 510		this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard);
 511		this.mAxolotlFingerprint = (TextView) findViewById(R.id.axolotl_fingerprint);
 512		this.mAxolotlFingerprintBox = (RelativeLayout) findViewById(R.id.axolotl_fingerprint_box);
 513		this.mAxolotlFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_axolotl_to_clipboard);
 514		this.mRegenerateAxolotlKeyButton = (ImageButton) findViewById(R.id.action_regenerate_axolotl_key);
 515		this.mOwnFingerprintDesc = (TextView) findViewById(R.id.own_fingerprint_desc);
 516		this.keysCard = (LinearLayout) findViewById(R.id.other_device_keys_card);
 517		this.keys = (LinearLayout) findViewById(R.id.other_device_keys);
 518		this.mNamePort = (LinearLayout) findViewById(R.id.name_port);
 519		this.mHostname = (EditText) findViewById(R.id.hostname);
 520		this.mHostname.addTextChangedListener(mTextWatcher);
 521		this.mClearDevicesButton = (Button) findViewById(R.id.clear_devices);
 522		this.mClearDevicesButton.setOnClickListener(new OnClickListener() {
 523			@Override
 524			public void onClick(View v) {
 525				showWipePepDialog();
 526			}
 527		});
 528		this.mPort = (EditText) findViewById(R.id.port);
 529		this.mPort.setText("5222");
 530		this.mPort.addTextChangedListener(mTextWatcher);
 531		this.mSaveButton = (Button) findViewById(R.id.save_button);
 532		this.mCancelButton = (Button) findViewById(R.id.cancel_button);
 533		this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener);
 534		this.mCancelButton.setOnClickListener(this.mCancelButtonClickListener);
 535		this.mMoreTable = (TableLayout) findViewById(R.id.server_info_more);
 536		if (savedInstanceState != null && savedInstanceState.getBoolean("showMoreTable")) {
 537			changeMoreTableVisibility(true);
 538		}
 539		final OnCheckedChangeListener OnCheckedShowConfirmPassword = new OnCheckedChangeListener() {
 540			@Override
 541			public void onCheckedChanged(final CompoundButton buttonView,
 542										 final boolean isChecked) {
 543				if (isChecked) {
 544					mPasswordConfirm.setVisibility(View.VISIBLE);
 545				} else {
 546					mPasswordConfirm.setVisibility(View.GONE);
 547				}
 548				updateSaveButton();
 549			}
 550		};
 551		this.mRegisterNew.setOnCheckedChangeListener(OnCheckedShowConfirmPassword);
 552		if (Config.DISALLOW_REGISTRATION_IN_UI) {
 553			this.mRegisterNew.setVisibility(View.GONE);
 554		}
 555	}
 556
 557	@Override
 558	public boolean onCreateOptionsMenu(final Menu menu) {
 559		super.onCreateOptionsMenu(menu);
 560		getMenuInflater().inflate(R.menu.editaccount, menu);
 561		final MenuItem showQrCode = menu.findItem(R.id.action_show_qr_code);
 562		final MenuItem showBlocklist = menu.findItem(R.id.action_show_block_list);
 563		final MenuItem showMoreInfo = menu.findItem(R.id.action_server_info_show_more);
 564		final MenuItem changePassword = menu.findItem(R.id.action_change_password_on_server);
 565		final MenuItem showPassword = menu.findItem(R.id.action_show_password);
 566		final MenuItem renewCertificate = menu.findItem(R.id.action_renew_certificate);
 567		final MenuItem mamPrefs = menu.findItem(R.id.action_mam_prefs);
 568		final MenuItem changePresence = menu.findItem(R.id.action_change_presence);
 569		final MenuItem share = menu.findItem(R.id.action_share);
 570		renewCertificate.setVisible(mAccount != null && mAccount.getPrivateKeyAlias() != null);
 571
 572		share.setVisible(mAccount != null && !mInitMode);
 573
 574		if (mAccount != null && mAccount.isOnlineAndConnected()) {
 575			if (!mAccount.getXmppConnection().getFeatures().blocking()) {
 576				showBlocklist.setVisible(false);
 577			} else {
 578				showBlocklist.setEnabled(mAccount.getBlocklist().size() > 0);
 579			}
 580			if (!mAccount.getXmppConnection().getFeatures().register()) {
 581				changePassword.setVisible(false);
 582			}
 583			mamPrefs.setVisible(mAccount.getXmppConnection().getFeatures().mam());
 584			changePresence.setVisible(manuallyChangePresence());
 585		} else {
 586			showQrCode.setVisible(false);
 587			showBlocklist.setVisible(false);
 588			showMoreInfo.setVisible(false);
 589			changePassword.setVisible(false);
 590			mamPrefs.setVisible(false);
 591			changePresence.setVisible(false);
 592		}
 593
 594		if (mAccount != null) {
 595			showPassword.setVisible(mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)
 596					&& !mAccount.isOptionSet(Account.OPTION_REGISTER));
 597		} else {
 598			showPassword.setVisible(false);
 599		}
 600		return super.onCreateOptionsMenu(menu);
 601	}
 602
 603	@Override
 604	public boolean onPrepareOptionsMenu(Menu menu) {
 605		final MenuItem showMoreInfo = menu.findItem(R.id.action_server_info_show_more);
 606		if (showMoreInfo.isVisible()) {
 607			showMoreInfo.setChecked(mMoreTable.getVisibility() == View.VISIBLE);
 608		}
 609		return super.onPrepareOptionsMenu(menu);
 610	}
 611
 612	@Override
 613	protected void onStart() {
 614		super.onStart();
 615		final int theme = findTheme();
 616		if (this.mTheme != theme) {
 617			recreate();
 618		} else if (getIntent() != null) {
 619			try {
 620				this.jidToEdit = Jid.fromString(getIntent().getStringExtra("jid"));
 621			} catch (final InvalidJidException | NullPointerException ignored) {
 622				this.jidToEdit = null;
 623			}
 624			boolean init = getIntent().getBooleanExtra("init", false);
 625			this.mInitMode = init || this.jidToEdit == null;
 626			this.messageFingerprint = getIntent().getStringExtra("fingerprint");
 627			if (!mInitMode) {
 628				this.mRegisterNew.setVisibility(View.GONE);
 629				if (getActionBar() != null) {
 630					getActionBar().setTitle(getString(R.string.account_details));
 631				}
 632			} else {
 633				this.mAvatar.setVisibility(View.GONE);
 634				ActionBar ab = getActionBar();
 635				if (ab != null) {
 636					if (init && Config.MAGIC_CREATE_DOMAIN == null) {
 637						ab.setDisplayShowHomeEnabled(false);
 638						ab.setDisplayHomeAsUpEnabled(false);
 639					}
 640					ab.setTitle(R.string.action_add_account);
 641				}
 642			}
 643		}
 644		SharedPreferences preferences = getPreferences();
 645		boolean useTor = Config.FORCE_ORBOT || preferences.getBoolean("use_tor", false);
 646		this.mShowOptions = useTor || preferences.getBoolean("show_connection_options", false);
 647		mHostname.setHint(useTor ? R.string.hostname_or_onion : R.string.hostname_example);
 648		this.mNamePort.setVisibility(mShowOptions ? View.VISIBLE : View.GONE);
 649	}
 650
 651	@Override
 652	public void onSaveInstanceState(final Bundle savedInstanceState) {
 653		if (mAccount != null) {
 654			savedInstanceState.putString("account", mAccount.getJid().toBareJid().toString());
 655			savedInstanceState.putBoolean("initMode", mInitMode);
 656			savedInstanceState.putBoolean("showMoreTable", mMoreTable.getVisibility() == View.VISIBLE);
 657		}
 658		super.onSaveInstanceState(savedInstanceState);
 659	}
 660
 661	protected void onBackendConnected() {
 662		boolean init = true;
 663		if (mSavedInstanceAccount != null) {
 664			try {
 665				this.mAccount = xmppConnectionService.findAccountByJid(Jid.fromString(mSavedInstanceAccount));
 666				this.mInitMode = mSavedInstanceInit;
 667				init = false;
 668			} catch (InvalidJidException e) {
 669				this.mAccount = null;
 670			}
 671
 672		} else if (this.jidToEdit != null) {
 673			this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit);
 674		}
 675
 676		if (mAccount != null) {
 677			this.mInitMode |= this.mAccount.isOptionSet(Account.OPTION_REGISTER);
 678			this.mUsernameMode |= mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && mAccount.isOptionSet(Account.OPTION_REGISTER);
 679			if (this.mAccount.getPrivateKeyAlias() != null) {
 680				this.mPassword.setHint(R.string.authenticate_with_certificate);
 681				if (this.mInitMode) {
 682					this.mPassword.requestFocus();
 683				}
 684			}
 685			if (mPendingFingerprintVerificationUri != null) {
 686				processFingerprintVerification(mPendingFingerprintVerificationUri);
 687				mPendingFingerprintVerificationUri = null;
 688			}
 689			updateAccountInformation(init);
 690		}
 691
 692
 693		if (Config.MAGIC_CREATE_DOMAIN == null && this.xmppConnectionService.getAccounts().size() == 0) {
 694			this.mCancelButton.setEnabled(false);
 695			this.mCancelButton.setTextColor(getSecondaryTextColor());
 696		}
 697		if (mUsernameMode) {
 698			this.mAccountJidLabel.setText(R.string.username);
 699			this.mAccountJid.setHint(R.string.username_hint);
 700		} else {
 701			final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
 702					R.layout.simple_list_item,
 703					xmppConnectionService.getKnownHosts());
 704			this.mAccountJid.setAdapter(mKnownHostsAdapter);
 705		}
 706		updateSaveButton();
 707		invalidateOptionsMenu();
 708	}
 709
 710	private String getUserModeDomain() {
 711		if (mAccount != null) {
 712			return mAccount.getJid().getDomainpart();
 713		} else {
 714			return Config.DOMAIN_LOCK;
 715		}
 716	}
 717
 718	@Override
 719	public boolean onOptionsItemSelected(final MenuItem item) {
 720		switch (item.getItemId()) {
 721			case R.id.action_show_block_list:
 722				final Intent showBlocklistIntent = new Intent(this, BlocklistActivity.class);
 723				showBlocklistIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString());
 724				startActivity(showBlocklistIntent);
 725				break;
 726			case R.id.action_server_info_show_more:
 727				changeMoreTableVisibility(!item.isChecked());
 728				break;
 729			case R.id.action_share_barcode:
 730				shareBarcode();
 731				break;
 732			case R.id.action_share_http:
 733				shareLink(true);
 734				break;
 735			case R.id.action_share_uri:
 736				shareLink(false);
 737				break;
 738			case R.id.action_change_password_on_server:
 739				gotoChangePassword(null);
 740				break;
 741			case R.id.action_mam_prefs:
 742				editMamPrefs();
 743				break;
 744			case R.id.action_renew_certificate:
 745				renewCertificate();
 746				break;
 747			case R.id.action_change_presence:
 748				changePresence();
 749				break;
 750			case R.id.action_show_password:
 751				showPassword();
 752				break;
 753		}
 754		return super.onOptionsItemSelected(item);
 755	}
 756
 757	private void shareLink(boolean http) {
 758		Intent intent = new Intent(Intent.ACTION_SEND);
 759		intent.setType("text/plain");
 760		String text;
 761		if (http) {
 762			text = mAccount.getShareableLink();
 763		} else {
 764			text = mAccount.getShareableUri();
 765		}
 766		intent.putExtra(Intent.EXTRA_TEXT,text);
 767		startActivity(Intent.createChooser(intent, getText(R.string.share_with)));
 768	}
 769
 770	private void shareBarcode() {
 771		Intent intent = new Intent(Intent.ACTION_SEND);
 772		intent.putExtra(Intent.EXTRA_STREAM,BarcodeProvider.getUriForAccount(this,mAccount));
 773		intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 774		intent.setType("image/png");
 775		startActivity(Intent.createChooser(intent, getText(R.string.share_with)));
 776	}
 777
 778	private void changeMoreTableVisibility(boolean visible) {
 779		mMoreTable.setVisibility(visible ? View.VISIBLE : View.GONE);
 780	}
 781
 782	private void gotoChangePassword(String newPassword) {
 783		final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
 784		changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString());
 785		if (newPassword != null) {
 786			changePasswordIntent.putExtra("password", newPassword);
 787		}
 788		startActivity(changePasswordIntent);
 789	}
 790
 791	private void renewCertificate() {
 792		KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
 793	}
 794
 795	private void changePresence() {
 796		Intent intent = new Intent(this, SetPresenceActivity.class);
 797		intent.putExtra(SetPresenceActivity.EXTRA_ACCOUNT,mAccount.getJid().toBareJid().toString());
 798		startActivity(intent);
 799	}
 800
 801	@Override
 802	public void alias(String alias) {
 803		if (alias != null) {
 804			xmppConnectionService.updateKeyInAccount(mAccount, alias);
 805		}
 806	}
 807
 808	private void updateAccountInformation(boolean init) {
 809		if (init) {
 810			this.mAccountJid.getEditableText().clear();
 811			if (mUsernameMode) {
 812				this.mAccountJid.getEditableText().append(this.mAccount.getJid().getLocalpart());
 813			} else {
 814				this.mAccountJid.getEditableText().append(this.mAccount.getJid().toBareJid().toString());
 815			}
 816			this.mPassword.setText(this.mAccount.getPassword());
 817			this.mHostname.setText("");
 818			this.mHostname.getEditableText().append(this.mAccount.getHostname());
 819			this.mPort.setText("");
 820			this.mPort.getEditableText().append(String.valueOf(this.mAccount.getPort()));
 821			this.mNamePort.setVisibility(mShowOptions ? View.VISIBLE : View.GONE);
 822
 823		}
 824
 825		if (!mInitMode) {
 826			this.mAvatar.setVisibility(View.VISIBLE);
 827			this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72)));
 828		} else {
 829			this.mAvatar.setVisibility(View.GONE);
 830		}
 831		if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) {
 832			this.mRegisterNew.setVisibility(View.VISIBLE);
 833			this.mRegisterNew.setChecked(true);
 834			this.mPasswordConfirm.setText(this.mAccount.getPassword());
 835		} else {
 836			this.mRegisterNew.setVisibility(View.GONE);
 837			this.mRegisterNew.setChecked(false);
 838		}
 839		if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) {
 840			Features features = this.mAccount.getXmppConnection().getFeatures();
 841			this.mStats.setVisibility(View.VISIBLE);
 842			boolean showBatteryWarning = !xmppConnectionService.getPushManagementService().available(mAccount) && isOptimizingBattery();
 843			boolean showDataSaverWarning = isAffectedByDataSaver();
 844			showOsOptimizationWarning(showBatteryWarning,showDataSaverWarning);
 845			this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(this, this.mAccount.getXmppConnection()
 846					.getLastSessionEstablished()));
 847			if (features.rosterVersioning()) {
 848				this.mServerInfoRosterVersion.setText(R.string.server_info_available);
 849			} else {
 850				this.mServerInfoRosterVersion.setText(R.string.server_info_unavailable);
 851			}
 852			if (features.carbons()) {
 853				this.mServerInfoCarbons.setText(R.string.server_info_available);
 854			} else {
 855				this.mServerInfoCarbons
 856						.setText(R.string.server_info_unavailable);
 857			}
 858			if (features.mam()) {
 859				this.mServerInfoMam.setText(R.string.server_info_available);
 860			} else {
 861				this.mServerInfoMam.setText(R.string.server_info_unavailable);
 862			}
 863			if (features.csi()) {
 864				this.mServerInfoCSI.setText(R.string.server_info_available);
 865			} else {
 866				this.mServerInfoCSI.setText(R.string.server_info_unavailable);
 867			}
 868			if (features.blocking()) {
 869				this.mServerInfoBlocking.setText(R.string.server_info_available);
 870			} else {
 871				this.mServerInfoBlocking.setText(R.string.server_info_unavailable);
 872			}
 873			if (features.sm()) {
 874				this.mServerInfoSm.setText(R.string.server_info_available);
 875			} else {
 876				this.mServerInfoSm.setText(R.string.server_info_unavailable);
 877			}
 878			if (features.pep()) {
 879				AxolotlService axolotlService = this.mAccount.getAxolotlService();
 880				if (axolotlService != null && axolotlService.isPepBroken()) {
 881					this.mServerInfoPep.setText(R.string.server_info_broken);
 882				} else {
 883					this.mServerInfoPep.setText(R.string.server_info_available);
 884				}
 885			} else {
 886				this.mServerInfoPep.setText(R.string.server_info_unavailable);
 887			}
 888			if (features.httpUpload(0)) {
 889				this.mServerInfoHttpUpload.setText(R.string.server_info_available);
 890			} else {
 891				this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable);
 892			}
 893
 894			this.mPushRow.setVisibility(xmppConnectionService.getPushManagementService().isStub() ? View.GONE : View.VISIBLE);
 895
 896			if (xmppConnectionService.getPushManagementService().available(mAccount)) {
 897				this.mServerInfoPush.setText(R.string.server_info_available);
 898			} else {
 899				this.mServerInfoPush.setText(R.string.server_info_unavailable);
 900			}
 901			final String otrFingerprint = this.mAccount.getOtrFingerprint();
 902			if (otrFingerprint != null && Config.supportOtr()) {
 903				this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
 904				this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(otrFingerprint));
 905				this.mOtrFingerprintToClipboardButton
 906						.setVisibility(View.VISIBLE);
 907				this.mOtrFingerprintToClipboardButton
 908						.setOnClickListener(new View.OnClickListener() {
 909
 910							@Override
 911							public void onClick(final View v) {
 912
 913								if (copyTextToClipboard(otrFingerprint, R.string.otr_fingerprint)) {
 914									Toast.makeText(
 915											EditAccountActivity.this,
 916											R.string.toast_message_otr_fingerprint,
 917											Toast.LENGTH_SHORT).show();
 918								}
 919							}
 920						});
 921			} else {
 922				this.mOtrFingerprintBox.setVisibility(View.GONE);
 923			}
 924			final String ownAxolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint();
 925			if (ownAxolotlFingerprint != null && Config.supportOmemo()) {
 926				this.mAxolotlFingerprintBox.setVisibility(View.VISIBLE);
 927				if (ownAxolotlFingerprint.equals(messageFingerprint)) {
 928					this.mOwnFingerprintDesc.setTextColor(getResources().getColor(R.color.accent));
 929				} else {
 930					this.mOwnFingerprintDesc.setTextColor(getSecondaryTextColor());
 931				}
 932				this.mAxolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(ownAxolotlFingerprint.substring(2)));
 933				this.mAxolotlFingerprintToClipboardButton
 934						.setVisibility(View.VISIBLE);
 935				this.mAxolotlFingerprintToClipboardButton
 936						.setOnClickListener(new View.OnClickListener() {
 937
 938							@Override
 939							public void onClick(final View v) {
 940								copyOmemoFingerprint(ownAxolotlFingerprint);
 941							}
 942						});
 943				if (Config.SHOW_REGENERATE_AXOLOTL_KEYS_BUTTON) {
 944					this.mRegenerateAxolotlKeyButton
 945							.setVisibility(View.VISIBLE);
 946					this.mRegenerateAxolotlKeyButton
 947							.setOnClickListener(new View.OnClickListener() {
 948
 949								@Override
 950								public void onClick(final View v) {
 951									showRegenerateAxolotlKeyDialog();
 952								}
 953							});
 954				}
 955			} else {
 956				this.mAxolotlFingerprintBox.setVisibility(View.GONE);
 957			}
 958			boolean hasKeys = false;
 959			keys.removeAllViews();
 960			for(XmppAxolotlSession session : mAccount.getAxolotlService().findOwnSessions()) {
 961				if (!session.getTrust().isCompromised()) {
 962					boolean highlight = session.getFingerprint().equals(messageFingerprint);
 963					addFingerprintRow(keys,session,highlight);
 964					hasKeys = true;
 965				}
 966			}
 967			if (hasKeys && Config.supportOmemo()) {
 968				keysCard.setVisibility(View.VISIBLE);
 969				Set<Integer> otherDevices = mAccount.getAxolotlService().getOwnDeviceIds();
 970				if (otherDevices == null || otherDevices.isEmpty()) {
 971					mClearDevicesButton.setVisibility(View.GONE);
 972				} else {
 973					mClearDevicesButton.setVisibility(View.VISIBLE);
 974				}
 975			} else {
 976				keysCard.setVisibility(View.GONE);
 977			}
 978		} else {
 979			if (this.mAccount.errorStatus()) {
 980				final EditText errorTextField;
 981				if (this.mAccount.getStatus() == Account.State.UNAUTHORIZED) {
 982					errorTextField = this.mPassword;
 983				} else if (mShowOptions
 984						&& this.mAccount.getStatus() == Account.State.SERVER_NOT_FOUND
 985						&& this.mHostname.getText().length() > 0) {
 986					errorTextField = this.mHostname;
 987				} else {
 988					errorTextField = this.mAccountJid;
 989				}
 990				errorTextField.setError(getString(this.mAccount.getStatus().getReadableId()));
 991				if (init || !accountInfoEdited()) {
 992					errorTextField.requestFocus();
 993				}
 994			} else {
 995				this.mAccountJid.setError(null);
 996				this.mPassword.setError(null);
 997				this.mHostname.setError(null);
 998			}
 999			this.mStats.setVisibility(View.GONE);
1000		}
1001	}
1002
1003	private void showOsOptimizationWarning(boolean showBatteryWarning, boolean showDataSaverWarning) {
1004		this.mOsOptimizations.setVisibility(showBatteryWarning || showDataSaverWarning ? View.VISIBLE : View.GONE);
1005		if (showDataSaverWarning) {
1006			this.mDisableOsOptimizationsHeadline.setText(R.string.data_saver_enabled);
1007			this.getmDisableOsOptimizationsBody.setText(R.string.data_saver_enabled_explained);
1008			this.mDisableOsOptimizationsButton.setText(R.string.allow);
1009			this.mDisableOsOptimizationsButton.setOnClickListener(new OnClickListener() {
1010				@Override
1011				public void onClick(View v) {
1012					Intent intent = new Intent(Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS);
1013					Uri uri = Uri.parse("package:"+getPackageName());
1014					intent.setData(uri);
1015					try {
1016						startActivityForResult(intent, REQUEST_DATA_SAVER);
1017					} catch (ActivityNotFoundException e) {
1018						Toast.makeText(EditAccountActivity.this, R.string.device_does_not_support_data_saver, Toast.LENGTH_SHORT).show();
1019					}
1020				}
1021			});
1022		} else if (showBatteryWarning) {
1023			this.mDisableOsOptimizationsButton.setText(R.string.disable);
1024			this.mDisableOsOptimizationsHeadline.setText(R.string.battery_optimizations_enabled);
1025			this.getmDisableOsOptimizationsBody.setText(R.string.battery_optimizations_enabled_explained);
1026			this.mDisableOsOptimizationsButton.setOnClickListener(new OnClickListener() {
1027				@Override
1028				public void onClick(View v) {
1029					Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
1030					Uri uri = Uri.parse("package:"+getPackageName());
1031					intent.setData(uri);
1032					try {
1033						startActivityForResult(intent, REQUEST_BATTERY_OP);
1034					} catch (ActivityNotFoundException e) {
1035						Toast.makeText(EditAccountActivity.this, R.string.device_does_not_support_battery_op, Toast.LENGTH_SHORT).show();
1036					}
1037				}
1038			});
1039		}
1040	}
1041
1042	public void showRegenerateAxolotlKeyDialog() {
1043		Builder builder = new Builder(this);
1044		builder.setTitle("Regenerate Key");
1045		builder.setIconAttribute(android.R.attr.alertDialogIcon);
1046		builder.setMessage("Are you sure you want to regenerate your Identity Key? (This will also wipe all established sessions and contact Identity Keys)");
1047		builder.setNegativeButton(getString(R.string.cancel), null);
1048		builder.setPositiveButton("Yes",
1049				new DialogInterface.OnClickListener() {
1050					@Override
1051					public void onClick(DialogInterface dialog, int which) {
1052						mAccount.getAxolotlService().regenerateKeys(false);
1053					}
1054				});
1055		builder.create().show();
1056	}
1057
1058	public void showWipePepDialog() {
1059		Builder builder = new Builder(this);
1060		builder.setTitle(getString(R.string.clear_other_devices));
1061		builder.setIconAttribute(android.R.attr.alertDialogIcon);
1062		builder.setMessage(getString(R.string.clear_other_devices_desc));
1063		builder.setNegativeButton(getString(R.string.cancel), null);
1064		builder.setPositiveButton(getString(R.string.accept),
1065				new DialogInterface.OnClickListener() {
1066					@Override
1067					public void onClick(DialogInterface dialog, int which) {
1068						mAccount.getAxolotlService().wipeOtherPepDevices();
1069					}
1070				});
1071		builder.create().show();
1072	}
1073
1074	private void editMamPrefs() {
1075		this.mFetchingMamPrefsToast = Toast.makeText(this, R.string.fetching_mam_prefs, Toast.LENGTH_LONG);
1076		this.mFetchingMamPrefsToast.show();
1077		xmppConnectionService.fetchMamPreferences(mAccount, this);
1078	}
1079
1080	private void showPassword() {
1081		AlertDialog.Builder builder = new AlertDialog.Builder(this);
1082		View view = getLayoutInflater().inflate(R.layout.dialog_show_password, null);
1083		TextView password = (TextView) view.findViewById(R.id.password);
1084		password.setText(mAccount.getPassword());
1085		builder.setTitle(R.string.password);
1086		builder.setView(view);
1087		builder.setPositiveButton(R.string.cancel, null);
1088		builder.create().show();
1089	}
1090
1091	@Override
1092	public void onKeyStatusUpdated(AxolotlService.FetchStatus report) {
1093		refreshUi();
1094	}
1095
1096	@Override
1097	public void onCaptchaRequested(final Account account, final String id, final Data data, final Bitmap captcha) {
1098		runOnUiThread(new Runnable() {
1099			@Override
1100			public void run() {
1101				if ((mCaptchaDialog != null) && mCaptchaDialog.isShowing()) {
1102					mCaptchaDialog.dismiss();
1103				}
1104				final AlertDialog.Builder builder = new AlertDialog.Builder(EditAccountActivity.this);
1105				final View view = getLayoutInflater().inflate(R.layout.captcha, null);
1106				final ImageView imageView = (ImageView) view.findViewById(R.id.captcha);
1107				final EditText input = (EditText) view.findViewById(R.id.input);
1108				imageView.setImageBitmap(captcha);
1109
1110				builder.setTitle(getString(R.string.captcha_required));
1111				builder.setView(view);
1112
1113				builder.setPositiveButton(getString(R.string.ok),
1114						new DialogInterface.OnClickListener() {
1115							@Override
1116							public void onClick(DialogInterface dialog, int which) {
1117								String rc = input.getText().toString();
1118								data.put("username", account.getUsername());
1119								data.put("password", account.getPassword());
1120								data.put("ocr", rc);
1121								data.submit();
1122
1123								if (xmppConnectionServiceBound) {
1124									xmppConnectionService.sendCreateAccountWithCaptchaPacket(
1125											account, id, data);
1126								}
1127							}
1128						});
1129				builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
1130					@Override
1131					public void onClick(DialogInterface dialog, int which) {
1132						if (xmppConnectionService != null) {
1133							xmppConnectionService.sendCreateAccountWithCaptchaPacket(account, null, null);
1134						}
1135					}
1136				});
1137
1138				builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
1139					@Override
1140					public void onCancel(DialogInterface dialog) {
1141						if (xmppConnectionService != null) {
1142							xmppConnectionService.sendCreateAccountWithCaptchaPacket(account, null, null);
1143						}
1144					}
1145				});
1146				mCaptchaDialog = builder.create();
1147				mCaptchaDialog.show();
1148			}
1149		});
1150	}
1151
1152	public void onShowErrorToast(final int resId) {
1153		runOnUiThread(new Runnable() {
1154			@Override
1155			public void run() {
1156				Toast.makeText(EditAccountActivity.this, resId, Toast.LENGTH_SHORT).show();
1157			}
1158		});
1159	}
1160
1161	@Override
1162	public void onPreferencesFetched(final Element prefs) {
1163		runOnUiThread(new Runnable() {
1164			@Override
1165			public void run() {
1166				if (mFetchingMamPrefsToast != null) {
1167					mFetchingMamPrefsToast.cancel();
1168				}
1169				AlertDialog.Builder builder = new Builder(EditAccountActivity.this);
1170				builder.setTitle(R.string.server_side_mam_prefs);
1171				String defaultAttr = prefs.getAttribute("default");
1172				final List<String> defaults = Arrays.asList("never", "roster", "always");
1173				final AtomicInteger choice = new AtomicInteger(Math.max(0,defaults.indexOf(defaultAttr)));
1174				builder.setSingleChoiceItems(R.array.mam_prefs, choice.get(), new DialogInterface.OnClickListener() {
1175					@Override
1176					public void onClick(DialogInterface dialog, int which) {
1177						choice.set(which);
1178					}
1179				});
1180				builder.setNegativeButton(R.string.cancel, null);
1181				builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
1182					@Override
1183					public void onClick(DialogInterface dialog, int which) {
1184						prefs.setAttribute("default",defaults.get(choice.get()));
1185						xmppConnectionService.pushMamPreferences(mAccount, prefs);
1186					}
1187				});
1188				builder.create().show();
1189			}
1190		});
1191	}
1192
1193	@Override
1194	public void onPreferencesFetchFailed() {
1195		runOnUiThread(new Runnable() {
1196			@Override
1197			public void run() {
1198				if (mFetchingMamPrefsToast != null) {
1199					mFetchingMamPrefsToast.cancel();
1200				}
1201				Toast.makeText(EditAccountActivity.this,R.string.unable_to_fetch_mam_prefs,Toast.LENGTH_LONG).show();
1202			}
1203		});
1204	}
1205
1206	@Override
1207	public void OnUpdateBlocklist(Status status) {
1208		refreshUi();
1209	}
1210}