Browse Source

Fix up internet reconnections

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic 5 years ago
parent
commit
27d69e73d1

+ 2 - 0
app/build.gradle

@@ -215,6 +215,8 @@ dependencies {
 
     implementation 'com.github.natario1:Autocomplete:v1.1.0'
 
+    implementation 'com.novoda:merlin:1.2.0'
+
     implementation 'com.github.Kennyc1012:BottomSheet:2.4.1'
     implementation 'com.github.mario:PopupBubble:a365177d96'
     implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'

+ 4 - 0
app/src/main/AndroidManifest.xml

@@ -95,5 +95,9 @@
                 <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
             </intent-filter>
         </receiver>
+
+        <service
+            android:exported="false"
+            android:name="com.novoda.merlin.MerlinService" />
     </application>
 </manifest>

+ 3 - 0
app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java

@@ -50,6 +50,7 @@ import com.nextcloud.talk.utils.DisplayUtils;
 import com.nextcloud.talk.utils.OkHttpNetworkFetcherWithCache;
 import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule;
 import com.nextcloud.talk.utils.database.user.UserModule;
+import com.nextcloud.talk.utils.singletons.MerlinTheWizard;
 import com.nextcloud.talk.webrtc.MagicWebRTCUtils;
 import com.vanniktech.emoji.EmojiManager;
 import com.vanniktech.emoji.twitter.TwitterEmojiProvider;
@@ -150,6 +151,8 @@ public class NextcloudTalkApplication extends MultiDexApplication implements Lif
         OneTimeWorkRequest capabilitiesUpdateWork = new OneTimeWorkRequest.Builder(CapabilitiesWorker.class).build();
         OneTimeWorkRequest signalingSettingsWork = new OneTimeWorkRequest.Builder(SignalingSettingsWorker.class).build();
 
+        new MerlinTheWizard().initMerlin();
+
         WorkManager.getInstance().enqueue(pushRegistrationWork);
         WorkManager.getInstance().enqueue(accountRemovalWork);
         WorkManager.getInstance().enqueue(capabilitiesUpdateWork);

+ 0 - 1
app/src/main/java/com/nextcloud/talk/controllers/CallController.java

@@ -582,7 +582,6 @@ public class CallController extends BaseController {
     public void onEnableSpeakerphoneClick() {
         if (audioManager != null) {
             audioManager.toggleUseSpeakerphone();
-            //callControlEnableSpeaker.flipSilently(!callControlEnableSpeaker.isFlipped());
         }
     }
 

+ 7 - 0
app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java

@@ -68,6 +68,7 @@ import com.nextcloud.talk.utils.database.user.UserUtils;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 import com.nextcloud.talk.utils.preferences.MagicUserInputModule;
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
+import com.nextcloud.talk.utils.singletons.MerlinTheWizard;
 import com.yarolegovich.lovelydialog.LovelySaveStateHandler;
 import com.yarolegovich.lovelydialog.LovelyStandardDialog;
 import com.yarolegovich.mp.*;
@@ -361,6 +362,12 @@ public class SettingsController extends BaseController {
     private void removeCurrentAccount() {
         boolean otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser.getId());
 
+        if (otherUserExists) {
+            new MerlinTheWizard().initMerlin();
+        } else {
+            new MerlinTheWizard().getMerlin().unbind();
+        }
+
         OneTimeWorkRequest accountRemovalWork = new OneTimeWorkRequest.Builder(AccountRemovalWorker.class).build();
         WorkManager.getInstance().enqueue(accountRemovalWork);
 

+ 36 - 0
app/src/main/java/com/nextcloud/talk/events/NetworkEvent.java

@@ -0,0 +1,36 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.events;
+
+import lombok.Data;
+
+@Data
+public class NetworkEvent {
+    public enum NetworkConnectionEvent {
+        NETWORK_CONNECTED, NETWORK_DISCONNECTED
+    }
+
+    private final NetworkConnectionEvent networkConnectionEvent;
+
+    public NetworkEvent(NetworkConnectionEvent networkConnectionEvent) {
+        this.networkConnectionEvent = networkConnectionEvent;
+    }
+}

+ 112 - 0
app/src/main/java/com/nextcloud/talk/utils/singletons/MerlinTheWizard.java

@@ -0,0 +1,112 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.utils.singletons;
+
+import android.content.Context;
+import android.database.Observable;
+import android.util.Log;
+import autodagger.AutoInjector;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.events.NetworkEvent;
+import com.nextcloud.talk.models.database.User;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.utils.database.user.UserUtils;
+import com.novoda.merlin.*;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
+import io.requery.Persistable;
+import io.requery.reactivex.ReactiveEntityStore;
+import io.requery.reactivex.ReactiveResult;
+import io.requery.util.ObservableList;
+import org.greenrobot.eventbus.EventBus;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@AutoInjector(NextcloudTalkApplication.class)
+public class MerlinTheWizard {
+    private static Merlin merlin;
+    private static MerlinsBeard merlinsBeard;
+
+    private  UserEntity currentUserEntity;
+
+    @Inject
+    EventBus eventBus;
+
+    @Inject
+    Context context;
+
+    @Inject
+    UserUtils userUtils;
+
+    public MerlinTheWizard() {
+        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
+    }
+
+    public void initMerlin() {
+        if (userUtils.anyUserExists() && (currentUserEntity == null ||
+                (userUtils.getCurrentUser().getId() != currentUserEntity.getId()))) {
+            currentUserEntity = userUtils.getCurrentUser();
+            setupMerlinForCurrentUserEntity();
+        }
+    }
+
+    public Merlin getMerlin() {
+        return merlin;
+    }
+
+    public MerlinsBeard getMerlinsBeard() {
+        return merlinsBeard;
+    }
+
+
+    private void setupMerlinForCurrentUserEntity() {
+        Endpoint endpoint = Endpoint.from(currentUserEntity.getBaseUrl() + "/index.php/204");
+        ResponseCodeValidator responseCodeValidator =
+                new ResponseCodeValidator.CaptivePortalResponseCodeValidator();
+
+        if (merlin != null) {
+            merlin.unbind();
+        }
+
+        merlin = new Merlin.Builder().withAllCallbacks().withEndpoint(endpoint).withResponseCodeValidator(responseCodeValidator).build(context);
+
+        merlin.bind();
+
+        merlinsBeard = new MerlinsBeard.Builder().withEndpoint(Endpoint.from(currentUserEntity.getBaseUrl() +
+                "/index.php/204")).withResponseCodeValidator(new ResponseCodeValidator.CaptivePortalResponseCodeValidator()).build(context);
+
+        merlin.registerConnectable(new Connectable() {
+            @Override
+            public void onConnect() {
+                eventBus.post(new NetworkEvent(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED));
+            }
+        });
+
+        merlin.registerDisconnectable(new Disconnectable() {
+            @Override
+            public void onDisconnect() {
+                eventBus.post(new NetworkEvent(NetworkEvent.NetworkConnectionEvent.NETWORK_DISCONNECTED));
+            }
+        });
+    }
+
+}

+ 29 - 3
app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java

@@ -20,21 +20,29 @@
 
 package com.nextcloud.talk.webrtc;
 
+import android.content.Context;
 import android.text.TextUtils;
 import android.util.Log;
 import autodagger.AutoInjector;
 import com.bluelinelabs.logansquare.LoganSquare;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.events.NetworkEvent;
 import com.nextcloud.talk.events.WebSocketCommunicationEvent;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.signaling.NCMessageWrapper;
 import com.nextcloud.talk.models.json.signaling.NCSignalingMessage;
 import com.nextcloud.talk.models.json.websocket.*;
 import com.nextcloud.talk.utils.MagicMap;
+import com.nextcloud.talk.utils.singletons.MerlinTheWizard;
+import com.novoda.merlin.Endpoint;
+import com.novoda.merlin.MerlinsBeard;
+import com.novoda.merlin.ResponseCodeValidator;
 import okhttp3.*;
 import okio.ByteString;
 import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
 
 import javax.inject.Inject;
 import java.io.IOException;
@@ -53,6 +61,9 @@ public class MagicWebSocketInstance extends WebSocketListener {
     @Inject
     EventBus eventBus;
 
+    @Inject
+    Context context;
+
     private UserEntity conversationUser;
     private String webSocketTicket;
     private String resumeId;
@@ -71,6 +82,7 @@ public class MagicWebSocketInstance extends WebSocketListener {
     private HashMap<String, String> displayNameHashMap;
     private HashMap<String, String> userIdSesssionHashMap;
 
+    private MerlinTheWizard merlinTheWizard;
     private List<String> messagesQueue = new ArrayList<>();
 
     MagicWebSocketInstance(UserEntity conversationUser, String connectionUrl, String webSocketTicket) {
@@ -84,7 +96,10 @@ public class MagicWebSocketInstance extends WebSocketListener {
         this.userIdSesssionHashMap = new HashMap<>();
         magicMap = new MagicMap();
 
+        merlinTheWizard = new MerlinTheWizard();
         connected = false;
+        eventBus.register(this);
+
         restartWebSocket();
     }
 
@@ -107,6 +122,7 @@ public class MagicWebSocketInstance extends WebSocketListener {
     }
 
     private void closeWebSocket(WebSocket webSocket) {
+        connected = false;
         webSocket.close(1000, null);
         webSocket.cancel();
         messagesQueue = new ArrayList<>();
@@ -116,9 +132,11 @@ public class MagicWebSocketInstance extends WebSocketListener {
     private void restartWebSocket() {
         reconnecting = true;
 
-        Request request = new Request.Builder().url(connectionUrl).build();
-        okHttpClient.newWebSocket(request, this);
-        restartCount++;
+        if (merlinTheWizard.getMerlinsBeard().hasInternetAccess()) {
+            Request request = new Request.Builder().url(connectionUrl).build();
+            okHttpClient.newWebSocket(request, this);
+            restartCount++;
+        }
     }
 
     @Override
@@ -335,4 +353,12 @@ public class MagicWebSocketInstance extends WebSocketListener {
     public String getSessionForUserId(String userId) {
         return userIdSesssionHashMap.get(userId);
     }
+
+    @Subscribe(threadMode = ThreadMode.BACKGROUND)
+    public void onMessageEvent(NetworkEvent networkEvent) {
+        if (networkEvent.getNetworkConnectionEvent().equals(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED) && !isConnected()) {
+            restartWebSocket();
+        }
+    }
+
 }

+ 1 - 0
app/src/main/res/layout/controller_call.xml

@@ -155,6 +155,7 @@
             <com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
                 android:id="@+id/callControlEnableSpeaker"
                 app:backgroundImage="@color/colorPrimary"
+                app:placeholderImage="@drawable/ic_volume_up_white_24dp"
                 app:roundAsCircle="true"
                 android:layout_width="60dp"
                 android:layout_height="60dp"