diff --git a/CHANGES.md b/CHANGES.md index 2f20c8b7f6..360357c126 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ Bugfix 🐛: - Various report of people that cannot play video (#2107) - Rooms incorrectly marked as unread (#588) - Allow users to show/hide room member state events (#1231) + - Fix stuck on loader when launching home Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt index ee94013d1b..cc67f633eb 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt @@ -22,36 +22,63 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import im.vector.app.core.platform.VectorBaseActivity -fun VectorBaseActivity.addFragment(frameId: Int, fragment: Fragment) { - supportFragmentManager.commitTransaction { add(frameId, fragment) } +fun VectorBaseActivity.addFragment( + frameId: Int, + fragment: Fragment, + allowStateLoss: Boolean = false +) { + supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseActivity.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - supportFragmentManager.commitTransaction { +fun VectorBaseActivity.addFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseActivity.replaceFragment(frameId: Int, fragment: Fragment, tag: String? = null) { - supportFragmentManager.commitTransaction { replace(frameId, fragment, tag) } +fun VectorBaseActivity.replaceFragment( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { + supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseActivity.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - supportFragmentManager.commitTransaction { +fun VectorBaseActivity.replaceFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) { - supportFragmentManager.commitTransaction { replace(frameId, fragment).addToBackStack(tag) } +fun VectorBaseActivity.addFragmentToBackstack( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { + supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, + allowStateLoss: Boolean = false, option: ((FragmentTransaction) -> Unit)? = null) { - supportFragmentManager.commitTransaction { + supportFragmentManager.commitTransaction(allowStateLoss) { option?.invoke(this) replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } diff --git a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt index 6ba250ee1b..fbcd6900c1 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt @@ -26,62 +26,126 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -fun VectorBaseFragment.addFragment(frameId: Int, fragment: Fragment) { - parentFragmentManager.commitTransaction { add(frameId, fragment) } +fun VectorBaseFragment.addFragment( + frameId: Int, + fragment: Fragment, + allowStateLoss: Boolean = false +) { + parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseFragment.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - parentFragmentManager.commitTransaction { +fun VectorBaseFragment.addFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.replaceFragment(frameId: Int, fragment: Fragment) { - parentFragmentManager.commitTransaction { replace(frameId, fragment) } +fun VectorBaseFragment.replaceFragment( + frameId: Int, + fragment: Fragment, + allowStateLoss: Boolean = false +) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) } } -fun VectorBaseFragment.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - parentFragmentManager.commitTransaction { +fun VectorBaseFragment.replaceFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) { - parentFragmentManager.commitTransaction { replace(frameId, fragment, tag).addToBackStack(tag) } +fun VectorBaseFragment.addFragmentToBackstack( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) } } -fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - parentFragmentManager.commitTransaction { +fun VectorBaseFragment.addFragmentToBackstack( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } } -fun VectorBaseFragment.addChildFragment(frameId: Int, fragment: Fragment, tag: String? = null) { - childFragmentManager.commitTransaction { add(frameId, fragment, tag) } +fun VectorBaseFragment.addChildFragment( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { + childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) } } -fun VectorBaseFragment.addChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - childFragmentManager.commitTransaction { +fun VectorBaseFragment.addChildFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragment: Fragment, tag: String? = null) { - childFragmentManager.commitTransaction { replace(frameId, fragment, tag) } +fun VectorBaseFragment.replaceChildFragment( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - childFragmentManager.commitTransaction { +fun VectorBaseFragment.replaceChildFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) { - childFragmentManager.commitTransaction { replace(frameId, fragment).addToBackStack(tag) } +fun VectorBaseFragment.addChildFragmentToBackstack( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } -fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - childFragmentManager.commitTransaction { +fun VectorBaseFragment.addChildFragmentToBackstack( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } } diff --git a/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt b/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt index 1d437c0701..49b28fb190 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt @@ -27,6 +27,11 @@ inline fun androidx.fragment.app.FragmentManager.commitTransactionNow(func: Frag } } -inline fun androidx.fragment.app.FragmentManager.commitTransaction(func: FragmentTransaction.() -> FragmentTransaction) { - beginTransaction().func().commit() +inline fun androidx.fragment.app.FragmentManager.commitTransaction(allowStateLoss: Boolean = false, func: FragmentTransaction.() -> FragmentTransaction) { + val transaction = beginTransaction().func() + if (allowStateLoss) { + transaction.commitAllowingStateLoss() + } else { + transaction.commit() + } } diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt new file mode 100644 index 0000000000..4ca21a0f1d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.call + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class VectorCallViewActions : VectorViewModelAction { + object EndCall : VectorCallViewActions() + object AcceptCall : VectorCallViewActions() + object DeclineCall : VectorCallViewActions() + object ToggleMute : VectorCallViewActions() + object ToggleVideo : VectorCallViewActions() + data class ChangeAudioDevice(val device: CallAudioManager.SoundDevice) : VectorCallViewActions() + object SwitchSoundDevice : VectorCallViewActions() + object HeadSetButtonPressed : VectorCallViewActions() + object ToggleCamera : VectorCallViewActions() + object ToggleHDSD : VectorCallViewActions() +} diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt new file mode 100644 index 0000000000..b79cd5d772 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.call + +import im.vector.app.core.platform.VectorViewEvents +import org.matrix.android.sdk.api.session.call.TurnServerResponse + +sealed class VectorCallViewEvents : VectorViewEvents { + + object DismissNoCall : VectorCallViewEvents() + data class ConnectionTimeout(val turn: TurnServerResponse?) : VectorCallViewEvents() + data class ShowSoundDeviceChooser( + val available: List, + val current: CallAudioManager.SoundDevice + ) : VectorCallViewEvents() +// data class CallAnswered(val content: CallAnswerContent) : VectorCallViewEvents() +// data class CallHangup(val content: CallHangupContent) : VectorCallViewEvents() +// object CallAccepted : VectorCallViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index cee67cd818..edb75441c8 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -16,10 +16,8 @@ package im.vector.app.features.call -import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized @@ -27,9 +25,7 @@ import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive -import im.vector.app.core.platform.VectorViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.core.platform.VectorViewModelAction import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.call.CallState @@ -41,48 +37,6 @@ import org.webrtc.PeerConnection import java.util.Timer import java.util.TimerTask -data class VectorCallViewState( - val callId: String? = null, - val roomId: String = "", - val isVideoCall: Boolean, - val isAudioMuted: Boolean = false, - val isVideoEnabled: Boolean = true, - val isVideoCaptureInError: Boolean = false, - val isHD: Boolean = false, - val isFrontCamera: Boolean = true, - val canSwitchCamera: Boolean = true, - val soundDevice: CallAudioManager.SoundDevice = CallAudioManager.SoundDevice.PHONE, - val availableSoundDevices: List = emptyList(), - val otherUserMatrixItem: Async = Uninitialized, - val callState: Async = Uninitialized -) : MvRxState - -sealed class VectorCallViewActions : VectorViewModelAction { - object EndCall : VectorCallViewActions() - object AcceptCall : VectorCallViewActions() - object DeclineCall : VectorCallViewActions() - object ToggleMute : VectorCallViewActions() - object ToggleVideo : VectorCallViewActions() - data class ChangeAudioDevice(val device: CallAudioManager.SoundDevice) : VectorCallViewActions() - object SwitchSoundDevice : VectorCallViewActions() - object HeadSetButtonPressed : VectorCallViewActions() - object ToggleCamera : VectorCallViewActions() - object ToggleHDSD : VectorCallViewActions() -} - -sealed class VectorCallViewEvents : VectorViewEvents { - - object DismissNoCall : VectorCallViewEvents() - data class ConnectionTimeout(val turn: TurnServerResponse?) : VectorCallViewEvents() - data class ShowSoundDeviceChooser( - val available: List, - val current: CallAudioManager.SoundDevice - ) : VectorCallViewEvents() -// data class CallAnswered(val content: CallAnswerContent) : VectorCallViewEvents() -// data class CallHangup(val content: CallHangupContent) : VectorCallViewEvents() -// object CallAccepted : VectorCallViewEvents() -} - class VectorCallViewModel @AssistedInject constructor( @Assisted initialState: VectorCallViewState, @Assisted val args: CallArgs, @@ -91,23 +45,23 @@ class VectorCallViewModel @AssistedInject constructor( val proximityManager: CallProximityManager ) : VectorViewModel(initialState) { - var call: MxCall? = null + private var call: MxCall? = null - var connectionTimoutTimer: Timer? = null - var hasBeenConnectedOnce = false + private var connectionTimeoutTimer: Timer? = null + private var hasBeenConnectedOnce = false private val callStateListener = object : MxCall.StateListener { override fun onStateUpdate(call: MxCall) { val callState = call.state if (callState is CallState.Connected && callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) { hasBeenConnectedOnce = true - connectionTimoutTimer?.cancel() - connectionTimoutTimer = null + connectionTimeoutTimer?.cancel() + connectionTimeoutTimer = null } else { // do we reset as long as it's moving? - connectionTimoutTimer?.cancel() + connectionTimeoutTimer?.cancel() if (hasBeenConnectedOnce) { - connectionTimoutTimer = Timer().apply { + connectionTimeoutTimer = Timer().apply { schedule(object : TimerTask() { override fun run() { session.callSignalingService().getTurnServer(object : MatrixCallback { @@ -136,17 +90,17 @@ class VectorCallViewModel @AssistedInject constructor( override fun onCurrentCallChange(call: MxCall?) { } - override fun onCaptureStateChanged(mgr: WebRtcPeerConnectionManager) { + override fun onCaptureStateChanged() { setState { copy( - isVideoCaptureInError = mgr.capturerIsInError, - isHD = mgr.currentCaptureFormat() is CaptureFormat.HD + isVideoCaptureInError = webRtcPeerConnectionManager.capturerIsInError, + isHD = webRtcPeerConnectionManager.currentCaptureFormat() is CaptureFormat.HD ) } } - override fun onAudioDevicesChange(mgr: WebRtcPeerConnectionManager) { - val currentSoundDevice = mgr.audioManager.getCurrentSoundDevice() + override fun onAudioDevicesChange() { + val currentSoundDevice = webRtcPeerConnectionManager.callAudioManager.getCurrentSoundDevice() if (currentSoundDevice == CallAudioManager.SoundDevice.PHONE) { proximityManager.start() } else { @@ -155,17 +109,17 @@ class VectorCallViewModel @AssistedInject constructor( setState { copy( - availableSoundDevices = mgr.audioManager.getAvailableSoundDevices(), + availableSoundDevices = webRtcPeerConnectionManager.callAudioManager.getAvailableSoundDevices(), soundDevice = currentSoundDevice ) } } - override fun onCameraChange(mgr: WebRtcPeerConnectionManager) { + override fun onCameraChange() { setState { copy( - canSwitchCamera = mgr.canSwitchCamera(), - isFrontCamera = mgr.currentCameraType() == CameraType.FRONT + canSwitchCamera = webRtcPeerConnectionManager.canSwitchCamera(), + isFrontCamera = webRtcPeerConnectionManager.currentCameraType() == CameraType.FRONT ) } } @@ -182,7 +136,7 @@ class VectorCallViewModel @AssistedInject constructor( mxCall.addListener(callStateListener) - val currentSoundDevice = webRtcPeerConnectionManager.audioManager.getCurrentSoundDevice() + val currentSoundDevice = webRtcPeerConnectionManager.callAudioManager.getCurrentSoundDevice() if (currentSoundDevice == CallAudioManager.SoundDevice.PHONE) { proximityManager.start() } @@ -193,7 +147,7 @@ class VectorCallViewModel @AssistedInject constructor( callState = Success(mxCall.state), otherUserMatrixItem = item?.let { Success(it) } ?: Uninitialized, soundDevice = currentSoundDevice, - availableSoundDevices = webRtcPeerConnectionManager.audioManager.getAvailableSoundDevices(), + availableSoundDevices = webRtcPeerConnectionManager.callAudioManager.getAvailableSoundDevices(), isFrontCamera = webRtcPeerConnectionManager.currentCameraType() == CameraType.FRONT, canSwitchCamera = webRtcPeerConnectionManager.canSwitchCamera(), isHD = mxCall.isVideoCall && webRtcPeerConnectionManager.currentCaptureFormat() is CaptureFormat.HD @@ -250,10 +204,10 @@ class VectorCallViewModel @AssistedInject constructor( Unit } is VectorCallViewActions.ChangeAudioDevice -> { - webRtcPeerConnectionManager.audioManager.setCurrentSoundDevice(action.device) + webRtcPeerConnectionManager.callAudioManager.setCurrentSoundDevice(action.device) setState { copy( - soundDevice = webRtcPeerConnectionManager.audioManager.getCurrentSoundDevice() + soundDevice = webRtcPeerConnectionManager.callAudioManager.getCurrentSoundDevice() ) } } diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt new file mode 100644 index 0000000000..f24e810400 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.call + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized +import org.matrix.android.sdk.api.session.call.CallState +import org.matrix.android.sdk.api.util.MatrixItem + +data class VectorCallViewState( + val callId: String? = null, + val roomId: String = "", + val isVideoCall: Boolean, + val isAudioMuted: Boolean = false, + val isVideoEnabled: Boolean = true, + val isVideoCaptureInError: Boolean = false, + val isHD: Boolean = false, + val isFrontCamera: Boolean = true, + val canSwitchCamera: Boolean = true, + val soundDevice: CallAudioManager.SoundDevice = CallAudioManager.SoundDevice.PHONE, + val availableSoundDevices: List = emptyList(), + val otherUserMatrixItem: Async = Uninitialized, + val callState: Async = Uninitialized +) : MvRxState diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index 655de3376c..3230e97809 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -23,6 +23,9 @@ import im.vector.app.ActiveSessionDataSource import im.vector.app.core.services.BluetoothHeadsetReceiver import im.vector.app.core.services.CallService import im.vector.app.core.services.WiredHeadsetStateReceiver +import io.reactivex.disposables.Disposable +import io.reactivex.subjects.PublishSubject +import io.reactivex.subjects.ReplaySubject import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.session.Session @@ -35,9 +38,6 @@ import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent -import io.reactivex.disposables.Disposable -import io.reactivex.subjects.PublishSubject -import io.reactivex.subjects.ReplaySubject import org.webrtc.AudioSource import org.webrtc.AudioTrack import org.webrtc.Camera1Enumerator @@ -79,9 +79,9 @@ class WebRtcPeerConnectionManager @Inject constructor( interface CurrentCallListener { fun onCurrentCallChange(call: MxCall?) - fun onCaptureStateChanged(mgr: WebRtcPeerConnectionManager) {} - fun onAudioDevicesChange(mgr: WebRtcPeerConnectionManager) {} - fun onCameraChange(mgr: WebRtcPeerConnectionManager) {} + fun onCaptureStateChanged() {} + fun onAudioDevicesChange() {} + fun onCameraChange() {} } private val currentCallsListeners = emptyList().toMutableList() @@ -93,9 +93,9 @@ class WebRtcPeerConnectionManager @Inject constructor( currentCallsListeners.remove(listener) } - val audioManager = CallAudioManager(context.applicationContext) { + val callAudioManager = CallAudioManager(context.applicationContext) { currentCallsListeners.forEach { - tryThis { it.onAudioDevicesChange(this) } + tryThis { it.onAudioDevicesChange() } } } @@ -174,7 +174,7 @@ class WebRtcPeerConnectionManager @Inject constructor( set(value) { field = value currentCallsListeners.forEach { - tryThis { it.onCaptureStateChanged(this) } + tryThis { it.onCaptureStateChanged() } } } @@ -577,7 +577,7 @@ class WebRtcPeerConnectionManager @Inject constructor( fun close() { Timber.v("## VOIP WebRtcPeerConnectionManager close() >") CallService.onNoActiveCall(context) - audioManager.stop() + callAudioManager.stop() val callToEnd = currentCall currentCall = null // This must be done in this thread @@ -631,7 +631,7 @@ class WebRtcPeerConnectionManager @Inject constructor( val createdCall = currentSession?.callSignalingService()?.createOutgoingCall(signalingRoomId, otherUserId, isVideoCall) ?: return val callContext = CallContext(createdCall) - audioManager.startForCall(createdCall) + callAudioManager.startForCall(createdCall) currentCall = callContext val name = currentSession?.getUser(createdCall.otherUserId)?.getBestName() @@ -684,7 +684,7 @@ class WebRtcPeerConnectionManager @Inject constructor( val callContext = CallContext(mxCall) currentCall = callContext - audioManager.startForCall(mxCall) + callAudioManager.startForCall(mxCall) executor.execute { callContext.remoteCandidateSource = ReplaySubject.create() } @@ -745,7 +745,7 @@ class WebRtcPeerConnectionManager @Inject constructor( } currentCallsListeners.forEach { - tryThis { it.onCameraChange(this@WebRtcPeerConnectionManager) } + tryThis { it.onCameraChange() } } } @@ -771,7 +771,7 @@ class WebRtcPeerConnectionManager @Inject constructor( // videoCapturer?.stopCapture() videoCapturer?.changeCaptureFormat(format.width, format.height, format.fps) currentCaptureMode = format - currentCallsListeners.forEach { tryThis { it.onCaptureStateChanged(this) } } + currentCallsListeners.forEach { tryThis { it.onCaptureStateChanged() } } } } @@ -802,12 +802,12 @@ class WebRtcPeerConnectionManager @Inject constructor( Timber.v("## VOIP onWiredDeviceEvent $event") currentCall ?: return // sometimes we received un-wanted unplugged... - audioManager.wiredStateChange(event) + callAudioManager.wiredStateChange(event) } fun onWirelessDeviceEvent(event: BluetoothHeadsetReceiver.BTHeadsetPlugEvent) { Timber.v("## VOIP onWirelessDeviceEvent $event") - audioManager.bluetoothStateChange(event.plugged) + callAudioManager.bluetoothStateChange(event.plugged) } override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { @@ -862,7 +862,7 @@ class WebRtcPeerConnectionManager @Inject constructor( */ PeerConnection.PeerConnectionState.CONNECTED -> { callContext.mxCall.state = CallState.Connected(newState) - audioManager.onCallConnected(callContext.mxCall) + callAudioManager.onCallConnected(callContext.mxCall) } /** * One or more of the ICE transports on the connection is in the "failed" state. diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt index bef8788f75..40953cb5f6 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt @@ -87,13 +87,13 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() { viewModel.navigateEvent.observeEvent(this) { uxStateEvent -> when (uxStateEvent) { KeysBackupRestoreSharedViewModel.NAVIGATE_TO_RECOVER_WITH_KEY -> { - addFragmentToBackstack(R.id.container, KeysBackupRestoreFromKeyFragment::class.java) + addFragmentToBackstack(R.id.container, KeysBackupRestoreFromKeyFragment::class.java, allowStateLoss = true) } KeysBackupRestoreSharedViewModel.NAVIGATE_TO_SUCCESS -> { viewModel.keyVersionResult.value?.version?.let { KeysBackupBanner.onRecoverDoneForVersion(this, it) } - replaceFragment(R.id.container, KeysBackupRestoreSuccessFragment::class.java) + replaceFragment(R.id.container, KeysBackupRestoreSuccessFragment::class.java, allowStateLoss = true) } KeysBackupRestoreSharedViewModel.NAVIGATE_TO_4S -> { launch4SActivity() diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 76de2daf54..eb024c4db1 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -121,7 +121,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START) is HomeActivitySharedAction.OpenGroup -> { drawerLayout.closeDrawer(GravityCompat.START) - replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java) + replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true) } }.exhaustive } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt index 129e057148..f011702dca 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt @@ -20,6 +20,7 @@ import android.content.Intent import android.net.Uri import android.provider.Settings import androidx.preference.Preference +import im.vector.app.BuildConfig import org.matrix.android.sdk.api.Matrix import im.vector.app.R import im.vector.app.core.preference.VectorPreference @@ -58,7 +59,13 @@ class VectorSettingsHelpAboutFragment @Inject constructor( // application version findPreference(VectorPreferences.SETTINGS_VERSION_PREFERENCE_KEY)!!.let { - it.summary = versionProvider.getVersion(longFormat = false, useBuildNumber = true) + it.summary = buildString { + append(versionProvider.getVersion(longFormat = false, useBuildNumber = true)) + if (BuildConfig.DEBUG) { + append(" ") + append(BuildConfig.GIT_BRANCH_NAME) + } + } it.setOnPreferenceClickListener { pref -> copyToClipboard(requireContext(), pref.summary)