diff --git a/app/build.gradle b/app/build.gradle index 47ea25db2..2496da965 100644 --- a/app/build.gradle +++ b/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' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 22facacdf..209b743bf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -95,5 +95,9 @@ + + diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java index bd2b15e33..f50b1de30 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java +++ b/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); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java index b3e131e24..498b07498 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java +++ b/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()); } } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java b/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java index 6a3491b3e..fc3f02c16 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java +++ b/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); diff --git a/app/src/main/java/com/nextcloud/talk/events/NetworkEvent.java b/app/src/main/java/com/nextcloud/talk/events/NetworkEvent.java new file mode 100644 index 000000000..76406661d --- /dev/null +++ b/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 + * + * 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 . + */ + +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; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/singletons/MerlinTheWizard.java b/app/src/main/java/com/nextcloud/talk/utils/singletons/MerlinTheWizard.java new file mode 100644 index 000000000..f75966882 --- /dev/null +++ b/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 + * + * 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 . + */ + +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)); + } + }); + } + +} diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java index de6e86b7f..e1e85fa08 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java +++ b/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 displayNameHashMap; private HashMap userIdSesssionHashMap; + private MerlinTheWizard merlinTheWizard; private List 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(); + } + } + } diff --git a/app/src/main/res/layout/controller_call.xml b/app/src/main/res/layout/controller_call.xml index 235bb1e2e..9e86af0b4 100644 --- a/app/src/main/res/layout/controller_call.xml +++ b/app/src/main/res/layout/controller_call.xml @@ -155,6 +155,7 @@