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 d618a141a..e8a866e68 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java @@ -73,6 +73,7 @@ import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.power.PowerManagerUtils; import com.nextcloud.talk.utils.preferences.AppPreferences; import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder; +import com.nextcloud.talk.utils.singletons.MerlinTheWizard; import com.nextcloud.talk.webrtc.*; import com.wooplr.spotlight.SpotlightView; import io.reactivex.Observable; @@ -88,6 +89,7 @@ import org.apache.commons.lang3.StringEscapeUtils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import org.parceler.Parcel; import org.webrtc.*; import pub.devrel.easypermissions.AfterPermissionGranted; @@ -165,7 +167,7 @@ public class CallController extends BaseController { private VideoCapturer videoCapturer; private EglBase rootEglBase; private boolean leavingCall = false; - private boolean inCall = false; + private boolean connectedToCall = false; private Disposable signalingDisposable; private Disposable pingDisposable; private List iceServers; @@ -199,7 +201,7 @@ public class CallController extends BaseController { private SpotlightView spotlightView; private ExternalSignalingServer externalSignalingServer; - private MagicWebSocketInstance webSocketClient ; + private MagicWebSocketInstance webSocketClient; private WebSocketConnectionHelper webSocketConnectionHelper; private boolean hasMCU; private boolean hasExternalSignalingServer; @@ -207,6 +209,15 @@ public class CallController extends BaseController { private PowerManagerUtils powerManagerUtils; + private Handler handler; + + private CallStatus currentCallStatus; + + @Parcel + public enum CallStatus { + CALLING, CALLING_TIMEOUT, ESTABLISHED, RECONNECTING, OFFLINE + } + public CallController(Bundle args) { super(args); NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this); @@ -227,6 +238,7 @@ public class CallController extends BaseController { isFromNotification = TextUtils.isEmpty(roomToken); powerManagerUtils = new PowerManagerUtils(); + currentCallStatus = CallStatus.CALLING; } @Override @@ -273,13 +285,9 @@ public class CallController extends BaseController { callControls.setZ(100.0f); basicInitialization(); + initViews(); - if (isFromNotification) { - handleFromNotification(); - } else { - initViews(); - checkPermissions(); - } + initiateCall(); } private void basicInitialization() { @@ -357,7 +365,6 @@ public class CallController extends BaseController { } } - initViews(); checkPermissions(); } @@ -427,7 +434,7 @@ public class CallController extends BaseController { } } - if (!inCall) { + if (!connectedToCall) { fetchSignalingSettings(); } } else if (getActivity() != null && EffortlessPermissions.somePermissionPermanentlyDenied(getActivity(), @@ -466,7 +473,7 @@ public class CallController extends BaseController { microphoneControlButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px); } - if (!inCall) { + if (!connectedToCall) { fetchSignalingSettings(); } } @@ -484,7 +491,7 @@ public class CallController extends BaseController { if (getActivity() != null && (EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA) || EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_MICROPHONE))) { checkIfSomeAreApproved(); - } else if (!inCall) { + } else if (!connectedToCall) { fetchSignalingSettings(); } } @@ -634,7 +641,7 @@ public class CallController extends BaseController { toggleMedia(true, false); } - if (isVoiceOnlyCall && !inCall) { + if (isVoiceOnlyCall && !connectedToCall) { fetchSignalingSettings(); } @@ -656,7 +663,7 @@ public class CallController extends BaseController { @OnClick(R.id.callControlHangupView) void onHangupClick() { - hangup(false); + hangup(true); } @OnClick(R.id.call_control_camera) @@ -751,7 +758,7 @@ public class CallController extends BaseController { } } - if (inCall) { + if (connectedToCall) { if (!hasMCU) { for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) { magicPeerConnectionWrapperList.get(i).sendChannelData(new DataChannelMessage(message)); @@ -1056,7 +1063,8 @@ public class CallController extends BaseController { @Override public void onNext(GenericOverall genericOverall) { - inCall = true; + connectedToCall = true; + currentCallStatus = CallStatus.CALLING; if (connectingView != null) { connectingView.setVisibility(View.GONE); @@ -1077,8 +1085,8 @@ public class CallController extends BaseController { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .repeatWhen(observable -> observable.delay(5000, TimeUnit.MILLISECONDS)) - .takeWhile(observable -> inCall) - .retry(3, observable -> inCall) + .takeWhile(observable -> connectedToCall) + .retry(3, observable -> connectedToCall) .subscribe(new Observer() { @Override public void onSubscribe(Disposable d) { @@ -1110,7 +1118,7 @@ public class CallController extends BaseController { if (!conversationUser.hasSpreedCapabilityWithName("no-ping") && !TextUtils.isEmpty(roomId)) { NotificationUtils.cancelExistingNotifications(getApplicationContext(), conversationUser, roomId); - } else if (!TextUtils.isEmpty(roomToken)){ + } else if (!TextUtils.isEmpty(roomToken)) { NotificationUtils.cancelExistingNotifications(getApplicationContext(), conversationUser, roomToken); } @@ -1119,8 +1127,8 @@ public class CallController extends BaseController { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .repeatWhen(observable -> observable) - .takeWhile(observable -> inCall) - .retry(3, observable -> inCall) + .takeWhile(observable -> connectedToCall) + .retry(3, observable -> connectedToCall) .subscribe(new Observer() { @Override public void onSubscribe(Disposable d) { @@ -1177,11 +1185,24 @@ public class CallController extends BaseController { joinRoomAndCall(); } + private void initiateCall() { + if (!TextUtils.isEmpty(roomToken)) { + checkPermissions(); + } else { + handleFromNotification(); + } + } @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessageEvent(WebSocketCommunicationEvent webSocketCommunicationEvent) { switch (webSocketCommunicationEvent.getType()) { case "hello": - joinRoomAndCall(); + if (!currentCallStatus.equals(CallStatus.RECONNECTING)) { + if (!webSocketCommunicationEvent.getHashMap().containsKey("oldResumeId")) { + initiateCall(); + } else { + // do nothing, let's just continue + } + } break; case "roomJoined": if (hasExternalSignalingServer) { @@ -1300,104 +1321,105 @@ public class CallController extends BaseController { } } - private void hangup(boolean dueToNetworkChange) { + private void hangup(boolean shutDownView) { leavingCall = true; - inCall = false; + connectedToCall = false; - if (videoCapturer != null) { - try { - videoCapturer.stopCapture(); - } catch (InterruptedException e) { - Log.e(TAG, "Failed to stop capturing while hanging up"); + if (shutDownView) { + if (videoCapturer != null) { + try { + videoCapturer.stopCapture(); + } catch (InterruptedException e) { + Log.e(TAG, "Failed to stop capturing while hanging up"); + } + videoCapturer.dispose(); + videoCapturer = null; + } + + if (pipVideoView != null) { + pipVideoView.release(); + } + + if (audioSource != null) { + audioSource.dispose(); + audioSource = null; + } + + if (audioManager != null) { + audioManager.stop(); + audioManager = null; + } + + if (videoSource != null) { + videoSource = null; + } + + if (peerConnectionFactory != null) { + peerConnectionFactory = null; + } + + localMediaStream = null; + localAudioTrack = null; + localVideoTrack = null; + + + if (TextUtils.isEmpty(credentials) && hasExternalSignalingServer) { + WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(-1); } - videoCapturer.dispose(); - videoCapturer = null; } for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) { endPeerConnection(magicPeerConnectionWrapperList.get(i).getSessionId(), false); - } - if (pipVideoView != null) { - pipVideoView.release(); - } - - if (audioSource != null) { - audioSource.dispose(); - audioSource = null; - } - - if (audioManager != null) { - audioManager.stop(); - audioManager = null; - } - - if (videoSource != null) { - videoSource = null; - } - - if (peerConnectionFactory != null) { - peerConnectionFactory = null; - } - - localMediaStream = null; - localAudioTrack = null; - localVideoTrack = null; - - - if (TextUtils.isEmpty(credentials) && hasExternalSignalingServer) { - WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(-1); - } - - if (!dueToNetworkChange) { - hangupNetworkCalls(); - } else { - if (getActivity() != null) { - getActivity().finish(); - } - } + hangupNetworkCalls(shutDownView); } - private void hangupNetworkCalls() { - ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { + private void hangupNetworkCalls(boolean shutDownView) { + if (MerlinTheWizard.isConnectedToInternet()) { + ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { - } - - @Override - public void onNext(GenericOverall genericOverall) { - if (hasExternalSignalingServer) { - webSocketClient.joinRoomWithRoomTokenAndSession("", callSession); } - if (isMultiSession) { - if (getActivity() != null) { - getActivity().finish(); + @Override + public void onNext(GenericOverall genericOverall) { + if (!TextUtils.isEmpty(credentials) && hasExternalSignalingServer) { + webSocketClient.joinRoomWithRoomTokenAndSession("", callSession); + } + + if (isMultiSession) { + if (shutDownView && getActivity() != null) { + getActivity().finish(); + } else if (!shutDownView && currentCallStatus.equals(CallStatus.RECONNECTING)) { + initiateCall(); + } + } else { + leaveRoom(shutDownView); } - } else { - leaveRoom(); } - } - @Override - public void onError(Throwable e) { + @Override + public void onError(Throwable e) { - } + } - @Override - public void onComplete() { + @Override + public void onComplete() { - } - }); + } + }); + } else if (shutDownView && getActivity() != null) { + getActivity().finish(); + } } - private void leaveRoom() { + private void leaveRoom(boolean shutDownView) { ncApi.leaveRoom(credentials, ApiUtils.getUrlForSettingMyselfAsActiveParticipant(baseUrl, roomToken)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -1409,7 +1431,7 @@ public class CallController extends BaseController { @Override public void onNext(GenericOverall genericOverall) { - if (getActivity() != null) { + if (shutDownView && getActivity() != null) { getActivity().finish(); } } @@ -1431,7 +1453,7 @@ public class CallController extends BaseController { videoCapturer.startCapture(1280, 720, 30); } } - + private void processUsersInRoom(List> users) { List newSessions = new ArrayList<>(); Set oldSesssions = new HashSet<>(); @@ -1633,6 +1655,7 @@ public class CallController extends BaseController { pipVideoView.setLayoutParams(layoutParams); } } + @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) { if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType @@ -1647,7 +1670,7 @@ public class CallController extends BaseController { boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent .PeerConnectionEventType.SENSOR_FAR) && videoOn; if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA) && - inCall && videoOn + connectedToCall && videoOn && enableVideo != localVideoTrack.enabled()) { toggleMedia(enableVideo, true); } @@ -1678,7 +1701,7 @@ public class CallController extends BaseController { int finalI = i; Observable .interval(1, TimeUnit.SECONDS) - .takeWhile(observer -> inCall) + .takeWhile(observer -> connectedToCall) .observeOn(Schedulers.io()) .doOnNext(n -> magicPeerConnectionWrapperList.get(finalI).sendChannelData(dataChannelMessage)); break; @@ -1796,14 +1819,23 @@ public class CallController extends BaseController { if (relativeLayout != null) { SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView); - if (participantMap.containsKey(session) && avatarImageView.getDrawable() == null) { + String userId; + + if (hasMCU) { + userId = webSocketClient.getUserIdForSession(session); + } else { + userId = participantMap.get(session).getUserId(); + } + + if (!TextUtils.isEmpty(userId)) { if (getActivity() != null) { + avatarImageView.setController(null); + DraweeController draweeController = Fresco.newDraweeControllerBuilder() .setOldController(avatarImageView.getController()) - .setAutoPlayAnimations(true) .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(baseUrl, - participantMap.get(session).getUserId(), + userId, R.dimen.avatar_size_big), null)) .build(); avatarImageView.setController(draweeController); @@ -1958,4 +1990,24 @@ public class CallController extends BaseController { showCallControls(); } } + + @Subscribe(threadMode = ThreadMode.BACKGROUND) + public void onMessageEvent(NetworkEvent networkEvent) { + if (networkEvent.getNetworkConnectionEvent().equals(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED)) { + if (handler != null) { + handler.removeCallbacksAndMessages(null); + } + + currentCallStatus = CallStatus.RECONNECTING; + hangupNetworkCalls(false); + + } else if (networkEvent.getNetworkConnectionEvent().equals(NetworkEvent.NetworkConnectionEvent.NETWORK_DISCONNECTED)) { + if (handler != null) { + handler.removeCallbacksAndMessages(null); + } + + currentCallStatus = CallStatus.OFFLINE; + hangup(false); + } + } } 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 index 162f1386b..5e348a4d9 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/singletons/MerlinTheWizard.java +++ b/app/src/main/java/com/nextcloud/talk/utils/singletons/MerlinTheWizard.java @@ -34,7 +34,6 @@ import javax.inject.Inject; @AutoInjector(NextcloudTalkApplication.class) public class MerlinTheWizard { private static Merlin merlin; - private static MerlinsBeard merlinsBeard; private UserEntity currentUserEntity; @@ -47,10 +46,16 @@ public class MerlinTheWizard { @Inject UserUtils userUtils; + private static boolean isConnectedToInternet; + public MerlinTheWizard() { NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this); } + public static boolean isConnectedToInternet() { + return isConnectedToInternet; + } + public void initMerlin() { if (userUtils.anyUserExists() && (currentUserEntity == null || (userUtils.getCurrentUser().getId() != currentUserEntity.getId()))) { @@ -60,14 +65,13 @@ public class MerlinTheWizard { } public Merlin getMerlin() { + if (merlin == null) { + initMerlin(); + } + return merlin; } - public MerlinsBeard getMerlinsBeard() { - return merlinsBeard; - } - - private void setupMerlinForCurrentUserEntity() { Endpoint endpoint = Endpoint.from(currentUserEntity.getBaseUrl() + "/index.php/204"); ResponseCodeValidator responseCodeValidator = @@ -81,12 +85,10 @@ public class MerlinTheWizard { 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() { + isConnectedToInternet = true; eventBus.post(new NetworkEvent(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED)); } }); @@ -94,6 +96,7 @@ public class MerlinTheWizard { merlin.registerDisconnectable(new Disconnectable() { @Override public void onDisconnect() { + isConnectedToInternet = false; eventBus.post(new NetworkEvent(NetworkEvent.NetworkConnectionEvent.NETWORK_DISCONNECTED)); } }); diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java index a0beed66c..13016bc0b 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java @@ -36,6 +36,7 @@ import com.nextcloud.talk.events.WebSocketCommunicationEvent; import com.nextcloud.talk.models.json.signaling.DataChannelMessage; import com.nextcloud.talk.models.json.signaling.NCIceCandidate; import com.nextcloud.talk.utils.LoggingUtils; +import com.nextcloud.talk.utils.singletons.MerlinTheWizard; import org.greenrobot.eventbus.EventBus; import org.webrtc.*; @@ -53,7 +54,7 @@ public class MagicPeerConnectionWrapper { private PeerConnection peerConnection; private String sessionId; private String nick; - private MediaConstraints mediaConstraints; + private MediaConstraints sdpConstraints; private DataChannel magicDataChannel; private MagicSdpObserver magicSdpObserver; private MediaStream remoteMediaStream; @@ -65,14 +66,17 @@ public class MagicPeerConnectionWrapper { private MediaStream localMediaStream; private boolean isMCUPublisher; + private boolean hasMCU; private String videoStreamType; + private int connectionAttempts = 0; + @Inject Context context; public MagicPeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory, List iceServerList, - MediaConstraints mediaConstraints, + MediaConstraints sdpConstraints, String sessionId, String localSession, @Nullable MediaStream mediaStream, boolean isMCUPublisher, boolean hasMCU, String videoStreamType) { @@ -80,15 +84,16 @@ public class MagicPeerConnectionWrapper { this.localMediaStream = mediaStream; this.videoStreamType = videoStreamType; + this.hasMCU = hasMCU; this.sessionId = sessionId; - this.mediaConstraints = mediaConstraints; + this.sdpConstraints = sdpConstraints; magicSdpObserver = new MagicSdpObserver(); hasInitiated = sessionId.compareTo(localSession) < 0; this.isMCUPublisher = isMCUPublisher; - - peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, mediaConstraints, + + peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, sdpConstraints, new MagicPeerConnectionObserver()); if (peerConnection != null) { @@ -102,13 +107,13 @@ public class MagicPeerConnectionWrapper { magicDataChannel = peerConnection.createDataChannel("status", init); magicDataChannel.registerObserver(new MagicDataChannelObserver()); if (isMCUPublisher) { - peerConnection.createOffer(magicSdpObserver, mediaConstraints); + peerConnection.createOffer(magicSdpObserver, sdpConstraints); } else if (hasMCU) { HashMap hashMap = new HashMap<>(); hashMap.put("sessionId", sessionId); EventBus.getDefault().post(new WebSocketCommunicationEvent("peerReadyForRequestingOffer", hashMap)); } else if (hasInitiated) { - peerConnection.createOffer(magicSdpObserver, mediaConstraints); + peerConnection.createOffer(magicSdpObserver, sdpConstraints); } } @@ -287,6 +292,26 @@ public class MagicPeerConnectionWrapper { } } + private void restartIce() { + if (connectionAttempts <= 5) { + if (!hasMCU || isMCUPublisher) { + MediaConstraints.KeyValuePair iceRestartConstraint = + new MediaConstraints.KeyValuePair("IceRestart", "true"); + + if (sdpConstraints.mandatory.contains(iceRestartConstraint)) { + sdpConstraints.mandatory.add(iceRestartConstraint); + } + + peerConnection.createOffer(magicSdpObserver, sdpConstraints); + } else { + // we have an MCU and this is not the publisher + // Do something if we have an MCU + } + + connectionAttempts++; + } + } + private class MagicPeerConnectionObserver implements PeerConnection.Observer { private final String TAG = "MagicPeerConnectionObserver"; @@ -300,6 +325,7 @@ public class MagicPeerConnectionWrapper { "iceConnectionChangeTo: " + iceConnectionState.name() + " over " + peerConnection.hashCode() + " " + sessionId); if (iceConnectionState.equals(PeerConnection.IceConnectionState.CONNECTED)) { + connectionAttempts = 0; /*EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType .PEER_CONNECTED, sessionId, null, null));*/ @@ -314,6 +340,11 @@ public class MagicPeerConnectionWrapper { } else if (iceConnectionState.equals(PeerConnection.IceConnectionState.CLOSED)) { EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType .PEER_CLOSED, sessionId, null, null, videoStreamType)); + connectionAttempts = 0; + } else if (iceConnectionState.equals(PeerConnection.IceConnectionState.FAILED)) { + if (MerlinTheWizard.isConnectedToInternet() && connectionAttempts < 5) { + restartIce(); + } } } @@ -413,7 +444,7 @@ public class MagicPeerConnectionWrapper { public void onSetSuccess() { if (peerConnection != null) { if (peerConnection.getLocalDescription() == null) { - peerConnection.createAnswer(magicSdpObserver, mediaConstraints); + peerConnection.createAnswer(magicSdpObserver, sdpConstraints); } if (peerConnection.getRemoteDescription() != null) { 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 da630ede6..289562f21 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java @@ -30,15 +30,13 @@ 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.participants.Participant; 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.LoggingUtils; 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; @@ -80,10 +78,8 @@ public class MagicWebSocketInstance extends WebSocketListener { private int restartCount = 0; private boolean reconnecting = false; - private HashMap displayNameHashMap; - private HashMap userIdSesssionHashMap; + private HashMap usersHashMap; - private MerlinTheWizard merlinTheWizard; private List messagesQueue = new ArrayList<>(); MagicWebSocketInstance(UserEntity conversationUser, String connectionUrl, String webSocketTicket) { @@ -93,11 +89,9 @@ public class MagicWebSocketInstance extends WebSocketListener { this.conversationUser = conversationUser; this.webSocketTicket = webSocketTicket; this.webSocketConnectionHelper = new WebSocketConnectionHelper(); - this.displayNameHashMap = new HashMap<>(); - this.userIdSesssionHashMap = new HashMap<>(); + this.usersHashMap = new HashMap<>(); magicMap = new MagicMap(); - merlinTheWizard = new MerlinTheWizard(); connected = false; eventBus.register(this); @@ -133,7 +127,7 @@ public class MagicWebSocketInstance extends WebSocketListener { private void restartWebSocket() { reconnecting = true; - if (merlinTheWizard.getMerlinsBeard().hasInternetAccess()) { + if (MerlinTheWizard.isConnectedToInternet()) { Request request = new Request.Builder().url(connectionUrl).build(); okHttpClient.newWebSocket(request, this); restartCount++; @@ -155,6 +149,7 @@ public class MagicWebSocketInstance extends WebSocketListener { connected = true; reconnecting = false; restartCount = 0; + String oldResumeId = resumeId; HelloResponseOverallWebSocketMessage helloResponseWebSocketMessage = LoganSquare.parse(text, HelloResponseOverallWebSocketMessage.class); resumeId = helloResponseWebSocketMessage.getHelloResponseWebSocketMessage().getResumeId(); sessionId = helloResponseWebSocketMessage.getHelloResponseWebSocketMessage().getSessionId(); @@ -165,7 +160,11 @@ public class MagicWebSocketInstance extends WebSocketListener { } messagesQueue = new ArrayList<>(); - eventBus.post(new WebSocketCommunicationEvent("hello", null)); + HashMap helloHasHap = new HashMap<>(); + if (!TextUtils.isEmpty(oldResumeId)) { + helloHasHap.put("oldResumeId", oldResumeId); + } + eventBus.post(new WebSocketCommunicationEvent("hello", helloHasHap)); break; case "error": ErrorOverallWebSocketMessage errorOverallWebSocketMessage = LoganSquare.parse(text, ErrorOverallWebSocketMessage.class); @@ -187,8 +186,7 @@ public class MagicWebSocketInstance extends WebSocketListener { joinRoomHashMap.put("roomToken", currentRoomToken); eventBus.post(new WebSocketCommunicationEvent("roomJoined", joinRoomHashMap)); } else { - userIdSesssionHashMap = new HashMap<>(); - displayNameHashMap = new HashMap<>(); + usersHashMap = new HashMap<>(); } break; case "event": @@ -216,11 +214,14 @@ public class MagicWebSocketInstance extends WebSocketListener { } else if (eventOverallWebSocketMessage.getEventMap().get("type").equals("join")) { List> joinEventMap = (List>) eventOverallWebSocketMessage.getEventMap().get("join"); HashMap internalHashMap; + Participant participant; for (int i = 0; i < joinEventMap.size(); i++) { internalHashMap = joinEventMap.get(i); HashMap userMap = (HashMap) internalHashMap.get("user"); - displayNameHashMap.put((String) internalHashMap.get("sessionid"), (String) userMap.get("displayname")); - userIdSesssionHashMap.put((String) internalHashMap.get("userid"), (String) internalHashMap.get("sessionid")); + participant = new Participant(); + participant.setUserId((String) internalHashMap.get("userid")); + participant.setDisplayName((String) userMap.get("displayname")); + usersHashMap.put((String) internalHashMap.get("sessionid"), participant); } } break; @@ -359,15 +360,29 @@ public class MagicWebSocketInstance extends WebSocketListener { } public String getDisplayNameForSession(String session) { - if (displayNameHashMap.containsKey(session)) { - return displayNameHashMap.get(session); + if (usersHashMap.containsKey(session)) { + return usersHashMap.get(session).getDisplayName(); } return NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_nick_guest); } public String getSessionForUserId(String userId) { - return userIdSesssionHashMap.get(userId); + for (String session : usersHashMap.keySet()) { + if (userId.equals(usersHashMap.get(session).getUserId())) { + return session; + } + } + + return ""; + } + + public String getUserIdForSession(String session) { + if (usersHashMap.containsKey(session)) { + return usersHashMap.get(session).getUserId(); + } + + return ""; } @Subscribe(threadMode = ThreadMode.BACKGROUND) @@ -376,5 +391,4 @@ public class MagicWebSocketInstance extends WebSocketListener { restartWebSocket(); } } - } diff --git a/app/src/main/res/values/setup.xml b/app/src/main/res/values/setup.xml index ede3507a6..8bb13c6f3 100644 --- a/app/src/main/res/values/setup.xml +++ b/app/src/main/res/values/setup.xml @@ -23,7 +23,7 @@ HvAfHtAy/QdFYqAWFFXa1VV_Iv6ZQ1.tf5swMc^45wS_vz=Wm[oyRP5D- nc - true + false Nextcloud Talk Nextcloud