AccountStateProcessor.java

  1package im.conversations.android.xmpp.processor;
  2
  3import static eu.siacs.conversations.utils.Random.SECURE_RANDOM;
  4
  5import android.util.Log;
  6import eu.siacs.conversations.Config;
  7import eu.siacs.conversations.entities.Account;
  8import eu.siacs.conversations.http.ServiceOutageStatus;
  9import eu.siacs.conversations.services.XmppConnectionService;
 10import eu.siacs.conversations.xmpp.XmppConnection;
 11import eu.siacs.conversations.xmpp.manager.MultiUserChatManager;
 12import java.util.concurrent.TimeUnit;
 13import java.util.function.Consumer;
 14
 15public class AccountStateProcessor extends XmppConnection.Delegate
 16        implements Consumer<Account.State> {
 17
 18    private final XmppConnectionService service;
 19
 20    public AccountStateProcessor(final XmppConnectionService service, XmppConnection connection) {
 21        super(service, connection);
 22        this.service = service;
 23    }
 24
 25    @Override
 26    public void accept(final Account.State status) {
 27        final var account = getAccount();
 28        if (ServiceOutageStatus.isPossibleOutage(status)) {
 29            this.service.fetchServiceOutageStatus(account);
 30        }
 31        this.service.updateAccountUi();
 32
 33        if (account.getStatus() == Account.State.ONLINE || account.getStatus().isError()) {
 34            this.service.getQuickConversationsService().signalAccountStateChange();
 35        }
 36
 37        if (account.getStatus() == Account.State.ONLINE) {
 38            synchronized (this.service.mLowPingTimeoutMode) {
 39                if (this.service.mLowPingTimeoutMode.remove(account.getJid().asBareJid())) {
 40                    Log.d(
 41                            Config.LOGTAG,
 42                            account.getJid().asBareJid() + ": leaving low ping timeout mode");
 43                }
 44            }
 45            if (account.setShowErrorNotification(true)) {
 46                this.service.databaseBackend.updateAccount(account);
 47            }
 48            this.service.getMessageArchiveService().executePendingQueries(account);
 49            if (this.connection.getFeatures().csi()) {
 50                if (this.service.checkListeners()) {
 51                    Log.d(Config.LOGTAG, account.getJid().asBareJid() + " sending csi//inactive");
 52                    connection.sendInactive();
 53                } else {
 54                    Log.d(Config.LOGTAG, account.getJid().asBareJid() + " sending csi//active");
 55                    connection.sendActive();
 56                }
 57            }
 58            final var mucManager = getManager(MultiUserChatManager.class);
 59            final var conversations = this.service.getConversations();
 60            for (final var conversation : conversations) {
 61                final boolean inProgressJoin = mucManager.isJoinInProgress(conversation);
 62                if (conversation.getAccount() == account && !inProgressJoin) {
 63                    this.service.sendUnsentMessages(conversation);
 64                }
 65            }
 66            this.service.scheduleWakeUpCall(
 67                    Config.PING_MAX_INTERVAL * 1000L, account.getUuid().hashCode());
 68        } else if (account.getStatus() == Account.State.OFFLINE
 69                || account.getStatus() == Account.State.DISABLED
 70                || account.getStatus() == Account.State.LOGGED_OUT) {
 71            this.service.resetSendingToWaiting(account);
 72            if (account.isConnectionEnabled() && this.service.isInLowPingTimeoutMode(account)) {
 73                Log.d(
 74                        Config.LOGTAG,
 75                        account.getJid().asBareJid()
 76                                + ": went into offline state during low ping mode."
 77                                + " reconnecting now");
 78                this.service.reconnectAccount(account, true, false);
 79            } else {
 80                final int timeToReconnect = SECURE_RANDOM.nextInt(10) + 2;
 81                this.service.scheduleWakeUpCall(timeToReconnect, account.getUuid().hashCode());
 82            }
 83        } else if (account.getStatus() == Account.State.REGISTRATION_SUCCESSFUL) {
 84            this.service.databaseBackend.updateAccount(account);
 85            this.service.reconnectAccount(account, true, false);
 86        } else if (account.getStatus() != Account.State.CONNECTING
 87                && account.getStatus() != Account.State.NO_INTERNET) {
 88            this.service.resetSendingToWaiting(account);
 89            if (connection != null && account.getStatus().isAttemptReconnect()) {
 90                final boolean aggressive =
 91                        account.getStatus() == Account.State.SEE_OTHER_HOST
 92                                || this.service.hasJingleRtpConnection(account);
 93                final int next = connection.getTimeToNextAttempt(aggressive);
 94                final boolean lowPingTimeoutMode = this.service.isInLowPingTimeoutMode(account);
 95                if (next <= 0) {
 96                    Log.d(
 97                            Config.LOGTAG,
 98                            account.getJid().asBareJid()
 99                                    + ": error connecting account. reconnecting now."
100                                    + " lowPingTimeout="
101                                    + lowPingTimeoutMode);
102                    this.service.reconnectAccount(account, true, false);
103                } else {
104                    final int attempt = connection.getAttempt() + 1;
105                    Log.d(
106                            Config.LOGTAG,
107                            account.getJid().asBareJid()
108                                    + ": error connecting account. try again in "
109                                    + next
110                                    + "s for the "
111                                    + attempt
112                                    + " time. lowPingTimeout="
113                                    + lowPingTimeoutMode
114                                    + ", aggressive="
115                                    + aggressive);
116                    this.service.scheduleWakeUpCall(next, account.getUuid().hashCode());
117                    if (aggressive) {
118                        this.service.internalPingExecutor.schedule(
119                                service::manageAccountConnectionStatesInternal,
120                                (next * 1000L) + 50,
121                                TimeUnit.MILLISECONDS);
122                    }
123                }
124            }
125        }
126        this.service.getNotificationService().updateErrorNotification();
127    }
128}