From e51ab67c379daee44dd9f2ff87e9d12e31228d5e Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 14 Nov 2024 11:46:12 +0100 Subject: [PATCH 1/4] fix check for remote server As remote server is empty instead null when not available, the check was also true when no remote server was in use. Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 8723a4beea..61c9bb91b0 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2514,7 +2514,7 @@ class ChatActivity : return } - if (currentConversation!!.remoteServer != null) { + if (currentConversation!!.remoteServer?.isNotEmpty() == true) { val apiVersion = ApiUtils.getSignalingApiVersion(conversationUser!!, intArrayOf(ApiUtils.API_V3, 2, 1)) ncApi.getSignalingSettings( credentials, From 3bd1a533e3664e4ace46c70e9b18de1982d86314 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 14 Nov 2024 11:50:26 +0100 Subject: [PATCH 2/4] fix ANR error (blockingSubscribe in setupWebsocket) The request seems to cause problems so blockingSubscribe doesn't seem to be a good choice here. This commit will replace blockingSubscribe by subscribe and modify the related code in order to be executed when the request succeeds. The root cause why the request seems to cause problems may have to be analyzed further. I was not able to reproduce the ANR without this PR, however the following error was reported on gplay console very often!: at jdk.internal.misc.Unsafe.park (Native method) at java.util.concurrent.locks.LockSupport.park (LockSupport.java:341) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block (AbstractQueuedSynchronizer.java:506) at java.util.concurrent.ForkJoinPool.unmanagedBlock (ForkJoinPool.java:3466) at java.util.concurrent.ForkJoinPool.managedBlock (ForkJoinPool.java:3437) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await (AbstractQueuedSynchronizer.java:1623) at java.util.concurrent.LinkedBlockingQueue.take (LinkedBlockingQueue.java:435) at io.reactivex.internal.operators.observable.ObservableBlockingSubscribe.subscribe (ObservableBlockingSubscribe.java:56) at io.reactivex.Observable.blockingSubscribe (Observable.java:5552) at com.nextcloud.talk.chat.ChatActivity.setupWebsocket (ChatActivity.kt:2445) at com.nextcloud.talk.chat.ChatActivity.joinRoomWithPassword (ChatActivity.kt:2402) at com.nextcloud.talk.chat.ChatActivity.initObservers$lambda$13 (ChatActivity.kt:594) at com.nextcloud.talk.chat.ChatActivity.$r8$lambda$QKH5JCFLmCzRMlSJ-EV-m4IW5ig (unavailable) at com.nextcloud.talk.chat.ChatActivity$$ExternalSyntheticLambda38.invoke (D8$$SyntheticClass) at com.nextcloud.talk.chat.ChatActivity$sam$androidx_lifecycle_Observer$0.onChanged (unavailable:2) at androidx.lifecycle.LiveData.considerNotify (LiveData.java:133) at androidx.lifecycle.LiveData.dispatchingValue (LiveData.java:151) at androidx.lifecycle.LiveData.setValue (LiveData.java:309) at androidx.lifecycle.MutableLiveData.setValue (MutableLiveData.java:50) at com.nextcloud.talk.chat.viewmodels.ChatViewModel.getCapabilities (ChatViewModel.kt:240) at com.nextcloud.talk.chat.ChatActivity$initObservers$1$1.invokeSuspend (ChatActivity.kt:553) at com.nextcloud.talk.chat.ChatActivity$initObservers$1$1.invoke (unavailable:8) at com.nextcloud.talk.chat.ChatActivity$initObservers$1$1.invoke (unavailable:4) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit (Emitters.kt:219) at kotlinx.coroutines.flow.FlowKt__ErrorsKt$catchImpl$2.emit (Errors.kt:154) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit (Emitters.kt:220) at kotlinx.coroutines.flow.SharedFlowImpl.collect$suspendImpl (SharedFlow.kt:392) at kotlinx.coroutines.flow.SharedFlowImpl$collect$1.invokeSuspend (unavailable:15) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:104) at android.os.Handler.handleCallback (Handler.java:938) at android.os.Handler.dispatchMessage (Handler.java:99) at android.os.Looper.loopOnce (Looper.java:210) at android.os.Looper.loop (Looper.java:299) at android.app.ActivityThread.main (ActivityThread.java:8168) at java.lang.reflect.Method.invoke (Native method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:556) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1037) Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/chat/ChatActivity.kt | 116 ++++++++++-------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 61c9bb91b0..0161123c7f 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -184,7 +184,9 @@ import com.stfalcon.chatkit.messages.MessageHolders.ContentChecker import com.stfalcon.chatkit.messages.MessagesListAdapter import com.stfalcon.chatkit.utils.DateFormatter import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -702,14 +704,8 @@ class ChatActivity : logConversationInfos("joinRoomWithPassword#onNext") setupWebsocket() - if (webSocketInstance != null) { - webSocketInstance?.joinRoomWithRoomTokenAndSession( - roomToken, - sessionIdAfterRoomJoined, - externalSignalingServer?.federation - ) - } - if (startCallFromNotification != null && startCallFromNotification) { + + if (startCallFromNotification) { startCallFromNotification = false startACall(voiceOnly, false) } @@ -2477,13 +2473,6 @@ class ChatActivity : Log.d(TAG, "sessionID was valid -> skip joinRoom") setupWebsocket() - if (webSocketInstance != null) { - webSocketInstance?.joinRoomWithRoomTokenAndSession( - roomToken, - sessionIdAfterRoomJoined, - externalSignalingServer?.federation - ) - } } } @@ -2519,52 +2508,73 @@ class ChatActivity : ncApi.getSignalingSettings( credentials, ApiUtils.getUrlForSignalingSettings(apiVersion, conversationUser!!.baseUrl, roomToken) - ).blockingSubscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(signalingSettingsOverall: SignalingSettingsOverall) { - if (signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer == null || - signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer?.isEmpty() == true - ) { - return + ) + .subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm } - externalSignalingServer = ExternalSignalingServer() - externalSignalingServer!!.externalSignalingServer = signalingSettingsOverall.ocs!!.settings!! - .externalSignalingServer - externalSignalingServer!!.externalSignalingTicket = signalingSettingsOverall.ocs!!.settings!! - .externalSignalingTicket - externalSignalingServer!!.federation = signalingSettingsOverall.ocs!!.settings!!.federation - - webSocketInstance = WebSocketConnectionHelper.getExternalSignalingInstanceForServer( - externalSignalingServer!!.externalSignalingServer, - conversationUser, - externalSignalingServer!!.externalSignalingTicket, - TextUtils.isEmpty(credentials) - ) - } + override fun onNext(signalingSettingsOverall: SignalingSettingsOverall) { + if (signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer == null || + signalingSettingsOverall.ocs!!.settings!!.externalSignalingServer?.isEmpty() == true + ) { + return + } - override fun onError(e: Throwable) { - Log.e(CallActivity.TAG, e.message, e) - } + externalSignalingServer = ExternalSignalingServer() + externalSignalingServer!!.externalSignalingServer = signalingSettingsOverall.ocs!!.settings!! + .externalSignalingServer + externalSignalingServer!!.externalSignalingTicket = signalingSettingsOverall.ocs!!.settings!! + .externalSignalingTicket + externalSignalingServer!!.federation = signalingSettingsOverall.ocs!!.settings!!.federation + + webSocketInstance = WebSocketConnectionHelper.getExternalSignalingInstanceForServer( + externalSignalingServer!!.externalSignalingServer, + conversationUser, + externalSignalingServer!!.externalSignalingTicket, + TextUtils.isEmpty(credentials) + ) - override fun onComplete() { - // unused atm - } - }) + if (webSocketInstance != null) { + webSocketInstance?.joinRoomWithRoomTokenAndSession( + roomToken, + sessionIdAfterRoomJoined, + externalSignalingServer?.federation + ) + } + + signalingMessageSender = webSocketInstance?.signalingMessageSender + webSocketInstance?.getSignalingMessageReceiver()?.addListener(localParticipantMessageListener) + webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) + } + + override fun onError(e: Throwable) { + Log.e(TAG, e.message, e) + } + + override fun onComplete() { + // unused atm + } + }) } else { webSocketInstance = WebSocketConnectionHelper.getWebSocketInstanceForUser(conversationUser!!) - } - if (webSocketInstance == null) { - Log.d(TAG, "webSocketInstance not set up. This should only happen when not using the HPB") - } + if (webSocketInstance != null) { + webSocketInstance?.joinRoomWithRoomTokenAndSession( + roomToken, + sessionIdAfterRoomJoined, + null + ) - signalingMessageSender = webSocketInstance?.signalingMessageSender - webSocketInstance?.getSignalingMessageReceiver()?.addListener(localParticipantMessageListener) - webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) + signalingMessageSender = webSocketInstance?.signalingMessageSender + webSocketInstance?.getSignalingMessageReceiver()?.addListener(localParticipantMessageListener) + webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) + } else { + Log.d(TAG, "webSocketInstance not set up. This is only expected when not using the HPB") + } + } } private fun processCallStartedMessages(chatMessageList: List) { From 8dd1b885f3eaa63e6544d7f8b7acb454e05e32b6 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 14 Nov 2024 12:04:12 +0100 Subject: [PATCH 3/4] fix check if federated is still the same Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt index 10f338b1a2..c6d1a9df25 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt @@ -391,7 +391,7 @@ class WebSocketInstance internal constructor( roomToken == currentRoomToken && normalBackendSession == currentNormalBackendSession && federation?.roomId == currentFederation?.roomId && - federation?.nextcloudServer == federation?.nextcloudServer + federation?.nextcloudServer == currentFederation?.nextcloudServer ) { Log.d(TAG, "roomToken & session are unchanged. Joining locally without to send websocket message") sendRoomJoinedEvent() From acd964869d5f52bdae8c50020cef2ce71b85146a Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 14 Nov 2024 12:27:22 +0100 Subject: [PATCH 4/4] add disposable however i was not able to see onDestroy being executed. anyway, disposables won't be necessary when coroutine is used. also: remove a useless outdated log line Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 0161123c7f..8becfc6c82 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -2448,7 +2448,7 @@ class ChatActivity : currentlyPlayedVoiceMessage?.let { stopMediaPlayer(it) } // FIXME, mediaplayer can sometimes be null here adapter = null - Log.d(TAG, "inConversation was set to false!") + disposables.dispose() } private fun joinRoomWithPassword() { @@ -2513,7 +2513,7 @@ class ChatActivity : ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(object : Observer { override fun onSubscribe(d: Disposable) { - // unused atm + disposables.add(d) } override fun onNext(signalingSettingsOverall: SignalingSettingsOverall) {