зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 5 changesets (bug 1699480) for causing lint failures.
CLOSED TREE Backed out changeset 5ed626994de6 (bug 1699480) Backed out changeset e4be23f4dbe9 (bug 1699480) Backed out changeset 68b5f5c2f1e6 (bug 1699480) Backed out changeset 425aa354f1ca (bug 1699480) Backed out changeset e3005001299c (bug 1699480)
This commit is contained in:
Родитель
5cf5cf50d5
Коммит
e8904db16a
|
@ -127,6 +127,16 @@ static const nsLiteralCString kPreloadPermissions[] = {
|
|||
// removed. See bug 1428130.
|
||||
"cookie"_ns};
|
||||
|
||||
// Certain permissions should never be persisted to disk under GeckoView; it's
|
||||
// the responsibility of the app to manage storing these beyond the scope of
|
||||
// a single session.
|
||||
#ifdef ANDROID
|
||||
static const nsLiteralCString kGeckoViewRestrictedPermissions[] = {
|
||||
"MediaManagerVideo"_ns, "geolocation"_ns,
|
||||
"desktop-notification"_ns, "persistent-storage"_ns,
|
||||
"trackingprotection"_ns, "trackingprotection-pb"_ns};
|
||||
#endif
|
||||
|
||||
// NOTE: nullptr can be passed as aType - if it is this function will return
|
||||
// "false" unconditionally.
|
||||
bool IsPreloadPermission(const nsACString& aType) {
|
||||
|
@ -544,6 +554,11 @@ bool IsExpandedPrincipal(nsIPrincipal* aPrincipal) {
|
|||
bool IsPersistentExpire(uint32_t aExpire, const nsACString& aType) {
|
||||
bool res = (aExpire != nsIPermissionManager::EXPIRE_SESSION &&
|
||||
aExpire != nsIPermissionManager::EXPIRE_POLICY);
|
||||
#ifdef ANDROID
|
||||
for (const auto& perm : kGeckoViewRestrictedPermissions) {
|
||||
res = res && !perm.Equals(aType);
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
|
||||
GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
@ -246,37 +245,31 @@ class GeckoViewPermission {
|
|||
.sendRequestForResult({
|
||||
type: "GeckoView:ContentPermission",
|
||||
uri: aRequest.principal.URI.displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(aRequest.principal),
|
||||
perm: perm.type,
|
||||
value: perm.capability,
|
||||
contextId:
|
||||
aRequest.principal.originAttributes.geckoViewSessionContextId ?? null,
|
||||
privateMode: aRequest.principal.privateBrowsingId != 0,
|
||||
})
|
||||
.then(value => {
|
||||
if (value == Services.perms.ALLOW_ACTION) {
|
||||
// Ask for app permission after asking for content permission.
|
||||
if (perm.type === "geolocation") {
|
||||
return this.getAppPermissions(dispatcher, [
|
||||
PERM_ACCESS_FINE_LOCATION,
|
||||
]);
|
||||
}
|
||||
.then(granted => {
|
||||
if (!granted) {
|
||||
return false;
|
||||
}
|
||||
return value;
|
||||
// Ask for app permission after asking for content permission.
|
||||
if (perm.type === "geolocation") {
|
||||
return this.getAppPermissions(dispatcher, [
|
||||
PERM_ACCESS_FINE_LOCATION,
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.catch(error => {
|
||||
Cu.reportError("Permission error: " + error);
|
||||
return /* value */ Services.perms.DENY_ACTION;
|
||||
return /* granted */ false;
|
||||
})
|
||||
.then(value => {
|
||||
(value == Services.perms.ALLOW_ACTION
|
||||
? aRequest.allow
|
||||
: aRequest.cancel)();
|
||||
.then(granted => {
|
||||
(granted ? aRequest.allow : aRequest.cancel)();
|
||||
Services.perms.addFromPrincipal(
|
||||
aRequest.principal,
|
||||
perm.type,
|
||||
value,
|
||||
Services.perms.EXPIRE_NEVER
|
||||
granted ? Services.perms.ALLOW_ACTION : Services.perms.DENY_ACTION,
|
||||
Services.perms.EXPIRE_SESSION
|
||||
);
|
||||
// Manually release the target request here to facilitate garbage collection.
|
||||
aRequest = undefined;
|
||||
|
|
|
@ -103,8 +103,6 @@ class GeckoViewStartup {
|
|||
"GeckoView:ClearHostData",
|
||||
"GeckoView:GetAllPermissions",
|
||||
"GeckoView:GetPermissionsByURI",
|
||||
"GeckoView:SetPermission",
|
||||
"GeckoView:SetPermissionByURI",
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
@ -462,16 +462,16 @@ package org.mozilla.geckoview {
|
|||
@AnyThread public class ContentBlockingController {
|
||||
ctor public ContentBlockingController();
|
||||
method @UiThread public void addException(@NonNull GeckoSession);
|
||||
method @DeprecationSchedule(version=93,id="content-blocking-exception") @NonNull @UiThread public GeckoResult<Boolean> checkException(@NonNull GeckoSession);
|
||||
method @DeprecationSchedule(version=93,id="content-blocking-exception") @UiThread public void clearExceptionList();
|
||||
method @NonNull @UiThread public GeckoResult<Boolean> checkException(@NonNull GeckoSession);
|
||||
method @UiThread public void clearExceptionList();
|
||||
method @NonNull @UiThread public GeckoResult<List<ContentBlockingController.LogEntry>> getLog(@NonNull GeckoSession);
|
||||
method @DeprecationSchedule(version=93,id="content-blocking-exception") @UiThread public void removeException(@NonNull GeckoSession);
|
||||
method @AnyThread @DeprecationSchedule(version=93,id="content-blocking-exception") public void removeException(@NonNull ContentBlockingController.ContentBlockingException);
|
||||
method @AnyThread @DeprecationSchedule(version=93,id="content-blocking-exception") public void restoreExceptionList(@NonNull List<ContentBlockingController.ContentBlockingException>);
|
||||
method @DeprecationSchedule(version=93,id="content-blocking-exception") @NonNull @UiThread public GeckoResult<List<ContentBlockingController.ContentBlockingException>> saveExceptionList();
|
||||
method @UiThread public void removeException(@NonNull GeckoSession);
|
||||
method @AnyThread public void removeException(@NonNull ContentBlockingController.ContentBlockingException);
|
||||
method @AnyThread public void restoreExceptionList(@NonNull List<ContentBlockingController.ContentBlockingException>);
|
||||
method @NonNull @UiThread public GeckoResult<List<ContentBlockingController.ContentBlockingException>> saveExceptionList();
|
||||
}
|
||||
|
||||
@DeprecationSchedule(version=93,id="content-blocking-exception") @AnyThread public static class ContentBlockingController.ContentBlockingException {
|
||||
@AnyThread public static class ContentBlockingController.ContentBlockingException {
|
||||
method @NonNull public static ContentBlockingController.ContentBlockingException fromJson(@NonNull JSONObject);
|
||||
method @NonNull public JSONObject toJson();
|
||||
field @NonNull public final String uri;
|
||||
|
@ -965,7 +965,7 @@ package org.mozilla.geckoview {
|
|||
|
||||
public static interface GeckoSession.PermissionDelegate {
|
||||
method @UiThread default public void onAndroidPermissionsRequest(@NonNull GeckoSession, @Nullable String[], @NonNull GeckoSession.PermissionDelegate.Callback);
|
||||
method @Nullable @UiThread default public GeckoResult<Integer> onContentPermissionRequest(@NonNull GeckoSession, @NonNull GeckoSession.PermissionDelegate.ContentPermission);
|
||||
method @UiThread default public void onContentPermissionRequest(@NonNull GeckoSession, @Nullable String, int, @NonNull GeckoSession.PermissionDelegate.Callback);
|
||||
method @UiThread default public void onMediaPermissionRequest(@NonNull GeckoSession, @NonNull String, @Nullable GeckoSession.PermissionDelegate.MediaSource[], @Nullable GeckoSession.PermissionDelegate.MediaSource[], @NonNull GeckoSession.PermissionDelegate.MediaCallback);
|
||||
field public static final int PERMISSION_AUTOPLAY_AUDIBLE = 5;
|
||||
field public static final int PERMISSION_AUTOPLAY_INAUDIBLE = 4;
|
||||
|
@ -973,7 +973,6 @@ package org.mozilla.geckoview {
|
|||
field public static final int PERMISSION_GEOLOCATION = 0;
|
||||
field public static final int PERMISSION_MEDIA_KEY_SYSTEM_ACCESS = 6;
|
||||
field public static final int PERMISSION_PERSISTENT_STORAGE = 2;
|
||||
field public static final int PERMISSION_TRACKING = 7;
|
||||
field public static final int PERMISSION_XR = 3;
|
||||
}
|
||||
|
||||
|
@ -984,12 +983,9 @@ package org.mozilla.geckoview {
|
|||
|
||||
public static class GeckoSession.PermissionDelegate.ContentPermission {
|
||||
ctor protected ContentPermission();
|
||||
method @AnyThread @Nullable public static GeckoSession.PermissionDelegate.ContentPermission fromJson(@NonNull JSONObject);
|
||||
method @AnyThread @NonNull public JSONObject toJson();
|
||||
field public static final int VALUE_ALLOW = 1;
|
||||
field public static final int VALUE_DENY = 2;
|
||||
field public static final int VALUE_PROMPT = 3;
|
||||
field @Nullable public final String contextId;
|
||||
field public final int permission;
|
||||
field public final boolean privateMode;
|
||||
field @NonNull public final String uri;
|
||||
|
@ -1703,8 +1699,6 @@ package org.mozilla.geckoview {
|
|||
method @AnyThread @NonNull public GeckoResult<Void> clearDataFromHost(@NonNull String, long);
|
||||
method @AnyThread @NonNull public GeckoResult<List<GeckoSession.PermissionDelegate.ContentPermission>> getAllPermissions();
|
||||
method @AnyThread @NonNull public GeckoResult<List<GeckoSession.PermissionDelegate.ContentPermission>> getPermissions(@NonNull String);
|
||||
method @AnyThread @NonNull public GeckoResult<List<GeckoSession.PermissionDelegate.ContentPermission>> getPermissions(@NonNull String, @Nullable String);
|
||||
method @AnyThread public void setPermission(@NonNull GeckoSession.PermissionDelegate.ContentPermission, int);
|
||||
}
|
||||
|
||||
public static class StorageController.ClearFlags {
|
||||
|
|
|
@ -25,9 +25,9 @@ class OpenWindowTest : BaseSessionTest() {
|
|||
|
||||
// Grant "desktop notification" permission
|
||||
mainSession.delegateUntilTestEnd(object : Callbacks.PermissionDelegate {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission): GeckoResult<Int>? {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW);
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", type, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
callback.grant()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package org.mozilla.geckoview.test
|
||||
|
||||
import org.mozilla.geckoview.GeckoResult
|
||||
import org.mozilla.geckoview.GeckoSession
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.RejectedPromiseException
|
||||
|
@ -24,7 +23,6 @@ import org.junit.Assume.assumeThat
|
|||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.Ignore
|
||||
import org.mozilla.geckoview.GeckoSessionSettings
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
|
@ -162,12 +160,12 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
// Ensure the content permission is asked first, before the Android permission.
|
||||
@AssertCalled(count = 1, order = [1])
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("URI should match", uri, endsWith(url))
|
||||
assertThat("Type should match", type,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
callback.grant()
|
||||
}
|
||||
|
||||
@AssertCalled(count = 1, order = [2])
|
||||
|
@ -232,9 +230,9 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
callback.reject()
|
||||
}
|
||||
|
||||
@AssertCalled(count = 0)
|
||||
|
@ -291,12 +289,12 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("URI should match", uri, endsWith(url))
|
||||
assertThat("Type should match", type,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
callback.grant()
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -333,11 +331,6 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
})
|
||||
mainSession.reload()
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
val result2 = mainSession.waitForJS("Notification.permission")
|
||||
|
||||
assertThat("Permission should be granted",
|
||||
result2 as String, equalTo("granted"))
|
||||
}
|
||||
|
||||
@Ignore("disable test for frequently failing Bug 1542525")
|
||||
|
@ -349,9 +342,9 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
session: GeckoSession, uri: String?, type: Int,
|
||||
callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
callback.reject()
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -400,356 +393,14 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
|
||||
mainSession.waitUntilCalled(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
val expectedType = if (sessionRule.currentCall.counter == 1) GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE else GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE
|
||||
assertThat("Type should match", perm.permission, equalTo(expectedType))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
assertThat("Type should match", type, equalTo(expectedType))
|
||||
callback.reject()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun contextId() {
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
|
||||
val url = createTestUrl(HELLO_HTML_PATH)
|
||||
mainSession.loadUri(url)
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
assertThat("Context ID should match", perm.contextId, equalTo(mainSession.settings.contextId))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
val result = mainSession.waitForJS("Notification.requestPermission()")
|
||||
|
||||
assertThat("Permission should be granted",
|
||||
result as String, equalTo("granted"))
|
||||
|
||||
val perms = sessionRule.waitForResult(sessionRule.runtime.storageController.getPermissions(url))
|
||||
|
||||
assertThat("Permissions should not be null", perms, notNullValue())
|
||||
var permFound: Boolean = false
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
url.startsWith(perm.uri) && perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) {
|
||||
permFound = true
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("Notification permission should be set to allow", permFound, equalTo(true))
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
var permFound2: Boolean = false
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) {
|
||||
permFound2 = true
|
||||
}
|
||||
}
|
||||
assertThat("Notification permission must be present on refresh", permFound2, equalTo(true))
|
||||
}
|
||||
})
|
||||
mainSession.reload()
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
val session2 = sessionRule.createOpenSession(
|
||||
GeckoSessionSettings.Builder()
|
||||
.contextId("foo")
|
||||
.build())
|
||||
|
||||
session2.loadUri(url)
|
||||
session2.waitForPageStop()
|
||||
|
||||
session2.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
assertThat("Context ID should match", perm.contextId,
|
||||
equalTo(session2.settings.contextId))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
val result2 = session2.waitForJS("Notification.requestPermission()")
|
||||
|
||||
assertThat("Permission should be granted",
|
||||
result2 as String, equalTo("granted"))
|
||||
|
||||
val perms2 = sessionRule.waitForResult(sessionRule.runtime.storageController.getPermissions(url))
|
||||
|
||||
assertThat("Permissions should not be null", perms, notNullValue())
|
||||
permFound = false
|
||||
for (perm in perms2) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
url.startsWith(perm.uri) && perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) {
|
||||
permFound = true
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("Notification permission should be set to allow", permFound, equalTo(true))
|
||||
|
||||
session2.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
var permFound2: Boolean = false
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW &&
|
||||
perm.contextId == session2.settings.contextId) {
|
||||
permFound2 = true
|
||||
}
|
||||
}
|
||||
assertThat("Notification permission must be present on refresh", permFound2, equalTo(true))
|
||||
}
|
||||
})
|
||||
session2.reload()
|
||||
session2.waitForPageStop()
|
||||
}
|
||||
|
||||
@Test fun setPermissionAllow() {
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
|
||||
val url = createTestUrl(HELLO_HTML_PATH)
|
||||
mainSession.loadUri(url)
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
}
|
||||
})
|
||||
mainSession.waitForJS("Notification.requestPermission()")
|
||||
|
||||
val perms = sessionRule.waitForResult(sessionRule.runtime.storageController.getPermissions(url))
|
||||
|
||||
assertThat("Permissions should not be null", perms, notNullValue())
|
||||
var permFound : Boolean = false
|
||||
var notificationPerm : GeckoSession.PermissionDelegate.ContentPermission? = null
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
url.startsWith(perm.uri) && perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY) {
|
||||
notificationPerm = perm
|
||||
permFound = true
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("Notification permission should be set to allow", permFound, equalTo(true))
|
||||
|
||||
sessionRule.runtime.storageController.setPermission(notificationPerm!!,
|
||||
GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
var permFound2 : Boolean = false
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) {
|
||||
permFound2 = true
|
||||
}
|
||||
}
|
||||
assertThat("Notification permission must be present on refresh", permFound2, equalTo(true))
|
||||
}
|
||||
})
|
||||
mainSession.reload()
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
val result = mainSession.waitForJS("Notification.permission")
|
||||
|
||||
assertThat("Permission should be granted",
|
||||
result as String, equalTo("granted"))
|
||||
}
|
||||
|
||||
@Test fun setPermissionDeny() {
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
|
||||
val url = createTestUrl(HELLO_HTML_PATH)
|
||||
mainSession.loadUri(url)
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
val result = mainSession.waitForJS("Notification.requestPermission()")
|
||||
|
||||
assertThat("Permission should be granted",
|
||||
result as String, equalTo("granted"))
|
||||
|
||||
val perms = sessionRule.waitForResult(sessionRule.runtime.storageController.getPermissions(url))
|
||||
|
||||
assertThat("Permissions should not be null", perms, notNullValue())
|
||||
var permFound : Boolean = false
|
||||
var notificationPerm : GeckoSession.PermissionDelegate.ContentPermission? = null
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
url.startsWith(perm.uri) && perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) {
|
||||
notificationPerm = perm
|
||||
permFound = true
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("Notification permission should be set to allow", permFound, equalTo(true))
|
||||
|
||||
sessionRule.runtime.storageController.setPermission(notificationPerm!!,
|
||||
GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY)
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList<GeckoSession.PermissionDelegate.ContentPermission>) {
|
||||
var permFound2 : Boolean = false
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY) {
|
||||
permFound2 = true
|
||||
}
|
||||
}
|
||||
assertThat("Notification permission must be present on refresh", permFound2, equalTo(true))
|
||||
}
|
||||
})
|
||||
mainSession.reload()
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
val result2 = mainSession.waitForJS("Notification.permission")
|
||||
|
||||
assertThat("Permission should be denied",
|
||||
result2 as String, equalTo("denied"))
|
||||
}
|
||||
|
||||
@Test fun setPermissionPrompt() {
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
|
||||
val url = createTestUrl(HELLO_HTML_PATH)
|
||||
mainSession.loadUri(url)
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
val result = mainSession.waitForJS("Notification.requestPermission()")
|
||||
|
||||
assertThat("Permission should be granted",
|
||||
result as String, equalTo("granted"))
|
||||
|
||||
val perms = sessionRule.waitForResult(sessionRule.runtime.storageController.getPermissions(url))
|
||||
|
||||
assertThat("Permissions should not be null", perms, notNullValue())
|
||||
var permFound : Boolean = false
|
||||
var notificationPerm : GeckoSession.PermissionDelegate.ContentPermission? = null
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
url.startsWith(perm.uri) && perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) {
|
||||
notificationPerm = perm
|
||||
permFound = true
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("Notification permission should be set to allow", permFound, equalTo(true))
|
||||
|
||||
sessionRule.runtime.storageController.setPermission(notificationPerm!!,
|
||||
GeckoSession.PermissionDelegate.ContentPermission.VALUE_PROMPT)
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_PROMPT)
|
||||
}
|
||||
})
|
||||
|
||||
val result2 = mainSession.waitForJS("Notification.requestPermission()")
|
||||
|
||||
assertThat("Permission should be default",
|
||||
result2 as String, equalTo("default"))
|
||||
}
|
||||
|
||||
@Test fun permissionJsonConversion() {
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
|
||||
val url = createTestUrl(HELLO_HTML_PATH)
|
||||
mainSession.loadUri(url)
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
mainSession.delegateDuringNextWait(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onContentPermissionRequest(
|
||||
session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("URI should match", perm.uri, endsWith(url))
|
||||
assertThat("Type should match", perm.permission,
|
||||
equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
val result = mainSession.waitForJS("Notification.requestPermission()")
|
||||
|
||||
assertThat("Permission should be granted",
|
||||
result as String, equalTo("granted"))
|
||||
|
||||
val perms = sessionRule.waitForResult(sessionRule.runtime.storageController.getPermissions(url))
|
||||
|
||||
assertThat("Permissions should not be null", perms, notNullValue())
|
||||
var permFound : Boolean = false
|
||||
var notificationPerm : GeckoSession.PermissionDelegate.ContentPermission? = null
|
||||
for (perm in perms) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION &&
|
||||
url.startsWith(perm.uri) && perm.value == GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) {
|
||||
notificationPerm = perm
|
||||
permFound = true
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("Notification permission should be set to allow", permFound, equalTo(true))
|
||||
|
||||
val jsonPerm = notificationPerm?.toJson()
|
||||
assertThat("JSON export should not be null", jsonPerm, notNullValue())
|
||||
|
||||
val importedPerm = GeckoSession.PermissionDelegate.ContentPermission.fromJson(jsonPerm!!)
|
||||
assertThat("JSON import should not be null", importedPerm, notNullValue())
|
||||
|
||||
assertThat("URIs should match", importedPerm?.uri, equalTo(notificationPerm?.uri))
|
||||
assertThat("Types should match", importedPerm?.permission, equalTo(notificationPerm?.permission))
|
||||
assertThat("Values should match", importedPerm?.value, equalTo(notificationPerm?.value))
|
||||
assertThat("Context IDs should match", importedPerm?.contextId, equalTo(notificationPerm?.contextId))
|
||||
assertThat("Private mode should match", importedPerm?.privateMode, equalTo(notificationPerm?.privateMode))
|
||||
}
|
||||
|
||||
// @Test fun persistentStorage() {
|
||||
// mainSession.loadTestPath(HELLO_HTML_PATH)
|
||||
// mainSession.waitForPageStop()
|
||||
|
|
|
@ -100,8 +100,8 @@ public class TestRunnerActivity extends Activity {
|
|||
|
||||
private GeckoSession.PermissionDelegate mPermissionDelegate = new GeckoSession.PermissionDelegate() {
|
||||
@Override
|
||||
public GeckoResult<Integer> onContentPermissionRequest(@NonNull final GeckoSession session, @NonNull GeckoSession.PermissionDelegate.ContentPermission perm) {
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW);
|
||||
public void onContentPermissionRequest(@NonNull final GeckoSession session, @Nullable final String uri, final int type, @NonNull final Callback callback) {
|
||||
callback.grant();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,10 +25,9 @@ class WebNotificationTest : BaseSessionTest() {
|
|||
|
||||
// Grant "desktop notification" permission
|
||||
mainSession.delegateUntilTestEnd(object : Callbacks.PermissionDelegate {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", type, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
callback.grant()
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -60,10 +60,9 @@ class WebPushTest : BaseSessionTest() {
|
|||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false))
|
||||
// Grant "desktop notification" permission
|
||||
mainSession.delegateUntilTestEnd(object : Callbacks.PermissionDelegate {
|
||||
override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission):
|
||||
GeckoResult<Int>? {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW)
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
assertThat("Should grant DESKTOP_NOTIFICATIONS permission", type, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION))
|
||||
callback.grant()
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.List;
|
|||
public class ContentBlockingController {
|
||||
private static final String LOGTAG = "GeckoContentBlocking";
|
||||
|
||||
@DeprecationSchedule(version = 93, id = "content-blocking-exception")
|
||||
@AnyThread
|
||||
public static class ContentBlockingException {
|
||||
private final @NonNull String mEncodedPrincipal;
|
||||
|
@ -99,7 +98,6 @@ public class ContentBlockingController {
|
|||
* @param session A {@link GeckoSession} whose site will be removed from the content
|
||||
* blocking exceptions list.
|
||||
*/
|
||||
@DeprecationSchedule(version = 93, id = "content-blocking-exception")
|
||||
@UiThread
|
||||
public void removeException(final @NonNull GeckoSession session) {
|
||||
final GeckoBundle msg = new GeckoBundle(1);
|
||||
|
@ -115,7 +113,6 @@ public class ContentBlockingController {
|
|||
* @param exception A {@link ContentBlockingException} which will be removed from the
|
||||
* content blocking exception list.
|
||||
*/
|
||||
@DeprecationSchedule(version = 93, id = "content-blocking-exception")
|
||||
@AnyThread
|
||||
public void removeException(final @NonNull ContentBlockingException exception) {
|
||||
final GeckoBundle msg = new GeckoBundle(1);
|
||||
|
@ -133,7 +130,6 @@ public class ContentBlockingController {
|
|||
* @return A {@link GeckoResult} which resolves to a Boolean indicating whether or
|
||||
* not the current site is on the exception list.
|
||||
*/
|
||||
@DeprecationSchedule(version = 93, id = "content-blocking-exception")
|
||||
@UiThread
|
||||
public @NonNull GeckoResult<Boolean> checkException(final @NonNull GeckoSession session) {
|
||||
final GeckoBundle msg = new GeckoBundle(1);
|
||||
|
@ -165,7 +161,6 @@ public class ContentBlockingController {
|
|||
* @return A List of {@link ContentBlockingException} which can be used to restore or
|
||||
* inspect the current exception list.
|
||||
*/
|
||||
@DeprecationSchedule(version = 93, id = "content-blocking-exception")
|
||||
@UiThread
|
||||
public @NonNull GeckoResult<List<ContentBlockingException>> saveExceptionList() {
|
||||
return EventDispatcher.getInstance()
|
||||
|
@ -178,7 +173,6 @@ public class ContentBlockingController {
|
|||
*
|
||||
* @param list A List of {@link ContentBlockingException} originally created by {@link #saveExceptionList}.
|
||||
*/
|
||||
@DeprecationSchedule(version = 93, id = "content-blocking-exception")
|
||||
@AnyThread
|
||||
public void restoreExceptionList(final @NonNull List<ContentBlockingException> list) {
|
||||
final GeckoBundle bundle = new GeckoBundle(2);
|
||||
|
@ -199,7 +193,6 @@ public class ContentBlockingController {
|
|||
/**
|
||||
* Clear the content blocking exception list entirely.
|
||||
*/
|
||||
@DeprecationSchedule(version = 93, id = "content-blocking-exception")
|
||||
@UiThread
|
||||
public void clearExceptionList() {
|
||||
EventDispatcher.getInstance().dispatch("ContentBlocking:ClearList", null);
|
||||
|
|
|
@ -716,13 +716,33 @@ public class GeckoSession {
|
|||
GeckoSession.this, message.getStringArray("perms"),
|
||||
new PermissionCallback("android", callback));
|
||||
} else if ("GeckoView:ContentPermission".equals(event)) {
|
||||
final GeckoResult<Integer> res = delegate.onContentPermissionRequest(GeckoSession.this, new PermissionDelegate.ContentPermission(message));
|
||||
if (res == null) {
|
||||
callback.sendSuccess(PermissionDelegate.ContentPermission.VALUE_PROMPT);
|
||||
final String typeString = message.getString("perm");
|
||||
final int type;
|
||||
if ("geolocation".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_GEOLOCATION;
|
||||
} else if ("desktop-notification".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION;
|
||||
} else if ("persistent-storage".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_PERSISTENT_STORAGE;
|
||||
} else if ("xr".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_XR;
|
||||
} else if ("midi".equals(typeString)) {
|
||||
// We can get this from WPT and presumably other content, but Gecko
|
||||
// doesn't support Web MIDI.
|
||||
callback.sendError("Unsupported");
|
||||
return;
|
||||
} else if ("autoplay-media-inaudible".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE;
|
||||
} else if ("autoplay-media-audible".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE;
|
||||
} else if ("media-key-system-access".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown permission request: " + typeString);
|
||||
}
|
||||
|
||||
callback.resolveTo(res);
|
||||
delegate.onContentPermissionRequest(
|
||||
GeckoSession.this, message.getString("uri"),
|
||||
type, new PermissionCallback(typeString, callback));
|
||||
} else if ("GeckoView:MediaPermission".equals(event)) {
|
||||
final GeckoBundle[] videoBundles = message.getBundleArray("video");
|
||||
final GeckoBundle[] audioBundles = message.getBundleArray("audio");
|
||||
|
@ -5429,12 +5449,6 @@ public class GeckoSession {
|
|||
*/
|
||||
int PERMISSION_MEDIA_KEY_SYSTEM_ACCESS = 6;
|
||||
|
||||
/**
|
||||
* Permission for trackers to operate on the page -- disables all tracking protection
|
||||
* features for a given site.
|
||||
*/
|
||||
int PERMISSION_TRACKING = 7;
|
||||
|
||||
/**
|
||||
* Represents a content permission -- including the type of permission,
|
||||
* the present value of the permission, the URL the permission pertains to,
|
||||
|
@ -5481,12 +5495,6 @@ public class GeckoSession {
|
|||
*/
|
||||
final public @Value int value;
|
||||
|
||||
/**
|
||||
* The context ID associated with the permission if any.
|
||||
* @see GeckoSessionSettings.Builder#contextId
|
||||
*/
|
||||
final public @Nullable String contextId;
|
||||
|
||||
final private String mPrincipal;
|
||||
|
||||
protected ContentPermission() {
|
||||
|
@ -5495,7 +5503,6 @@ public class GeckoSession {
|
|||
this.permission = PERMISSION_GEOLOCATION;
|
||||
this.value = VALUE_ALLOW;
|
||||
this.mPrincipal = "";
|
||||
this.contextId = null;
|
||||
}
|
||||
|
||||
private ContentPermission(final @NonNull GeckoBundle bundle) {
|
||||
|
@ -5503,45 +5510,10 @@ public class GeckoSession {
|
|||
this.mPrincipal = bundle.getString("principal");
|
||||
this.privateMode = bundle.getBoolean("privateMode");
|
||||
|
||||
final String permission = bundle.getString("perm");
|
||||
final String permission = bundle.getString("type");
|
||||
this.permission = convertType(permission);
|
||||
|
||||
this.value = bundle.getInt("value");
|
||||
this.contextId = StorageController.retrieveUnsafeSessionContextId(bundle.getString("contextId"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JSONObject to a ContentPermission -- should only be used on the output of
|
||||
* {@link #toJson()}.
|
||||
*
|
||||
* @param perm A JSONObject representing a ContentPermission, output by {@link #toJson()}.
|
||||
*
|
||||
* @return The corresponding ContentPermission.
|
||||
*/
|
||||
@AnyThread
|
||||
public static @Nullable ContentPermission fromJson(final @NonNull JSONObject perm) {
|
||||
ContentPermission res = null;
|
||||
try {
|
||||
res = new ContentPermission(GeckoBundle.fromJSONObject(perm));
|
||||
} catch (final JSONException e) {
|
||||
Log.w(LOGTAG, "Failed to create ContentPermission; invalid JSONObject.", e);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a ContentPermission to a JSONObject that can be converted back to
|
||||
* a ContentPermission by {@link #fromJson(JSONObject)}.
|
||||
*
|
||||
* @return A JSONObject representing this ContentPermission. Modifying any of
|
||||
* the fields may result in undefined behavior when converted back
|
||||
* to a ContentPermission and used.
|
||||
*
|
||||
* @throws JSONException if the conversion fails for any reason.
|
||||
*/
|
||||
@AnyThread
|
||||
public @NonNull JSONObject toJson() throws JSONException {
|
||||
return toGeckoBundle().toJSONObject();
|
||||
}
|
||||
|
||||
private static int convertType(final @NonNull String type) {
|
||||
|
@ -5559,37 +5531,11 @@ public class GeckoSession {
|
|||
return PERMISSION_AUTOPLAY_AUDIBLE;
|
||||
} else if ("media-key-system-access".equals(type)) {
|
||||
return PERMISSION_MEDIA_KEY_SYSTEM_ACCESS;
|
||||
} else if ("trackingprotection".equals(type) || "trackingprotection-pb".equals(type)) {
|
||||
return PERMISSION_TRACKING;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// This also gets used in StorageController, so it's package rather than private.
|
||||
/* package */ static String convertType(final int type, final boolean privateMode) {
|
||||
switch (type) {
|
||||
case PERMISSION_GEOLOCATION:
|
||||
return "geolocation";
|
||||
case PERMISSION_DESKTOP_NOTIFICATION:
|
||||
return "desktop-notification";
|
||||
case PERMISSION_PERSISTENT_STORAGE:
|
||||
return "persistent-storage";
|
||||
case PERMISSION_XR:
|
||||
return "xr";
|
||||
case PERMISSION_AUTOPLAY_INAUDIBLE:
|
||||
return "autoplay-media-inaudible";
|
||||
case PERMISSION_AUTOPLAY_AUDIBLE:
|
||||
return "autoplay-media-audible";
|
||||
case PERMISSION_MEDIA_KEY_SYSTEM_ACCESS:
|
||||
return "media-key-system-access";
|
||||
case PERMISSION_TRACKING:
|
||||
return privateMode ? "trackingprotection-pb" : "trackingprotection";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ static @NonNull ArrayList<ContentPermission> fromBundleArray(final @NonNull GeckoBundle[] bundleArray) {
|
||||
final ArrayList<ContentPermission> res = new ArrayList<ContentPermission>();
|
||||
if (bundleArray == null) {
|
||||
|
@ -5605,17 +5551,6 @@ public class GeckoSession {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* package */ @NonNull GeckoBundle toGeckoBundle() {
|
||||
final GeckoBundle res = new GeckoBundle(5);
|
||||
res.putString("uri", uri);
|
||||
res.putString("principal", mPrincipal);
|
||||
res.putBoolean("privateMode", privateMode);
|
||||
res.putString("perm", convertType(permission, privateMode));
|
||||
res.putInt("value", value);
|
||||
res.putString("contextId", contextId);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5664,14 +5599,18 @@ public class GeckoSession {
|
|||
* from being redisplayed to the user.
|
||||
*
|
||||
* @param session GeckoSession instance requesting the permission.
|
||||
* @param perm An {@link ContentPermission} describing the permission being requested and its current status.
|
||||
*
|
||||
* @return A {@link GeckoResult} resolving to one of {@link ContentPermission#VALUE_PROMPT VALUE_*}, determining
|
||||
* the response to the permission request and updating the permissions for this site.
|
||||
* @param uri The URI of the content requesting the permission.
|
||||
* @param type The type of the requested permission; possible values are,
|
||||
* PERMISSION_GEOLOCATION
|
||||
* PERMISSION_DESKTOP_NOTIFICATION
|
||||
* PERMISSION_PERSISTENT_STORAGE
|
||||
* PERMISSION_XR
|
||||
* @param callback Callback interface.
|
||||
*/
|
||||
@UiThread
|
||||
default @Nullable GeckoResult<Integer> onContentPermissionRequest(@NonNull final GeckoSession session, @NonNull ContentPermission perm) {
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_PROMPT);
|
||||
default void onContentPermissionRequest(@NonNull final GeckoSession session, @Nullable final String uri,
|
||||
@Permission final int type, @NonNull final Callback callback) {
|
||||
callback.reject();
|
||||
}
|
||||
|
||||
class MediaSource {
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.mozilla.geckoview;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -18,8 +17,6 @@ import androidx.annotation.LongDef;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.ContentPermission;
|
||||
|
@ -30,7 +27,6 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.ContentPermission;
|
|||
* Retrieve an instance via {@link GeckoRuntime#getStorageController}.
|
||||
*/
|
||||
public final class StorageController {
|
||||
private static final String LOGTAG = "StorageController";
|
||||
|
||||
// Keep in sync with GeckoViewStorageController.ClearFlags.
|
||||
/**
|
||||
|
@ -172,7 +168,7 @@ public final class StorageController {
|
|||
"GeckoView:ClearSessionContextData", bundle);
|
||||
}
|
||||
|
||||
/* package */ static @Nullable String createSafeSessionContextId(
|
||||
/* package */ static @NonNull String createSafeSessionContextId(
|
||||
final @Nullable String contextId) {
|
||||
if (contextId == null) {
|
||||
return null;
|
||||
|
@ -188,18 +184,6 @@ public final class StorageController {
|
|||
.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/* package */ static @Nullable String retrieveUnsafeSessionContextId(
|
||||
final @Nullable String contextId) {
|
||||
if (contextId == null || contextId.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if ("gvctxempty".equals(contextId)) {
|
||||
return "";
|
||||
}
|
||||
final byte[] bytes = new BigInteger(contextId.substring(5), 16).toByteArray();
|
||||
return new String(bytes, Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions.
|
||||
*
|
||||
|
@ -215,7 +199,7 @@ public final class StorageController {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions for a given URI and default (unset) context ID.
|
||||
* Get all currently stored permissions for a given URI.
|
||||
*
|
||||
* @param uri A String representing the URI to get permissions for.
|
||||
*
|
||||
|
@ -224,87 +208,11 @@ public final class StorageController {
|
|||
*/
|
||||
@AnyThread
|
||||
public @NonNull GeckoResult<List<ContentPermission>> getPermissions(final @NonNull String uri) {
|
||||
return getPermissions(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently stored permissions for a given URI and context ID.
|
||||
*
|
||||
* @param uri A String representing the URI to get permissions for.
|
||||
* @param contextId A String specifying the context ID.
|
||||
*
|
||||
* @return A {@link GeckoResult} that will complete with a list of all
|
||||
* currently stored {@link ContentPermission}s for the URI.
|
||||
*/
|
||||
@AnyThread
|
||||
public @NonNull GeckoResult<List<ContentPermission>> getPermissions(final @NonNull String uri, final @Nullable String contextId) {
|
||||
final GeckoBundle msg = new GeckoBundle(2);
|
||||
final GeckoBundle msg = new GeckoBundle(1);
|
||||
msg.putString("uri", uri);
|
||||
msg.putString("contextId", createSafeSessionContextId(contextId));
|
||||
return EventDispatcher.getInstance().queryBundle("GeckoView:GetPermissionsByURI", msg).map(bundle -> {
|
||||
final GeckoBundle[] permsArray = bundle.getBundleArray("permissions");
|
||||
return ContentPermission.fromBundleArray(permsArray);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new value for an existing permission.
|
||||
*
|
||||
* @param perm A {@link ContentPermission} that you wish to update the value of.
|
||||
* @param value The new value for the permission.
|
||||
*/
|
||||
@AnyThread
|
||||
public void setPermission(final @NonNull ContentPermission perm, final @ContentPermission.Value int value) {
|
||||
if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_TRACKING &&
|
||||
value == ContentPermission.VALUE_PROMPT) {
|
||||
Log.w(LOGTAG, "Cannot set a tracking permission to VALUE_PROMPT, aborting.");
|
||||
return;
|
||||
}
|
||||
final GeckoBundle msg = perm.toGeckoBundle();
|
||||
msg.putInt("newValue", value);
|
||||
EventDispatcher.getInstance().dispatch("GeckoView:SetPermission", msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or modify a permission for a URI given by String. Assumes default context ID and
|
||||
* regular (non-private) browsing mode.
|
||||
*
|
||||
* @param uri A String representing the URI for which you are adding/modifying permissions.
|
||||
* @param type An int representing the permission you wish to add/modify.
|
||||
* @param value The new value for the permission.
|
||||
*/
|
||||
@AnyThread
|
||||
@DeprecationSchedule(id = "setpermission-string", version = 93)
|
||||
public void setPermission(final @NonNull String uri, final int type, final @ContentPermission.Value int value) {
|
||||
setPermission(uri, null, false, type, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or modify a permission for a URI given by String.
|
||||
*
|
||||
* @param uri A String representing the URI for which you are adding/modifying permissions.
|
||||
* @param contextId A String specifying the context ID under which the permission will apply.
|
||||
* @param privateMode A boolean indicating whether this permission should apply in private mode or normal mode.
|
||||
* @param type An int representing the permission you wish to add/modify.
|
||||
* @param value The new value for the permission.
|
||||
*/
|
||||
@AnyThread
|
||||
@DeprecationSchedule(id = "setpermission-string", version = 93)
|
||||
public void setPermission(final @NonNull String uri, final @Nullable String contextId, final boolean privateMode, final int type, final @ContentPermission.Value int value) {
|
||||
if (type < GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION || type > GeckoSession.PermissionDelegate.PERMISSION_TRACKING) {
|
||||
Log.w(LOGTAG, "Invalid permission, aborting.");
|
||||
return;
|
||||
}
|
||||
if (type == GeckoSession.PermissionDelegate.PERMISSION_TRACKING && value == ContentPermission.VALUE_PROMPT) {
|
||||
Log.w(LOGTAG, "Cannot set a tracking permission to VALUE_PROMPT, aborting.");
|
||||
return;
|
||||
}
|
||||
final GeckoBundle msg = new GeckoBundle(5);
|
||||
msg.putString("uri", uri);
|
||||
msg.putString("contextId", createSafeSessionContextId(contextId));
|
||||
msg.putString("perm", GeckoSession.PermissionDelegate.ContentPermission.convertType(type, privateMode));
|
||||
msg.putInt("newValue", value);
|
||||
msg.putInt("privateId", privateMode ? 1 : 0);
|
||||
EventDispatcher.getInstance().dispatch("GeckoView:SetPermissionByURI", msg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,6 @@ exclude: true
|
|||
([bug 1701269]({{bugzilla}}1701269))
|
||||
- Removed deprecated [`GeckoView.onTouchEventForResult`][88.4].
|
||||
([bug 1706403]({{bugzilla}}1706403))
|
||||
- ⚠️ Updated [`onContentPermissionRequest`][90.7] to use [`ContentPermission`][90.8]; added
|
||||
[`setPermission`][90.9] to [`StorageController`][90.10] for modifying existing permissions, and
|
||||
allowed Gecko to handle persisting permissions.
|
||||
- ⚠️ Added a deprecation schedule to most existing content blocking exception functionality;
|
||||
other than [`addException`][90.11], content blocking exceptions should be treated as content
|
||||
permissions going forward.
|
||||
|
||||
[90.1]: {{javadoc_uri}}/WebNotification.html#silent
|
||||
[90.2]: {{javadoc_uri}}/WebNotification.html#vibrate
|
||||
|
@ -38,11 +32,6 @@ exclude: true
|
|||
[90.4]: https://developer.mozilla.org/en-US/docs/Web/API/Notification/vibrate
|
||||
[90.5]: {{javadoc_uri}}/GeckoRuntime.html#getProfileDir--
|
||||
[90.6]: {{javadoc_uri}}/GeckoRuntimeSettings.html#setForceEnableAccessibility-boolean-
|
||||
[90.7]: {{javadoc_uri}}/GeckoSession.PermissionDelegate.html#onContentPermissionRequest-org.mozilla.geckoview.GeckoSession-org.mozilla.geckoview.GeckoSession.PermissionDelegate.ContentPermission-
|
||||
[90.8]: {{javadoc_uri}}/GeckoSession.PermissionDelegate.ContentPermission.html
|
||||
[90.9]: {{javadoc_uri}}/StorageController.html#setPermission-org.mozilla.geckoview.GeckoSession.PermissionDelegate.ContentPermission-int-
|
||||
[90.10]: {{javadoc_uri}}/StorageController.html
|
||||
[90.11]: {{javadoc_uri}}/ContentBlockingController.html#addException-org.mozilla.geckoview.GeckoSession-
|
||||
|
||||
## v89
|
||||
- Added [`ContentPermission`][89.1], which is used to report what permissions content
|
||||
|
|
|
@ -869,32 +869,30 @@ final class BasicGeckoViewPrompt implements GeckoSession.PromptDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public GeckoResult<Integer> onPermissionPrompt(final GeckoSession session, final String title,
|
||||
final GeckoSession.PermissionDelegate.ContentPermission perm) {
|
||||
public void onPermissionPrompt(final GeckoSession session, final String title,
|
||||
final GeckoSession.PermissionDelegate.Callback callback) {
|
||||
final Activity activity = mActivity;
|
||||
final GeckoResult<Integer> res = new GeckoResult<>();
|
||||
if (activity == null) {
|
||||
res.complete(GeckoSession.PermissionDelegate.ContentPermission.VALUE_PROMPT);
|
||||
return res;
|
||||
callback.reject();
|
||||
return;
|
||||
}
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(title)
|
||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
res.complete(GeckoSession.PermissionDelegate.ContentPermission.VALUE_DENY);
|
||||
callback.reject();
|
||||
}
|
||||
})
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
res.complete(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW);
|
||||
callback.grant();
|
||||
}
|
||||
});
|
||||
|
||||
final AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
return res;
|
||||
}
|
||||
|
||||
public void onSlowScriptPrompt(GeckoSession geckoSession, String title, GeckoResult<SlowScriptResponse> reportAction) {
|
||||
|
|
|
@ -1779,39 +1779,51 @@ public class GeckoViewActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public GeckoResult<Integer> onContentPermissionRequest(final GeckoSession session, final ContentPermission perm) {
|
||||
public void onContentPermissionRequest(final GeckoSession session, final String uri,
|
||||
final int type, final Callback callback) {
|
||||
final int resId;
|
||||
switch (perm.permission) {
|
||||
case PERMISSION_GEOLOCATION:
|
||||
resId = R.string.request_geolocation;
|
||||
break;
|
||||
case PERMISSION_DESKTOP_NOTIFICATION:
|
||||
resId = R.string.request_notification;
|
||||
break;
|
||||
case PERMISSION_PERSISTENT_STORAGE:
|
||||
resId = R.string.request_storage;
|
||||
break;
|
||||
case PERMISSION_XR:
|
||||
resId = R.string.request_xr;
|
||||
break;
|
||||
case PERMISSION_AUTOPLAY_AUDIBLE:
|
||||
case PERMISSION_AUTOPLAY_INAUDIBLE:
|
||||
if (!mAllowAutoplay.value()) {
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_DENY);
|
||||
} else {
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_ALLOW);
|
||||
}
|
||||
case PERMISSION_MEDIA_KEY_SYSTEM_ACCESS:
|
||||
resId = R.string.request_media_key_system_access;
|
||||
break;
|
||||
default:
|
||||
return GeckoResult.fromValue(ContentPermission.VALUE_DENY);
|
||||
Callback contentPermissionCallback = callback;
|
||||
if (PERMISSION_GEOLOCATION == type) {
|
||||
resId = R.string.request_geolocation;
|
||||
} else if (PERMISSION_DESKTOP_NOTIFICATION == type) {
|
||||
if (mShowNotificationsRejected) {
|
||||
Log.w(LOGTAG, "Desktop notifications already denied by user.");
|
||||
callback.reject();
|
||||
return;
|
||||
}
|
||||
resId = R.string.request_notification;
|
||||
contentPermissionCallback = new ExampleNotificationCallback(callback);
|
||||
} else if (PERMISSION_PERSISTENT_STORAGE == type) {
|
||||
if (mAcceptedPersistentStorage.contains(uri)) {
|
||||
Log.w(LOGTAG, "Persistent Storage for " + uri + " already granted by user.");
|
||||
callback.grant();
|
||||
return;
|
||||
}
|
||||
resId = R.string.request_storage;
|
||||
contentPermissionCallback = new ExamplePersistentStorageCallback(callback, uri);
|
||||
} else if (PERMISSION_XR == type) {
|
||||
resId = R.string.request_xr;
|
||||
} else if (PERMISSION_AUTOPLAY_AUDIBLE == type || PERMISSION_AUTOPLAY_INAUDIBLE == type) {
|
||||
if (!mAllowAutoplay.value()) {
|
||||
Log.d(LOGTAG, "Rejecting autoplay request");
|
||||
callback.reject();
|
||||
} else {
|
||||
Log.d(LOGTAG, "Granting autoplay request");
|
||||
callback.grant();
|
||||
}
|
||||
return;
|
||||
} else if (PERMISSION_MEDIA_KEY_SYSTEM_ACCESS == type) {
|
||||
resId = R.string.request_media_key_system_access;
|
||||
} else {
|
||||
Log.w(LOGTAG, "Unknown permission: " + type);
|
||||
callback.reject();
|
||||
return;
|
||||
}
|
||||
|
||||
final String title = getString(resId, Uri.parse(perm.uri).getAuthority());
|
||||
final String title = getString(resId, Uri.parse(uri).getAuthority());
|
||||
final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt)
|
||||
mTabSessionManager.getCurrentSession().getPromptDelegate();
|
||||
return prompt.onPermissionPrompt(session, title, perm);
|
||||
prompt.onPermissionPrompt(session, title, contentPermissionCallback);
|
||||
}
|
||||
|
||||
private String[] normalizeMediaName(final MediaSource[] sources) {
|
||||
|
|
|
@ -567,9 +567,8 @@ class GeckoViewNavigation extends GeckoViewModule {
|
|||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
perm: p.type,
|
||||
type: p.type,
|
||||
value: p.capability,
|
||||
contextId: p.principal.originAttributes.geckoViewSessionContextId,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -115,9 +115,8 @@ const GeckoViewStorageController = {
|
|||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
perm: p.type,
|
||||
type: p.type,
|
||||
value: p.capability,
|
||||
contextId: p.principal.originAttributes.geckoViewSessionContextId,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
|
@ -126,51 +125,23 @@ const GeckoViewStorageController = {
|
|||
}
|
||||
case "GeckoView:GetPermissionsByURI": {
|
||||
const uri = Services.io.newURI(aData.uri);
|
||||
const principal = Services.scriptSecurityManager.createContentPrincipal(
|
||||
const prin = Services.scriptSecurityManager.createContentPrincipal(
|
||||
uri,
|
||||
aData.contextId ? { geckoViewSessionContextId: aData.contextId } : {}
|
||||
{}
|
||||
);
|
||||
const rawPerms = Services.perms.getAllForPrincipal(principal);
|
||||
const rawPerms = Services.perms.getAllForPrincipal(prin);
|
||||
const permissions = rawPerms.map(p => {
|
||||
return {
|
||||
uri: Services.io.createExposableURI(p.principal.URI).displaySpec,
|
||||
principal: E10SUtils.serializePrincipal(p.principal),
|
||||
perm: p.type,
|
||||
type: p.type,
|
||||
value: p.capability,
|
||||
contextId: p.principal.originAttributes.geckoViewSessionContextId,
|
||||
privateMode: p.principal.privateBrowsingId != 0,
|
||||
};
|
||||
});
|
||||
aCallback.onSuccess({ permissions });
|
||||
break;
|
||||
}
|
||||
case "GeckoView:SetPermission": {
|
||||
const principal = E10SUtils.deserializePrincipal(aData.principal);
|
||||
Services.perms.addFromPrincipal(
|
||||
principal,
|
||||
aData.perm,
|
||||
aData.newValue,
|
||||
Ci.nsIPermissionManager.EXPIRE_NEVER
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "GeckoView:SetPermissionByURI": {
|
||||
const uri = Services.io.newURI(aData.uri);
|
||||
const principal = Services.scriptSecurityManager.createContentPrincipal(
|
||||
uri,
|
||||
{
|
||||
geckoViewSessionContextId: aData.contextId ?? undefined,
|
||||
privateBrowsingId: aData.privateId,
|
||||
}
|
||||
);
|
||||
Services.perms.addFromPrincipal(
|
||||
principal,
|
||||
aData.perm,
|
||||
aData.newValue,
|
||||
Ci.nsIPermissionManager.EXPIRE_NEVER
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ const ContentBlockingAllowList = {
|
|||
p,
|
||||
"trackingprotection",
|
||||
Services.perms.ALLOW_ACTION,
|
||||
Ci.nsIPermissionManager.EXPIRE_NEVER
|
||||
Ci.nsIPermissionManager.EXPIRE_SESSION
|
||||
)
|
||||
);
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче