From 19fe8dd57b97ac16740ed853d528ea6f96bf0a80 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 10 Sep 2020 11:19:38 +0200 Subject: [PATCH] In-call audio/camera permissions improvements --- .../activities/call/IncomingCallActivity.kt | 24 ++++++++++ .../activities/call/OutgoingCallActivity.kt | 45 ++++++++++++------- .../call/fragments/ControlsFragment.kt | 34 ++++++++++++-- .../call/viewmodels/ControlsViewModel.kt | 23 +++++++++- .../res/layout/call_outgoing_activity.xml | 15 ++----- 5 files changed, 108 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/org/linphone/activities/call/IncomingCallActivity.kt b/app/src/main/java/org/linphone/activities/call/IncomingCallActivity.kt index 9472e09c7..697c82193 100644 --- a/app/src/main/java/org/linphone/activities/call/IncomingCallActivity.kt +++ b/app/src/main/java/org/linphone/activities/call/IncomingCallActivity.kt @@ -19,9 +19,11 @@ */ package org.linphone.activities.call +import android.Manifest import android.annotation.TargetApi import android.app.KeyguardManager import android.content.Context +import android.content.pm.PackageManager import android.os.Bundle import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider @@ -113,10 +115,12 @@ class IncomingCallActivity : GenericActivity() { Log.i("[Incoming Call Activity] Asking for RECORD_AUDIO permission") permissionsRequiredList.add(android.Manifest.permission.RECORD_AUDIO) } + if (viewModel.call.currentParams.videoEnabled() && !PermissionHelper.get().hasCameraPermission()) { Log.i("[Incoming Call Activity] Asking for CAMERA permission") permissionsRequiredList.add(android.Manifest.permission.CAMERA) } + if (permissionsRequiredList.isNotEmpty()) { val permissionsRequired = arrayOfNulls(permissionsRequiredList.size) permissionsRequiredList.toArray(permissionsRequired) @@ -124,6 +128,26 @@ class IncomingCallActivity : GenericActivity() { } } + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + if (requestCode == 0) { + for (i in permissions.indices) { + when (permissions[i]) { + Manifest.permission.RECORD_AUDIO -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + Log.i("[Incoming Call Activity] RECORD_AUDIO permission has been granted") + } + Manifest.permission.CAMERA -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + Log.i("[Incoming Call Activity] CAMERA permission has been granted") + coreContext.core.reloadVideoDevices() + } + } + } + } + } + private fun findIncomingCall(): Call? { for (call in coreContext.core.calls) { if (call.state == Call.State.IncomingReceived || diff --git a/app/src/main/java/org/linphone/activities/call/OutgoingCallActivity.kt b/app/src/main/java/org/linphone/activities/call/OutgoingCallActivity.kt index a19d25a73..90a64b27b 100644 --- a/app/src/main/java/org/linphone/activities/call/OutgoingCallActivity.kt +++ b/app/src/main/java/org/linphone/activities/call/OutgoingCallActivity.kt @@ -19,7 +19,9 @@ */ package org.linphone.activities.call +import android.Manifest import android.annotation.TargetApi +import android.content.pm.PackageManager import android.os.Bundle import android.view.WindowManager import androidx.databinding.DataBindingUtil @@ -64,22 +66,6 @@ class OutgoingCallActivity : ProximitySensorActivity() { controlsViewModel = ViewModelProvider(this).get(ControlsViewModel::class.java) binding.controlsViewModel = controlsViewModel - binding.setTerminateCallClickListener { - viewModel.terminateCall() - } - - binding.setToggleMicrophoneClickListener { - if (PermissionHelper.get().hasRecordAudioPermission()) { - controlsViewModel.toggleMuteMicrophone() - } else { - checkPermissions() - } - } - - binding.setToggleSpeakerClickListener { - controlsViewModel.toggleSpeaker() - } - viewModel.callEndedEvent.observe(this, { it.consume { Log.i("[Outgoing Call Activity] Call ended, finish activity") @@ -98,6 +84,12 @@ class OutgoingCallActivity : ProximitySensorActivity() { enableProximitySensor(!it) }) + controlsViewModel.askPermissionEvent.observe(this, { + it.consume { permission -> + requestPermissions(arrayOf(permission), 0) + } + }) + if (Version.sdkAboveOrEqual(Version.API23_MARSHMALLOW_60)) { checkPermissions() } @@ -131,6 +123,27 @@ class OutgoingCallActivity : ProximitySensorActivity() { } } + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + if (requestCode == 0) { + for (i in permissions.indices) { + when (permissions[i]) { + Manifest.permission.RECORD_AUDIO -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + Log.i("[Outgoing Call Activity] RECORD_AUDIO permission has been granted") + controlsViewModel.updateMuteMicState() + } + Manifest.permission.CAMERA -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + Log.i("[Outgoing Call Activity] CAMERA permission has been granted") + coreContext.core.reloadVideoDevices() + } + } + } + } + } + private fun findOutgoingCall(): Call? { for (call in coreContext.core.calls) { if (call.state == Call.State.OutgoingInit || diff --git a/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt b/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt index fd3911214..39e0bbaf0 100644 --- a/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt +++ b/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt @@ -19,13 +19,15 @@ */ package org.linphone.activities.call.fragments +import android.Manifest import android.annotation.TargetApi import android.app.Dialog import android.content.Intent -import android.content.pm.PackageManager +import android.content.pm.PackageManager.PERMISSION_GRANTED import android.os.Bundle import android.os.SystemClock import androidx.lifecycle.ViewModelProvider +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R import org.linphone.activities.GenericFragment import org.linphone.activities.call.viewmodels.CallsViewModel @@ -122,6 +124,13 @@ class ControlsFragment : GenericFragment() { } }) + controlsViewModel.askPermissionEvent.observe(viewLifecycleOwner, { + it.consume { permission -> + Log.i("[Controls Fragment] Asking for $permission permission") + requestPermissions(arrayOf(permission), 0) + } + }) + controlsViewModel.somethingClickedEvent.observe(viewLifecycleOwner, { it.consume { sharedViewModel.resetHiddenInterfaceTimerInVideoCallEvent.value = Event(true) @@ -138,9 +147,19 @@ class ControlsFragment : GenericFragment() { permissions: Array, grantResults: IntArray ) { - if (requestCode == 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - Log.i("[Controls Fragment] RECORD_AUDIO permission has been granted") - controlsViewModel.updateMuteMicState() + if (requestCode == 0) { + for (i in permissions.indices) { + when (permissions[i]) { + Manifest.permission.RECORD_AUDIO -> if (grantResults[i] == PERMISSION_GRANTED) { + Log.i("[Controls Fragment] RECORD_AUDIO permission has been granted") + controlsViewModel.updateMuteMicState() + } + Manifest.permission.CAMERA -> if (grantResults[i] == PERMISSION_GRANTED) { + Log.i("[Controls Fragment] CAMERA permission has been granted") + coreContext.core.reloadVideoDevices() + } + } + } } super.onRequestPermissionsResult(requestCode, permissions, grantResults) } @@ -148,10 +167,17 @@ class ControlsFragment : GenericFragment() { @TargetApi(Version.API23_MARSHMALLOW_60) private fun checkPermissions() { val permissionsRequiredList = arrayListOf() + if (!PermissionHelper.get().hasRecordAudioPermission()) { Log.i("[Controls Fragment] Asking for RECORD_AUDIO permission") permissionsRequiredList.add(android.Manifest.permission.RECORD_AUDIO) } + + if (coreContext.isVideoCallOrConferenceActive() && !PermissionHelper.get().hasCameraPermission()) { + Log.i("[Controls Fragment] Asking for CAMERA permission") + permissionsRequiredList.add(android.Manifest.permission.CAMERA) + } + if (permissionsRequiredList.isNotEmpty()) { val permissionsRequired = arrayOfNulls(permissionsRequiredList.size) permissionsRequiredList.toArray(permissionsRequired) diff --git a/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt b/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt index 7ffabc387..f13c5bc42 100644 --- a/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt +++ b/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt @@ -19,6 +19,7 @@ */ package org.linphone.activities.call.viewmodels +import android.Manifest import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import kotlin.math.max @@ -74,6 +75,10 @@ class ControlsViewModel : ViewModel() { MutableLiveData>() } + val askPermissionEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + val somethingClickedEvent = MutableLiveData>() val onKeyClick: NumpadDigitListener = object : NumpadDigitListener { @@ -105,6 +110,10 @@ class ControlsViewModel : ViewModel() { ) { if (state == Call.State.StreamsRunning) isVideoUpdateInProgress.value = false + if (coreContext.isVideoCallOrConferenceActive() && !PermissionHelper.get().hasCameraPermission()) { + askPermissionEvent.value = Event(Manifest.permission.CAMERA) + } + updateUI() } @@ -147,6 +156,11 @@ class ControlsViewModel : ViewModel() { } fun toggleMuteMicrophone() { + if (!PermissionHelper.get().hasRecordAudioPermission()) { + askPermissionEvent.value = Event(Manifest.permission.RECORD_AUDIO) + return + } + somethingClickedEvent.value = Event(true) val micEnabled = coreContext.core.micEnabled() coreContext.core.enableMic(!micEnabled) @@ -178,6 +192,11 @@ class ControlsViewModel : ViewModel() { } fun toggleVideo() { + if (!PermissionHelper.get().hasCameraPermission()) { + askPermissionEvent.value = Event(Manifest.permission.CAMERA) + return + } + val core = coreContext.core val currentCall = core.currentCall val conference = core.conference @@ -314,6 +333,7 @@ class ControlsViewModel : ViewModel() { fun updateMuteMicState() { isMicrophoneMuted.value = !PermissionHelper.get().hasRecordAudioPermission() || !coreContext.core.micEnabled() + isMuteMicrophoneEnabled.value = coreContext.core.currentCall != null || coreContext.core.isInConference } private fun updateSpeakerState() { @@ -349,7 +369,8 @@ class ControlsViewModel : ViewModel() { } private fun updateVideoEnabled() { - isVideoEnabled.value = coreContext.isVideoCallOrConferenceActive() + val enabled = coreContext.isVideoCallOrConferenceActive() + isVideoEnabled.value = enabled } private fun updateConferenceState() { diff --git a/app/src/main/res/layout/call_outgoing_activity.xml b/app/src/main/res/layout/call_outgoing_activity.xml index d5e6e1999..b48dfd05f 100644 --- a/app/src/main/res/layout/call_outgoing_activity.xml +++ b/app/src/main/res/layout/call_outgoing_activity.xml @@ -5,15 +5,6 @@ - - - @@ -99,7 +90,7 @@ android:orientation="horizontal">