From 7a4d951c0bae3b65ae2b47048b19db8128f089e1 Mon Sep 17 00:00:00 2001 From: Jannis Mattheis Date: Fri, 4 Jan 2019 22:45:35 +0100 Subject: [PATCH 1/3] Add permission ACCESS_NETWORK_STATE --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 997f0e1..eefcbda 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + Date: Fri, 4 Jan 2019 22:47:10 +0100 Subject: [PATCH 2/3] Wait for network when websocket connection failed --- .../gotify/service/ReconnectListener.java | 30 ++++++++++++++++ .../gotify/service/WebSocketConnection.java | 23 +++++++++++- .../gotify/service/WebSocketService.java | 36 ++++++++++++++++++- app/src/main/res/values/strings.xml | 1 + 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/github/gotify/service/ReconnectListener.java diff --git a/app/src/main/java/com/github/gotify/service/ReconnectListener.java b/app/src/main/java/com/github/gotify/service/ReconnectListener.java new file mode 100644 index 0000000..eae2d75 --- /dev/null +++ b/app/src/main/java/com/github/gotify/service/ReconnectListener.java @@ -0,0 +1,30 @@ +package com.github.gotify.service; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import com.github.gotify.log.Log; + +public class ReconnectListener extends BroadcastReceiver { + + private Runnable reconnected; + + ReconnectListener(Runnable reconnected) { + this.reconnected = reconnected; + } + + @Override + public void onReceive(Context context, Intent intent) { + ConnectivityManager cm = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + + NetworkInfo network = cm.getActiveNetworkInfo(); + + if (network != null && network.isConnected()) { + Log.i("Network reconnected"); + reconnected.run(); + } + } +} diff --git a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java index 3112700..cc1f544 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java @@ -1,5 +1,7 @@ package com.github.gotify.service; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.os.Handler; import com.github.gotify.SSLSettings; import com.github.gotify.Utils; @@ -16,6 +18,7 @@ import okhttp3.WebSocket; import okhttp3.WebSocketListener; public class WebSocketConnection { + private final ConnectivityManager connectivityManager; private OkHttpClient client; private final Handler handler = new Handler(); @@ -31,8 +34,14 @@ public class WebSocketConnection { private OnFailureCallback onFailure; private Runnable onReconnected; private boolean isClosed; + private Runnable onDisconnect; - WebSocketConnection(String baseUrl, SSLSettings settings, String token) { + WebSocketConnection( + String baseUrl, + SSLSettings settings, + String token, + ConnectivityManager connectivityManager) { + this.connectivityManager = connectivityManager; OkHttpClient.Builder builder = new OkHttpClient.Builder() .readTimeout(0, TimeUnit.MILLISECONDS) @@ -66,6 +75,11 @@ public class WebSocketConnection { return this; } + synchronized WebSocketConnection onDisconnect(Runnable onDisconnect) { + this.onDisconnect = onDisconnect; + return this; + } + synchronized WebSocketConnection onFailure(OnFailureCallback onFailure) { this.onFailure = onFailure; return this; @@ -153,6 +167,13 @@ public class WebSocketConnection { return; } + NetworkInfo network = connectivityManager.getActiveNetworkInfo(); + if (network == null || !network.isConnected()) { + Log.i("WebSocket: Network not connected"); + onDisconnect.run(); + return; + } + int minutes = Math.min(errorCount * 2 + 1, 20); Log.i("WebSocket: trying to restart in " + minutes + " minute(s)"); diff --git a/app/src/main/java/com/github/gotify/service/WebSocketService.java b/app/src/main/java/com/github/gotify/service/WebSocketService.java index b279908..467c5a0 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketService.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketService.java @@ -6,8 +6,11 @@ import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.graphics.Color; +import android.net.ConnectivityManager; import android.os.Build; +import android.os.Handler; import android.os.IBinder; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -25,6 +28,7 @@ import com.github.gotify.log.Log; import com.github.gotify.log.UncaughtExceptionHandler; import com.github.gotify.messages.MessagesActivity; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class WebSocketService extends Service { @@ -84,15 +88,45 @@ public class WebSocketService extends Service { missingMessageUtil.lastReceivedMessage(lastReceivedMessage::set); } + ConnectivityManager cm = + (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + connection = - new WebSocketConnection(settings.url(), settings.sslSettings(), settings.token()) + new WebSocketConnection( + settings.url(), settings.sslSettings(), settings.token(), cm) .onOpen(this::onOpen) .onClose(() -> foreground(getString(R.string.websocket_closed))) .onBadRequest(this::onBadRequest) .onFailure((min) -> foreground(getString(R.string.websocket_failed, min))) + .onDisconnect(this::onDisconnect) .onMessage(this::onMessage) .onReconnected(this::notifyMissedNotifications) .start(); + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + ReconnectListener receiver = new ReconnectListener(this::doReconnect); + registerReceiver(receiver, intentFilter); + } + + private void onDisconnect() { + foreground(getString(R.string.websocket_no_network)); + } + + private void doReconnect() { + if (connection == null) { + return; + } + + new Handler() + .postDelayed( + () -> new Thread(this::notifyAndStart).start(), + TimeUnit.SECONDS.toMillis(5)); + } + + private void notifyAndStart() { + notifyMissedNotifications(); + connection.start(); } private void onBadRequest(String message) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bdba0b9..c55b3ab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,4 +57,5 @@ Warning Using http is insecure and it\'s recommend to use https instead. Use your favorite search engine to get more information about this topic. I Understand + Waiting for network From 0c3ebb9bce57c735a8956c35e6c1289233df9936 Mon Sep 17 00:00:00 2001 From: eternal-flame-AD Date: Sat, 5 Jan 2019 10:36:49 +0800 Subject: [PATCH 3/3] Remove obsolete reconnect callbacks removes obsolete reconnect callbacks scheduled before network reconnects to prevent unwanted reconnection also renamed WebSocketConnection.onFailure to onNetworkFailure to clear confusion --- .../gotify/service/WebSocketConnection.java | 36 ++++++++++++------- .../gotify/service/WebSocketService.java | 14 ++------ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java index cc1f544..ebda4da 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java @@ -21,7 +21,8 @@ public class WebSocketConnection { private final ConnectivityManager connectivityManager; private OkHttpClient client; - private final Handler handler = new Handler(); + private final Handler reconnectHandler = new Handler(); + private Runnable reconnectCallback = this::start; private int errorCount = 0; private final String baseUrl; @@ -31,7 +32,7 @@ public class WebSocketConnection { private Runnable onClose; private Runnable onOpen; private BadRequestRunnable onBadRequest; - private OnFailureCallback onFailure; + private OnNetworkFailureRunnable onNetworkFailure; private Runnable onReconnected; private boolean isClosed; private Runnable onDisconnect; @@ -80,8 +81,8 @@ public class WebSocketConnection { return this; } - synchronized WebSocketConnection onFailure(OnFailureCallback onFailure) { - this.onFailure = onFailure; + synchronized WebSocketConnection onNetworkFailure(OnNetworkFailureRunnable onNetworkFailure) { + this.onNetworkFailure = onNetworkFailure; return this; } @@ -118,7 +119,18 @@ public class WebSocketConnection { } } + public synchronized void scheduleReconnect(long millis) { + reconnectHandler.removeCallbacks(reconnectCallback); + + Log.i( + "WebSocket: scheduling a restart in " + + TimeUnit.SECONDS.convert(millis, TimeUnit.MILLISECONDS) + + " second(s)"); + reconnectHandler.postDelayed(reconnectCallback, millis); + } + private class Listener extends WebSocketListener { + @Override public void onOpen(WebSocket webSocket, Response response) { Log.i("WebSocket: opened"); @@ -167,6 +179,8 @@ public class WebSocketConnection { return; } + errorCount++; + NetworkInfo network = connectivityManager.getActiveNetworkInfo(); if (network == null || !network.isConnected()) { Log.i("WebSocket: Network not connected"); @@ -174,14 +188,10 @@ public class WebSocketConnection { return; } - int minutes = Math.min(errorCount * 2 + 1, 20); + int minutes = Math.min(errorCount * 2 - 1, 20); - Log.i("WebSocket: trying to restart in " + minutes + " minute(s)"); - - errorCount++; - handler.postDelayed( - WebSocketConnection.this::start, TimeUnit.MINUTES.toMillis(minutes)); - onFailure.execute(minutes); + onNetworkFailure.execute(minutes); + scheduleReconnect(TimeUnit.MINUTES.toMillis(minutes)); } super.onFailure(webSocket, t, response); @@ -192,7 +202,7 @@ public class WebSocketConnection { void execute(String message); } - interface OnFailureCallback { - void execute(int minutesToTryAgain); + interface OnNetworkFailureRunnable { + void execute(long millis); } } diff --git a/app/src/main/java/com/github/gotify/service/WebSocketService.java b/app/src/main/java/com/github/gotify/service/WebSocketService.java index 467c5a0..158eb37 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketService.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketService.java @@ -10,7 +10,6 @@ import android.content.IntentFilter; import android.graphics.Color; import android.net.ConnectivityManager; import android.os.Build; -import android.os.Handler; import android.os.IBinder; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -97,7 +96,8 @@ public class WebSocketService extends Service { .onOpen(this::onOpen) .onClose(() -> foreground(getString(R.string.websocket_closed))) .onBadRequest(this::onBadRequest) - .onFailure((min) -> foreground(getString(R.string.websocket_failed, min))) + .onNetworkFailure( + (min) -> foreground(getString(R.string.websocket_failed, min))) .onDisconnect(this::onDisconnect) .onMessage(this::onMessage) .onReconnected(this::notifyMissedNotifications) @@ -118,15 +118,7 @@ public class WebSocketService extends Service { return; } - new Handler() - .postDelayed( - () -> new Thread(this::notifyAndStart).start(), - TimeUnit.SECONDS.toMillis(5)); - } - - private void notifyAndStart() { - notifyMissedNotifications(); - connection.start(); + connection.scheduleReconnect(TimeUnit.SECONDS.toMillis(5)); } private void onBadRequest(String message) {