From f9ee06cd2a5e78ab3bf4198f22991bf6f4fb97c4 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 21 Apr 2022 11:23:25 +0300 Subject: [PATCH] Implement foreground service for Android Q and later. --- .../features/call/CallControlsBottomSheet.kt | 3 +- .../app/features/call/VectorCallActivity.kt | 10 ++++ .../features/call/VectorCallViewActions.kt | 2 +- .../app/features/call/VectorCallViewEvents.kt | 1 + .../app/features/call/VectorCallViewModel.kt | 36 ++++++++++--- .../app/features/call/VectorCallViewState.kt | 3 +- .../webrtc/ScreenCaptureServiceConnection.kt | 54 +++++++++++++++++++ .../app/features/call/webrtc/WebRtcCall.kt | 6 ++- .../res/layout/bottom_sheet_call_controls.xml | 2 +- vector/src/main/res/values/strings.xml | 3 +- 10 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureServiceConnection.kt diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt index 32d32c9fa6..1c6ead33cc 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt @@ -68,7 +68,7 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment(), CallContro @Inject lateinit var callManager: WebRtcCallManager @Inject lateinit var avatarRenderer: AvatarRenderer + @Inject lateinit var screenCaptureServiceConnection: ScreenCaptureServiceConnection private val callViewModel: VectorCallViewModel by viewModel() @@ -528,6 +530,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } is VectorCallViewEvents.FailToTransfer -> showSnackbar(getString(R.string.call_transfer_failure)) is VectorCallViewEvents.ShowScreenSharingPermissionDialog -> handleShowScreenSharingPermissionDialog() + is VectorCallViewEvents.StopScreenSharingService -> handleStopScreenSharingService() else -> Unit } } @@ -640,6 +643,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro this, Intent(this, ScreenCaptureService::class.java) ) + screenCaptureServiceConnection.bind() } } } @@ -650,6 +654,12 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } } + private fun handleStopScreenSharingService() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + screenCaptureServiceConnection.stopScreenCapturing() + } + } + companion object { private const val EXTRA_MODE = "EXTRA_MODE" private const val FRAGMENT_DIAL_PAD_TAG = "FRAGMENT_DIAL_PAD_TAG" 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 index daad8a2332..c84f733b9a 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt @@ -40,6 +40,6 @@ sealed class VectorCallViewActions : VectorViewModelAction { object CallTransferSelectionCancelled : VectorCallViewActions() data class CallTransferSelectionResult(val callTransferResult: CallTransferResult) : VectorCallViewActions() object TransferCall : VectorCallViewActions() - object InitiateScreenSharing : VectorCallViewActions() + object ToggleScreenSharing : VectorCallViewActions() object StartScreenSharing : 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 index a2b6fbaf92..68170b0f11 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt @@ -31,6 +31,7 @@ sealed class VectorCallViewEvents : VectorViewEvents { object ShowCallTransferScreen : VectorCallViewEvents() object FailToTransfer : VectorCallViewEvents() object ShowScreenSharingPermissionDialog : VectorCallViewEvents() + object StopScreenSharingService : 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 4e622c4ab3..ef827472a9 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 @@ -256,7 +256,10 @@ class VectorCallViewModel @AssistedInject constructor( override fun handle(action: VectorCallViewActions) = withState { state -> when (action) { - VectorCallViewActions.EndCall -> call?.endCall() + VectorCallViewActions.EndCall -> { + call?.endCall() + _viewEvents.post(VectorCallViewEvents.StopScreenSharingService) + } VectorCallViewActions.AcceptCall -> { setState { copy(callState = Loading()) @@ -337,21 +340,38 @@ class VectorCallViewModel @AssistedInject constructor( VectorCallViewActions.TransferCall -> { handleCallTransfer() } - is VectorCallViewActions.SwitchCall -> { + is VectorCallViewActions.SwitchCall -> { setState { VectorCallViewState(action.callArgs) } setupCallWithCurrentState() } - is VectorCallViewActions.InitiateScreenSharing -> { - _viewEvents.post( - VectorCallViewEvents.ShowScreenSharingPermissionDialog - ) + is VectorCallViewActions.ToggleScreenSharing -> { + handleToggleScreenSharing(state.isSharingScreen) } - is VectorCallViewActions.StartScreenSharing -> { - call?.shareScreen() + is VectorCallViewActions.StartScreenSharing -> { + call?.startSharingScreen() + setState { + copy(isSharingScreen = true) + } } } } + private fun handleToggleScreenSharing(isSharingScreen: Boolean) { + if (isSharingScreen) { + call?.stopSharingScreen() + setState { + copy(isSharingScreen = false) + } + _viewEvents.post( + VectorCallViewEvents.StopScreenSharingService + ) + } else { + _viewEvents.post( + VectorCallViewEvents.ShowScreenSharingPermissionDialog + ) + } + } + private fun handleCallTransfer() { viewModelScope.launch { val currentCall = call ?: return@launch 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 index 2d33cbf9b9..2cd819b5f5 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt @@ -42,7 +42,8 @@ data class VectorCallViewState( val callInfo: CallInfo? = null, val formattedDuration: String = "", val canOpponentBeTransferred: Boolean = false, - val transferee: TransfereeState = TransfereeState.NoTransferee + val transferee: TransfereeState = TransfereeState.NoTransferee, + val isSharingScreen: Boolean = false ) : MavericksState { sealed class TransfereeState { diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureServiceConnection.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureServiceConnection.kt new file mode 100644 index 0000000000..922e9676a8 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureServiceConnection.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 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.webrtc + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import javax.inject.Inject + +class ScreenCaptureServiceConnection @Inject constructor( + private val context: Context +) : ServiceConnection { + + private var isBound = false + private var screenCaptureService: ScreenCaptureService? = null + + fun bind() { + if (!isBound) { + Intent(context, ScreenCaptureService::class.java).also { intent -> + context.bindService(intent, this, 0) + } + } + } + + fun stopScreenCapturing() { + screenCaptureService?.stopService() + } + + override fun onServiceConnected(className: ComponentName, binder: IBinder) { + screenCaptureService = (binder as ScreenCaptureService.LocalBinder).getService() + isBound = true + } + + override fun onServiceDisconnected(className: ComponentName) { + isBound = false + screenCaptureService = null + } +} diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index c744f317ab..bc8ae51a88 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -770,7 +770,11 @@ class WebRtcCall( return currentCaptureFormat } - fun shareScreen() { + fun startSharingScreen() { + // TODO. Will be handled within the next PR. + } + + fun stopSharingScreen() { // TODO. Will be handled within the next PR. } diff --git a/vector/src/main/res/layout/bottom_sheet_call_controls.xml b/vector/src/main/res/layout/bottom_sheet_call_controls.xml index 0b67059dd8..516dc29fa3 100644 --- a/vector/src/main/res/layout/bottom_sheet_call_controls.xml +++ b/vector/src/main/res/layout/bottom_sheet_call_controls.xml @@ -11,7 +11,7 @@ android:id="@+id/callControlsShareScreen" android:layout_width="match_parent" android:layout_height="wrap_content" - app:actionTitle="@string/call_share_screen" + app:actionTitle="@string/call_start_screen_sharing" app:leftIcon="@drawable/ic_share_screen" app:tint="?vctr_content_primary" app:titleTextColor="?vctr_content_primary" /> diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 4b8009d10b..11eb3c64fa 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -480,7 +480,8 @@ Back Turn HD off Turn HD on - Share screen + Share screen + Stop screen sharing Send files Send sticker