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