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