From 8f9c61e48d801cc800391c5ab21d80ba8ec76a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 3 Dec 2020 14:38:08 +0100 Subject: [PATCH] Handle GeckoView EME permission requests. This allows Fenix to play EME content without having to toggle manually `media.eme.require-app-approval=false` in `about:config`. Closes #7121 --- .../permission/GeckoPermissionRequest.kt | 4 +- .../permission/GeckoPermissionRequest.kt | 4 +- .../permission/GeckoPermissionRequest.kt | 4 +- .../engine/permission/PermissionRequest.kt | 2 + .../4.json | 94 +++++++++++++++++++ .../db/OnDeviceSitePermissionsStorageTest.kt | 25 +++++ .../sitepermissions/SitePermissions.kt | 2 + .../sitepermissions/SitePermissionsFeature.kt | 25 ++++- .../sitepermissions/SitePermissionsRules.kt | 13 ++- .../sitepermissions/SitePermissionsStorage.kt | 4 +- .../db/SitePermissionsDatabase.kt | 17 +++- .../db/SitePermissionsEntity.kt | 5 + .../src/main/res/values/strings.xml | 4 +- .../SitePermissionsFeatureTest.kt | 4 +- .../SitePermissionsRulesTest.kt | 18 +++- .../SitePermissionsStorageTest.kt | 2 + .../db/SitePermissionEntityTest.kt | 8 ++ docs/changelog.md | 4 + .../samples/browser/BaseBrowserFragment.kt | 3 +- 19 files changed, 226 insertions(+), 16 deletions(-) create mode 100644 components/feature/sitepermissions/schemas/mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase/4.json diff --git a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt index f5ea619e403..bf8f84d52e9 100644 --- a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt +++ b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt @@ -21,6 +21,7 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION +import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_PERSISTENT_STORAGE import java.util.UUID @@ -59,7 +60,8 @@ sealed class GeckoPermissionRequest constructor( PERMISSION_GEOLOCATION to Permission.ContentGeoLocation(), PERMISSION_AUTOPLAY_AUDIBLE to Permission.ContentAutoPlayAudible(), PERMISSION_AUTOPLAY_INAUDIBLE to Permission.ContentAutoPlayInaudible(), - PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage() + PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage(), + PERMISSION_MEDIA_KEY_SYSTEM_ACCESS to Permission.ContentMediaKeySystemAccess() ) } } diff --git a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt index f5ea619e403..bf8f84d52e9 100644 --- a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt +++ b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt @@ -21,6 +21,7 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION +import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_PERSISTENT_STORAGE import java.util.UUID @@ -59,7 +60,8 @@ sealed class GeckoPermissionRequest constructor( PERMISSION_GEOLOCATION to Permission.ContentGeoLocation(), PERMISSION_AUTOPLAY_AUDIBLE to Permission.ContentAutoPlayAudible(), PERMISSION_AUTOPLAY_INAUDIBLE to Permission.ContentAutoPlayInaudible(), - PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage() + PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage(), + PERMISSION_MEDIA_KEY_SYSTEM_ACCESS to Permission.ContentMediaKeySystemAccess() ) } } diff --git a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt index f5ea619e403..bf8f84d52e9 100644 --- a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt +++ b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt @@ -21,6 +21,7 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION +import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_PERSISTENT_STORAGE import java.util.UUID @@ -59,7 +60,8 @@ sealed class GeckoPermissionRequest constructor( PERMISSION_GEOLOCATION to Permission.ContentGeoLocation(), PERMISSION_AUTOPLAY_AUDIBLE to Permission.ContentAutoPlayAudible(), PERMISSION_AUTOPLAY_INAUDIBLE to Permission.ContentAutoPlayInaudible(), - PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage() + PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage(), + PERMISSION_MEDIA_KEY_SYSTEM_ACCESS to Permission.ContentMediaKeySystemAccess() ) } } diff --git a/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt b/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt index a52af746f55..6c7d20b6851 100644 --- a/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt +++ b/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt @@ -80,6 +80,8 @@ sealed class Permission { data class ContentAutoPlayAudible(override val id: String? = "", override val desc: String? = "") : Permission() data class ContentAutoPlayInaudible(override val id: String? = "", override val desc: String? = "") : Permission() data class ContentPersistentStorage(override val id: String? = "", override val desc: String? = "") : Permission() + data class ContentMediaKeySystemAccess(override val id: String? = "", override val desc: String? = "") : + Permission() data class AppCamera(override val id: String? = "", override val desc: String? = "") : Permission() data class AppAudio(override val id: String? = "", override val desc: String? = "") : Permission() diff --git a/components/feature/sitepermissions/schemas/mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase/4.json b/components/feature/sitepermissions/schemas/mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase/4.json new file mode 100644 index 00000000000..f91ee575159 --- /dev/null +++ b/components/feature/sitepermissions/schemas/mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase/4.json @@ -0,0 +1,94 @@ +{ + "formatVersion": 1, + "database": { + "version": 4, + "identityHash": "f5379c8eb4f1519eb5994e508626ca10", + "entities": [ + { + "tableName": "site_permissions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`origin` TEXT NOT NULL, `location` INTEGER NOT NULL, `notification` INTEGER NOT NULL, `microphone` INTEGER NOT NULL, `camera` INTEGER NOT NULL, `bluetooth` INTEGER NOT NULL, `local_storage` INTEGER NOT NULL, `autoplay_audible` INTEGER NOT NULL, `autoplay_inaudible` INTEGER NOT NULL, `media_key_system_access` INTEGER NOT NULL, `saved_at` INTEGER NOT NULL, PRIMARY KEY(`origin`))", + "fields": [ + { + "fieldPath": "origin", + "columnName": "origin", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "location", + "columnName": "location", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notification", + "columnName": "notification", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "microphone", + "columnName": "microphone", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "camera", + "columnName": "camera", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "bluetooth", + "columnName": "bluetooth", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localStorage", + "columnName": "local_storage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "autoplayAudible", + "columnName": "autoplay_audible", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "autoplayInaudible", + "columnName": "autoplay_inaudible", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mediaKeySystemAccess", + "columnName": "media_key_system_access", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "savedAt", + "columnName": "saved_at", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "origin" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f5379c8eb4f1519eb5994e508626ca10')" + ] + } +} \ No newline at end of file diff --git a/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt b/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt index cc217a2dde8..4f8f1e9eae7 100644 --- a/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt +++ b/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt @@ -127,4 +127,29 @@ class OnDeviceSitePermissionsStorageTest { assertEquals(Status.ALLOWED.id, cursor.getInt(cursor.getColumnIndexOrThrow("autoplay_inaudible"))) } } + + @Test + fun migrate3to4() { + helper.createDatabase(MIGRATION_TEST_DB, 3).apply { + query("SELECT * FROM site_permissions").use { cursor -> + assertEquals(10, cursor.columnCount) + } + execSQL( + "INSERT INTO " + + "site_permissions " + + "(origin, location, notification, microphone,camera,bluetooth,local_storage,autoplay_audible,autoplay_inaudible,saved_at) " + + "VALUES " + + "('mozilla.org',1,1,1,1,1,1,1,1,1)" + ) + } + + val dbVersion3 = helper.runMigrationsAndValidate(MIGRATION_TEST_DB, 4, true, Migrations.migration_3_4) + + dbVersion3.query("SELECT * FROM site_permissions").use { cursor -> + assertEquals(11, cursor.columnCount) + + cursor.moveToFirst() + assertEquals(Status.NO_DECISION.id, cursor.getInt(cursor.getColumnIndexOrThrow("media_key_system_access"))) + } + } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt index e1ab995f68d..b68a44a65be 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt @@ -23,6 +23,7 @@ data class SitePermissions( val localStorage: Status = NO_DECISION, val autoplayAudible: Status = NO_DECISION, val autoplayInaudible: Status = NO_DECISION, + val mediaKeySystemAccess: Status = NO_DECISION, val savedAt: Long ) : Parcelable { enum class Status( @@ -53,6 +54,7 @@ data class SitePermissions( Permission.LOCATION -> location Permission.AUTOPLAY_AUDIBLE -> autoplayAudible Permission.AUTOPLAY_INAUDIBLE -> autoplayInaudible + Permission.MEDIA_KEY_SYSTEM_ACCESS -> mediaKeySystemAccess } } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt index 50c60eb6438..6ff77aa46de 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt @@ -35,6 +35,7 @@ import mozilla.components.concept.engine.permission.Permission.ContentNotificati import mozilla.components.concept.engine.permission.Permission.ContentVideoCamera import mozilla.components.concept.engine.permission.Permission.ContentVideoCapture import mozilla.components.concept.engine.permission.Permission.ContentPersistentStorage +import mozilla.components.concept.engine.permission.Permission.ContentMediaKeySystemAccess import mozilla.components.concept.engine.permission.Permission.AppLocationCoarse import mozilla.components.concept.engine.permission.Permission.AppLocationFine import mozilla.components.concept.engine.permission.Permission.AppAudio @@ -438,6 +439,9 @@ class SitePermissionsFeature( is ContentPersistentStorage -> { permissionFromStore.localStorage.doNotAskAgain() } + is ContentMediaKeySystemAccess -> { + permissionFromStore.mediaKeySystemAccess.doNotAskAgain() + } else -> false } } @@ -499,6 +503,9 @@ class SitePermissionsFeature( is ContentPersistentStorage -> { sitePermissions.copy(localStorage = status) } + is ContentMediaKeySystemAccess -> { + sitePermissions.copy(mediaKeySystemAccess = status) + } else -> throw InvalidParameterException("$permission is not a valid permission.") } @@ -526,6 +533,7 @@ class SitePermissionsFeature( } } + @Suppress("LongMethod") @VisibleForTesting internal fun handlingSingleContentPermissions( permissionRequest: PermissionRequest, @@ -592,6 +600,17 @@ class SitePermissionsFeature( shouldSelectRememberChoice = true ) } + is ContentMediaKeySystemAccess -> { + createSinglePermissionPrompt( + context, + host, + permissionRequest, + R.string.mozac_feature_sitepermissions_media_key_system_access_title, + R.drawable.mozac_ic_link, + showDoNotAskAgainCheckBox = false, + shouldSelectRememberChoice = true + ) + } else -> throw InvalidParameterException("$permission is not a valid permission.") } @@ -727,6 +746,9 @@ internal fun isPermissionGranted( is ContentPersistentStorage -> { permissionFromStorage.localStorage.isAllowed() } + is ContentMediaKeySystemAccess -> { + permissionFromStorage.mediaKeySystemAccess.isAllowed() + } else -> throw InvalidParameterException("$permission is not a valid permission.") } @@ -739,7 +761,8 @@ private fun Permission.isSupported(): Boolean { is ContentPersistentStorage, is ContentAudioCapture, is ContentAudioMicrophone, is ContentVideoCamera, is ContentVideoCapture, - is ContentAutoPlayAudible, is ContentAutoPlayInaudible -> true + is ContentAutoPlayAudible, is ContentAutoPlayInaudible, + is ContentMediaKeySystemAccess -> true else -> false } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsRules.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsRules.kt index 1d5ca18ab34..c89733e54a6 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsRules.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsRules.kt @@ -19,7 +19,8 @@ data class SitePermissionsRules internal constructor( val microphone: Action, val autoplayAudible: Action, val autoplayInaudible: Action, - val persistentStorage: Action + val persistentStorage: Action, + val mediaKeySystemAccess: Action ) { constructor( @@ -29,7 +30,8 @@ data class SitePermissionsRules internal constructor( microphone: Action, autoplayAudible: AutoplayAction, autoplayInaudible: AutoplayAction, - persistentStorage: Action + persistentStorage: Action, + mediaKeySystemAccess: Action ) : this( camera = camera, location = location, @@ -37,7 +39,8 @@ data class SitePermissionsRules internal constructor( microphone = microphone, autoplayAudible = autoplayAudible.toAction(), autoplayInaudible = autoplayInaudible.toAction(), - persistentStorage = persistentStorage + persistentStorage = persistentStorage, + mediaKeySystemAccess = mediaKeySystemAccess ) enum class Action { @@ -93,6 +96,9 @@ data class SitePermissionsRules internal constructor( is Permission.ContentAutoPlayInaudible -> { autoplayInaudible } + is Permission.ContentMediaKeySystemAccess -> { + mediaKeySystemAccess + } else -> ASK_TO_ALLOW } } @@ -118,6 +124,7 @@ data class SitePermissionsRules internal constructor( autoplayAudible = autoplayAudible.toStatus(), autoplayInaudible = autoplayInaudible.toStatus(), localStorage = persistentStorage.toStatus(), + mediaKeySystemAccess = mediaKeySystemAccess.toStatus(), savedAt = savedAt ) } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt index 40ed2c2b440..5ea07f71cd6 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt @@ -23,6 +23,7 @@ import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permiss import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.NOTIFICATION import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.AUTOPLAY_AUDIBLE import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.AUTOPLAY_INAUDIBLE +import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.MEDIA_KEY_SYSTEM_ACCESS import mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase import mozilla.components.feature.sitepermissions.db.toSitePermissionsEntity @@ -116,6 +117,7 @@ class SitePermissionsStorage( map.putIfAllowed(LOCATION, location, permission) map.putIfAllowed(AUTOPLAY_AUDIBLE, autoplayAudible, permission) map.putIfAllowed(AUTOPLAY_INAUDIBLE, autoplayInaudible, permission) + map.putIfAllowed(MEDIA_KEY_SYSTEM_ACCESS, mediaKeySystemAccess, permission) } } return map @@ -173,6 +175,6 @@ class SitePermissionsStorage( enum class Permission { MICROPHONE, BLUETOOTH, CAMERA, LOCAL_STORAGE, NOTIFICATION, LOCATION, AUTOPLAY_AUDIBLE, - AUTOPLAY_INAUDIBLE + AUTOPLAY_INAUDIBLE, MEDIA_KEY_SYSTEM_ACCESS } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt index d46e28c62e3..285c5e2156b 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt @@ -17,7 +17,7 @@ import mozilla.components.feature.sitepermissions.SitePermissions /** * Internal database for saving site permissions. */ -@Database(entities = [SitePermissionsEntity::class], version = 3) +@Database(entities = [SitePermissionsEntity::class], version = 4) @TypeConverters(StatusConverter::class) internal abstract class SitePermissionsDatabase : RoomDatabase() { abstract fun sitePermissionsDao(): SitePermissionsDao @@ -38,6 +38,8 @@ internal abstract class SitePermissionsDatabase : RoomDatabase() { Migrations.migration_1_2 ).addMigrations( Migrations.migration_2_3 + ).addMigrations( + Migrations.migration_3_4 ).build().also { instance = it } } } @@ -98,4 +100,17 @@ internal object Migrations { } } } + + @Suppress("MagicNumber") + val migration_3_4 = object : Migration(3, 4) { + override fun migrate(database: SupportSQLiteDatabase) { + val hasEmeColumn = database.query("SELECT * FROM site_permissions").columnCount == 11 + if (!hasEmeColumn) { + database.execSQL( + "ALTER TABLE site_permissions ADD COLUMN media_key_system_access INTEGER NOT NULL DEFAULT 0") + // default is NO_DECISION + database.execSQL("UPDATE site_permissions SET media_key_system_access = 0") + } + } + } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt index a244cdf8ecb..6d55c7ad5c1 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt @@ -43,6 +43,9 @@ internal data class SitePermissionsEntity( @ColumnInfo(name = "autoplay_inaudible") var autoplayInaudible: SitePermissions.Status, + @ColumnInfo(name = "media_key_system_access") + var mediaKeySystemAccess: SitePermissions.Status, + @ColumnInfo(name = "saved_at") var savedAt: Long ) { @@ -58,6 +61,7 @@ internal data class SitePermissionsEntity( localStorage, autoplayAudible, autoplayInaudible, + mediaKeySystemAccess, savedAt ) } @@ -74,6 +78,7 @@ internal fun SitePermissions.toSitePermissionsEntity(): SitePermissionsEntity { localStorage, autoplayAudible, autoplayInaudible, + mediaKeySystemAccess, savedAt ) } diff --git a/components/feature/sitepermissions/src/main/res/values/strings.xml b/components/feature/sitepermissions/src/main/res/values/strings.xml index f0bcabbc64e..3211942fd20 100644 --- a/components/feature/sitepermissions/src/main/res/values/strings.xml +++ b/components/feature/sitepermissions/src/main/res/values/strings.xml @@ -36,4 +36,6 @@ Never Allow %1$s to store data in persistent storage? - \ No newline at end of file + + Allow %1$s to play DRM-controlled content? + diff --git a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt index 2075f58edbb..f188098a102 100644 --- a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt +++ b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt @@ -772,7 +772,8 @@ class SitePermissionsFeatureTest { microphone = SitePermissionsRules.Action.BLOCKED, autoplayAudible = SitePermissionsRules.Action.BLOCKED, autoplayInaudible = SitePermissionsRules.Action.ALLOWED, - persistentStorage = SitePermissionsRules.Action.BLOCKED + persistentStorage = SitePermissionsRules.Action.BLOCKED, + mediaKeySystemAccess = SitePermissionsRules.Action.ASK_TO_ALLOW ) sitePermissionFeature.sitePermissionsRules = rules @@ -787,6 +788,7 @@ class SitePermissionsFeatureTest { assertEquals(BLOCKED, sitePermissions.autoplayAudible) assertEquals(ALLOWED, sitePermissions.autoplayInaudible) assertEquals(BLOCKED, sitePermissions.localStorage) + assertEquals(NO_DECISION, sitePermissions.mediaKeySystemAccess) } @Test diff --git a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsRulesTest.kt b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsRulesTest.kt index 23799c1169a..83d909d5db9 100644 --- a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsRulesTest.kt +++ b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsRulesTest.kt @@ -59,7 +59,8 @@ class SitePermissionsRulesTest { microphone = BLOCKED, autoplayAudible = ASK_TO_ALLOW, autoplayInaudible = BLOCKED, - persistentStorage = BLOCKED + persistentStorage = BLOCKED, + mediaKeySystemAccess = ASK_TO_ALLOW ) val mockRequest: PermissionRequest = mock() @@ -95,6 +96,10 @@ class SitePermissionsRulesTest { doReturn(listOf(Permission.ContentPersistentStorage())).`when`(mockRequest).permissions action = rules.getActionFrom(mockRequest) assertEquals(action, rules.persistentStorage) + + doReturn(listOf(Permission.ContentMediaKeySystemAccess())).`when`(mockRequest).permissions + action = rules.getActionFrom(mockRequest) + assertEquals(action, rules.mediaKeySystemAccess) } @Test @@ -106,7 +111,8 @@ class SitePermissionsRulesTest { notification = ASK_TO_ALLOW, microphone = BLOCKED, autoplayInaudible = ASK_TO_ALLOW, - autoplayAudible = ASK_TO_ALLOW + autoplayAudible = ASK_TO_ALLOW, + mediaKeySystemAccess = ASK_TO_ALLOW ) val mockRequest: PermissionRequest = mock() @@ -122,7 +128,8 @@ class SitePermissionsRulesTest { microphone = ASK_TO_ALLOW, autoplayInaudible = BLOCKED, autoplayAudible = BLOCKED, - persistentStorage = BLOCKED + persistentStorage = BLOCKED, + mediaKeySystemAccess = ASK_TO_ALLOW ) action = rules.getActionFrom(mockRequest) @@ -140,6 +147,7 @@ class SitePermissionsRulesTest { microphone = Status.BLOCKED, autoplayInaudible = Status.NO_DECISION, autoplayAudible = Status.NO_DECISION, + mediaKeySystemAccess = Status.BLOCKED, savedAt = 1L ) @@ -150,7 +158,8 @@ class SitePermissionsRulesTest { microphone = BLOCKED, autoplayInaudible = ASK_TO_ALLOW, autoplayAudible = ASK_TO_ALLOW, - persistentStorage = BLOCKED + persistentStorage = BLOCKED, + mediaKeySystemAccess = BLOCKED ) val convertedSitePermissions = rules.toSitePermissions(origin = "origin", savedAt = 1L) @@ -163,6 +172,7 @@ class SitePermissionsRulesTest { assertEquals(expectedSitePermission.autoplayInaudible, convertedSitePermissions.autoplayInaudible) assertEquals(expectedSitePermission.autoplayAudible, convertedSitePermissions.autoplayAudible) assertEquals(expectedSitePermission.localStorage, convertedSitePermissions.localStorage) + assertEquals(expectedSitePermission.mediaKeySystemAccess, convertedSitePermissions.mediaKeySystemAccess) assertEquals(expectedSitePermission.savedAt, convertedSitePermissions.savedAt) } } diff --git a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt index 1d655704ddd..dfc190fefca 100644 --- a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt +++ b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt @@ -162,6 +162,7 @@ class SitePermissionsStorageTest { bluetooth = ALLOWED, autoplayAudible = BLOCKED, autoplayInaudible = NO_DECISION, + mediaKeySystemAccess = NO_DECISION, savedAt = 0 ), SitePermissionsEntity( @@ -174,6 +175,7 @@ class SitePermissionsStorageTest { bluetooth = ALLOWED, autoplayAudible = BLOCKED, autoplayInaudible = NO_DECISION, + mediaKeySystemAccess = NO_DECISION, savedAt = 0 ) ) diff --git a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt index 675a7bfb54d..22de388a37a 100644 --- a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt +++ b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt @@ -25,6 +25,7 @@ class SitePermissionEntityTest { bluetooth = ALLOWED, autoplayInaudible = BLOCKED, autoplayAudible = NO_DECISION, + mediaKeySystemAccess = NO_DECISION, savedAt = 0 ) @@ -40,6 +41,7 @@ class SitePermissionEntityTest { assertEquals(bluetooth, domainClass.bluetooth) assertEquals(autoplayAudible, domainClass.autoplayAudible) assertEquals(autoplayInaudible, domainClass.autoplayInaudible) + assertEquals(mediaKeySystemAccess, domainClass.mediaKeySystemAccess) assertEquals(savedAt, domainClass.savedAt) } } @@ -54,6 +56,9 @@ class SitePermissionEntityTest { microphone = NO_DECISION, camera = NO_DECISION, bluetooth = ALLOWED, + autoplayInaudible = BLOCKED, + autoplayAudible = NO_DECISION, + mediaKeySystemAccess = NO_DECISION, savedAt = 0 ) @@ -67,6 +72,9 @@ class SitePermissionEntityTest { assertEquals(microphone, domainClass.microphone) assertEquals(camera, domainClass.camera) assertEquals(bluetooth, domainClass.bluetooth) + assertEquals(autoplayAudible, domainClass.autoplayAudible) + assertEquals(autoplayInaudible, domainClass.autoplayInaudible) + assertEquals(mediaKeySystemAccess, domainClass.mediaKeySystemAccess) assertEquals(savedAt, domainClass.savedAt) } } diff --git a/docs/changelog.md b/docs/changelog.md index 4c4fa2d82d2..74ece79520a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -28,6 +28,10 @@ permalink: /changelog/ * **browser-menu**: * 🚒 Bug fixed [issue #9101](https://github.com/mozilla-mobile/android-components/issues/9101) - Fix BrowserMenu position after rotating the screen on Android <=23 +* **feature-sitepermissions** + * ⚠️ **This is a breaking change**: The `SitePermissionsRules` constructor, now requires a new parameter `mediaKeySystemAccess`. + * 🌟 Added support for EME permission prompts, see [#7121](https://github.com/mozilla-mobile/android-components/issues/7121). + # 68.0.0 * [Commits](https://github.com/mozilla-mobile/android-components/compare/v67.0.0...v68.0.0) diff --git a/samples/browser/src/main/java/org/mozilla/samples/browser/BaseBrowserFragment.kt b/samples/browser/src/main/java/org/mozilla/samples/browser/BaseBrowserFragment.kt index 113fc9a25b0..db1d61b8618 100644 --- a/samples/browser/src/main/java/org/mozilla/samples/browser/BaseBrowserFragment.kt +++ b/samples/browser/src/main/java/org/mozilla/samples/browser/BaseBrowserFragment.kt @@ -154,7 +154,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler { location = SitePermissionsRules.Action.ASK_TO_ALLOW, notification = SitePermissionsRules.Action.ASK_TO_ALLOW, microphone = SitePermissionsRules.Action.ASK_TO_ALLOW, - persistentStorage = SitePermissionsRules.Action.ASK_TO_ALLOW + persistentStorage = SitePermissionsRules.Action.ASK_TO_ALLOW, + mediaKeySystemAccess = SitePermissionsRules.Action.ASK_TO_ALLOW ), onNeedToRequestPermissions = { permissions -> requestPermissions(permissions, REQUEST_CODE_APP_PERMISSIONS)