show login mechanism, sasl 2, bind 2 in server info

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 758 +
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java    |  15 
src/main/res/layout/activity_edit_account.xml                    | 103 
src/main/res/values/strings.xml                                  |   3 
4 files changed, 551 insertions(+), 328 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -40,6 +40,7 @@ import com.google.android.material.color.MaterialColors;
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.textfield.TextInputLayout;
 import com.google.common.base.CharMatcher;
+import com.google.common.base.Strings;
 
 import eu.siacs.conversations.AppSettings;
 import eu.siacs.conversations.Config;
@@ -88,8 +89,14 @@ import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class EditAccountActivity extends OmemoActivity implements OnAccountUpdate, OnUpdateBlocklist,
-        OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnMamPreferencesFetched {
+public class EditAccountActivity extends OmemoActivity
+        implements OnAccountUpdate,
+                OnUpdateBlocklist,
+                OnKeyStatusUpdated,
+                OnCaptchaRequested,
+                KeyChainAliasCallback,
+                XmppConnectionService.OnShowErrorToast,
+                XmppConnectionService.OnMamPreferencesFetched {
 
     public static final String EXTRA_OPENED_FROM_NOTIFICATION = "opened_from_notification";
     public static final String EXTRA_FORCE_REGISTER = "force_register";
@@ -105,37 +112,44 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     private boolean mUsernameMode = false;
     private boolean mShowOptions = false;
     private Account mAccount;
-    private final OnClickListener mCancelButtonClickListener = v -> {
-        deleteAccountAndReturnIfNecessary();
-        finish();
-    };
-    private final UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
+    private final OnClickListener mCancelButtonClickListener =
+            v -> {
+                deleteAccountAndReturnIfNecessary();
+                finish();
+            };
+    private final UiCallback<Avatar> mAvatarFetchCallback =
+            new UiCallback<Avatar>() {
 
-        @Override
-        public void userInputRequired(final PendingIntent pi, final Avatar avatar) {
-            finishInitialSetup(avatar);
-        }
+                @Override
+                public void userInputRequired(final PendingIntent pi, final Avatar avatar) {
+                    finishInitialSetup(avatar);
+                }
 
-        @Override
-        public void success(final Avatar avatar) {
-            finishInitialSetup(avatar);
-        }
+                @Override
+                public void success(final Avatar avatar) {
+                    finishInitialSetup(avatar);
+                }
 
-        @Override
-        public void error(final int errorCode, final Avatar avatar) {
-            finishInitialSetup(avatar);
-        }
-    };
-    private final OnClickListener mAvatarClickListener = new OnClickListener() {
-        @Override
-        public void onClick(final View view) {
-            if (mAccount != null) {
-                final Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
-                intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
-                startActivity(intent);
-            }
-        }
-    };
+                @Override
+                public void error(final int errorCode, final Avatar avatar) {
+                    finishInitialSetup(avatar);
+                }
+            };
+    private final OnClickListener mAvatarClickListener =
+            new OnClickListener() {
+                @Override
+                public void onClick(final View view) {
+                    if (mAccount != null) {
+                        final Intent intent =
+                                new Intent(
+                                        getApplicationContext(),
+                                        PublishProfilePictureActivity.class);
+                        intent.putExtra(
+                                EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
+                        startActivity(intent);
+                    }
+                }
+            };
     private String messageFingerprint;
     private boolean mFetchingAvatar = false;
     private Toast mFetchingMamPrefsToast;
@@ -144,209 +158,263 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     private XmppUri pendingUri = null;
     private boolean mUseTor;
     private ActivityEditAccountBinding binding;
-    private final OnClickListener mSaveButtonClickListener = new OnClickListener() {
-
-        @Override
-        public void onClick(final View v) {
-            final String password = binding.accountPassword.getText().toString();
-            final boolean wasDisabled = mAccount != null && mAccount.getStatus() == Account.State.DISABLED;
-            final boolean accountInfoEdited = accountInfoEdited();
-
-            if (mInitMode && mAccount != null) {
-                mAccount.setOption(Account.OPTION_DISABLED, false);
-            }
-            if (mAccount != null && Arrays.asList(Account.State.DISABLED, Account.State.LOGGED_OUT).contains(mAccount.getStatus()) && !accountInfoEdited) {
-                mAccount.setOption(Account.OPTION_SOFT_DISABLED, false);
-                mAccount.setOption(Account.OPTION_DISABLED, false);
-                if (!xmppConnectionService.updateAccount(mAccount)) {
-                    Toast.makeText(EditAccountActivity.this, R.string.unable_to_update_account, Toast.LENGTH_SHORT).show();
-                }
-                return;
-            }
-            final boolean registerNewAccount;
-            if (mForceRegister != null) {
-                registerNewAccount = mForceRegister;
-            } else {
-                registerNewAccount = binding.accountRegisterNew.isChecked() && !Config.DISALLOW_REGISTRATION_IN_UI;
-            }
-            if (mUsernameMode && binding.accountJid.getText().toString().contains("@")) {
-                binding.accountJidLayout.setError(getString(R.string.invalid_username));
-                removeErrorsOnAllBut(binding.accountJidLayout);
-                binding.accountJid.requestFocus();
-                return;
-            }
+    private final OnClickListener mSaveButtonClickListener =
+            new OnClickListener() {
+
+                @Override
+                public void onClick(final View v) {
+                    final String password = binding.accountPassword.getText().toString();
+                    final boolean wasDisabled =
+                            mAccount != null && mAccount.getStatus() == Account.State.DISABLED;
+                    final boolean accountInfoEdited = accountInfoEdited();
+
+                    if (mInitMode && mAccount != null) {
+                        mAccount.setOption(Account.OPTION_DISABLED, false);
+                    }
+                    if (mAccount != null
+                            && Arrays.asList(Account.State.DISABLED, Account.State.LOGGED_OUT)
+                                    .contains(mAccount.getStatus())
+                            && !accountInfoEdited) {
+                        mAccount.setOption(Account.OPTION_SOFT_DISABLED, false);
+                        mAccount.setOption(Account.OPTION_DISABLED, false);
+                        if (!xmppConnectionService.updateAccount(mAccount)) {
+                            Toast.makeText(
+                                            EditAccountActivity.this,
+                                            R.string.unable_to_update_account,
+                                            Toast.LENGTH_SHORT)
+                                    .show();
+                        }
+                        return;
+                    }
+                    final boolean registerNewAccount;
+                    if (mForceRegister != null) {
+                        registerNewAccount = mForceRegister;
+                    } else {
+                        registerNewAccount =
+                                binding.accountRegisterNew.isChecked()
+                                        && !Config.DISALLOW_REGISTRATION_IN_UI;
+                    }
+                    if (mUsernameMode && binding.accountJid.getText().toString().contains("@")) {
+                        binding.accountJidLayout.setError(getString(R.string.invalid_username));
+                        removeErrorsOnAllBut(binding.accountJidLayout);
+                        binding.accountJid.requestFocus();
+                        return;
+                    }
 
-            XmppConnection connection = mAccount == null ? null : mAccount.getXmppConnection();
-            final boolean startOrbot = mAccount != null && mAccount.getStatus() == Account.State.TOR_NOT_AVAILABLE;
-            if (startOrbot) {
-                if (TorServiceUtils.isOrbotInstalled(EditAccountActivity.this)) {
-                    TorServiceUtils.startOrbot(EditAccountActivity.this, REQUEST_ORBOT);
-                } else {
-                    TorServiceUtils.downloadOrbot(EditAccountActivity.this, REQUEST_ORBOT);
-                }
-                return;
-            }
+                    XmppConnection connection =
+                            mAccount == null ? null : mAccount.getXmppConnection();
+                    final boolean startOrbot =
+                            mAccount != null
+                                    && mAccount.getStatus() == Account.State.TOR_NOT_AVAILABLE;
+                    if (startOrbot) {
+                        if (TorServiceUtils.isOrbotInstalled(EditAccountActivity.this)) {
+                            TorServiceUtils.startOrbot(EditAccountActivity.this, REQUEST_ORBOT);
+                        } else {
+                            TorServiceUtils.downloadOrbot(EditAccountActivity.this, REQUEST_ORBOT);
+                        }
+                        return;
+                    }
 
-            if (inNeedOfSaslAccept()) {
-                mAccount.resetPinnedMechanism();
-                if (!xmppConnectionService.updateAccount(mAccount)) {
-                    Toast.makeText(EditAccountActivity.this, R.string.unable_to_update_account, Toast.LENGTH_SHORT).show();
-                }
-                return;
-            }
+                    if (inNeedOfSaslAccept()) {
+                        mAccount.resetPinnedMechanism();
+                        if (!xmppConnectionService.updateAccount(mAccount)) {
+                            Toast.makeText(
+                                            EditAccountActivity.this,
+                                            R.string.unable_to_update_account,
+                                            Toast.LENGTH_SHORT)
+                                    .show();
+                        }
+                        return;
+                    }
 
-            final boolean openRegistrationUrl = registerNewAccount && !accountInfoEdited && mAccount != null && mAccount.getStatus() == Account.State.REGISTRATION_WEB;
-            final boolean openPaymentUrl = mAccount != null && mAccount.getStatus() == Account.State.PAYMENT_REQUIRED;
-            final boolean redirectionWorthyStatus = openPaymentUrl || openRegistrationUrl;
-            final HttpUrl url = connection != null && redirectionWorthyStatus ? connection.getRedirectionUrl() : null;
-            if (url != null && !wasDisabled) {
-                try {
-                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url.toString())));
-                    return;
-                } catch (ActivityNotFoundException e) {
-                    Toast.makeText(EditAccountActivity.this, R.string.application_found_to_open_website, Toast.LENGTH_SHORT).show();
-                    return;
-                }
-            }
+                    final boolean openRegistrationUrl =
+                            registerNewAccount
+                                    && !accountInfoEdited
+                                    && mAccount != null
+                                    && mAccount.getStatus() == Account.State.REGISTRATION_WEB;
+                    final boolean openPaymentUrl =
+                            mAccount != null
+                                    && mAccount.getStatus() == Account.State.PAYMENT_REQUIRED;
+                    final boolean redirectionWorthyStatus = openPaymentUrl || openRegistrationUrl;
+                    final HttpUrl url =
+                            connection != null && redirectionWorthyStatus
+                                    ? connection.getRedirectionUrl()
+                                    : null;
+                    if (url != null && !wasDisabled) {
+                        try {
+                            startActivity(
+                                    new Intent(Intent.ACTION_VIEW, Uri.parse(url.toString())));
+                            return;
+                        } catch (ActivityNotFoundException e) {
+                            Toast.makeText(
+                                            EditAccountActivity.this,
+                                            R.string.application_found_to_open_website,
+                                            Toast.LENGTH_SHORT)
+                                    .show();
+                            return;
+                        }
+                    }
 
-            final Jid jid;
-            try {
-                if (mUsernameMode) {
-                    jid = Jid.ofEscaped(binding.accountJid.getText().toString(), getUserModeDomain(), null);
-                } else {
-                    jid = Jid.ofEscaped(binding.accountJid.getText().toString());
-                    Resolver.checkDomain(jid);
-                }
-            } catch (final NullPointerException | IllegalArgumentException e) {
-                if (mUsernameMode) {
-                    binding.accountJidLayout.setError(getString(R.string.invalid_username));
-                } else {
-                    binding.accountJidLayout.setError(getString(R.string.invalid_jid));
-                }
-                binding.accountJid.requestFocus();
-                removeErrorsOnAllBut(binding.accountJidLayout);
-                return;
-            }
-            final String hostname;
-            int numericPort = 5222;
-            if (mShowOptions) {
-                hostname = CharMatcher.whitespace().removeFrom(binding.hostname.getText());
-                final String port = CharMatcher.whitespace().removeFrom(binding.port.getText());
-                if (Resolver.invalidHostname(hostname)) {
-                    binding.hostnameLayout.setError(getString(R.string.not_valid_hostname));
-                    binding.hostname.requestFocus();
-                    removeErrorsOnAllBut(binding.hostnameLayout);
-                    return;
-                }
-                if (!hostname.isEmpty()) {
+                    final Jid jid;
                     try {
-                        numericPort = Integer.parseInt(port);
-                        if (numericPort < 0 || numericPort > 65535) {
-                            binding.portLayout.setError(getString(R.string.not_a_valid_port));
-                            removeErrorsOnAllBut(binding.portLayout);
-                            binding.port.requestFocus();
+                        if (mUsernameMode) {
+                            jid =
+                                    Jid.ofEscaped(
+                                            binding.accountJid.getText().toString(),
+                                            getUserModeDomain(),
+                                            null);
+                        } else {
+                            jid = Jid.ofEscaped(binding.accountJid.getText().toString());
+                            Resolver.checkDomain(jid);
+                        }
+                    } catch (final NullPointerException | IllegalArgumentException e) {
+                        if (mUsernameMode) {
+                            binding.accountJidLayout.setError(getString(R.string.invalid_username));
+                        } else {
+                            binding.accountJidLayout.setError(getString(R.string.invalid_jid));
+                        }
+                        binding.accountJid.requestFocus();
+                        removeErrorsOnAllBut(binding.accountJidLayout);
+                        return;
+                    }
+                    final String hostname;
+                    int numericPort = 5222;
+                    if (mShowOptions) {
+                        hostname = CharMatcher.whitespace().removeFrom(binding.hostname.getText());
+                        final String port =
+                                CharMatcher.whitespace().removeFrom(binding.port.getText());
+                        if (Resolver.invalidHostname(hostname)) {
+                            binding.hostnameLayout.setError(getString(R.string.not_valid_hostname));
+                            binding.hostname.requestFocus();
+                            removeErrorsOnAllBut(binding.hostnameLayout);
                             return;
                         }
+                        if (!hostname.isEmpty()) {
+                            try {
+                                numericPort = Integer.parseInt(port);
+                                if (numericPort < 0 || numericPort > 65535) {
+                                    binding.portLayout.setError(
+                                            getString(R.string.not_a_valid_port));
+                                    removeErrorsOnAllBut(binding.portLayout);
+                                    binding.port.requestFocus();
+                                    return;
+                                }
+
+                            } catch (NumberFormatException e) {
+                                binding.portLayout.setError(getString(R.string.not_a_valid_port));
+                                removeErrorsOnAllBut(binding.portLayout);
+                                binding.port.requestFocus();
+                                return;
+                            }
+                        }
+                    } else {
+                        hostname = null;
+                    }
 
-                    } catch (NumberFormatException e) {
-                        binding.portLayout.setError(getString(R.string.not_a_valid_port));
-                        removeErrorsOnAllBut(binding.portLayout);
-                        binding.port.requestFocus();
+                    if (jid.getLocal() == null) {
+                        if (mUsernameMode) {
+                            binding.accountJidLayout.setError(getString(R.string.invalid_username));
+                        } else {
+                            binding.accountJidLayout.setError(getString(R.string.invalid_jid));
+                        }
+                        removeErrorsOnAllBut(binding.accountJidLayout);
+                        binding.accountJid.requestFocus();
                         return;
                     }
+                    if (mAccount != null) {
+                        if (mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
+                            mAccount.setOption(
+                                    Account.OPTION_MAGIC_CREATE,
+                                    mAccount.getPassword().contains(password));
+                        }
+                        mAccount.setJid(jid);
+                        mAccount.setPort(numericPort);
+                        mAccount.setHostname(hostname);
+                        binding.accountJidLayout.setError(null);
+                        mAccount.setPassword(password);
+                        mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
+                        if (!xmppConnectionService.updateAccount(mAccount)) {
+                            Toast.makeText(
+                                            EditAccountActivity.this,
+                                            R.string.unable_to_update_account,
+                                            Toast.LENGTH_SHORT)
+                                    .show();
+                            return;
+                        }
+                    } else {
+                        if (xmppConnectionService.findAccountByJid(jid) != null) {
+                            binding.accountJidLayout.setError(
+                                    getString(R.string.account_already_exists));
+                            removeErrorsOnAllBut(binding.accountJidLayout);
+                            binding.accountJid.requestFocus();
+                            return;
+                        }
+                        mAccount = new Account(jid.asBareJid(), password);
+                        mAccount.setPort(numericPort);
+                        mAccount.setHostname(hostname);
+                        mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
+                        xmppConnectionService.createAccount(mAccount);
+                    }
+                    binding.hostnameLayout.setError(null);
+                    binding.portLayout.setError(null);
+                    if (mAccount.isOnion()) {
+                        Toast.makeText(
+                                        EditAccountActivity.this,
+                                        R.string.audio_video_disabled_tor,
+                                        Toast.LENGTH_LONG)
+                                .show();
+                    }
+                    if (mAccount.isEnabled() && !registerNewAccount && !mInitMode) {
+                        finish();
+                    } else {
+                        updateSaveButton();
+                        updateAccountInformation(true);
+                    }
                 }
-            } else {
-                hostname = null;
-            }
-
-            if (jid.getLocal() == null) {
-                if (mUsernameMode) {
-                    binding.accountJidLayout.setError(getString(R.string.invalid_username));
-                } else {
-                    binding.accountJidLayout.setError(getString(R.string.invalid_jid));
-                }
-                removeErrorsOnAllBut(binding.accountJidLayout);
-                binding.accountJid.requestFocus();
-                return;
-            }
-            if (mAccount != null) {
-                if (mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
-                    mAccount.setOption(Account.OPTION_MAGIC_CREATE, mAccount.getPassword().contains(password));
-                }
-                mAccount.setJid(jid);
-                mAccount.setPort(numericPort);
-                mAccount.setHostname(hostname);
-                binding.accountJidLayout.setError(null);
-                mAccount.setPassword(password);
-                mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
-                if (!xmppConnectionService.updateAccount(mAccount)) {
-                    Toast.makeText(EditAccountActivity.this, R.string.unable_to_update_account, Toast.LENGTH_SHORT).show();
-                    return;
-                }
-            } else {
-                if (xmppConnectionService.findAccountByJid(jid) != null) {
-                    binding.accountJidLayout.setError(getString(R.string.account_already_exists));
-                    removeErrorsOnAllBut(binding.accountJidLayout);
-                    binding.accountJid.requestFocus();
-                    return;
+            };
+    private final TextWatcher mTextWatcher =
+            new TextWatcher() {
+
+                @Override
+                public void onTextChanged(
+                        final CharSequence s, final int start, final int before, final int count) {
+                    updatePortLayout();
+                    updateSaveButton();
                 }
-                mAccount = new Account(jid.asBareJid(), password);
-                mAccount.setPort(numericPort);
-                mAccount.setHostname(hostname);
-                mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
-                xmppConnectionService.createAccount(mAccount);
-            }
-            binding.hostnameLayout.setError(null);
-            binding.portLayout.setError(null);
-            if (mAccount.isOnion()) {
-                Toast.makeText(EditAccountActivity.this, R.string.audio_video_disabled_tor, Toast.LENGTH_LONG).show();
-            }
-            if (mAccount.isEnabled()
-                    && !registerNewAccount
-                    && !mInitMode) {
-                finish();
-            } else {
-                updateSaveButton();
-                updateAccountInformation(true);
-            }
 
-        }
-    };
-    private final TextWatcher mTextWatcher = new TextWatcher() {
-
-        @Override
-        public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
-            updatePortLayout();
-            updateSaveButton();
-        }
-
-        @Override
-        public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
-        }
-
-        @Override
-        public void afterTextChanged(final Editable s) {
-
-        }
-    };
-    private final View.OnFocusChangeListener mEditTextFocusListener = new View.OnFocusChangeListener() {
-        @Override
-        public void onFocusChange(View view, boolean b) {
-            EditText et = (EditText) view;
-            if (b) {
-                int resId = mUsernameMode ? R.string.username : R.string.account_settings_example_jabber_id;
-                if (view.getId() == R.id.hostname) {
-                    resId = mUseTor ? R.string.hostname_or_onion : R.string.hostname_example;
+                @Override
+                public void beforeTextChanged(
+                        final CharSequence s, final int start, final int count, final int after) {}
+
+                @Override
+                public void afterTextChanged(final Editable s) {}
+            };
+    private final View.OnFocusChangeListener mEditTextFocusListener =
+            new View.OnFocusChangeListener() {
+                @Override
+                public void onFocusChange(View view, boolean b) {
+                    EditText et = (EditText) view;
+                    if (b) {
+                        int resId =
+                                mUsernameMode
+                                        ? R.string.username
+                                        : R.string.account_settings_example_jabber_id;
+                        if (view.getId() == R.id.hostname) {
+                            resId =
+                                    mUseTor
+                                            ? R.string.hostname_or_onion
+                                            : R.string.hostname_example;
+                        }
+                        final int res = resId;
+                        new Handler().postDelayed(() -> et.setHint(res), 200);
+                    } else {
+                        et.setHint(null);
+                    }
                 }
-                final int res = resId;
-                new Handler().postDelayed(() -> et.setHint(res), 200);
-            } else {
-                et.setHint(null);
-            }
-        }
-    };
+            };
 
-    private static void setAvailabilityRadioButton(Presence.Status status, DialogPresenceBinding binding) {
+    private static void setAvailabilityRadioButton(
+            Presence.Status status, DialogPresenceBinding binding) {
         if (status == null) {
             binding.online.setChecked(true);
             return;
@@ -380,9 +448,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
 
     public void refreshUiReal() {
         invalidateOptionsMenu();
-        if (mAccount != null
-                && mAccount.getStatus() != Account.State.ONLINE
-                && mFetchingAvatar) {
+        if (mAccount != null && mAccount.getStatus() != Account.State.ONLINE && mFetchingAvatar) {
             Intent intent = new Intent(this, StartConversationActivity.class);
             StartConversationActivity.addInviteUri(intent, getIntent());
             startActivity(intent);
@@ -412,30 +478,41 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     private void deleteAccountAndReturnIfNecessary() {
-        if (mInitMode && mAccount != null && !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)) {
+        if (mInitMode
+                && mAccount != null
+                && !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)) {
             xmppConnectionService.deleteAccount(mAccount);
         }
 
-        final boolean magicCreate = mAccount != null && mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY);
+        final boolean magicCreate =
+                mAccount != null
+                        && mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)
+                        && !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY);
         final Jid jid = mAccount == null ? null : mAccount.getJid();
 
-        if (SignupUtils.isSupportTokenRegistry() && jid != null && magicCreate && !jid.getDomain().equals(Config.MAGIC_CREATE_DOMAIN)) {
+        if (SignupUtils.isSupportTokenRegistry()
+                && jid != null
+                && magicCreate
+                && !jid.getDomain().equals(Config.MAGIC_CREATE_DOMAIN)) {
             final Jid preset;
             if (mAccount.isOptionSet(Account.OPTION_FIXED_USERNAME)) {
                 preset = jid.asBareJid();
             } else {
                 preset = jid.getDomain();
             }
-            final Intent intent = SignupUtils.getTokenRegistrationIntent(this, preset, mAccount.getKey(Account.KEY_PRE_AUTH_REGISTRATION_TOKEN));
+            final Intent intent =
+                    SignupUtils.getTokenRegistrationIntent(
+                            this, preset, mAccount.getKey(Account.KEY_PRE_AUTH_REGISTRATION_TOKEN));
             StartConversationActivity.addInviteUri(intent, getIntent());
             startActivity(intent);
             return;
         }
 
-
-        final List<Account> accounts = xmppConnectionService == null ? null : xmppConnectionService.getAccounts();
+        final List<Account> accounts =
+                xmppConnectionService == null ? null : xmppConnectionService.getAccounts();
         if (accounts != null && accounts.size() == 0 && Config.MAGIC_CREATE_DOMAIN != null) {
-            Intent intent = SignupUtils.getSignUpIntent(this, mForceRegister != null && mForceRegister);
+            Intent intent =
+                    SignupUtils.getSignUpIntent(this, mForceRegister != null && mForceRegister);
             StartConversationActivity.addInviteUri(intent, getIntent());
             startActivity(intent);
         }
@@ -447,29 +524,40 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     protected void finishInitialSetup(final Avatar avatar) {
-        runOnUiThread(() -> {
-            SoftKeyboardUtils.hideSoftKeyboard(EditAccountActivity.this);
-            final Intent intent;
-            final XmppConnection connection = mAccount.getXmppConnection();
-            final boolean wasFirstAccount = xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1;
-            if (avatar != null || (connection != null && !connection.getFeatures().pep())) {
-                intent = new Intent(getApplicationContext(), StartConversationActivity.class);
-                if (wasFirstAccount) {
-                    intent.putExtra("init", true);
-                }
-                intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
-            } else {
-                intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
-                intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
-                intent.putExtra("setup", true);
-            }
-            if (wasFirstAccount) {
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            }
-            StartConversationActivity.addInviteUri(intent, getIntent());
-            startActivity(intent);
-            finish();
-        });
+        runOnUiThread(
+                () -> {
+                    SoftKeyboardUtils.hideSoftKeyboard(EditAccountActivity.this);
+                    final Intent intent;
+                    final XmppConnection connection = mAccount.getXmppConnection();
+                    final boolean wasFirstAccount =
+                            xmppConnectionService != null
+                                    && xmppConnectionService.getAccounts().size() == 1;
+                    if (avatar != null || (connection != null && !connection.getFeatures().pep())) {
+                        intent =
+                                new Intent(
+                                        getApplicationContext(), StartConversationActivity.class);
+                        if (wasFirstAccount) {
+                            intent.putExtra("init", true);
+                        }
+                        intent.putExtra(
+                                EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
+                    } else {
+                        intent =
+                                new Intent(
+                                        getApplicationContext(),
+                                        PublishProfilePictureActivity.class);
+                        intent.putExtra(
+                                EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
+                        intent.putExtra("setup", true);
+                    }
+                    if (wasFirstAccount) {
+                        intent.setFlags(
+                                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                    }
+                    StartConversationActivity.addInviteUri(intent, getIntent());
+                    startActivity(intent);
+                    finish();
+                });
     }
 
     @Override
@@ -498,7 +586,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     protected void processFingerprintVerification(XmppUri uri, boolean showWarningToast) {
-        if (mAccount != null && mAccount.getJid().asBareJid().equals(uri.getJid()) && uri.hasFingerprints()) {
+        if (mAccount != null
+                && mAccount.getJid().asBareJid().equals(uri.getJid())
+                && uri.hasFingerprints()) {
             if (xmppConnectionService.verifyFingerprints(mAccount, uri.getFingerprints())) {
                 Toast.makeText(this, R.string.verified_fingerprints, Toast.LENGTH_SHORT).show();
                 updateAccountInformation(false);
@@ -525,10 +615,14 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             this.binding.saveButton.setText(R.string.save);
             this.binding.saveButton.setEnabled(true);
         } else if (mAccount != null
-                && (mAccount.getStatus() == Account.State.CONNECTING || mAccount.getStatus() == Account.State.REGISTRATION_SUCCESSFUL || mFetchingAvatar)) {
+                && (mAccount.getStatus() == Account.State.CONNECTING
+                        || mAccount.getStatus() == Account.State.REGISTRATION_SUCCESSFUL
+                        || mFetchingAvatar)) {
             this.binding.saveButton.setEnabled(false);
             this.binding.saveButton.setText(R.string.account_status_connecting);
-        } else if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !mInitMode) {
+        } else if (mAccount != null
+                && mAccount.getStatus() == Account.State.DISABLED
+                && !mInitMode) {
             this.binding.saveButton.setEnabled(true);
             this.binding.saveButton.setText(R.string.enable);
         } else if (torNeedsInstall(mAccount)) {
@@ -546,8 +640,14 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                         this.binding.saveButton.setEnabled(false);
                     }
                 } else {
-                    XmppConnection connection = mAccount == null ? null : mAccount.getXmppConnection();
-                    HttpUrl url = connection != null && mAccount.getStatus() == Account.State.PAYMENT_REQUIRED ? connection.getRedirectionUrl() : null;
+                    XmppConnection connection =
+                            mAccount == null ? null : mAccount.getXmppConnection();
+                    HttpUrl url =
+                            connection != null
+                                            && mAccount.getStatus()
+                                                    == Account.State.PAYMENT_REQUIRED
+                                    ? connection.getRedirectionUrl()
+                                    : null;
                     if (url != null) {
                         this.binding.saveButton.setText(R.string.open_website);
                     } else if (inNeedOfSaslAccept()) {
@@ -558,8 +658,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                 }
             } else {
                 XmppConnection connection = mAccount == null ? null : mAccount.getXmppConnection();
-                HttpUrl url = connection != null && mAccount.getStatus() == Account.State.REGISTRATION_WEB ? connection.getRedirectionUrl() : null;
-                if (url != null && this.binding.accountRegisterNew.isChecked() && !accountInfoEdited) {
+                HttpUrl url =
+                        connection != null && mAccount.getStatus() == Account.State.REGISTRATION_WEB
+                                ? connection.getRedirectionUrl()
+                                : null;
+                if (url != null
+                        && this.binding.accountRegisterNew.isChecked()
+                        && !accountInfoEdited) {
                     this.binding.saveButton.setText(R.string.open_website);
                 } else {
                     this.binding.saveButton.setText(R.string.next);
@@ -569,7 +674,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     private boolean torNeedsInstall(final Account account) {
-        return account != null && account.getStatus() == Account.State.TOR_NOT_AVAILABLE && !TorServiceUtils.isOrbotInstalled(this);
+        return account != null
+                && account.getStatus() == Account.State.TOR_NOT_AVAILABLE
+                && !TorServiceUtils.isOrbotInstalled(this);
     }
 
     private boolean torNeedsStart(final Account account) {
@@ -580,10 +687,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         if (this.mAccount == null) {
             return false;
         }
-        return jidEdited() ||
-                !this.mAccount.getPassword().equals(this.binding.accountPassword.getText().toString()) ||
-                !this.mAccount.getHostname().equals(this.binding.hostname.getText().toString()) ||
-                !String.valueOf(this.mAccount.getPort()).equals(this.binding.port.getText().toString());
+        return jidEdited()
+                || !this.mAccount
+                        .getPassword()
+                        .equals(this.binding.accountPassword.getText().toString())
+                || !this.mAccount.getHostname().equals(this.binding.hostname.getText().toString())
+                || !String.valueOf(this.mAccount.getPort())
+                        .equals(this.binding.port.getText().toString());
     }
 
     protected boolean jidEdited() {
@@ -630,7 +740,8 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         if (savedInstanceState != null && savedInstanceState.getBoolean("showMoreTable")) {
             changeMoreTableVisibility(true);
         }
-        final OnCheckedChangeListener OnCheckedShowConfirmPassword = (buttonView, isChecked) -> updateSaveButton();
+        final OnCheckedChangeListener OnCheckedShowConfirmPassword =
+                (buttonView, isChecked) -> updateSaveButton();
         this.binding.accountRegisterNew.setOnCheckedChangeListener(OnCheckedShowConfirmPassword);
         if (Config.DISALLOW_REGISTRATION_IN_UI) {
             this.binding.accountRegisterNew.setVisibility(View.GONE);
@@ -640,18 +751,23 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     private void onEditYourNameClicked(View view) {
-        quickEdit(mAccount.getDisplayName(), R.string.your_name, value -> {
-            final String displayName = value.trim();
-            updateDisplayName(displayName);
-            mAccount.setDisplayName(displayName);
-            xmppConnectionService.publishDisplayName(mAccount);
-            refreshAvatar();
-            return null;
-        }, true);
+        quickEdit(
+                mAccount.getDisplayName(),
+                R.string.your_name,
+                value -> {
+                    final String displayName = value.trim();
+                    updateDisplayName(displayName);
+                    mAccount.setDisplayName(displayName);
+                    xmppConnectionService.publishDisplayName(mAccount);
+                    refreshAvatar();
+                    return null;
+                },
+                true);
     }
 
     private void refreshAvatar() {
-        AvatarWorkerTask.loadAvatar(mAccount, binding.avater, R.dimen.avatar_on_details_screen_size);
+        AvatarWorkerTask.loadAvatar(
+                mAccount, binding.avater, R.dimen.avatar_on_details_screen_size);
     }
 
     @Override
@@ -726,9 +842,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                 }
             }
             boolean init = intent.getBooleanExtra("init", false);
-            boolean openedFromNotification = intent.getBooleanExtra(EXTRA_OPENED_FROM_NOTIFICATION, false);
+            boolean openedFromNotification =
+                    intent.getBooleanExtra(EXTRA_OPENED_FROM_NOTIFICATION, false);
             Log.d(Config.LOGTAG, "extras " + intent.getExtras());
-            this.mForceRegister = intent.hasExtra(EXTRA_FORCE_REGISTER) ? intent.getBooleanExtra(EXTRA_FORCE_REGISTER, false) : null;
+            this.mForceRegister =
+                    intent.hasExtra(EXTRA_FORCE_REGISTER)
+                            ? intent.getBooleanExtra(EXTRA_FORCE_REGISTER, false)
+                            : null;
             Log.d(Config.LOGTAG, "force register=" + mForceRegister);
             this.mInitMode = init || this.jidToEdit == null;
             this.messageFingerprint = intent.getStringExtra("fingerprint");
@@ -738,7 +858,8 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                 configureActionBar(getSupportActionBar(), !openedFromNotification);
             } else {
                 this.binding.avater.setVisibility(View.GONE);
-                configureActionBar(getSupportActionBar(), !(init && Config.MAGIC_CREATE_DOMAIN == null));
+                configureActionBar(
+                        getSupportActionBar(), !(init && Config.MAGIC_CREATE_DOMAIN == null));
                 if (mForceRegister != null) {
                     if (mForceRegister) {
                         setTitle(R.string.register_new_account);
@@ -751,8 +872,16 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             }
         }
         SharedPreferences preferences = getPreferences();
-        mUseTor = QuickConversationsService.isConversations() && preferences.getBoolean("use_tor", getResources().getBoolean(R.bool.use_tor));
-        this.mShowOptions = mUseTor || (QuickConversationsService.isConversations() && preferences.getBoolean("show_connection_options", getResources().getBoolean(R.bool.show_connection_options)));
+        mUseTor =
+                QuickConversationsService.isConversations()
+                        && preferences.getBoolean(
+                                "use_tor", getResources().getBoolean(R.bool.use_tor));
+        this.mShowOptions =
+                mUseTor
+                        || (QuickConversationsService.isConversations()
+                                && preferences.getBoolean(
+                                        "show_connection_options",
+                                        getResources().getBoolean(R.bool.show_connection_options)));
         this.binding.namePort.setVisibility(mShowOptions ? View.VISIBLE : View.GONE);
         if (mForceRegister != null) {
             this.binding.accountRegisterNew.setVisibility(View.GONE);
@@ -767,13 +896,15 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         TextView warning = view.findViewById(R.id.warning);
         warning.setText(R.string.verifying_omemo_keys_trusted_source_account);
         builder.setView(view);
-        builder.setPositiveButton(R.string.continue_btn, (dialog, which) -> {
-            if (isTrustedSource.isChecked()) {
-                processFingerprintVerification(xmppUri, false);
-            } else {
-                finish();
-            }
-        });
+        builder.setPositiveButton(
+                R.string.continue_btn,
+                (dialog, which) -> {
+                    if (isTrustedSource.isChecked()) {
+                        processFingerprintVerification(xmppUri, false);
+                    } else {
+                        finish();
+                    }
+                });
         builder.setNegativeButton(R.string.cancel, (dialog, which) -> finish());
         final var dialog = builder.create();
         dialog.setCanceledOnTouchOutside(false);
@@ -797,9 +928,11 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     @Override
     public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
         if (mAccount != null) {
-            savedInstanceState.putString("account", mAccount.getJid().asBareJid().toEscapedString());
+            savedInstanceState.putString(
+                    "account", mAccount.getJid().asBareJid().toEscapedString());
             savedInstanceState.putBoolean("initMode", mInitMode);
-            savedInstanceState.putBoolean("showMoreTable", binding.serverInfoMore.getVisibility() == View.VISIBLE);
+            savedInstanceState.putBoolean(
+                    "showMoreTable", binding.serverInfoMore.getVisibility() == View.VISIBLE);
         }
         super.onSaveInstanceState(savedInstanceState);
     }
@@ -808,7 +941,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         boolean init = true;
         if (mSavedInstanceAccount != null) {
             try {
-                this.mAccount = xmppConnectionService.findAccountByJid(Jid.ofEscaped(mSavedInstanceAccount));
+                this.mAccount =
+                        xmppConnectionService.findAccountByJid(
+                                Jid.ofEscaped(mSavedInstanceAccount));
                 this.mInitMode = mSavedInstanceInit;
                 init = false;
             } catch (IllegalArgumentException e) {
@@ -821,7 +956,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
 
         if (mAccount != null) {
             this.mInitMode |= this.mAccount.isOptionSet(Account.OPTION_REGISTER);
-            this.mUsernameMode |= mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && mAccount.isOptionSet(Account.OPTION_REGISTER);
+            this.mUsernameMode |=
+                    mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)
+                            && mAccount.isOptionSet(Account.OPTION_REGISTER);
             if (mPendingFingerprintVerificationUri != null) {
                 processFingerprintVerification(mPendingFingerprintVerificationUri, false);
                 mPendingFingerprintVerificationUri = null;
@@ -829,16 +966,18 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             updateAccountInformation(init);
         }
 
-
-        if (Config.MAGIC_CREATE_DOMAIN == null && this.xmppConnectionService.getAccounts().size() == 0) {
+        if (Config.MAGIC_CREATE_DOMAIN == null
+                && this.xmppConnectionService.getAccounts().size() == 0) {
             this.binding.cancelButton.setEnabled(false);
         }
         if (mUsernameMode) {
             this.binding.accountJidLayout.setHint(getString(R.string.username_hint));
         } else {
-            final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
-                    R.layout.item_autocomplete,
-                    xmppConnectionService.getKnownHosts());
+            final KnownHostsAdapter mKnownHostsAdapter =
+                    new KnownHostsAdapter(
+                            this,
+                            R.layout.item_autocomplete,
+                            xmppConnectionService.getKnownHosts());
             this.binding.accountJid.setAdapter(mKnownHostsAdapter);
         }
 
@@ -886,7 +1025,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                 shareLink(false);
                 break;
             case R.id.action_change_password_on_server:
-                gotoChangePassword(null);
+                gotoChangePassword();
                 break;
             case R.id.action_delete_account:
                 deleteAccount();
@@ -905,13 +1044,18 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     private void deleteAccount() {
-        this.deleteAccount(mAccount,()->{
-            finish();
-        });
+        this.deleteAccount(
+                mAccount,
+                () -> {
+                    finish();
+                });
     }
 
     private boolean inNeedOfSaslAccept() {
-        return mAccount != null && mAccount.getLastErrorStatus() == Account.State.DOWNGRADE_ATTACK && mAccount.getPinnedMechanismPriority() >= 0 && !accountInfoEdited();
+        return mAccount != null
+                && mAccount.getLastErrorStatus() == Account.State.DOWNGRADE_ATTACK
+                && mAccount.getPinnedMechanismPriority() >= 0
+                && !accountInfoEdited();
     }
 
     private void shareBarcode() {
@@ -922,16 +1066,14 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         startActivity(Intent.createChooser(intent, getText(R.string.share_with)));
     }
 
-    private void changeMoreTableVisibility(boolean visible) {
+    private void changeMoreTableVisibility(final boolean visible) {
         binding.serverInfoMore.setVisibility(visible ? View.VISIBLE : View.GONE);
+        binding.serverInfoLoginMechanism.setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 
-    private void gotoChangePassword(String newPassword) {
+    private void gotoChangePassword() {
         final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
         changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toEscapedString());
-        if (newPassword != null) {
-            changePasswordIntent.putExtra("password", newPassword);
-        }
         startActivity(changePasswordIntent);
     }
 
@@ -941,9 +1083,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
 
     private void changePresence() {
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-        boolean manualStatus = sharedPreferences.getBoolean(AppSettings.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence));
+        boolean manualStatus =
+                sharedPreferences.getBoolean(
+                        AppSettings.MANUALLY_CHANGE_PRESENCE,
+                        getResources().getBoolean(R.bool.manually_change_presence));
         final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
-        final DialogPresenceBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_presence, null, false);
+        final DialogPresenceBinding binding =
+                DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_presence, null, false);
         String current = mAccount.getPresenceStatusMessage();
         if (current != null && !current.trim().isEmpty()) {
             binding.statusMessage.append(current);

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -2981,6 +2981,21 @@ public class XmppConnection implements Runnable {
             }
         }
 
+        public boolean bind2() {
+            final var loginInfo = XmppConnection.this.loginInfo;
+            return loginInfo != null && !loginInfo.inlineBindFeatures.isEmpty();
+        }
+
+        public boolean sasl2() {
+            final var loginInfo = XmppConnection.this.loginInfo;
+            return loginInfo != null && loginInfo.saslVersion == SaslMechanism.Version.SASL_2;
+        }
+
+        public String loginMechanism() {
+            final var loginInfo = XmppConnection.this.loginInfo;
+            return loginInfo == null ? null : loginInfo.saslMechanism.getMechanism();
+        }
+
         public boolean pepPublishOptions() {
             return hasDiscoFeature(account.getJid().asBareJid(), Namespace.PUBSUB_PUBLISH_OPTIONS);
         }

src/main/res/layout/activity_edit_account.xml 🔗

@@ -244,7 +244,36 @@
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
                                     android:layout_gravity="end"
-                                    android:paddingLeft="4dp"
+                                    android:textAppearance="?textAppearanceBodyMedium" />
+                            </TableRow>
+
+                        </TableLayout>
+
+                        <TableLayout
+                            android:id="@+id/server_info_login_mechanism"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:shrinkColumns="0"
+                            android:stretchColumns="1"
+                            android:visibility="gone">
+
+                            <TableRow
+                                android:layout_width="fill_parent"
+                                android:layout_height="wrap_content">
+
+                                <TextView
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:ellipsize="end"
+                                    android:singleLine="true"
+                                    android:text="@string/server_info_login_mechanism"
+                                    android:textAppearance="?textAppearanceBodyMedium" />
+
+                                <TextView
+                                    android:id="@+id/login_mechanism"
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium" />
                             </TableRow>
 
@@ -274,8 +303,7 @@
                                     android:id="@+id/server_info_pep"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -296,8 +324,7 @@
                                     android:id="@+id/server_info_blocking"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -318,8 +345,7 @@
                                     android:id="@+id/server_info_sm"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -340,8 +366,7 @@
                                     android:id="@+id/server_info_external_service"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -362,8 +387,7 @@
                                     android:id="@+id/server_info_roster_version"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -384,8 +408,7 @@
                                     android:id="@+id/server_info_carbons"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -406,8 +429,7 @@
                                     android:id="@+id/server_info_mam"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -428,8 +450,7 @@
                                     android:id="@+id/server_info_csi"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium"
                                     tools:ignore="RtlHardcoded" />
                             </TableRow>
@@ -451,8 +472,7 @@
                                     android:id="@+id/server_info_push"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium" />
                             </TableRow>
 
@@ -461,7 +481,6 @@
                                 android:layout_height="wrap_content">
 
                                 <TextView
-                                    android:id="@+id/server_info_http_upload_description"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
                                     android:ellipsize="end"
@@ -473,10 +492,50 @@
                                     android:id="@+id/server_info_http_upload"
                                     android:layout_width="wrap_content"
                                     android:layout_height="wrap_content"
-                                    android:layout_gravity="right"
-                                    android:paddingLeft="4dp"
+                                    android:layout_gravity="end"
+                                    android:textAppearance="?textAppearanceBodyMedium" />
+                            </TableRow>
+
+                            <TableRow
+                                android:layout_width="fill_parent"
+                                android:layout_height="wrap_content">
+
+                                <TextView
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:ellipsize="end"
+                                    android:singleLine="true"
+                                    android:text="@string/server_info_bind2"
+                                    android:textAppearance="?textAppearanceBodyMedium" />
+
+                                <TextView
+                                    android:id="@+id/server_info_bind2"
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:layout_gravity="end"
                                     android:textAppearance="?textAppearanceBodyMedium" />
                             </TableRow>
+
+                            <TableRow
+                                android:layout_width="fill_parent"
+                                android:layout_height="wrap_content">
+
+                                <TextView
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:ellipsize="end"
+                                    android:singleLine="true"
+                                    android:text="@string/server_info_sasl2"
+                                    android:textAppearance="?textAppearanceBodyMedium" />
+
+                                <TextView
+                                    android:id="@+id/server_info_sasl2"
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:layout_gravity="end"
+                                    android:textAppearance="?textAppearanceBodyMedium" />
+                            </TableRow>
+
                         </TableLayout>
 
                         <RelativeLayout

src/main/res/values/strings.xml 🔗

@@ -201,6 +201,8 @@
     <string name="server_info_external_service_discovery">XEP-0215: External Service Discovery</string>
     <string name="server_info_pep">XEP-0163: PEP (Avatars / OMEMO)</string>
     <string name="server_info_http_upload">XEP-0363: HTTP File Upload</string>
+    <string name="server_info_bind2">XEP-0386: Bind 2</string>
+    <string name="server_info_sasl2">XEP-0388: Extensible SASL Profile</string>
     <string name="server_info_push">XEP-0357: Push</string>
     <string name="server_info_available">available</string>
     <string name="server_info_unavailable">unavailable</string>
@@ -1079,4 +1081,5 @@
     <string name="flip_camera">Flip camera</string>
     <string name="video_is_enabled_tap_to_disable">Video is enabled. Tap to disable.</string>
     <string name="video_is_disabled_tap_to_enable">Video is disabled. Tap to enable.</string>
+    <string name="server_info_login_mechanism">Login mechanism</string>
 </resources>