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