Commit f900423f authored by Leonardo Aramaki's avatar Leonardo Aramaki

Update reconnection logic to dispatch a KeepAliveJob when connections goes...

Update reconnection logic to dispatch a KeepAliveJob when connections goes off. Change a tidbits of the logic to close connections and reconnect
parent e251631d
......@@ -84,7 +84,11 @@ public class DDPClient {
}
public void close() {
impl.close(REASON_CLOSED_BY_USER, "closed by DDPClient#close()");
close(REASON_CLOSED_BY_USER);
}
public void close(int reason) {
impl.close(reason, "closed by DDPClient#close()");
}
/**
......
......@@ -5,7 +5,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.graphics.drawable.AnimatedVectorDrawableCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SlidingPaneLayout;
......@@ -20,6 +20,7 @@ import com.facebook.drawee.view.SimpleDraweeView;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import chat.rocket.android.ConnectionStatusManager;
import chat.rocket.android.LaunchUtil;
import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache;
......@@ -31,6 +32,7 @@ import chat.rocket.android.helper.KeyboardHelper;
import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.android.service.ConnectivityManagerApi;
import chat.rocket.android.widget.RoomToolbar;
import chat.rocket.android.widget.helper.DebouncingOnClickListener;
import chat.rocket.android.widget.helper.FrescoHelper;
import chat.rocket.core.interactors.CanCreateRoomInteractor;
import chat.rocket.core.interactors.RoomInteractor;
......@@ -41,6 +43,8 @@ import chat.rocket.persistence.realm.repositories.RealmPublicSettingRepository;
import chat.rocket.persistence.realm.repositories.RealmRoomRepository;
import chat.rocket.persistence.realm.repositories.RealmSessionRepository;
import chat.rocket.persistence.realm.repositories.RealmUserRepository;
import de.keyboardsurfer.android.widget.crouton.Configuration;
import de.keyboardsurfer.android.widget.crouton.Crouton;
import hugo.weaving.DebugLog;
/**
......@@ -50,7 +54,11 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
private RoomToolbar toolbar;
private SlidingPaneLayout pane;
private MainContract.Presenter presenter;
private volatile AtomicReference<Snackbar> statusTicker = new AtomicReference<>();
private volatile AtomicReference<Crouton> croutonStatusTicker = new AtomicReference<>();
private View croutonView;
private ImageView croutonTryAgainImage;
private TextView croutonText;
private AnimatedVectorDrawableCompat tryAgainSpinnerAnimatedDrawable;
@Override
public int getLayoutContainerForFragment() {
......@@ -63,6 +71,7 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.activity_main_toolbar);
pane = findViewById(R.id.sliding_pane);
loadCroutonViewIfNeeded();
setupToolbar();
}
......@@ -95,10 +104,7 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
if (presenter != null) {
presenter.release();
}
// Dismiss any status ticker
if (statusTicker.get() != null) {
statusTicker.get().dismiss();
}
Crouton.cancelAllCroutons();
super.onPause();
}
......@@ -254,44 +260,80 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
@Override
public void showConnectionError() {
if (statusTicker.get() != null && statusTicker.get().isShown()) {
statusTicker.get().setText(R.string.fragment_retry_login_error_title)
.setAction(R.string.fragment_retry_login_retry_title, view -> retryConnection());
} else {
Snackbar newStatusTicker = Snackbar.make(findViewById(getLayoutContainerForFragment()),
R.string.fragment_retry_login_error_title, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.fragment_retry_login_retry_title, view -> retryConnection());
statusTicker.set(newStatusTicker);
statusTicker.get().show();
}
ConnectionStatusManager.INSTANCE.setConnectionError(this::showConnectionErrorCrouton);
}
@Override
public void showConnecting() {
if (statusTicker.get() != null && statusTicker.get().isShown()) {
statusTicker.get().setText(R.string.server_config_activity_authenticating)
.setAction(null, null);
} else {
Snackbar newStatusTicker = Snackbar.make(findViewById(getLayoutContainerForFragment()),
R.string.server_config_activity_authenticating, Snackbar.LENGTH_INDEFINITE);
statusTicker.set(newStatusTicker);
statusTicker.get().show();
}
ConnectionStatusManager.INSTANCE.setConnecting(this::showConnectingCrouton);
}
@Override
public void showConnectionOk() {
dismissStatusTickerIfShowing();
ConnectionStatusManager.INSTANCE.setOnline(this::dismissStatusTickerIfShowing);
}
private void showConnectingCrouton(boolean success) {
if (success) {
croutonText.setText(R.string.server_config_activity_authenticating);
croutonTryAgainImage.setOnClickListener(null);
tryAgainSpinnerAnimatedDrawable.start();
Crouton.cancelAllCroutons();
updateCrouton();
croutonStatusTicker.get().show();
}
}
private void showConnectionErrorCrouton(boolean success) {
if (success) {
tryAgainSpinnerAnimatedDrawable.stop();
croutonText.setText(R.string.fragment_retry_login_error_title);
croutonTryAgainImage.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View v) {
retryConnection();
}
});
Crouton.cancelAllCroutons();
updateCrouton();
croutonStatusTicker.get().show();
}
}
private void loadCroutonViewIfNeeded() {
if (croutonView == null) {
croutonView = LayoutInflater.from(this).inflate(R.layout.crouton_status_ticker, null);
croutonTryAgainImage = croutonView.findViewById(R.id.try_again_image);
croutonText = croutonView.findViewById(R.id.text_view_status);
tryAgainSpinnerAnimatedDrawable =
AnimatedVectorDrawableCompat.create(this, R.drawable.ic_loading_animated);
croutonTryAgainImage.setImageDrawable(tryAgainSpinnerAnimatedDrawable);
updateCrouton();
}
}
private void updateCrouton() {
Configuration configuration = new Configuration.Builder()
.setDuration(Configuration.DURATION_INFINITE).build();
Crouton crouton = Crouton.make(this, croutonView, getLayoutContainerForFragment())
.setConfiguration(configuration);
croutonStatusTicker.set(crouton);
}
private void dismissStatusTickerIfShowing() {
if (statusTicker != null) {
statusTicker.get().dismiss();
private void dismissStatusTickerIfShowing(boolean success) {
if (success && croutonStatusTicker.get() != null) {
croutonStatusTicker.get().hide();
}
}
private void retryConnection() {
statusTicker.set(null);
croutonStatusTicker.set(null);
showConnecting();
ConnectivityManager.getInstance(getApplicationContext()).keepAliveServer();
}
......
......@@ -16,7 +16,6 @@ import chat.rocket.android.helper.LogIfError;
import chat.rocket.android.helper.Logger;
import chat.rocket.android.log.RCLog;
import chat.rocket.android.service.ConnectivityManagerApi;
import chat.rocket.android.service.KeepAliveJob;
import chat.rocket.android.service.ServerConnectivity;
import chat.rocket.android.shared.BasePresenter;
import chat.rocket.android_ddp.DDPClient;
......@@ -228,13 +227,10 @@ public class MainPresenter extends BasePresenter<MainContract.View>
.subscribe(
connectivity -> {
if (connectivity.state == ServerConnectivity.STATE_CONNECTED) {
KeepAliveJob.Companion.cancel();
//TODO: notify almost connected or something like that.
// view.showConnectionOk();
} else if (connectivity.state == ServerConnectivity.STATE_DISCONNECTED) {
KeepAliveJob.Companion.cancel();
if (connectivity.code == DDPClient.REASON_NETWORK_ERROR) {
KeepAliveJob.Companion.schedule();
view.showConnectionError();
}
} else if (connectivity.state == ServerConnectivity.STATE_SESSION_ESTABLISHED) {
......
......@@ -80,7 +80,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
}
if (currentWebSocketThread != null) {
return currentWebSocketThread.terminate()
return currentWebSocketThread.terminate(false)
// after disconnection from server
.doAfterTerminate(() -> {
currentWebSocketThread = null;
......@@ -106,7 +106,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
}
if (currentWebSocketThread != null) {
return currentWebSocketThread.terminate()
return currentWebSocketThread.terminate(isDisconnected)
.doAfterTerminate(() -> currentWebSocketThread = null)
.flatMap(terminated ->
RocketChatWebSocketThread.getStarted(getApplicationContext(), hostname)
......
......@@ -54,7 +54,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
LoginServiceConfigurationSubscriber.class,
ActiveUsersSubscriber.class,
UserDataSubscriber.class,
MethodCallObserver.class,
// MethodCallObserver.class,
LoadMessageProcedureObserver.class,
GetUsersOfRoomsProcedureObserver.class,
NewMessageObserver.class,
......@@ -125,16 +125,21 @@ public class RocketChatWebSocketThread extends HandlerThread {
/**
* terminate WebSocket thread.
*
* @param isDisconnected {@code true} If we're trying to terminate a disconnected a websocket
* thread which means it has failed.
*/
@DebugLog
/* package */ Single<Boolean> terminate() {
/* package */ Single<Boolean> terminate(boolean isDisconnected) {
if (isAlive()) {
return Single.create(emitter -> {
new Handler(getLooper()).post(() -> {
RCLog.d("thread %s: terminated()", Thread.currentThread().getId());
unregisterListenersAndClose();
int reason = (isDisconnected) ?
DDPClient.REASON_NETWORK_ERROR : DDPClient.REASON_CLOSED_BY_USER;
unregisterListenersAndClose(reason);
connectivityManager.notifyConnectionLost(hostname,
DDPClient.REASON_CLOSED_BY_USER);
isDisconnected ? DDPClient.REASON_NETWORK_ERROR : DDPClient.REASON_CLOSED_BY_USER);
RocketChatWebSocketThread.super.quit();
emitter.onSuccess(true);
});
......@@ -162,7 +167,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
@DebugLog
/* package */ Single<Boolean> keepAlive() {
return checkIfConnectionAlive()
.flatMap(alive -> alive ? Single.just(true) : connectWithExponentialBackoff());
.flatMap(alive -> connectWithExponentialBackoff());
}
@DebugLog
......@@ -228,8 +233,6 @@ public class RocketChatWebSocketThread extends HandlerThread {
RxWebSocketCallback.Close result = _task.getResult();
if (result.code == DDPClient.REASON_NETWORK_ERROR) {
reconnect();
} else {
unregisterListenersAndClose();
}
return null;
});
......@@ -367,9 +370,6 @@ public class RocketChatWebSocketThread extends HandlerThread {
@DebugLog
private void createObserversAndRegister() {
SessionObserver sessionObserver = new SessionObserver(appContext, hostname, realmHelper);
sessionObserver.register();
listeners.add(sessionObserver);
for (Class clazz : REGISTERABLE_CLASSES) {
try {
Constructor ctor = clazz.getConstructor(Context.class, String.class, RealmHelper.class);
......@@ -384,6 +384,10 @@ public class RocketChatWebSocketThread extends HandlerThread {
RCLog.w(exception, "Failed to register listeners!!");
}
}
// Register SessionObserver late.
SessionObserver sessionObserver = new SessionObserver(appContext, hostname, realmHelper);
sessionObserver.register();
listeners.add(sessionObserver);
listenersRegistered = true;
startHeartBeat();
}
......@@ -412,9 +416,9 @@ public class RocketChatWebSocketThread extends HandlerThread {
}
@DebugLog
private void unregisterListenersAndClose() {
private void unregisterListenersAndClose(int reason) {
unregisterListeners();
DDPClient.get().close();
DDPClient.get().close(reason);
}
@DebugLog
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment