store connection settings after pressing submit in hostname fragment
This commit is contained in:
parent
99c11fba17
commit
d54978f593
|
@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData;
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Insert;
|
import androidx.room.Insert;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
|
import androidx.room.Transaction;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import im.conversations.android.database.entity.AccountEntity;
|
import im.conversations.android.database.entity.AccountEntity;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
|
@ -13,64 +14,80 @@ import java.util.List;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public interface AccountDao {
|
public abstract class AccountDao {
|
||||||
|
|
||||||
@Query("SELECT EXISTS (SELECT id FROM account WHERE address=:address)")
|
@Query("SELECT EXISTS (SELECT id FROM account WHERE address=:address)")
|
||||||
boolean hasAccount(BareJid address);
|
public abstract boolean hasAccount(BareJid address);
|
||||||
|
|
||||||
@Query("SELECT NOT EXISTS (SELECT id FROM account)")
|
@Query("SELECT NOT EXISTS (SELECT id FROM account)")
|
||||||
LiveData<Boolean> hasNoAccounts();
|
public abstract LiveData<Boolean> hasNoAccounts();
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
long insert(final AccountEntity account);
|
public abstract long insert(final AccountEntity account);
|
||||||
|
|
||||||
@Query("SELECT id,address,randomSeed FROM account WHERE enabled = 1")
|
@Query("SELECT id,address,randomSeed FROM account WHERE enabled = 1")
|
||||||
ListenableFuture<List<Account>> getEnabledAccounts();
|
public abstract ListenableFuture<List<Account>> getEnabledAccounts();
|
||||||
|
|
||||||
@Query("SELECT id,address,randomSeed FROM account WHERE address=:address AND enabled=1")
|
@Query("SELECT id,address,randomSeed FROM account WHERE address=:address AND enabled=1")
|
||||||
ListenableFuture<Account> getEnabledAccount(BareJid address);
|
public abstract ListenableFuture<Account> getEnabledAccount(BareJid address);
|
||||||
|
|
||||||
@Query("SELECT id,address,randomSeed FROM account WHERE id=:id AND enabled=1")
|
@Query("SELECT id,address,randomSeed FROM account WHERE id=:id AND enabled=1")
|
||||||
ListenableFuture<Account> getEnabledAccount(long id);
|
public abstract ListenableFuture<Account> getEnabledAccount(long id);
|
||||||
|
|
||||||
@Query("SELECT id,address FROM account")
|
@Query("SELECT id,address FROM account")
|
||||||
LiveData<List<AccountIdentifier>> getAccounts();
|
public abstract LiveData<List<AccountIdentifier>> getAccounts();
|
||||||
|
|
||||||
@Query("SELECT hostname,port,directTls FROM account WHERE id=:id AND hostname != null")
|
@Query("SELECT hostname,port,directTls FROM account WHERE id=:id AND hostname IS NOT null")
|
||||||
Connection getConnectionSettings(long id);
|
public abstract Connection getConnectionSettings(long id);
|
||||||
|
|
||||||
@Query("SELECT resource FROM account WHERE id=:id")
|
@Query("SELECT resource FROM account WHERE id=:id")
|
||||||
String getResource(long id);
|
public abstract String getResource(long id);
|
||||||
|
|
||||||
@Query("SELECT rosterVersion FROM account WHERE id=:id")
|
@Query("SELECT rosterVersion FROM account WHERE id=:id")
|
||||||
String getRosterVersion(long id);
|
public abstract String getRosterVersion(long id);
|
||||||
|
|
||||||
@Query("SELECT quickStartAvailable FROM account where id=:id")
|
@Query("SELECT quickStartAvailable FROM account where id=:id")
|
||||||
boolean quickStartAvailable(long id);
|
public abstract boolean quickStartAvailable(long id);
|
||||||
|
|
||||||
@Query("SELECT loginAndBind FROM account where id=:id")
|
@Query("SELECT loginAndBind FROM account where id=:id")
|
||||||
boolean loginAndBind(long id);
|
public abstract boolean loginAndBind(long id);
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"UPDATE account set quickStartAvailable=:available WHERE id=:id AND"
|
"UPDATE account set quickStartAvailable=:available WHERE id=:id AND"
|
||||||
+ " quickStartAvailable != :available")
|
+ " quickStartAvailable != :available")
|
||||||
void setQuickStartAvailable(long id, boolean available);
|
public abstract void setQuickStartAvailable(long id, boolean available);
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"UPDATE account set loginAndBind=:loginAndBind WHERE id=:id AND"
|
"UPDATE account set loginAndBind=:loginAndBind WHERE id=:id AND"
|
||||||
+ " loginAndBind != :loginAndBind")
|
+ " loginAndBind != :loginAndBind")
|
||||||
void setLoginAndBind(long id, boolean loginAndBind);
|
public abstract void setLoginAndBind(long id, boolean loginAndBind);
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"UPDATE account set showErrorNotification=:showErrorNotification WHERE id=:id AND"
|
"UPDATE account set showErrorNotification=:showErrorNotification WHERE id=:id AND"
|
||||||
+ " showErrorNotification != :showErrorNotification")
|
+ " showErrorNotification != :showErrorNotification")
|
||||||
int setShowErrorNotification(long id, boolean showErrorNotification);
|
public abstract int setShowErrorNotification(long id, boolean showErrorNotification);
|
||||||
|
|
||||||
@Query("UPDATE account set resource=:resource WHERE id=:id")
|
@Query("UPDATE account set resource=:resource WHERE id=:id")
|
||||||
void setResource(long id, String resource);
|
public abstract void setResource(long id, String resource);
|
||||||
|
|
||||||
@Query("DELETE FROM account WHERE id=:id")
|
@Query("DELETE FROM account WHERE id=:id")
|
||||||
int delete(long id);
|
public abstract int delete(long id);
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"UPDATE account SET hostname=:hostname, port=:port, directTls=:directTls WHERE"
|
||||||
|
+ " id=:account")
|
||||||
|
protected abstract int setConnection(
|
||||||
|
long account, String hostname, int port, boolean directTls);
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public void setConnection(final Account account, final Connection connection) {
|
||||||
|
final var count =
|
||||||
|
setConnection(
|
||||||
|
account.id, connection.hostname, connection.port, connection.directTls);
|
||||||
|
if (count != 1) {
|
||||||
|
throw new IllegalStateException("Could not update account");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO on disable set resource to null
|
// TODO on disable set resource to null
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package im.conversations.android.database.model;
|
package im.conversations.android.database.model;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
|
||||||
public class Connection {
|
public class Connection {
|
||||||
|
|
||||||
public final String hostname;
|
public final String hostname;
|
||||||
|
@ -11,4 +13,13 @@ public class Connection {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.directTls = directTls;
|
this.directTls = directTls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("hostname", hostname)
|
||||||
|
.add("port", port)
|
||||||
|
.add("directTls", directTls)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import im.conversations.android.database.CredentialStore;
|
||||||
import im.conversations.android.database.entity.AccountEntity;
|
import im.conversations.android.database.entity.AccountEntity;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
import im.conversations.android.database.model.AccountIdentifier;
|
import im.conversations.android.database.model.AccountIdentifier;
|
||||||
|
import im.conversations.android.database.model.Connection;
|
||||||
import im.conversations.android.xmpp.ConnectionPool;
|
import im.conversations.android.xmpp.ConnectionPool;
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.manager.RegistrationManager;
|
import im.conversations.android.xmpp.manager.RegistrationManager;
|
||||||
|
@ -74,7 +75,7 @@ public class AccountRepository extends AbstractRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListenableFuture<Void> deleteAccountAsync(@NonNull Account account) {
|
public ListenableFuture<Void> deleteAccountAsync(@NonNull Account account) {
|
||||||
return Futures.submit(() -> deleteAccount(account), IO_EXECUTOR);
|
return Futures.submit(() -> deleteAccount(account), database.getQueryExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Void deleteAccount(@NonNull Account account) {
|
private Void deleteAccount(@NonNull Account account) {
|
||||||
|
@ -86,7 +87,7 @@ public class AccountRepository extends AbstractRepository {
|
||||||
public ListenableFuture<XmppConnection> getConnectedFuture(@NonNull final Account account) {
|
public ListenableFuture<XmppConnection> getConnectedFuture(@NonNull final Account account) {
|
||||||
final var optional = ConnectionPool.getInstance(context).get(account);
|
final var optional = ConnectionPool.getInstance(context).get(account);
|
||||||
if (optional.isPresent()) {
|
if (optional.isPresent()) {
|
||||||
return optional.get().asConnectedFuture();
|
return optional.get().asConnectedFuture(false);
|
||||||
} else {
|
} else {
|
||||||
return Futures.immediateFailedFuture(
|
return Futures.immediateFailedFuture(
|
||||||
new IllegalStateException(
|
new IllegalStateException(
|
||||||
|
@ -106,6 +107,18 @@ public class AccountRepository extends AbstractRepository {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ListenableFuture<Account> setConnectionAsync(
|
||||||
|
final Account account, final Connection connection) {
|
||||||
|
return Futures.submit(
|
||||||
|
() -> setConnection(account, connection), database.getQueryExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account setConnection(final Account account, final Connection connection) {
|
||||||
|
database.accountDao().setConnection(account, connection);
|
||||||
|
ConnectionPool.getInstance(context).reconnect(account);
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
public void reconnect(final Account account) {
|
public void reconnect(final Account account) {
|
||||||
ConnectionPool.getInstance(context).reconnect(account);
|
ConnectionPool.getInstance(context).reconnect(account);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.os.Bundle;
|
||||||
import androidx.databinding.DataBindingUtil;
|
import androidx.databinding.DataBindingUtil;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.navigation.NavController;
|
import androidx.navigation.NavController;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import im.conversations.android.R;
|
import im.conversations.android.R;
|
||||||
import im.conversations.android.SetupNavigationDirections;
|
import im.conversations.android.SetupNavigationDirections;
|
||||||
import im.conversations.android.databinding.ActivitySetupBinding;
|
import im.conversations.android.databinding.ActivitySetupBinding;
|
||||||
|
@ -30,9 +31,19 @@ public class SetupActivity extends BaseActivity {
|
||||||
new ViewModelProvider(this, getDefaultViewModelProviderFactory());
|
new ViewModelProvider(this, getDefaultViewModelProviderFactory());
|
||||||
this.setupViewModel = viewModelProvider.get(SetupViewModel.class);
|
this.setupViewModel = viewModelProvider.get(SetupViewModel.class);
|
||||||
this.setupViewModel.getRedirection().observe(this, this::onRedirectionEvent);
|
this.setupViewModel.getRedirection().observe(this, this::onRedirectionEvent);
|
||||||
|
this.setupViewModel.getGenericErrorEvent().observe(this, this::onGenericErrorEvent);
|
||||||
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
|
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onGenericErrorEvent(final Event<String> errorEvent) {
|
||||||
|
if (errorEvent.isConsumable()) {
|
||||||
|
new MaterialAlertDialogBuilder(this)
|
||||||
|
.setMessage(errorEvent.consume())
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onRedirectionEvent(final Event<SetupViewModel.Target> targetEvent) {
|
private void onRedirectionEvent(final Event<SetupViewModel.Target> targetEvent) {
|
||||||
if (targetEvent.isConsumable()) {
|
if (targetEvent.isConsumable()) {
|
||||||
final NavController navController = getNavController();
|
final NavController navController = getNavController();
|
||||||
|
|
|
@ -6,19 +6,24 @@ import androidx.lifecycle.AndroidViewModel;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.Transformations;
|
import androidx.lifecycle.Transformations;
|
||||||
|
import com.google.common.base.CharMatcher;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import im.conversations.android.R;
|
import im.conversations.android.R;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
|
import im.conversations.android.database.model.Connection;
|
||||||
import im.conversations.android.repository.AccountRepository;
|
import im.conversations.android.repository.AccountRepository;
|
||||||
import im.conversations.android.ui.Event;
|
import im.conversations.android.ui.Event;
|
||||||
|
import im.conversations.android.util.ConnectionStates;
|
||||||
import im.conversations.android.xmpp.ConnectionException;
|
import im.conversations.android.xmpp.ConnectionException;
|
||||||
import im.conversations.android.xmpp.ConnectionState;
|
import im.conversations.android.xmpp.ConnectionState;
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
@ -35,8 +40,12 @@ public class SetupViewModel extends AndroidViewModel {
|
||||||
private final MutableLiveData<String> password = new MutableLiveData<>();
|
private final MutableLiveData<String> password = new MutableLiveData<>();
|
||||||
private final MutableLiveData<String> passwordError = new MutableLiveData<>();
|
private final MutableLiveData<String> passwordError = new MutableLiveData<>();
|
||||||
private final MutableLiveData<String> hostname = new MutableLiveData<>();
|
private final MutableLiveData<String> hostname = new MutableLiveData<>();
|
||||||
|
private final MutableLiveData<String> hostnameError = new MutableLiveData<>();
|
||||||
private final MutableLiveData<String> port = new MutableLiveData<>();
|
private final MutableLiveData<String> port = new MutableLiveData<>();
|
||||||
|
private final MutableLiveData<String> portError = new MutableLiveData<>();
|
||||||
private final MutableLiveData<Boolean> opportunisticTls = new MutableLiveData<>();
|
private final MutableLiveData<Boolean> opportunisticTls = new MutableLiveData<>();
|
||||||
|
|
||||||
|
private final MutableLiveData<Event<String>> genericErrorEvent = new MutableLiveData<>();
|
||||||
private final MutableLiveData<Boolean> loading = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> loading = new MutableLiveData<>(false);
|
||||||
|
|
||||||
private final MutableLiveData<Event<Target>> redirection = new MutableLiveData<>();
|
private final MutableLiveData<Event<Target>> redirection = new MutableLiveData<>();
|
||||||
|
@ -54,6 +63,9 @@ public class SetupViewModel extends AndroidViewModel {
|
||||||
.observeForever(s -> xmppAddressError.postValue(null));
|
.observeForever(s -> xmppAddressError.postValue(null));
|
||||||
Transformations.distinctUntilChanged(password)
|
Transformations.distinctUntilChanged(password)
|
||||||
.observeForever(s -> passwordError.postValue(null));
|
.observeForever(s -> passwordError.postValue(null));
|
||||||
|
Transformations.distinctUntilChanged(port).observeForever(s -> portError.postValue(null));
|
||||||
|
Transformations.distinctUntilChanged(hostname)
|
||||||
|
.observeForever(s -> hostnameError.postValue(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Boolean> isLoading() {
|
public LiveData<Boolean> isLoading() {
|
||||||
|
@ -76,10 +88,18 @@ public class SetupViewModel extends AndroidViewModel {
|
||||||
return hostname;
|
return hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<String> getHostnameError() {
|
||||||
|
return this.hostnameError;
|
||||||
|
}
|
||||||
|
|
||||||
public MutableLiveData<String> getPort() {
|
public MutableLiveData<String> getPort() {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<String> getPortError() {
|
||||||
|
return this.portError;
|
||||||
|
}
|
||||||
|
|
||||||
public MutableLiveData<Boolean> getOpportunisticTls() {
|
public MutableLiveData<Boolean> getOpportunisticTls() {
|
||||||
return this.opportunisticTls;
|
return this.opportunisticTls;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +108,10 @@ public class SetupViewModel extends AndroidViewModel {
|
||||||
return Transformations.distinctUntilChanged(this.passwordError);
|
return Transformations.distinctUntilChanged(this.passwordError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<Event<String>> getGenericErrorEvent() {
|
||||||
|
return this.genericErrorEvent;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean submitXmppAddress() {
|
public boolean submitXmppAddress() {
|
||||||
final var account = this.account;
|
final var account = this.account;
|
||||||
final var userInput = Strings.nullToEmpty(this.xmppAddress.getValue()).trim();
|
final var userInput = Strings.nullToEmpty(this.xmppAddress.getValue()).trim();
|
||||||
|
@ -111,6 +135,14 @@ public class SetupViewModel extends AndroidViewModel {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
this.account = null;
|
this.account = null;
|
||||||
|
|
||||||
|
// when the XMPP address changes we want to reset connection info too
|
||||||
|
// this is partially to indicate that Conversations might not actually use those
|
||||||
|
// connection settings if the connection works without them
|
||||||
|
this.hostname.setValue(null);
|
||||||
|
this.port.setValue(null);
|
||||||
|
this.opportunisticTls.setValue(false);
|
||||||
|
|
||||||
this.accountRepository.deleteAccountAsync(account);
|
this.accountRepository.deleteAccountAsync(account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +242,8 @@ public class SetupViewModel extends AndroidViewModel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO show generic error
|
this.genericErrorEvent.postValue(
|
||||||
|
new Event<>(getApplication().getString(ConnectionStates.toStringRes(state))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean redirectIfNecessary(final Target current, final Target next) {
|
private boolean redirectIfNecessary(final Target current, final Target next) {
|
||||||
|
@ -231,7 +264,37 @@ public class SetupViewModel extends AndroidViewModel {
|
||||||
this.redirectIfNecessary(Target.ENTER_HOSTNAME, Target.ENTER_ADDRESS);
|
this.redirectIfNecessary(Target.ENTER_HOSTNAME, Target.ENTER_ADDRESS);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
final String hostname =
|
||||||
|
Strings.nullToEmpty(this.hostname.getValue()).trim().toLowerCase(Locale.ROOT);
|
||||||
|
if (hostname.isEmpty() || CharMatcher.whitespace().matchesAnyOf(hostname)) {
|
||||||
|
this.hostnameError.postValue(getApplication().getString(R.string.not_valid_hostname));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final Integer port = Ints.tryParse(Strings.nullToEmpty(this.port.getValue()));
|
||||||
|
if (port == null || port < 0 || port > 65535) {
|
||||||
|
this.portError.postValue(getApplication().getString(R.string.invalid));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final boolean directTls = Boolean.FALSE.equals(this.opportunisticTls.getValue());
|
||||||
|
final var connection = new Connection(hostname, port, directTls);
|
||||||
|
final var setConnectionFuture =
|
||||||
|
this.accountRepository.setConnectionAsync(account, connection);
|
||||||
|
this.setCurrentOperation(setConnectionFuture);
|
||||||
|
Futures.addCallback(
|
||||||
|
setConnectionFuture,
|
||||||
|
new FutureCallback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final Account result) {
|
||||||
|
decideNextStep(Target.ENTER_HOSTNAME, account);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Throwable throwable) {
|
||||||
|
loading.postValue(false);
|
||||||
|
// TODO error message?!
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MoreExecutors.directExecutor());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package im.conversations.android.util;
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
import im.conversations.android.R;
|
||||||
|
import im.conversations.android.xmpp.ConnectionState;
|
||||||
|
|
||||||
|
public final class ConnectionStates {
|
||||||
|
|
||||||
|
private ConnectionStates() {
|
||||||
|
throw new IllegalStateException("Do not instantiate me");
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
public static int toStringRes(final ConnectionState state) {
|
||||||
|
switch (state) {
|
||||||
|
case ONLINE:
|
||||||
|
return R.string.account_status_online;
|
||||||
|
case CONNECTING:
|
||||||
|
return R.string.account_status_connecting;
|
||||||
|
case OFFLINE:
|
||||||
|
return R.string.account_status_offline;
|
||||||
|
case UNAUTHORIZED:
|
||||||
|
return R.string.account_status_unauthorized;
|
||||||
|
case SERVER_NOT_FOUND:
|
||||||
|
return R.string.account_status_not_found;
|
||||||
|
case TLS_ERROR:
|
||||||
|
return R.string.account_status_tls_error;
|
||||||
|
case TLS_ERROR_DOMAIN:
|
||||||
|
return R.string.account_status_tls_error_domain;
|
||||||
|
case INCOMPATIBLE_SERVER:
|
||||||
|
return R.string.account_status_incompatible_server;
|
||||||
|
case INCOMPATIBLE_CLIENT:
|
||||||
|
return R.string.account_status_incompatible_client;
|
||||||
|
case TOR_NOT_AVAILABLE:
|
||||||
|
return R.string.account_status_tor_unavailable;
|
||||||
|
case BIND_FAILURE:
|
||||||
|
return R.string.account_status_bind_failure;
|
||||||
|
case SESSION_FAILURE:
|
||||||
|
return R.string.session_failure;
|
||||||
|
case DOWNGRADE_ATTACK:
|
||||||
|
return R.string.sasl_downgrade;
|
||||||
|
case HOST_UNKNOWN:
|
||||||
|
return R.string.account_status_host_unknown;
|
||||||
|
case POLICY_VIOLATION:
|
||||||
|
return R.string.account_status_policy_violation;
|
||||||
|
case REGISTRATION_PLEASE_WAIT:
|
||||||
|
return R.string.registration_please_wait;
|
||||||
|
case REGISTRATION_PASSWORD_TOO_WEAK:
|
||||||
|
return R.string.registration_password_too_weak;
|
||||||
|
case STREAM_ERROR:
|
||||||
|
return R.string.account_status_stream_error;
|
||||||
|
case STREAM_OPENING_ERROR:
|
||||||
|
return R.string.account_status_stream_opening_error;
|
||||||
|
case PAYMENT_REQUIRED:
|
||||||
|
return R.string.payment_required;
|
||||||
|
case MISSING_INTERNET_PERMISSION:
|
||||||
|
return R.string.missing_internet_permission;
|
||||||
|
case TEMPORARY_AUTH_FAILURE:
|
||||||
|
return R.string.account_status_temporary_auth_failure;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(String.format("no string res for %s", state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -78,6 +78,7 @@ import java.security.Principal;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -97,7 +98,6 @@ import javax.net.ssl.SSLSocket;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.X509KeyManager;
|
import javax.net.ssl.X509KeyManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import okhttp3.HttpUrl;
|
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.jxmpp.stringprep.XmppStringprepException;
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
|
@ -151,7 +151,6 @@ public class XmppConnection implements Runnable {
|
||||||
private final PendingItem<SettableFuture<XmppConnection>> connectedFuture = new PendingItem<>();
|
private final PendingItem<SettableFuture<XmppConnection>> connectedFuture = new PendingItem<>();
|
||||||
private SaslMechanism saslMechanism;
|
private SaslMechanism saslMechanism;
|
||||||
private HashedToken.Mechanism hashTokenRequest;
|
private HashedToken.Mechanism hashTokenRequest;
|
||||||
private HttpUrl redirectionUrl = null;
|
|
||||||
private String verifiedHostname = null;
|
private String verifiedHostname = null;
|
||||||
private volatile Thread mThread;
|
private volatile Thread mThread;
|
||||||
private CountDownLatch mStreamCountDownLatch;
|
private CountDownLatch mStreamCountDownLatch;
|
||||||
|
@ -1392,26 +1391,12 @@ public class XmppConnection implements Runnable {
|
||||||
return bind;
|
return bind;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAccountCreationFailed(final String url) {
|
|
||||||
final HttpUrl httpUrl = url == null ? null : HttpUrl.parse(url);
|
|
||||||
if (httpUrl != null && httpUrl.isHttps()) {
|
|
||||||
this.redirectionUrl = httpUrl;
|
|
||||||
throw new StateChangingError(ConnectionState.REGISTRATION_WEB);
|
|
||||||
}
|
|
||||||
throw new StateChangingError(ConnectionState.REGISTRATION_FAILED);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpUrl getRedirectionUrl() {
|
|
||||||
return this.redirectionUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetEverything() {
|
public void resetEverything() {
|
||||||
resetAttemptCount(true);
|
resetAttemptCount(true);
|
||||||
resetStreamId();
|
resetStreamId();
|
||||||
clearIqCallbacks();
|
clearIqCallbacks();
|
||||||
this.stanzasSent = 0;
|
this.stanzasSent = 0;
|
||||||
mStanzaQueue.clear();
|
mStanzaQueue.clear();
|
||||||
this.redirectionUrl = null;
|
|
||||||
this.saslMechanism = null;
|
this.saslMechanism = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1892,13 +1877,19 @@ public class XmppConnection implements Runnable {
|
||||||
this.statusListener = listener;
|
this.statusListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListenableFuture<XmppConnection> asConnectedFuture() {
|
public ListenableFuture<XmppConnection> asConnectedFuture(final boolean waitOnError) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
final var state = this.connectionState;
|
||||||
// TODO some more permanent errors like 'unauthorized' should also return immediate
|
// TODO some more permanent errors like 'unauthorized' should also return immediate
|
||||||
if (this.connectionState == ConnectionState.ONLINE) {
|
if (this.connectionState == ConnectionState.ONLINE) {
|
||||||
return Futures.immediateFuture(this);
|
return Futures.immediateFuture(this);
|
||||||
}
|
} else if (Arrays.asList(ConnectionState.OFFLINE, ConnectionState.CONNECTING)
|
||||||
|
.contains(state)
|
||||||
|
|| waitOnError) {
|
||||||
return this.connectedFuture.peekOrCreate(SettableFuture::create);
|
return this.connectedFuture.peekOrCreate(SettableFuture::create);
|
||||||
|
} else {
|
||||||
|
return Futures.immediateFailedFuture(new ConnectionException(state));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,10 +102,10 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="4dp"
|
android:layout_marginHorizontal="4dp"
|
||||||
android:layout_weight="3"
|
android:layout_weight="5"
|
||||||
android:enabled="@{!setupViewModel.isLoading()}"
|
android:enabled="@{!setupViewModel.isLoading()}"
|
||||||
android:hint="@string/account_settings_hostname"
|
android:hint="@string/account_settings_hostname"
|
||||||
app:errorText="@{setupViewModel.xmppAddressError}">
|
app:errorText="@{setupViewModel.hostnameError}">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/hostname"
|
android:id="@+id/hostname"
|
||||||
|
@ -124,10 +124,10 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="4dp"
|
android:layout_marginHorizontal="4dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="2"
|
||||||
android:enabled="@{!setupViewModel.isLoading()}"
|
android:enabled="@{!setupViewModel.isLoading()}"
|
||||||
android:hint="@string/account_settings_port"
|
android:hint="@string/account_settings_port"
|
||||||
app:errorText="@{setupViewModel.xmppAddressError}">
|
app:errorText="@{setupViewModel.portError}">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/port"
|
android:id="@+id/port"
|
||||||
|
@ -136,6 +136,7 @@
|
||||||
android:imeOptions="flagNoExtractUi|actionNext"
|
android:imeOptions="flagNoExtractUi|actionNext"
|
||||||
android:inputType="number"
|
android:inputType="number"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
|
android:maxLength="5"
|
||||||
android:text="@={setupViewModel.port}"
|
android:text="@={setupViewModel.port}"
|
||||||
app:editorAction="@{()->setupViewModel.submitHostname()}" />
|
app:editorAction="@{()->setupViewModel.submitHostname()}" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
|
@ -1040,5 +1040,6 @@
|
||||||
<string name="pref_category_receiving">Receiving</string>
|
<string name="pref_category_receiving">Receiving</string>
|
||||||
<string name="use_opportunistic_tls">Opportunistic TLS (STARTTLS)</string>
|
<string name="use_opportunistic_tls">Opportunistic TLS (STARTTLS)</string>
|
||||||
<string name="info_required">Info required</string>
|
<string name="info_required">Info required</string>
|
||||||
|
<string name="invalid">Invalid!</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue