Merge pull request #5811 from vector-im/feature/ons/voip_screen_sharing_permission
VoIP Screen Sharing Permission
This commit is contained in:
commit
8eaa2f8dfb
1
changelog.d/5811.feature
Normal file
1
changelog.d/5811.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
VoIP Screen Sharing Permission
|
@ -60,6 +60,9 @@ class DebugVectorFeatures(
|
|||||||
override fun isLiveLocationEnabled(): Boolean = read(DebugFeatureKeys.liveLocationSharing)
|
override fun isLiveLocationEnabled(): Boolean = read(DebugFeatureKeys.liveLocationSharing)
|
||||||
?: vectorFeatures.isLiveLocationEnabled()
|
?: vectorFeatures.isLiveLocationEnabled()
|
||||||
|
|
||||||
|
override fun isScreenSharingEnabled(): Boolean = read(DebugFeatureKeys.screenSharing)
|
||||||
|
?: vectorFeatures.isScreenSharingEnabled()
|
||||||
|
|
||||||
fun <T> override(value: T?, key: Preferences.Key<T>) = updatePreferences {
|
fun <T> override(value: T?, key: Preferences.Key<T>) = updatePreferences {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
it.remove(key)
|
it.remove(key)
|
||||||
@ -114,4 +117,5 @@ object DebugFeatureKeys {
|
|||||||
val onboardingPersonalize = booleanPreferencesKey("onboarding-personalize")
|
val onboardingPersonalize = booleanPreferencesKey("onboarding-personalize")
|
||||||
val onboardingCombinedRegister = booleanPreferencesKey("onboarding-combined-register")
|
val onboardingCombinedRegister = booleanPreferencesKey("onboarding-combined-register")
|
||||||
val liveLocationSharing = booleanPreferencesKey("live-location-sharing")
|
val liveLocationSharing = booleanPreferencesKey("live-location-sharing")
|
||||||
|
val screenSharing = booleanPreferencesKey("screen-sharing")
|
||||||
}
|
}
|
||||||
|
@ -375,6 +375,12 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:foregroundServiceType="location" />
|
android:foregroundServiceType="location" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".features.call.webrtc.ScreenCaptureService"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="mediaProjection"
|
||||||
|
tools:targetApi="Q" />
|
||||||
|
|
||||||
<!-- Receivers -->
|
<!-- Receivers -->
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
|
@ -27,6 +27,7 @@ interface VectorFeatures {
|
|||||||
fun isOnboardingPersonalizeEnabled(): Boolean
|
fun isOnboardingPersonalizeEnabled(): Boolean
|
||||||
fun isOnboardingCombinedRegisterEnabled(): Boolean
|
fun isOnboardingCombinedRegisterEnabled(): Boolean
|
||||||
fun isLiveLocationEnabled(): Boolean
|
fun isLiveLocationEnabled(): Boolean
|
||||||
|
fun isScreenSharingEnabled(): Boolean
|
||||||
|
|
||||||
enum class OnboardingVariant {
|
enum class OnboardingVariant {
|
||||||
LEGACY,
|
LEGACY,
|
||||||
@ -43,4 +44,5 @@ class DefaultVectorFeatures : VectorFeatures {
|
|||||||
override fun isOnboardingPersonalizeEnabled() = false
|
override fun isOnboardingPersonalizeEnabled() = false
|
||||||
override fun isOnboardingCombinedRegisterEnabled() = false
|
override fun isOnboardingCombinedRegisterEnabled() = false
|
||||||
override fun isLiveLocationEnabled(): Boolean = false
|
override fun isLiveLocationEnabled(): Boolean = false
|
||||||
|
override fun isScreenSharingEnabled(): Boolean = false
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import im.vector.app.databinding.BottomSheetCallControlsBinding
|
import im.vector.app.databinding.BottomSheetCallControlsBinding
|
||||||
|
import im.vector.app.features.VectorFeatures
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCallControlsBinding>() {
|
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCallControlsBinding>() {
|
||||||
@ -34,6 +36,8 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetC
|
|||||||
return BottomSheetCallControlsBinding.inflate(inflater, container, false)
|
return BottomSheetCallControlsBinding.inflate(inflater, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject lateinit var vectorFeatures: VectorFeatures
|
||||||
|
|
||||||
private val callViewModel: VectorCallViewModel by activityViewModel()
|
private val callViewModel: VectorCallViewModel by activityViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@ -66,6 +70,12 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetC
|
|||||||
callViewModel.handle(VectorCallViewActions.InitiateCallTransfer)
|
callViewModel.handle(VectorCallViewActions.InitiateCallTransfer)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
views.callControlsShareScreen.isVisible = vectorFeatures.isScreenSharingEnabled()
|
||||||
|
views.callControlsShareScreen.views.bottomSheetActionClickableZone.debouncedClicks {
|
||||||
|
callViewModel.handle(VectorCallViewActions.ToggleScreenSharing)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderState(state: VectorCallViewState) {
|
private fun renderState(state: VectorCallViewState) {
|
||||||
@ -95,5 +105,6 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetC
|
|||||||
views.callControlsToggleHoldResume.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_call_hold_action)
|
views.callControlsToggleHoldResume.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_call_hold_action)
|
||||||
}
|
}
|
||||||
views.callControlsTransfer.isVisible = state.canOpponentBeTransferred
|
views.callControlsTransfer.isVisible = state.canOpponentBeTransferred
|
||||||
|
views.callControlsShareScreen.title = getString(if (state.isSharingScreen) R.string.call_stop_screen_sharing else R.string.call_start_screen_sharing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import android.content.Intent
|
|||||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
|
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.media.projection.MediaProjectionManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
@ -56,6 +57,8 @@ import im.vector.app.features.call.dialpad.CallDialPadBottomSheet
|
|||||||
import im.vector.app.features.call.dialpad.DialPadFragment
|
import im.vector.app.features.call.dialpad.DialPadFragment
|
||||||
import im.vector.app.features.call.transfer.CallTransferActivity
|
import im.vector.app.features.call.transfer.CallTransferActivity
|
||||||
import im.vector.app.features.call.utils.EglUtils
|
import im.vector.app.features.call.utils.EglUtils
|
||||||
|
import im.vector.app.features.call.webrtc.ScreenCaptureService
|
||||||
|
import im.vector.app.features.call.webrtc.ScreenCaptureServiceConnection
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCall
|
import im.vector.app.features.call.webrtc.WebRtcCall
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
@ -94,6 +97,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||||||
|
|
||||||
@Inject lateinit var callManager: WebRtcCallManager
|
@Inject lateinit var callManager: WebRtcCallManager
|
||||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
@Inject lateinit var screenCaptureServiceConnection: ScreenCaptureServiceConnection
|
||||||
|
|
||||||
private val callViewModel: VectorCallViewModel by viewModel()
|
private val callViewModel: VectorCallViewModel by viewModel()
|
||||||
|
|
||||||
@ -525,6 +529,8 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||||||
navigator.openCallTransfer(this, callTransferActivityResultLauncher, callId)
|
navigator.openCallTransfer(this, callTransferActivityResultLauncher, callId)
|
||||||
}
|
}
|
||||||
is VectorCallViewEvents.FailToTransfer -> showSnackbar(getString(R.string.call_transfer_failure))
|
is VectorCallViewEvents.FailToTransfer -> showSnackbar(getString(R.string.call_transfer_failure))
|
||||||
|
is VectorCallViewEvents.ShowScreenSharingPermissionDialog -> handleShowScreenSharingPermissionDialog()
|
||||||
|
is VectorCallViewEvents.StopScreenSharingService -> handleStopScreenSharingService()
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -628,6 +634,32 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val screenSharingPermissionActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||||
|
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||||
|
callViewModel.handle(VectorCallViewActions.StartScreenSharing)
|
||||||
|
// We need to start a foreground service with a sticky notification during screen sharing
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
ContextCompat.startForegroundService(
|
||||||
|
this,
|
||||||
|
Intent(this, ScreenCaptureService::class.java)
|
||||||
|
)
|
||||||
|
screenCaptureServiceConnection.bind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleShowScreenSharingPermissionDialog() {
|
||||||
|
getSystemService<MediaProjectionManager>()?.let {
|
||||||
|
navigator.openScreenSharingPermissionDialog(it.createScreenCaptureIntent(), screenSharingPermissionActivityResultLauncher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleStopScreenSharingService() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
screenCaptureServiceConnection.stopScreenCapturing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_MODE = "EXTRA_MODE"
|
private const val EXTRA_MODE = "EXTRA_MODE"
|
||||||
private const val FRAGMENT_DIAL_PAD_TAG = "FRAGMENT_DIAL_PAD_TAG"
|
private const val FRAGMENT_DIAL_PAD_TAG = "FRAGMENT_DIAL_PAD_TAG"
|
||||||
|
@ -40,4 +40,6 @@ sealed class VectorCallViewActions : VectorViewModelAction {
|
|||||||
object CallTransferSelectionCancelled : VectorCallViewActions()
|
object CallTransferSelectionCancelled : VectorCallViewActions()
|
||||||
data class CallTransferSelectionResult(val callTransferResult: CallTransferResult) : VectorCallViewActions()
|
data class CallTransferSelectionResult(val callTransferResult: CallTransferResult) : VectorCallViewActions()
|
||||||
object TransferCall : VectorCallViewActions()
|
object TransferCall : VectorCallViewActions()
|
||||||
|
object ToggleScreenSharing : VectorCallViewActions()
|
||||||
|
object StartScreenSharing : VectorCallViewActions()
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ sealed class VectorCallViewEvents : VectorViewEvents {
|
|||||||
object ShowDialPad : VectorCallViewEvents()
|
object ShowDialPad : VectorCallViewEvents()
|
||||||
object ShowCallTransferScreen : VectorCallViewEvents()
|
object ShowCallTransferScreen : VectorCallViewEvents()
|
||||||
object FailToTransfer : VectorCallViewEvents()
|
object FailToTransfer : VectorCallViewEvents()
|
||||||
// data class CallAnswered(val content: CallAnswerContent) : VectorCallViewEvents()
|
object ShowScreenSharingPermissionDialog : VectorCallViewEvents()
|
||||||
// data class CallHangup(val content: CallHangupContent) : VectorCallViewEvents()
|
object StopScreenSharingService : VectorCallViewEvents()
|
||||||
// object CallAccepted : VectorCallViewEvents()
|
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,10 @@ class VectorCallViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
override fun handle(action: VectorCallViewActions) = withState { state ->
|
override fun handle(action: VectorCallViewActions) = withState { state ->
|
||||||
when (action) {
|
when (action) {
|
||||||
VectorCallViewActions.EndCall -> call?.endCall()
|
VectorCallViewActions.EndCall -> {
|
||||||
|
call?.endCall()
|
||||||
|
_viewEvents.post(VectorCallViewEvents.StopScreenSharingService)
|
||||||
|
}
|
||||||
VectorCallViewActions.AcceptCall -> {
|
VectorCallViewActions.AcceptCall -> {
|
||||||
setState {
|
setState {
|
||||||
copy(callState = Loading())
|
copy(callState = Loading())
|
||||||
@ -341,6 +344,31 @@ class VectorCallViewModel @AssistedInject constructor(
|
|||||||
setState { VectorCallViewState(action.callArgs) }
|
setState { VectorCallViewState(action.callArgs) }
|
||||||
setupCallWithCurrentState()
|
setupCallWithCurrentState()
|
||||||
}
|
}
|
||||||
|
is VectorCallViewActions.ToggleScreenSharing -> {
|
||||||
|
handleToggleScreenSharing(state.isSharingScreen)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,8 @@ data class VectorCallViewState(
|
|||||||
val callInfo: CallInfo? = null,
|
val callInfo: CallInfo? = null,
|
||||||
val formattedDuration: String = "",
|
val formattedDuration: String = "",
|
||||||
val canOpponentBeTransferred: Boolean = false,
|
val canOpponentBeTransferred: Boolean = false,
|
||||||
val transferee: TransfereeState = TransfereeState.NoTransferee
|
val transferee: TransfereeState = TransfereeState.NoTransferee,
|
||||||
|
val isSharingScreen: Boolean = false
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
|
|
||||||
sealed class TransfereeState {
|
sealed class TransfereeState {
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.Intent
|
||||||
|
import android.os.Binder
|
||||||
|
import android.os.IBinder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.core.services.VectorService
|
||||||
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class ScreenCaptureService : VectorService() {
|
||||||
|
|
||||||
|
@Inject lateinit var notificationUtils: NotificationUtils
|
||||||
|
private val binder = LocalBinder()
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
showStickyNotification()
|
||||||
|
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showStickyNotification() {
|
||||||
|
val notificationId = System.currentTimeMillis().toInt()
|
||||||
|
val notification = notificationUtils.buildScreenSharingNotification()
|
||||||
|
startForeground(notificationId, notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder {
|
||||||
|
return binder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopService() {
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class LocalBinder : Binder() {
|
||||||
|
fun getService(): ScreenCaptureService = this@ScreenCaptureService
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -770,6 +770,14 @@ class WebRtcCall(
|
|||||||
return currentCaptureFormat
|
return currentCaptureFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startSharingScreen() {
|
||||||
|
// TODO. Will be handled within the next PR.
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopSharingScreen() {
|
||||||
|
// TODO. Will be handled within the next PR.
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun release() {
|
private suspend fun release() {
|
||||||
listeners.clear()
|
listeners.clear()
|
||||||
mxCall.removeListener(this)
|
mxCall.removeListener(this)
|
||||||
|
@ -600,4 +600,9 @@ class DefaultNavigator @Inject constructor(
|
|||||||
roomEncryptionTrustLevel = threadTimelineArgs.roomEncryptionTrustLevel
|
roomEncryptionTrustLevel = threadTimelineArgs.roomEncryptionTrustLevel
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openScreenSharingPermissionDialog(screenCaptureIntent: Intent,
|
||||||
|
activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
|
activityResultLauncher.launch(screenCaptureIntent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,4 +168,9 @@ interface Navigator {
|
|||||||
fun openThread(context: Context, threadTimelineArgs: ThreadTimelineArgs, eventIdToNavigate: String? = null)
|
fun openThread(context: Context, threadTimelineArgs: ThreadTimelineArgs, eventIdToNavigate: String? = null)
|
||||||
|
|
||||||
fun openThreadList(context: Context, threadTimelineArgs: ThreadTimelineArgs)
|
fun openThreadList(context: Context, threadTimelineArgs: ThreadTimelineArgs)
|
||||||
|
|
||||||
|
fun openScreenSharingPermissionDialog(
|
||||||
|
screenCaptureIntent: Intent,
|
||||||
|
activityResultLauncher: ActivityResultLauncher<Intent>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -535,6 +535,20 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a notification that indicates the application is capturing the screen.
|
||||||
|
*/
|
||||||
|
fun buildScreenSharingNotification(): Notification {
|
||||||
|
return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
|
||||||
|
.setContentTitle(stringProvider.getString(R.string.screen_sharing_notification_title))
|
||||||
|
.setContentText(stringProvider.getString(R.string.screen_sharing_notification_description))
|
||||||
|
.setSmallIcon(R.drawable.ic_share_screen)
|
||||||
|
.setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary))
|
||||||
|
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||||
|
.setContentIntent(buildOpenHomePendingIntentForSummary())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
fun buildDownloadFileNotification(uri: Uri, fileName: String, mimeType: String): Notification {
|
fun buildDownloadFileNotification(uri: Uri, fileName: String, mimeType: String): Notification {
|
||||||
return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
|
return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
|
||||||
.setGroup(stringProvider.getString(R.string.app_name))
|
.setGroup(stringProvider.getString(R.string.app_name))
|
||||||
|
10
vector/src/main/res/drawable/ic_share_screen.xml
Normal file
10
vector/src/main/res/drawable/ic_share_screen.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M3.4,4C2.0745,4 1,5.0745 1,6.4V17.6C1,18.9255 2.0745,20 3.4,20H20.6C21.9255,20 23,18.9255 23,17.6V6.4C23,5.0745 21.9255,4 20.6,4H3.4ZM11.9999,16C11.6464,16 11.3599,15.7135 11.3599,15.36V10.2049L9.3841,12.2166C9.1364,12.4688 8.7348,12.4688 8.4872,12.2166C8.2395,11.9644 8.2395,11.5556 8.4872,11.3034L11.5514,8.1834C11.7991,7.9312 12.2007,7.9312 12.4484,8.1834L15.5126,11.3034C15.7603,11.5556 15.7603,11.9644 15.5126,12.2166C15.265,12.4688 14.8634,12.4688 14.6157,12.2166L12.6399,10.2049V15.36C12.6399,15.7135 12.3534,16 11.9999,16Z"
|
||||||
|
android:fillColor="#737D8C"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</vector>
|
@ -7,6 +7,15 @@
|
|||||||
android:background="?colorSurface"
|
android:background="?colorSurface"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
|
android:id="@+id/callControlsShareScreen"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:actionTitle="@string/call_start_screen_sharing"
|
||||||
|
app:leftIcon="@drawable/ic_share_screen"
|
||||||
|
app:tint="?vctr_content_primary"
|
||||||
|
app:titleTextColor="?vctr_content_primary" />
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
android:id="@+id/callControlsSwitchCamera"
|
android:id="@+id/callControlsSwitchCamera"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -483,6 +483,8 @@
|
|||||||
<string name="call_camera_back">Back</string>
|
<string name="call_camera_back">Back</string>
|
||||||
<string name="call_format_turn_hd_off">Turn HD off</string>
|
<string name="call_format_turn_hd_off">Turn HD off</string>
|
||||||
<string name="call_format_turn_hd_on">Turn HD on</string>
|
<string name="call_format_turn_hd_on">Turn HD on</string>
|
||||||
|
<string name="call_start_screen_sharing">Share screen</string>
|
||||||
|
<string name="call_stop_screen_sharing">Stop screen sharing</string>
|
||||||
|
|
||||||
<string name="option_send_files">Send files</string>
|
<string name="option_send_files">Send files</string>
|
||||||
<string name="option_send_sticker">Send sticker</string>
|
<string name="option_send_sticker">Send sticker</string>
|
||||||
@ -3030,4 +3032,8 @@
|
|||||||
<string name="room_message_notify_everyone">Notify the whole room</string>
|
<string name="room_message_notify_everyone">Notify the whole room</string>
|
||||||
<string name="room_message_autocomplete_users">Users</string>
|
<string name="room_message_autocomplete_users">Users</string>
|
||||||
<string name="room_message_autocomplete_notification">Room notification</string>
|
<string name="room_message_autocomplete_notification">Room notification</string>
|
||||||
|
|
||||||
|
<!-- Screen sharing -->
|
||||||
|
<string name="screen_sharing_notification_title">${app_name} Screen Sharing</string>
|
||||||
|
<string name="screen_sharing_notification_description">Screen sharing is in progress</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user