The SDP constraints should be set when the MCU is used, but only for
publisher connections; receiver connections should use the general SDP
constraints.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
When the data channel is not open yet data channel messages are queued
and then sent once opened. "onStateChange" is called from the WebRTC
signaling thread, while "send" can be called potentially from any
thread, so to send the data channel messages in the same order that they
were added new messages need to be enqueued until all the pending
messages have been sent. Otherwise, even if there is synchronization
already, it could happen that "onStateChange" was called but, before
getting the lock, "send" gets it and sends the new message before the
pending messages were sent.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Adding and disposing remote data channels is done from different
threads; they are added from the WebRTC signaling thread when
"onDataChannel" is called, while they can be disposed potentially from
any thread when "removePeerConnection" is called. To prevent race
conditions between them now both operations are synchronized.
However, as "onDataChannel" belongs to an inner class it needs to use a
synchronized statement with the outer class lock. This could still cause
a race condition if the same data channel was added again; this should
not happen, but it is handled just in case.
Moreover, once a data channel is disposed it can be no longer used, and
trying to call any of its methods throws an "IllegalStateException". Due
to this, as sending can be also done potentially from any thread, it
needs to be synchronized too with removing the peer connection.
State changes on data channels as well as receiving messages are also
done in the WebRTC signaling thread. State changes needs synchronization
as well, although receiving messages should not, as it does not directly
use the data channel (and it is assumed that using the buffers of a
disposed data channel is safe). Nevertheless a little check (which in
this case requires synchronization) was added to ignore the received
messages if the peer connection was removed already.
Finally, the synchronization added to "send" and "onStateChange" had the
nice side effect of making the pending data channel messages thread-safe
too, as before it could happen that a message was enqueued when the
pending messages were being sent, which caused a
"ConcurrentModificationException".
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Getting the label is no longer possible once the data channel has been
disposed. This will help to make the observer thread-safe.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Data channel messages can be sent only when the data channel is open.
Otherwise the message is simply lost. Clients of the
PeerConnectionWrapper do not need to be aware of that detail or keep
track of whether the data channel was open already or not, so now data
channel messages sent before the data channel is open are queued and
sent once the data channel is opened.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Data channel messages are expected to be sent using the "status" data
channel that is locally created. However, if another data channel was
opened by the remote peer the reference to the "status" data channel was
overwritten with the new data channel, and messages were sent instead on
the remote data channel.
In current Talk versions that was not a problem, and the change makes no
difference either, because since the support for Janus 1.x was added
data channel messages are listened on all data channels, independently
of their label or whether they were created by the local or remote peer.
However, in older Talk versions this fixes a regression introduced with
the support for Janus 1.x. In those versions only messages coming from
the "status" or "JanusDataChannel" data channels were taken into
account. When Janus is not used the WebUI opens the legacy
"simplewebrtc" data channel, so that data channel may be the one used to
send data channel messages (if it is open after the "status" data
channel), but the messages received on that data channel were ignored by
the WebUI. Nevertheless, at this point this is more an academic problem
than a real world problem, as it is unlikely that there are many
Nextcloud servers with Talk < 16 and without HPB being used.
Independently of all that, when the peer connection is removed only the
"status" data channel is disposed, but none of the remote data channels
are. This is just a variation of an already existing bug (the last open
data channel was the one disposed due to being the last saved reference,
but the rest were not) and it will be fixed in another commit.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
The legacy name was a bit strange, so now it is renamed to just "send"
as the parameter type ("DataChannelMessage") gives enough context.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This implicitly fixes trying to send the initial state on the latest
remote data channel found (which is the one stored in the "dataChannel"
attribute of the "PeerConnectionWrapper") when any other existing data
channel changes its status to open. Nevertheless, as all this will be
reworked, no unit test was added for it.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Log methods are static, so they can not be mocked using Mockito.
Although it might be possible to use PowerMockito a dummy implementation
was added instead, as Log uses are widespread and it is not something
worth mocking anyway.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
The PeerConnectionWrapper does not need to be injected in the
application, nor the Context needs to be injected in the
PeerConnectionWrapper. This all seems to be leftovers from the past, and
removing them would ease adding unit tests for the
PeerConnectionWrapper.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Signed-off-by: Christian Reiner <foss@christian-reiner.info>
Themed the PlaybackSpeedControl + Work around onBind bug
Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
also:
create ChatMessageUtils as helper for the ViewHolders in this case.
Could help to avoid duplicated code until there is a clear inheritance solution.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
However this is only possible for the conversation info.
In other parts, the info if a guest changed the name or not is not available (like in the chat or in autocomplete)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
knowing if a guest did not change it's name is not possible at this point, so we also show the letter "G" if it's name is guest
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
objectId would be some long random string for email guests. displaying them would not make sense. It's also not done on web.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Open notification settings when click on warning
Also, still offer to enable notifications and disable battery optimization on first install
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Also add an option to not show the hint, when user doesn't want to ignore battery optimization.
Only show these features when gplay services are available. Otherwise don't show them as it would pretend notifications would be possible without gplay.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
followup to PR #4439
Exception java.lang.NullPointerException:
at com.nextcloud.talk.chat.MessageInputFragment.handleMessageQueue (MessageInputFragment.kt:251)
at com.nextcloud.talk.chat.MessageInputFragment.access$handleMessageQueue (MessageInputFragment.kt:82)
at com.nextcloud.talk.chat.MessageInputFragment$initObservers$4$1.invokeSuspend (MessageInputFragment.kt:192)
at com.nextcloud.talk.chat.MessageInputFragment$initObservers$4$1.invoke (Unknown Source:12)
at com.nextcloud.talk.chat.MessageInputFragment$initObservers$4$1.invoke (Unknown Source:8)
at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit (Emitters.kt:219)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt (Channels.kt:33)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.access$emitAllImpl$FlowKt__ChannelsKt (Channels.kt:1)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl$1.invokeSuspend (Unknown Source:14)
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:241)
at android.os.Looper.loop (Looper.java:342)
at android.app.ActivityThread.main (ActivityThread.java:8128)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:583)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1045)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
As the number of provided emojis grew, there was a bug that only one emoji was shown.
Putting all 12 emojis would have been too close, so it's implemented to scroll them horizontally
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
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 <dev@mhibbe.de>
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 <dev@mhibbe.de>
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 <dev@mhibbe.de>
when adapter has no items adapter!!.items[1].item will crash with IndexOutOfBoundsException
This could happen e.g. when chat history is cleared.
error was:
Exception java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 0
at jdk.internal.util.Preconditions.outOfBounds (Preconditions.java:64)
at jdk.internal.util.Preconditions.outOfBoundsCheckIndex (Preconditions.java:70)
at jdk.internal.util.Preconditions.checkIndex (Preconditions.java:266)
at java.util.Objects.checkIndex (Objects.java:359)
at java.util.ArrayList.get (ArrayList.java:434)
at com.nextcloud.talk.chat.ChatActivity.processMessagesFromTheFuture (ChatActivity.kt:2666)
at com.nextcloud.talk.chat.ChatActivity.access$processMessagesFromTheFuture (ChatActivity.kt:209)
at com.nextcloud.talk.chat.ChatActivity$initObservers$12$1.invokeSuspend (ChatActivity.kt:875)
at com.nextcloud.talk.chat.ChatActivity$initObservers$12$1.invoke (Unknown Source:8)
at com.nextcloud.talk.chat.ChatActivity$initObservers$12$1.invoke (Unknown Source: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 (Unknown Source: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:942)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:201)
at android.os.Looper.loop (Looper.java:288)
at android.app.ActivityThread.main (ActivityThread.java:7932)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:942)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
When messages were sorted out in handleSystemMessages it can happen that the chatMessageList is empty. Because setUnreadMessageMarker accessed chatMessageList[0] this crashed.
This can happen e.g. when only a reaction to a chat message was made before opening the chat.
Exception java.lang.IndexOutOfBoundsException: Empty list doesn't contain element at index 0.
at kotlin.collections.EmptyList.get (Collections.kt:37)
at kotlin.collections.EmptyList.get (Collections.kt:25)
at com.nextcloud.talk.chat.ChatActivity.setUnreadMessageMarker (ChatActivity.kt:2691)
at com.nextcloud.talk.chat.ChatActivity.processMessagesFromTheFuture (ChatActivity.kt:2651)
at com.nextcloud.talk.chat.ChatActivity.access$processMessagesFromTheFuture (ChatActivity.kt:209)
at com.nextcloud.talk.chat.ChatActivity$initObservers$12$1.invokeSuspend (ChatActivity.kt:875)
at com.nextcloud.talk.chat.ChatActivity$initObservers$12$1.invoke (Unknown Source:8)
at com.nextcloud.talk.chat.ChatActivity$initObservers$12$1.invoke (Unknown Source: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 (Unknown Source: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:942)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:226)
at android.os.Looper.loop (Looper.java:313)
at android.app.ActivityThread.main (ActivityThread.java:8762)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
currentConversation was not yet initialized in ChatActivity.
In the future this may be better handled via StateFlows. For now it's solved via arguments.
Without the fix, this NPE appeared:
Exception java.lang.RuntimeException:
at android.app.ActivityThread.performResumeActivity (ActivityThread.java:4768)
at android.app.ActivityThread.handleResumeActivity (ActivityThread.java:4801)
at android.app.servertransaction.ResumeActivityItem.execute (ResumeActivityItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2215)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loopOnce (Looper.java:346)
at android.os.Looper.loop (Looper.java:475)
at android.app.ActivityThread.main (ActivityThread.java:7889)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1009)
Caused by java.lang.NullPointerException:
at com.nextcloud.talk.chat.MessageInputFragment.onResume (MessageInputFragment.kt:146)
at androidx.fragment.app.Fragment.performResume (Fragment.java:3180)
at androidx.fragment.app.FragmentStateManager.resume (FragmentStateManager.java:606)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState (FragmentStateManager.java:285)
at androidx.fragment.app.FragmentStore.moveToExpectedState (FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:1433)
at androidx.fragment.app.FragmentManager.dispatchStateChange (FragmentManager.java:2977)
at androidx.fragment.app.FragmentManager.dispatchResume (FragmentManager.java:2909)
at androidx.fragment.app.FragmentController.dispatchResume (FragmentController.java:285)
at androidx.fragment.app.FragmentActivity.onResumeFragments (FragmentActivity.java:334)
at androidx.fragment.app.FragmentActivity.onPostResume (FragmentActivity.java:323)
at androidx.appcompat.app.AppCompatActivity.onPostResume (AppCompatActivity.java:245)
at android.app.Activity.performResume (Activity.java:8215)
at android.app.ActivityThread.performResumeActivity (ActivityThread.java:4758)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
For archived conversations, require "-v2".
This is done because on server api, "archived-conversations" was already released for 20.0.2 by mistake which should have only be done for 20.1
As it's planned to release android talk 20.0.3 with a fresh master state, the archived conversations feature must be hidden manually, This is done by required "-v2".
Either it's served as this in the future or it can be removed for the 20.1.0 release.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
only more complex checks should be made in CapabilitiesUtil, just checking a capability should be done directly via hasSpreedFeatureCapability
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
this will set NOT NULL and DEFAULT 0 to hasArchived column
Otherwise there would be an error when updating from the previous DB version:
IllegalStateException: Migration didn't properly handle: Conversations(com.nextcloud.talk.data.database.model.ConversationEntity)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
replace com.nextcloud.ui.popupbubble.PopupBubble with MaterialButton.
com.nextcloud.ui.popupbubble.PopupBubble was forked from
https://github.com/webianks/PopupBubble
which is quite outdated.
com.nextcloud.ui.popupbubble.PopupBubble is still used in ConversationsListActivity but there it should also be removed.
Removing this recycler view stuff will also help a bit to switch to JetpackCompose
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
this commit will avoid to fail to show messages in adapter. This was caused by the usage of
messagesListAdapter.deleteById("-1");
in UnreadNoticeMessageViewHolder.
The bug seems to exist in the past already but was never reported (Sometimes, when receiving a lot of messages it could happen that some message in between is not shown in UI). However with recent changes after release 20.0.2 the bug appeared more often.
The root cause was not analyzed, but the handling was modified in general as the unread marker behavior was never really good.
By not using deleteById but replace it with new unread marker logic, the bug of disappearing messages is solved and the unread messages marker behavior is improved.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>