Commit 184cfda5 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Get rid of StatusTicker internal class on MainActivity and notify more...

Get rid of StatusTicker internal class on MainActivity and notify more appropriately when there is a connection change
parent 61707e2d
...@@ -47,9 +47,9 @@ import hugo.weaving.DebugLog; ...@@ -47,9 +47,9 @@ import hugo.weaving.DebugLog;
*/ */
public class MainActivity extends AbstractAuthedActivity implements MainContract.View { public class MainActivity extends AbstractAuthedActivity implements MainContract.View {
private RoomToolbar toolbar; private RoomToolbar toolbar;
private StatusTicker statusTicker;
private SlidingPaneLayout pane; private SlidingPaneLayout pane;
private MainContract.Presenter presenter; private MainContract.Presenter presenter;
private volatile Snackbar statusTicker;
@Override @Override
public int getLayoutContainerForFragment() { public int getLayoutContainerForFragment() {
...@@ -61,7 +61,6 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract ...@@ -61,7 +61,6 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.activity_main_toolbar); toolbar = findViewById(R.id.activity_main_toolbar);
statusTicker = new StatusTicker();
pane = findViewById(R.id.sliding_pane); pane = findViewById(R.id.sliding_pane);
setupToolbar(); setupToolbar();
} }
...@@ -95,6 +94,8 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract ...@@ -95,6 +94,8 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
if (presenter != null) { if (presenter != null) {
presenter.release(); presenter.release();
} }
// Dismiss any status ticker
if (statusTicker != null) statusTicker.dismiss();
super.onPause(); super.onPause();
} }
...@@ -245,28 +246,36 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract ...@@ -245,28 +246,36 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
@Override @Override
public void showLoginScreen() { public void showLoginScreen() {
LaunchUtil.showLoginActivity(this, hostname); LaunchUtil.showLoginActivity(this, hostname);
statusTicker.updateStatus(StatusTicker.STATUS_DISMISS, null); showConnectionOk();
} }
@Override @Override
public void showConnectionError() { public synchronized void showConnectionError() {
statusTicker.updateStatus(StatusTicker.STATUS_CONNECTION_ERROR, dismissStatusTickerIfShowing();
Snackbar.make(findViewById(getLayoutContainerForFragment()), statusTicker = Snackbar.make(findViewById(getLayoutContainerForFragment()),
R.string.fragment_retry_login_error_title, Snackbar.LENGTH_INDEFINITE) R.string.fragment_retry_login_error_title, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.fragment_retry_login_retry_title, view -> .setAction(R.string.fragment_retry_login_retry_title, view ->
ConnectivityManager.getInstance(getApplicationContext()).keepAliveServer())); ConnectivityManager.getInstance(getApplicationContext()).keepAliveServer());
statusTicker.show();
} }
@Override @Override
public void showConnecting() { public synchronized void showConnecting() {
statusTicker.updateStatus(StatusTicker.STATUS_TOKEN_LOGIN, dismissStatusTickerIfShowing();
Snackbar.make(findViewById(getLayoutContainerForFragment()), statusTicker = Snackbar.make(findViewById(getLayoutContainerForFragment()),
R.string.server_config_activity_authenticating, Snackbar.LENGTH_INDEFINITE)); R.string.server_config_activity_authenticating, Snackbar.LENGTH_INDEFINITE);
statusTicker.show();
} }
@Override @Override
public void showConnectionOk() { public synchronized void showConnectionOk() {
statusTicker.updateStatus(StatusTicker.STATUS_DISMISS, null); dismissStatusTickerIfShowing();
}
private void dismissStatusTickerIfShowing() {
if (statusTicker != null) {
statusTicker.dismiss();
}
} }
@Override @Override
...@@ -349,34 +358,4 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract ...@@ -349,34 +358,4 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
public void beforeLogoutCleanUp() { public void beforeLogoutCleanUp() {
presenter.beforeLogoutCleanUp(); presenter.beforeLogoutCleanUp();
} }
//TODO: consider this class to define in layouthelper for more complicated operation.
private static class StatusTicker {
static final int STATUS_DISMISS = 0;
static final int STATUS_CONNECTION_ERROR = 1;
static final int STATUS_TOKEN_LOGIN = 2;
private int status;
private Snackbar snackbar;
StatusTicker() {
status = STATUS_DISMISS;
}
void updateStatus(int status, Snackbar snackbar) {
if (status == this.status) {
return;
}
this.status = status;
if (this.snackbar != null) {
this.snackbar.dismiss();
}
if (status != STATUS_DISMISS) {
this.snackbar = snackbar;
if (this.snackbar != null) {
this.snackbar.show();
}
}
}
}
} }
...@@ -220,6 +220,7 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -220,6 +220,7 @@ public class MainPresenter extends BasePresenter<MainContract.View>
private void subscribeToNetworkChanges() { private void subscribeToNetworkChanges() {
Disposable disposable = connectivityManagerApi.getServerConnectivityAsObservable() Disposable disposable = connectivityManagerApi.getServerConnectivityAsObservable()
.distinctUntilChanged()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
connectivity -> { connectivity -> {
...@@ -229,6 +230,8 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -229,6 +230,8 @@ public class MainPresenter extends BasePresenter<MainContract.View>
} else if (connectivity.state == ServerConnectivity.STATE_DISCONNECTED) { } else if (connectivity.state == ServerConnectivity.STATE_DISCONNECTED) {
if (connectivity.code == DDPClient.REASON_NETWORK_ERROR) { if (connectivity.code == DDPClient.REASON_NETWORK_ERROR) {
view.showConnectionError(); view.showConnectionError();
} else {
view.showConnectionOk();
} }
} else { } else {
view.showConnecting(); view.showConnecting();
......
...@@ -6,7 +6,7 @@ import android.support.annotation.Nullable; ...@@ -6,7 +6,7 @@ import android.support.annotation.Nullable;
import java.util.List; import java.util.List;
import chat.rocket.core.models.ServerInfo; import chat.rocket.core.models.ServerInfo;
import io.reactivex.Observable; import io.reactivex.Flowable;
import io.reactivex.Single; import io.reactivex.Single;
/** /**
...@@ -23,7 +23,7 @@ public interface ConnectivityManagerApi { ...@@ -23,7 +23,7 @@ public interface ConnectivityManagerApi {
List<ServerInfo> getServerList(); List<ServerInfo> getServerList();
Observable<ServerConnectivity> getServerConnectivityAsObservable(); Flowable<ServerConnectivity> getServerConnectivityAsObservable();
int getConnectivityState(@NonNull String hostname); int getConnectivityState(@NonNull String hostname);
......
...@@ -21,9 +21,12 @@ import chat.rocket.android_ddp.DDPClient; ...@@ -21,9 +21,12 @@ import chat.rocket.android_ddp.DDPClient;
import chat.rocket.core.models.ServerInfo; import chat.rocket.core.models.ServerInfo;
import chat.rocket.persistence.realm.models.RealmBasedServerInfo; import chat.rocket.persistence.realm.models.RealmBasedServerInfo;
import hugo.weaving.DebugLog; import hugo.weaving.DebugLog;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Single; import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
import io.reactivex.subjects.PublishSubject; import io.reactivex.subjects.PublishSubject;
/** /**
...@@ -32,7 +35,7 @@ import io.reactivex.subjects.PublishSubject; ...@@ -32,7 +35,7 @@ import io.reactivex.subjects.PublishSubject;
/*package*/ class RealmBasedConnectivityManager /*package*/ class RealmBasedConnectivityManager
implements ConnectivityManagerApi, ConnectivityManagerInternal { implements ConnectivityManagerApi, ConnectivityManagerInternal {
private volatile ConcurrentHashMap<String, Integer> serverConnectivityList = new ConcurrentHashMap<>(); private volatile ConcurrentHashMap<String, Integer> serverConnectivityList = new ConcurrentHashMap<>();
private final PublishSubject<ServerConnectivity> connectivitySubject = PublishSubject.create(); private volatile BehaviorSubject<ServerConnectivity> connectivitySubject = BehaviorSubject.createDefault(ServerConnectivity.CONNECTED);
private Context appContext; private Context appContext;
private final ServiceConnection serviceConnection = new ServiceConnection() { private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override @Override
...@@ -135,7 +138,9 @@ import io.reactivex.subjects.PublishSubject; ...@@ -135,7 +138,9 @@ import io.reactivex.subjects.PublishSubject;
@DebugLog @DebugLog
@Override @Override
public void notifyConnectionEstablished(String hostname, String session) { public void notifyConnectionEstablished(String hostname, String session) {
if (session != null) {
RealmBasedServerInfo.updateSession(hostname, session); RealmBasedServerInfo.updateSession(hostname, session);
}
serverConnectivityList.put(hostname, ServerConnectivity.STATE_CONNECTED); serverConnectivityList.put(hostname, ServerConnectivity.STATE_CONNECTED);
connectivitySubject.onNext( connectivitySubject.onNext(
new ServerConnectivity(hostname, ServerConnectivity.STATE_CONNECTED)); new ServerConnectivity(hostname, ServerConnectivity.STATE_CONNECTED));
...@@ -158,8 +163,8 @@ import io.reactivex.subjects.PublishSubject; ...@@ -158,8 +163,8 @@ import io.reactivex.subjects.PublishSubject;
} }
@Override @Override
public Observable<ServerConnectivity> getServerConnectivityAsObservable() { public Flowable<ServerConnectivity> getServerConnectivityAsObservable() {
return Observable.concat(Observable.fromIterable(getCurrentConnectivityList()), connectivitySubject); return connectivitySubject.toFlowable(BackpressureStrategy.LATEST);
} }
@Override @Override
...@@ -185,7 +190,7 @@ import io.reactivex.subjects.PublishSubject; ...@@ -185,7 +190,7 @@ import io.reactivex.subjects.PublishSubject;
} }
if (connectivity == ServerConnectivity.STATE_DISCONNECTED) { if (connectivity == ServerConnectivity.STATE_DISCONNECTED) {
notifyConnecting(hostname); // notifyConnecting(hostname);
} }
return connectToServer(hostname); return connectToServer(hostname);
......
...@@ -69,11 +69,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt ...@@ -69,11 +69,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
@Override @Override
public Single<Boolean> ensureConnectionToServer(String hostname) { //called via binder. public Single<Boolean> ensureConnectionToServer(String hostname) { //called via binder.
return getOrCreateWebSocketThread(hostname) return getOrCreateWebSocketThread(hostname)
.doOnError(err -> { .flatMap(RocketChatWebSocketThread::keepAlive);
err.printStackTrace();
currentWebSocketThread = null;
})
.flatMap(webSocketThreads -> webSocketThreads.keepAlive());
} }
@Override @Override
...@@ -109,12 +105,9 @@ public class RocketChatService extends Service implements ConnectivityServiceInt ...@@ -109,12 +105,9 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
return Single.just(currentWebSocketThread); return Single.just(currentWebSocketThread);
} }
connectivityManager.notifyConnecting(hostname);
if (currentWebSocketThread != null) { if (currentWebSocketThread != null) {
return currentWebSocketThread.terminate() return currentWebSocketThread.terminate()
.doAfterTerminate(() -> currentWebSocketThread = null) .doAfterTerminate(() -> currentWebSocketThread = null)
.doOnError(RCLog::e)
.flatMap(terminated -> .flatMap(terminated ->
RocketChatWebSocketThread.getStarted(getApplicationContext(), hostname) RocketChatWebSocketThread.getStarted(getApplicationContext(), hostname)
.doOnSuccess(thread -> { .doOnSuccess(thread -> {
......
...@@ -245,11 +245,11 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -245,11 +245,11 @@ public class RocketChatWebSocketThread extends HandlerThread {
return; return;
} }
RCLog.d("DDPClient#connect"); RCLog.d("DDPClient#connect");
connectivityManager.notifyConnecting(hostname);
DDPClient.get().connect(hostname, info.getSession(), info.isSecure()) DDPClient.get().connect(hostname, info.getSession(), info.isSecure())
.onSuccessTask(task -> { .onSuccessTask(task -> {
final String newSession = task.getResult().session; final String newSession = task.getResult().session;
connectivityManager.notifyConnectionEstablished(hostname, newSession); connectivityManager.notifyConnectionEstablished(hostname, newSession);
// handling WebSocket#onClose() callback. // handling WebSocket#onClose() callback.
task.getResult().client.getOnCloseCallback().onSuccess(_task -> { task.getResult().client.getOnCloseCallback().onSuccess(_task -> {
RxWebSocketCallback.Close result = _task.getResult(); RxWebSocketCallback.Close result = _task.getResult();
...@@ -292,18 +292,18 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -292,18 +292,18 @@ public class RocketChatWebSocketThread extends HandlerThread {
return; return;
} }
forceInvalidateTokens(); forceInvalidateTokens();
connectivityManager.notifyConnecting(hostname);
reconnectDisposable.add( reconnectDisposable.add(
connectWithExponentialBackoff() connectWithExponentialBackoff()
.subscribe(connected -> { .subscribe(connected -> {
if (!connected) { if (!connected) {
connectivityManager.notifyConnecting(hostname); connectivityManager.notifyConnectionLost(hostname,
DDPClient.REASON_NETWORK_ERROR);
} }
reconnectDisposable.clear(); reconnectDisposable.clear();
}, error -> { }, error -> {
logErrorAndUnsubscribe(reconnectDisposable, error);
connectivityManager.notifyConnectionLost(hostname, connectivityManager.notifyConnectionLost(hostname,
DDPClient.REASON_NETWORK_ERROR); DDPClient.REASON_NETWORK_ERROR);
logErrorAndUnsubscribe(reconnectDisposable, error);
} }
) )
); );
...@@ -315,7 +315,9 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -315,7 +315,9 @@ public class RocketChatWebSocketThread extends HandlerThread {
} }
private Single<Boolean> connectWithExponentialBackoff() { private Single<Boolean> connectWithExponentialBackoff() {
return connect().retryWhen(RxHelper.exponentialBackoff(3, 500, TimeUnit.MILLISECONDS)); return connect()
.retryWhen(RxHelper.exponentialBackoff(1, 250, TimeUnit.MILLISECONDS))
.onErrorResumeNext(Single.just(false));
} }
@DebugLog @DebugLog
......
...@@ -4,10 +4,13 @@ package chat.rocket.android.service; ...@@ -4,10 +4,13 @@ package chat.rocket.android.service;
* pair with server's hostname and its connectivity state. * pair with server's hostname and its connectivity state.
*/ */
public class ServerConnectivity { public class ServerConnectivity {
public static final int STATE_CONNECTED = 1; public static final int STATE_CONNECTED = 1;
public static final int STATE_DISCONNECTED = 2; public static final int STATE_DISCONNECTED = 2;
public static final int STATE_CONNECTING = 3; public static final int STATE_CONNECTING = 3;
/*package*/ static final int STATE_DISCONNECTING = 4; /*package*/ static final int STATE_DISCONNECTING = 4;
public static final ServerConnectivity CONNECTED = new ServerConnectivity(null, STATE_CONNECTED);
public final String hostname; public final String hostname;
public final int state; public final int state;
...@@ -25,6 +28,21 @@ public class ServerConnectivity { ...@@ -25,6 +28,21 @@ public class ServerConnectivity {
this.code = code; this.code = code;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ServerConnectivity that = (ServerConnectivity) o;
return state == that.state;
}
@Override
public int hashCode() {
return state;
}
/** /**
* This exception should be thrown when connection is lost during waiting for CONNECTED. * This exception should be thrown when connection is lost during waiting for CONNECTED.
*/ */
......
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