Skip to content

Commit a4b34ec

Browse files
MozLandoAmejia481
andcommitted
6301: Closes mozilla-mobile#6299: Auto reject any media site permission when a system permission is not allowed first r=rocketsroger a=Amejia481 Co-authored-by: Arturo Mejia <[email protected]>
2 parents 5e87326 + b020317 commit a4b34ec

File tree

3 files changed

+67
-9
lines changed

3 files changed

+67
-9
lines changed

components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package mozilla.components.feature.sitepermissions
66

7+
import android.Manifest.permission.CAMERA
78
import android.Manifest.permission.RECORD_AUDIO
89
import android.annotation.SuppressLint
910
import android.content.Context
@@ -221,9 +222,11 @@ class SitePermissionsFeature(
221222
request: PermissionRequest
222223
): SitePermissionsDialogFragment? {
223224

224-
// Preventing this behavior https://github.com/mozilla-mobile/android-components/issues/2668
225-
if (request.isMicrophone && isMicrophoneAndroidPermissionNotGranted) {
225+
// We want to warranty that all media permissions have the required system
226+
// permissions are granted first, otherwise, we reject the request
227+
if (request.isMedia && !request.areAllMediaPermissionsGranted) {
226228
request.reject()
229+
session.contentPermissionRequest.consume { true }
227230
return null
228231
}
229232

@@ -482,20 +485,29 @@ class SitePermissionsFeature(
482485
}
483486

484487
private val PermissionRequest.host get() = uri?.toUri()?.host ?: ""
485-
private val PermissionRequest.isMicrophone: Boolean
488+
private val PermissionRequest.isMedia: Boolean
486489
get() {
487-
if (containsVideoAndAudioSources()) {
488-
return false
489-
}
490490
return when (permissions.first()) {
491+
is ContentVideoCamera, is ContentVideoCapture,
491492
is ContentAudioCapture, is ContentAudioMicrophone -> true
492493
else -> false
493494
}
494495
}
495496

496-
private val isMicrophoneAndroidPermissionNotGranted: Boolean
497+
private val PermissionRequest.areAllMediaPermissionsGranted: Boolean
497498
get() {
498-
return !context.isPermissionGranted(RECORD_AUDIO)
499+
val systemPermissions = mutableListOf<String>()
500+
permissions.forEach { permission ->
501+
when (permission) {
502+
is ContentVideoCamera, is ContentVideoCapture -> {
503+
systemPermissions.add(CAMERA)
504+
}
505+
is ContentAudioCapture, is ContentAudioMicrophone -> {
506+
systemPermissions.add(RECORD_AUDIO)
507+
}
508+
}
509+
}
510+
return systemPermissions.all { context.isPermissionGranted((it)) }
499511
}
500512

501513
internal class SitePermissionsRequestObserver(

components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ class SitePermissionsFeatureTest {
215215
mockStorage = mock()
216216
session.contentPermissionRequest = Consumable.from(permissionRequest)
217217

218+
grantPermission(Manifest.permission.CAMERA)
218219
grantPermission(Manifest.permission.RECORD_AUDIO)
219220
runBlocking {
220221
val prompt = sitePermissionFeature.onContentPermissionRequested(session, permissionRequest)
@@ -722,7 +723,7 @@ class SitePermissionsFeatureTest {
722723
}
723724

724725
session.contentPermissionRequest = Consumable.from(permissionRequest)
725-
726+
grantPermission(Manifest.permission.CAMERA)
726727
runBlocking {
727728
val prompt = sitePermissionFeature.onContentPermissionRequested(session, permissionRequest)
728729

@@ -760,6 +761,8 @@ class SitePermissionsFeatureTest {
760761
}
761762

762763
session.contentPermissionRequest = Consumable.from(permissionRequest)
764+
grantPermission(Manifest.permission.CAMERA)
765+
grantPermission(Manifest.permission.RECORD_AUDIO)
763766

764767
runBlocking {
765768
val prompt = sitePermissionFeature.onContentPermissionRequested(session, permissionRequest)
@@ -797,6 +800,8 @@ class SitePermissionsFeatureTest {
797800
}
798801

799802
session.contentPermissionRequest = Consumable.from(permissionRequest)
803+
grantPermission(Manifest.permission.CAMERA)
804+
grantPermission(Manifest.permission.RECORD_AUDIO)
800805

801806
runBlocking {
802807
val prompt = sitePermissionFeature.onContentPermissionRequested(session, permissionRequest)
@@ -944,6 +949,44 @@ class SitePermissionsFeatureTest {
944949
assertEquals(ALLOWED, sitePermissions.autoplayInaudible)
945950
}
946951

952+
@Test
953+
fun `any media request must be rejected WHEN system permissions are not granted first`() {
954+
val permissions = listOf(
955+
ContentVideoCapture("", "back camera"),
956+
ContentVideoCamera("", "front camera"),
957+
ContentAudioCapture(),
958+
ContentAudioMicrophone()
959+
)
960+
961+
permissions.forEach { permission ->
962+
val session = getSelectedSession()
963+
var grantWasCalled = false
964+
965+
val permissionRequest: PermissionRequest = object : PermissionRequest {
966+
override val uri: String?
967+
get() = "http://www.mozilla.org"
968+
override val permissions: List<Permission>
969+
get() = listOf(permission)
970+
971+
override fun grant(permissions: List<Permission>) {
972+
grantWasCalled = true
973+
}
974+
975+
override fun reject() = Unit
976+
}
977+
978+
mockStorage = mock()
979+
session.contentPermissionRequest = Consumable.from(permissionRequest)
980+
981+
runBlocking {
982+
val prompt = sitePermissionFeature.onContentPermissionRequested(session, permissionRequest)
983+
assertNull(prompt)
984+
assertFalse(grantWasCalled)
985+
assertTrue(session.contentPermissionRequest.isConsumed())
986+
}
987+
}
988+
}
989+
947990
private fun mockFragmentManager(): FragmentManager {
948991
val fragmentManager: FragmentManager = mock()
949992
val transaction: FragmentTransaction = mock()

docs/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ permalink: /changelog/
3535
* ⚠️ **This is a breaking change**: `FxaWebChannelFeature` takes a `ServerConfig` as 4th parameter to ensure incoming WebChannel messages
3636
are sent by the expected FxA host.
3737

38+
* **feature-sitepermissions**
39+
* Fixed issue [#6299](https://github.com/mozilla-mobile/android-components/issues/6299), from now on, any media requests like a microphone or a camera permission will require the system permissions to be granted before a dialog can be shown.
40+
3841
* **service-sync-logins**
3942
* ⚠️ **This is a breaking change**: `DefaultLoginValidationDelegate`, `GeckoLoginStorageDelegate` constructors changed to take `Lazy<LoginsStorage>` instead of `LoginsStorage`, to facilitate late initialization.
4043

0 commit comments

Comments
 (0)