diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f59cb56485e2..05308e4a1fba 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,7 +17,11 @@ tools:ignore="QueryAllPackagesPermission" /> - + + + + + diff --git a/app/version/release-notes b/app/version/release-notes index 8ed107e79663..95a9ae75253a 100644 --- a/app/version/release-notes +++ b/app/version/release-notes @@ -1,2 +1 @@ -When websites ask for camera and mic permissions, you can now use these features on sites you visit. -We've also improved how you manage the permissions you've already granted, giving you global controls over permissions for individual websites and the ability to restrict whether websites can ask for permissions at all. \ No newline at end of file +When websites ask for camera and mic permissions, you can now use these features on sites you visit. \ No newline at end of file diff --git a/app/version/version.properties b/app/version/version.properties index 2d3e08f4663b..3c124a39c60d 100644 --- a/app/version/version.properties +++ b/app/version/version.properties @@ -1 +1 @@ -VERSION=5.139.0 \ No newline at end of file +VERSION=5.139.1 \ No newline at end of file diff --git a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerImpl.kt b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerImpl.kt index c86e2fb1997d..5a56437e5b24 100644 --- a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerImpl.kt +++ b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerImpl.kt @@ -16,22 +16,31 @@ package com.duckduckgo.site.permissions.impl +import android.content.pm.PackageManager import android.webkit.PermissionRequest import com.duckduckgo.site.permissions.api.SitePermissionsManager import javax.inject.Inject class SitePermissionsManagerImpl @Inject constructor( + private val packageManager: PackageManager, private val sitePermissionsRepository: SitePermissionsRepository ) : SitePermissionsManager { - override suspend fun getSitePermissionsGranted(url: String, tabId: String, resources: Array): Array = + override suspend fun getSitePermissionsGranted( + url: String, + tabId: String, + resources: Array + ): Array = resources .filter { sitePermissionsRepository.isDomainGranted(url, tabId, it) } .toTypedArray() - override suspend fun getSitePermissionsAllowedToAsk(url: String, resources: Array): Array = + override suspend fun getSitePermissionsAllowedToAsk( + url: String, + resources: Array + ): Array = resources - .filter { isPermissionSupported(it) } + .filter { isPermissionSupported(it) && isHardwareSupported(it) } .filter { sitePermissionsRepository.isDomainAllowedToAsk(url, it) } .toTypedArray() @@ -49,4 +58,12 @@ class SitePermissionsManagerImpl @Inject constructor( private fun isPermissionSupported(permission: String): Boolean = permission == PermissionRequest.RESOURCE_AUDIO_CAPTURE || permission == PermissionRequest.RESOURCE_VIDEO_CAPTURE + private fun isHardwareSupported(permission: String): Boolean = when (permission) { + PermissionRequest.RESOURCE_VIDEO_CAPTURE -> { + kotlin.runCatching { packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) }.getOrDefault(false) + } + else -> { + true + } + } } diff --git a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt index 3f393af23089..3cc7f9a3bc2d 100644 --- a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt +++ b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt @@ -17,6 +17,7 @@ package com.duckduckgo.site.permissions.impl.di import android.content.Context +import android.content.pm.PackageManager import androidx.room.Room import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.site.permissions.api.SitePermissionsManager @@ -58,8 +59,11 @@ object SitePermissionsModule { } @Provides - fun providesSitePermissionsManager(sitePermissionsRepository: SitePermissionsRepositoryImpl): SitePermissionsManager { - return SitePermissionsManagerImpl(sitePermissionsRepository) + fun providesSitePermissionsManager( + sitePermissionsRepository: SitePermissionsRepositoryImpl, + packageManager: PackageManager + ): SitePermissionsManager { + return SitePermissionsManagerImpl(packageManager, sitePermissionsRepository) } @Provides diff --git a/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerTest.kt b/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerTest.kt index 8a553b0154af..24d05e3db880 100644 --- a/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerTest.kt +++ b/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/SitePermissionsManagerTest.kt @@ -16,9 +16,11 @@ package com.duckduckgo.site.permissions.impl +import android.content.pm.PackageManager import android.webkit.PermissionRequest import com.duckduckgo.app.CoroutineTestRule import com.duckduckgo.site.permissions.store.sitepermissions.SitePermissionsEntity +import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify @@ -28,8 +30,11 @@ import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner @ExperimentalCoroutinesApi +@RunWith(RobolectricTestRunner::class) class SitePermissionsManagerTest { @ExperimentalCoroutinesApi @@ -37,8 +42,9 @@ class SitePermissionsManagerTest { var coroutineRule = CoroutineTestRule() private val mockSitePermissionsRepository: SitePermissionsRepository = mock() + private val mockPackageManager = mock() - private val testee = SitePermissionsManagerImpl(mockSitePermissionsRepository) + private val testee = SitePermissionsManagerImpl(mockPackageManager, mockSitePermissionsRepository) private val url = "https://domain.com/whatever" @@ -60,12 +66,25 @@ class SitePermissionsManagerTest { arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE, PermissionRequest.RESOURCE_MIDI_SYSEX, PermissionRequest.RESOURCE_AUDIO_CAPTURE) whenever(mockSitePermissionsRepository.isDomainAllowedToAsk(url, PermissionRequest.RESOURCE_VIDEO_CAPTURE)).thenReturn(true) whenever(mockSitePermissionsRepository.isDomainAllowedToAsk(url, PermissionRequest.RESOURCE_AUDIO_CAPTURE)).thenReturn(false) + whenever(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)).thenReturn(true) val permissionsAllowedToAsk = testee.getSitePermissionsAllowedToAsk(url, resources) assertEquals(1, permissionsAllowedToAsk.size) assertEquals(PermissionRequest.RESOURCE_VIDEO_CAPTURE, permissionsAllowedToAsk.first()) } + @Test + fun givenListOfPermissionsNoHardwareCameraThenFilterNotSupportedAndReturnOnlyPermissionsAllowedToAsk() = runTest { + val resources = + arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE, PermissionRequest.RESOURCE_MIDI_SYSEX, PermissionRequest.RESOURCE_AUDIO_CAPTURE) + whenever(mockSitePermissionsRepository.isDomainAllowedToAsk(url, PermissionRequest.RESOURCE_VIDEO_CAPTURE)).thenReturn(true) + whenever(mockSitePermissionsRepository.isDomainAllowedToAsk(url, PermissionRequest.RESOURCE_AUDIO_CAPTURE)).thenReturn(false) + whenever(mockPackageManager.hasSystemFeature(any())).thenReturn(false) + + val permissionsAllowedToAsk = testee.getSitePermissionsAllowedToAsk(url, resources) + assertEquals(0, permissionsAllowedToAsk.size) + } + @Test fun whenClearAllButFireproofThenDontDeleteEntitiesWhichDomainIsInTheFireproofList() = runTest { val fireproofDomain = "domain.com"