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}