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 invalidateOptionsMenu();
483 }
484
485 @Override
486 public boolean onOptionsItemSelected(final MenuItem item) {
487 switch (item.getItemId()) {
488 case R.id.action_show_block_list:
489 final Intent showBlocklistIntent = new Intent(this, BlocklistActivity.class);
490 showBlocklistIntent.putExtra("account", mAccount.getJid().toString());
491 startActivity(showBlocklistIntent);
492 break;
493 case R.id.action_server_info_show_more:
494 mMoreTable.setVisibility(item.isChecked() ? View.GONE : View.VISIBLE);
495 item.setChecked(!item.isChecked());
496 break;
497 case R.id.action_change_password_on_server:
498 final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
499 changePasswordIntent.putExtra("account", mAccount.getJid().toString());
500 startActivity(changePasswordIntent);
501 break;
502 case R.id.action_clear_devices:
503 showWipePepDialog();
504 break;
505 case R.id.action_renew_certificate:
506 renewCertificate();
507 break;
508 }
509 return super.onOptionsItemSelected(item);
510 }
511
512 private void renewCertificate() {
513 KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
514 }
515
516 @Override
517 public void alias(String alias) {
518 if (alias != null) {
519 xmppConnectionService.updateKeyInAccount(mAccount, alias);
520 }
521 }
522
523 private void updateAccountInformation(boolean init) {
524 if (init) {
525 this.mAccountJid.getEditableText().clear();
526 if (Config.DOMAIN_LOCK != null) {
527 this.mAccountJid.getEditableText().append(this.mAccount.getJid().getLocalpart());
528 } else {
529 this.mAccountJid.getEditableText().append(this.mAccount.getJid().toBareJid().toString());
530 }
531 this.mPassword.setText(this.mAccount.getPassword());
532 }
533 if (!mInitMode) {
534 this.mAvatar.setVisibility(View.VISIBLE);
535 this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72)));
536 }
537 if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) {
538 this.mRegisterNew.setVisibility(View.VISIBLE);
539 this.mRegisterNew.setChecked(true);
540 this.mPasswordConfirm.setText(this.mAccount.getPassword());
541 } else {
542 this.mRegisterNew.setVisibility(View.GONE);
543 this.mRegisterNew.setChecked(false);
544 }
545 if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) {
546 this.mStats.setVisibility(View.VISIBLE);
547 this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(this, this.mAccount.getXmppConnection()
548 .getLastSessionEstablished()));
549 Features features = this.mAccount.getXmppConnection().getFeatures();
550 if (features.rosterVersioning()) {
551 this.mServerInfoRosterVersion.setText(R.string.server_info_available);
552 } else {
553 this.mServerInfoRosterVersion.setText(R.string.server_info_unavailable);
554 }
555 if (features.carbons()) {
556 this.mServerInfoCarbons.setText(R.string.server_info_available);
557 } else {
558 this.mServerInfoCarbons
559 .setText(R.string.server_info_unavailable);
560 }
561 if (features.mam()) {
562 this.mServerInfoMam.setText(R.string.server_info_available);
563 } else {
564 this.mServerInfoMam.setText(R.string.server_info_unavailable);
565 }
566 if (features.csi()) {
567 this.mServerInfoCSI.setText(R.string.server_info_available);
568 } else {
569 this.mServerInfoCSI.setText(R.string.server_info_unavailable);
570 }
571 if (features.blocking()) {
572 this.mServerInfoBlocking.setText(R.string.server_info_available);
573 } else {
574 this.mServerInfoBlocking.setText(R.string.server_info_unavailable);
575 }
576 if (features.sm()) {
577 this.mServerInfoSm.setText(R.string.server_info_available);
578 } else {
579 this.mServerInfoSm.setText(R.string.server_info_unavailable);
580 }
581 if (features.pep()) {
582 AxolotlService axolotlService = this.mAccount.getAxolotlService();
583 if (axolotlService != null && axolotlService.isPepBroken()) {
584 this.mServerInfoPep.setText(R.string.server_info_broken);
585 } else {
586 this.mServerInfoPep.setText(R.string.server_info_available);
587 }
588 } else {
589 this.mServerInfoPep.setText(R.string.server_info_unavailable);
590 }
591 if (features.httpUpload()) {
592 this.mServerInfoHttpUpload.setText(R.string.server_info_available);
593 } else {
594 this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable);
595 }
596 final String otrFingerprint = this.mAccount.getOtrFingerprint();
597 if (otrFingerprint != null) {
598 this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
599 this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(otrFingerprint));
600 this.mOtrFingerprintToClipboardButton
601 .setVisibility(View.VISIBLE);
602 this.mOtrFingerprintToClipboardButton
603 .setOnClickListener(new View.OnClickListener() {
604
605 @Override
606 public void onClick(final View v) {
607
608 if (copyTextToClipboard(otrFingerprint, R.string.otr_fingerprint)) {
609 Toast.makeText(
610 EditAccountActivity.this,
611 R.string.toast_message_otr_fingerprint,
612 Toast.LENGTH_SHORT).show();
613 }
614 }
615 });
616 } else {
617 this.mOtrFingerprintBox.setVisibility(View.GONE);
618 }
619 final String axolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint();
620 if (axolotlFingerprint != null) {
621 this.mAxolotlFingerprintBox.setVisibility(View.VISIBLE);
622 this.mAxolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(axolotlFingerprint));
623 this.mAxolotlFingerprintToClipboardButton
624 .setVisibility(View.VISIBLE);
625 this.mAxolotlFingerprintToClipboardButton
626 .setOnClickListener(new View.OnClickListener() {
627
628 @Override
629 public void onClick(final View v) {
630
631 if (copyTextToClipboard(axolotlFingerprint, R.string.omemo_fingerprint)) {
632 Toast.makeText(
633 EditAccountActivity.this,
634 R.string.toast_message_omemo_fingerprint,
635 Toast.LENGTH_SHORT).show();
636 }
637 }
638 });
639 if (Config.SHOW_REGENERATE_AXOLOTL_KEYS_BUTTON) {
640 this.mRegenerateAxolotlKeyButton
641 .setVisibility(View.VISIBLE);
642 this.mRegenerateAxolotlKeyButton
643 .setOnClickListener(new View.OnClickListener() {
644
645 @Override
646 public void onClick(final View v) {
647 showRegenerateAxolotlKeyDialog();
648 }
649 });
650 }
651 } else {
652 this.mAxolotlFingerprintBox.setVisibility(View.GONE);
653 }
654 final String ownFingerprint = mAccount.getAxolotlService().getOwnFingerprint();
655 boolean hasKeys = false;
656 keys.removeAllViews();
657 for (final String fingerprint : mAccount.getAxolotlService().getFingerprintsForOwnSessions()) {
658 if (ownFingerprint.equals(fingerprint)) {
659 continue;
660 }
661 boolean highlight = fingerprint.equals(messageFingerprint);
662 hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight);
663 }
664 if (hasKeys) {
665 keysCard.setVisibility(View.VISIBLE);
666 } else {
667 keysCard.setVisibility(View.GONE);
668 }
669 } else {
670 if (this.mAccount.errorStatus()) {
671 this.mAccountJid.setError(getString(this.mAccount.getStatus().getReadableId()));
672 if (init || !accountInfoEdited()) {
673 this.mAccountJid.requestFocus();
674 }
675 } else {
676 this.mAccountJid.setError(null);
677 }
678 this.mStats.setVisibility(View.GONE);
679 }
680 }
681
682 public void showRegenerateAxolotlKeyDialog() {
683 Builder builder = new Builder(this);
684 builder.setTitle("Regenerate Key");
685 builder.setIconAttribute(android.R.attr.alertDialogIcon);
686 builder.setMessage("Are you sure you want to regenerate your Identity Key? (This will also wipe all established sessions and contact Identity Keys)");
687 builder.setNegativeButton(getString(R.string.cancel), null);
688 builder.setPositiveButton("Yes",
689 new DialogInterface.OnClickListener() {
690 @Override
691 public void onClick(DialogInterface dialog, int which) {
692 mAccount.getAxolotlService().regenerateKeys(false);
693 }
694 });
695 builder.create().show();
696 }
697
698 public void showWipePepDialog() {
699 Builder builder = new Builder(this);
700 builder.setTitle(getString(R.string.clear_other_devices));
701 builder.setIconAttribute(android.R.attr.alertDialogIcon);
702 builder.setMessage(getString(R.string.clear_other_devices_desc));
703 builder.setNegativeButton(getString(R.string.cancel), null);
704 builder.setPositiveButton(getString(R.string.accept),
705 new DialogInterface.OnClickListener() {
706 @Override
707 public void onClick(DialogInterface dialog, int which) {
708 mAccount.getAxolotlService().wipeOtherPepDevices();
709 }
710 });
711 builder.create().show();
712 }
713
714 @Override
715 public void onKeyStatusUpdated(AxolotlService.FetchStatus report) {
716 refreshUi();
717 }
718
719 @Override
720 public void onCaptchaRequested(final Account account, final String id, final Data data,
721 final Bitmap captcha) {
722 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
723 final ImageView view = new ImageView(this);
724 final LinearLayout layout = new LinearLayout(this);
725 final EditText input = new EditText(this);
726
727 view.setImageBitmap(captcha);
728 view.setScaleType(ImageView.ScaleType.FIT_CENTER);
729
730 input.setHint(getString(R.string.captcha_hint));
731
732 layout.setOrientation(LinearLayout.VERTICAL);
733 layout.addView(view);
734 layout.addView(input);
735
736 builder.setTitle(getString(R.string.captcha_required));
737 builder.setView(layout);
738
739 builder.setPositiveButton(getString(R.string.ok),
740 new DialogInterface.OnClickListener() {
741 @Override
742 public void onClick(DialogInterface dialog, int which) {
743 String rc = input.getText().toString();
744 data.put("username", account.getUsername());
745 data.put("password", account.getPassword());
746 data.put("ocr", rc);
747 data.submit();
748
749 if (xmppConnectionServiceBound) {
750 xmppConnectionService.sendCreateAccountWithCaptchaPacket(
751 account, id, data);
752 }
753 }
754 });
755 builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
756 @Override
757 public void onClick(DialogInterface dialog, int which) {
758 if (xmppConnectionService != null) {
759 xmppConnectionService.sendCreateAccountWithCaptchaPacket(account, null, null);
760 }
761 }
762 });
763
764 builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
765 @Override
766 public void onCancel(DialogInterface dialog) {
767 if (xmppConnectionService != null) {
768 xmppConnectionService.sendCreateAccountWithCaptchaPacket(account, null, null);
769 }
770 }
771 });
772
773 runOnUiThread(new Runnable() {
774 @Override
775 public void run() {
776 if ((mCaptchaDialog != null) && mCaptchaDialog.isShowing()) {
777 mCaptchaDialog.dismiss();
778 }
779 mCaptchaDialog = builder.create();
780 mCaptchaDialog.show();
781 }
782 });
783 }
784
785 public void onShowErrorToast(final int resId) {
786 runOnUiThread(new Runnable() {
787 @Override
788 public void run() {
789 Toast.makeText(EditAccountActivity.this, resId, Toast.LENGTH_SHORT).show();
790 }
791 });
792 }
793}