From 40a355a42d4a9444dc753c04c6608dade2f06a23 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:27 +0200 Subject: Adding upstream version 125.0.1. Signed-off-by: Daniel Baumann --- mobile/android/geckoview/api.txt | 11 +- mobile/android/geckoview/build.gradle | 8 +- .../actions/test-open-popup-browser-action.js | 2 +- .../actions/test-open-popup-page-action.js | 2 +- .../web_extensions/borderify-mv3/borderify.js | 1 + .../borderify-mv3/icons/border-48.png | Bin 0 -> 225 bytes .../web_extensions/borderify-mv3/icons/icon.svg | 1 + .../web_extensions/borderify-mv3/manifest.json | 26 ++++ .../assets/web_extensions/borderify/manifest.json | 3 +- .../clickToRequestPermission.html | 11 ++ .../optional-permission-request/manifest.json | 14 ++ .../request-permission.js | 10 ++ .../redirect-to-android-resource/background.js | 2 +- .../web_extensions/test-support/test-support.js | 2 +- .../web_extensions/update-postpone-1/background.js | 2 +- .../src/androidTest/assets/www/clickToReplace.html | 10 ++ .../assets/www/context_menu_blob_buffered.html | 2 +- .../assets/www/context_menu_blob_full.html | 2 +- .../src/androidTest/assets/www/forms.html | 2 +- .../assets/www/pull-to-refresh-subframe.html | 2 +- .../src/androidTest/assets/www/push/sw.js | 2 +- .../src/androidTest/assets/www/scroll.html | 2 +- .../src/androidTest/assets/www/touch-action.html | 2 +- .../src/androidTest/assets/www/touch.html | 2 +- .../src/androidTest/assets/www/touchstart.html | 2 +- .../org/mozilla/geckoview/test/AutocompleteTest.kt | 2 +- .../org/mozilla/geckoview/test/BaseSessionTest.kt | 1 + .../mozilla/geckoview/test/GeckoAppShellTest.kt | 1 + .../geckoview/test/GeckoSessionTestRuleTest.kt | 1 + .../org/mozilla/geckoview/test/GeolocationTest.kt | 3 +- .../mozilla/geckoview/test/HistoryDelegateTest.kt | 5 + .../java/org/mozilla/geckoview/test/LocaleTest.kt | 12 ++ .../geckoview/test/NavigationDelegateTest.kt | 163 ++++++++++++++------ .../org/mozilla/geckoview/test/OpenWindowTest.kt | 8 +- .../org/mozilla/geckoview/test/PdfCreationTest.kt | 12 ++ .../geckoview/test/PermissionDelegateTest.kt | 54 +++---- .../mozilla/geckoview/test/ProgressDelegateTest.kt | 22 ++- .../mozilla/geckoview/test/RuntimeSettingsTest.kt | 3 +- .../org/mozilla/geckoview/test/ScreenshotTest.kt | 5 + .../geckoview/test/SelectionActionDelegateTest.kt | 18 +-- .../geckoview/test/TestContentProvider.java | 19 ++- .../geckoview/test/TextInputDelegateTest.kt | 42 +++++- .../geckoview/test/TrackingPermissionService.java | 3 +- .../org/mozilla/geckoview/test/VideoCaptureTest.kt | 58 +++++++ .../org/mozilla/geckoview/test/WebExtensionTest.kt | 168 ++++++++++++++++++++- .../mozilla/geckoview/test/WebNotificationTest.kt | 15 +- .../java/org/mozilla/geckoview/test/WebPushTest.kt | 3 +- .../geckoview/test/rule/GeckoSessionTestRule.java | 3 +- .../org/mozilla/gecko/AndroidGamepadManager.java | 2 +- .../main/java/org/mozilla/gecko/GeckoAppShell.java | 15 -- .../java/org/mozilla/gecko/GeckoDragAndDrop.java | 6 +- .../main/java/org/mozilla/gecko/InputMethods.java | 9 ++ .../org/mozilla/gecko/media/MediaDrmProxy.java | 1 + .../java/org/mozilla/gecko/util/LocaleUtils.java | 32 ++++ .../org/mozilla/geckoview/ContentInputStream.java | 17 ++- .../mozilla/geckoview/GeckoInputConnection.java | 47 ++++++ .../mozilla/geckoview/GeckoRuntimeSettings.java | 26 +--- .../java/org/mozilla/geckoview/GeckoSession.java | 30 +++- .../mozilla/geckoview/GeckoSessionSettings.java | 4 +- .../main/java/org/mozilla/geckoview/GeckoView.java | 6 + .../java/org/mozilla/geckoview/WebExtension.java | 54 ++++++- .../org/mozilla/geckoview/doc-files/CHANGELOG.md | 25 ++- .../org/mozilla/gecko/util/LocaleUtilsTest.java | 47 ++++++ 63 files changed, 882 insertions(+), 183 deletions(-) create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/borderify.js create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/border-48.png create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/icon.svg create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/manifest.json create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/clickToRequestPermission.html create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/manifest.json create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/request-permission.js create mode 100644 mobile/android/geckoview/src/androidTest/assets/www/clickToReplace.html create mode 100644 mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VideoCaptureTest.kt create mode 100644 mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/LocaleUtils.java create mode 100644 mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/LocaleUtilsTest.java (limited to 'mobile/android/geckoview') diff --git a/mobile/android/geckoview/api.txt b/mobile/android/geckoview/api.txt index 86869c0abe..30c4d35585 100644 --- a/mobile/android/geckoview/api.txt +++ b/mobile/android/geckoview/api.txt @@ -51,6 +51,7 @@ import java.lang.Boolean; import java.lang.CharSequence; import java.lang.Class; import java.lang.Comparable; +import java.lang.Deprecated; import java.lang.Double; import java.lang.Exception; import java.lang.Float; @@ -85,6 +86,7 @@ import org.mozilla.geckoview.CompositorController; import org.mozilla.geckoview.ContentBlocking; import org.mozilla.geckoview.ContentBlockingController; import org.mozilla.geckoview.CrashHandler; +import org.mozilla.geckoview.DeprecationSchedule; import org.mozilla.geckoview.ExperimentDelegate; import org.mozilla.geckoview.GeckoDisplay; import org.mozilla.geckoview.GeckoResult; @@ -967,7 +969,7 @@ package org.mozilla.geckoview { method @NonNull public GeckoRuntimeSettings.Builder preferredColorScheme(int); method @NonNull public GeckoRuntimeSettings.Builder remoteDebuggingEnabled(boolean); method @NonNull public GeckoRuntimeSettings.Builder screenSizeOverride(int, int); - method @NonNull public GeckoRuntimeSettings.Builder telemetryDelegate(@NonNull RuntimeTelemetry.Delegate); + method @Deprecated @DeprecationSchedule(id="geckoview-gvst",version=127) @NonNull public GeckoRuntimeSettings.Builder telemetryDelegate(@NonNull RuntimeTelemetry.Delegate); method @NonNull public GeckoRuntimeSettings.Builder translationsOfferPopup(boolean); method @NonNull public GeckoRuntimeSettings.Builder trustedRecursiveResolverMode(int); method @NonNull public GeckoRuntimeSettings.Builder trustedRecursiveResolverUri(@NonNull String); @@ -1262,7 +1264,8 @@ package org.mozilla.geckoview { method @UiThread default public void onCanGoForward(@NonNull GeckoSession, boolean); method @Nullable @UiThread default public GeckoResult onLoadError(@NonNull GeckoSession, @Nullable String, @NonNull WebRequestError); method @Nullable @UiThread default public GeckoResult onLoadRequest(@NonNull GeckoSession, @NonNull GeckoSession.NavigationDelegate.LoadRequest); - method @UiThread default public void onLocationChange(@NonNull GeckoSession, @Nullable String, @NonNull List); + method @Deprecated @DeprecationSchedule(id="geckoview-onlocationchange",version=127) @UiThread default public void onLocationChange(@NonNull GeckoSession, @Nullable String, @NonNull List); + method @UiThread default public void onLocationChange(@NonNull GeckoSession, @Nullable String, @NonNull List, @NonNull Boolean); method @Nullable @UiThread default public GeckoResult onNewSession(@NonNull GeckoSession, @NonNull String); method @Nullable @UiThread default public GeckoResult onSubframeLoadRequest(@NonNull GeckoSession, @NonNull GeckoSession.NavigationDelegate.LoadRequest); field public static final int LOAD_REQUEST_IS_REDIRECT = 8388608; @@ -2674,12 +2677,16 @@ package org.mozilla.geckoview { field @Nullable public final String downloadUrl; field public final boolean enabled; field @Nullable public final String fullDescription; + field @NonNull public final String[] grantedOptionalOrigins; + field @NonNull public final String[] grantedOptionalPermissions; field @Nullable public final String homepageUrl; field @NonNull public final Image icon; field @Nullable public final String incognito; field public final boolean isRecommended; field @Nullable public final String name; field public final boolean openOptionsPageInTab; + field @NonNull public final String[] optionalOrigins; + field @NonNull public final String[] optionalPermissions; field @Nullable public final String optionsPageUrl; field @NonNull public final String[] origins; field @NonNull public final String[] permissions; diff --git a/mobile/android/geckoview/build.gradle b/mobile/android/geckoview/build.gradle index 32224dd5a2..6e5826655d 100644 --- a/mobile/android/geckoview/build.gradle +++ b/mobile/android/geckoview/build.gradle @@ -155,6 +155,10 @@ android { aidl = true } + publishing { + singleVariant('withGeckoBinariesDebug') + } + namespace 'org.mozilla.geckoview' } @@ -229,7 +233,7 @@ dependencies { implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "com.google.android.gms:play-services-fido:20.0.1" - implementation "org.yaml:snakeyaml:2.0" + implementation "org.yaml:snakeyaml:2.2" implementation "androidx.lifecycle:lifecycle-common:2.6.1" implementation "androidx.lifecycle:lifecycle-process:2.6.1" @@ -514,7 +518,7 @@ android.libraryVariants.all configureVariantDebugLevel // be somewhere where the Android plugin is available so that we can fish the // path to "android.jar". task("generateSDKBindings", type: JavaExec) { - classpath project(':annotations').jar.archivePath + classpath project(':annotations').jar.archiveFile classpath project(':annotations').compileJava.classpath classpath project(':annotations').sourceSets.main.runtimeClasspath diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js index cde31235ac..421859dfa2 100644 --- a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js @@ -1,7 +1,7 @@ window.addEventListener("DOMContentLoaded", init); function init() { - document.body.addEventListener("click", event => { + document.body.addEventListener("click", () => { browser.browserAction.openPopup(); }); } diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js index f16d96333f..6e38fc7858 100644 --- a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js @@ -1,7 +1,7 @@ window.addEventListener("DOMContentLoaded", init); function init() { - document.body.addEventListener("click", event => { + document.body.addEventListener("click", () => { browser.pageAction.openPopup(); }); } diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/borderify.js new file mode 100644 index 0000000000..9c3728b381 --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/borderify.js @@ -0,0 +1 @@ +document.body.style.border = "5px solid red"; diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/border-48.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/border-48.png new file mode 100644 index 0000000000..90687de26d Binary files /dev/null and b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/border-48.png differ diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/icon.svg b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/icon.svg new file mode 100644 index 0000000000..dd1fae7d15 --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/icons/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/manifest.json new file mode 100644 index 0000000000..f1dbe5fe71 --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-mv3/manifest.json @@ -0,0 +1,26 @@ +{ + "manifest_version": 3, + "name": "Borderify", + "version": "1.0", + "description": "Adds a red border to all webpages matching example.com.", + "browser_specific_settings": { + "gecko": { + "id": "borderify@tests.mozilla.org" + } + }, + "icons": { + "48": "icons/border-48.png" + }, + "content_scripts": [ + { + "matches": ["*://*.example.com/*"], + "js": ["borderify.js"] + } + ], + "options_ui": { + "page": "dummy.html" + }, + "granted_host_permissions": true, + "optional_permissions": ["clipboardRead", "*://opt-host-perm.example.com/*"], + "host_permissions": ["*://host-perm.example.com/*"] +} diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json index 4e3daf6708..4ea4eb093e 100644 --- a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json @@ -19,5 +19,6 @@ ], "options_ui": { "page": "dummy.html" - } + }, + "optional_permissions": ["clipboardRead", "*://developer.mozilla.org/*"] } diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/clickToRequestPermission.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/clickToRequestPermission.html new file mode 100644 index 0000000000..e6ddcb8c8d --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/clickToRequestPermission.html @@ -0,0 +1,11 @@ + + + + Hello, world! + + + + +

Hello, world!

+ + diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/manifest.json new file mode 100644 index 0000000000..0644eb637f --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/manifest.json @@ -0,0 +1,14 @@ +{ + "manifest_version": 3, + "name": "optional-permission-request", + "browser_specific_settings": { + "gecko": { + "id": "optional-permission-request@example.com" + } + }, + "version": "1.0", + "description": "Request optional extension permissions.", + "permissions": ["nativeMessaging", "geckoViewAddons"], + "granted_host_permissions": true, + "optional_permissions": ["geolocation", "*://example.com/*", "activeTab"] +} diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/request-permission.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/request-permission.js new file mode 100644 index 0000000000..bae3ceea6f --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/optional-permission-request/request-permission.js @@ -0,0 +1,10 @@ +window.onload = () => { + document.body.addEventListener("click", async () => { + const perms = { + permissions: ["activeTab"], + origins: ["*://example.com/*"], + }; + const response = await browser.permissions.request(perms); + browser.runtime.sendNativeMessage("browser", `${response}`); + }); +}; diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js index fdf088a505..e77d482e14 100644 --- a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js @@ -2,7 +2,7 @@ function setupRedirect(fromUrl, redirectUrl) { browser.webRequest.onBeforeRequest.addListener( - details => { + () => { console.log(`Extension redirects from ${fromUrl} to ${redirectUrl}`); return { redirectUrl }; }, diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js index 18e047ca1a..f47f42d12e 100644 --- a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js @@ -30,7 +30,7 @@ function connectNativePort() { } }); - function sendResponse(id, response, exception) { + function sendResponse(id, response) { Promise.resolve(response).then( value => sendSyncResponse(id, value), reason => sendSyncResponse(id, null, reason) diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js index a301506ca7..8266ad8258 100644 --- a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js +++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js @@ -1,3 +1,3 @@ -browser.runtime.onUpdateAvailable.addListener(details => { +browser.runtime.onUpdateAvailable.addListener(() => { // Do nothing, this is just here to prevent auto update. }); diff --git a/mobile/android/geckoview/src/androidTest/assets/www/clickToReplace.html b/mobile/android/geckoview/src/androidTest/assets/www/clickToReplace.html new file mode 100644 index 0000000000..6d583586f1 --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/www/clickToReplace.html @@ -0,0 +1,10 @@ + + + + Hello, world! + + + +

Hello, world!

+ + diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html index 9849747a41..950e48129e 100644 --- a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html +++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html @@ -8,7 +8,7 @@ diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touch-action.html b/mobile/android/geckoview/src/androidTest/assets/www/touch-action.html index 62266b6ef7..bf315cfb7e 100644 --- a/mobile/android/geckoview/src/androidTest/assets/www/touch-action.html +++ b/mobile/android/geckoview/src/androidTest/assets/www/touch-action.html @@ -41,7 +41,7 @@ } div.style.touchAction = searchParams.get("touch-action"); if (searchParams.has("event")) { - div.addEventListener("touchstart", e => {}); + div.addEventListener("touchstart", () => {}); } diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touch.html b/mobile/android/geckoview/src/androidTest/assets/www/touch.html index ba3bc098a9..6852a0f4fe 100644 --- a/mobile/android/geckoview/src/androidTest/assets/www/touch.html +++ b/mobile/android/geckoview/src/androidTest/assets/www/touch.html @@ -50,7 +50,7 @@ e.preventDefault(); }); - document.getElementById("three").addEventListener("touchstart", e => { + document.getElementById("three").addEventListener("touchstart", () => { console.log("not preventing default"); }); diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touchstart.html b/mobile/android/geckoview/src/androidTest/assets/www/touchstart.html index 9ee1f461a7..42d1787ef1 100644 --- a/mobile/android/geckoview/src/androidTest/assets/www/touchstart.html +++ b/mobile/android/geckoview/src/androidTest/assets/www/touchstart.html @@ -31,7 +31,7 @@
diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AutocompleteTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AutocompleteTest.kt index fbfe2fe46d..dddba77768 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AutocompleteTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AutocompleteTest.kt @@ -2407,7 +2407,7 @@ class AutocompleteTest : BaseSessionTest() { "Hint should match", option.hint, equalTo(LoginSaveOption.Hint.GENERATED)) - */ + */ assertThat( "Password should not be empty", diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/BaseSessionTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/BaseSessionTest.kt index 655db7248f..d57cd8f157 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/BaseSessionTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/BaseSessionTest.kt @@ -36,6 +36,7 @@ open class BaseSessionTest( const val RESUBMIT_CONFIRM = "/assets/www/resubmit.html" const val BEFORE_UNLOAD = "/assets/www/beforeunload.html" const val CLICK_TO_RELOAD_HTML_PATH = "/assets/www/clickToReload.html" + const val CLICK_TO_REPLACE_HTML_PATH = "/assets/www/clickToReplace.html" const val CLIPBOARD_READ_HTML_PATH = "/assets/www/clipboard_read.html" const val CONTENT_CRASH_URL = "about:crashcontent" const val DND_HTML_PATH = "/assets/www/dnd.html" diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoAppShellTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoAppShellTest.kt index c05820012d..75204a2f5d 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoAppShellTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoAppShellTest.kt @@ -86,6 +86,7 @@ class GeckoAppShellTest : BaseSessionTest() { // This is waiting and holding the test harness open while Android Lifecycle events complete mainSession.waitUntilCalled(object : GeckoSession.ContentDelegate, GeckoSession.NavigationDelegate { @GeckoSessionTestRule.AssertCalled(count = 2) + @Suppress("OVERRIDE_DEPRECATION") override fun onLocationChange( session: GeckoSession, url: String?, diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt index d6380bf5bf..2ec305f913 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt @@ -1115,6 +1115,7 @@ class GeckoSessionTestRuleTest : BaseSessionTest(noErrorCollector = true) { @NullDelegate(NavigationDelegate::class) fun delegateDuringNextWait_throwOnNullDelegate() { mainSession.delegateDuringNextWait(object : NavigationDelegate { + @Suppress("OVERRIDE_DEPRECATION") override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { } }) diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeolocationTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeolocationTest.kt index 1bb568123c..4deac5fb66 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeolocationTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeolocationTest.kt @@ -72,8 +72,7 @@ class GeolocationTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission, - ): - GeckoResult { + ): GeckoResult { return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) } override fun onAndroidPermissionsRequest( diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/HistoryDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/HistoryDelegateTest.kt index 370594a93f..2d2f4bb4af 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/HistoryDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/HistoryDelegateTest.kt @@ -250,6 +250,11 @@ class HistoryDelegateTest : BaseSessionTest() { } @Test fun onHistoryStateChangeSavingState() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt index 69deac1c89..608681d7d9 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/LocaleTest.kt @@ -40,4 +40,16 @@ class LocaleTest : BaseSessionTest() { equalTo(listOf("en-GB", "en-US", "en-FR")), ) } + + @Test + fun acceptLangaugeFormat() { + // No way to override default language settings from unit test. + // So we only test this on current settings. + + val intlAcceptLanauge = "intl.accept_languages" + val prefValue = (sessionRule.getPrefs(intlAcceptLanauge)[0] as String).split(",") + for (value in prefValue) { + assertThat("Accept-Lanauge format should be language or language-region", value.filter { it == '-' }.count(), lessThanOrEqualTo(1)) + } + } } diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt index aab32cd01d..839ac4b468 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt @@ -67,8 +67,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "URI should be " + testLoader.getUri(), request.uri, @@ -123,6 +122,7 @@ class NavigationDelegateTest : BaseSessionTest() { if (errorPageUrl != null) { sessionRule.waitUntilCalled(object : ContentDelegate, NavigationDelegate { @AssertCalled(count = 1, order = [1]) + @Suppress("OVERRIDE_DEPRECATION") override fun onLocationChange( session: GeckoSession, url: String?, @@ -492,8 +492,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("The URLs must match", request.uri, equalTo(forEachCall(uri, httpsUri))) return null } @@ -552,8 +551,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("The URLs must match", request.uri, equalTo(forEachCall(uri, httpsUri))) return null } @@ -593,6 +591,7 @@ class NavigationDelegateTest : BaseSessionTest() { sessionRule.waitUntilCalled(object : ContentDelegate, NavigationDelegate { @AssertCalled(count = 1, order = [1]) + @Suppress("OVERRIDE_DEPRECATION") override fun onLocationChange( session: GeckoSession, url: String?, @@ -611,8 +610,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("The URLs must match", request.uri, equalTo(forEachCall(uri, httpsUri))) return null } @@ -646,6 +644,7 @@ class NavigationDelegateTest : BaseSessionTest() { // No good way to wait for loading about:blank error page. Use onLocaitonChange etc. sessionRule.waitUntilCalled(object : ContentDelegate, NavigationDelegate { + @Suppress("OVERRIDE_DEPRECATION") override fun onLocationChange( session: GeckoSession, url: String?, @@ -665,8 +664,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { // We set http scheme only in case it's not iFrame assertThat("The URLs must match", request.uri, equalTo(uri)) return null @@ -717,8 +715,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "URI should be HTTP then redirected to HTTPS", request.uri, @@ -774,8 +771,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onSubframeLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("URI should not be null", request.uri, notNullValue()) assertThat("URI should match", request.uri, endsWith(iframeUri)) return null @@ -862,8 +858,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("Session should not be null", session, notNullValue()) assertThat("URI should not be null", request.uri, notNullValue()) assertThat( @@ -913,8 +908,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("Session should not be null", session, notNullValue()) assertThat("App requested this load", request.isDirectNavigation, equalTo(true)) assertThat("URI should not be null", request.uri, notNullValue()) @@ -927,8 +921,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onSubframeLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("Session should not be null", session, notNullValue()) assertThat("App did not request this load", request.isDirectNavigation, equalTo(false)) assertThat("URI should not be null", request.uri, notNullValue()) @@ -960,8 +953,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("Session should not be null", session, notNullValue()) assertThat("URI should not be null", request.uri, notNullValue()) assertThat( @@ -1023,8 +1015,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("URL should match", request.uri, equalTo(forEachCall(uri, redirectUri))) assertThat( "From app should be correct", @@ -1447,8 +1438,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("Session should not be null", session, notNullValue()) assertThat("URI should not be null", request.uri, notNullValue()) assertThat("URI should match", request.uri, endsWith(HELLO_HTML_PATH)) @@ -1478,10 +1468,12 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("Session should not be null", session, notNullValue()) assertThat("URL should not be null", url, notNullValue()) assertThat("URL should match", url, endsWith(HELLO_HTML_PATH)) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1, order = [2]) @@ -1514,8 +1506,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should match the provided data URL", url, equalTo(dataUrl)) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1) @@ -1542,6 +1536,7 @@ class NavigationDelegateTest : BaseSessionTest() { // Test that if we unset the navigation delegate during a load, the load still proceeds. var onLocationCount = 0 mainSession.navigationDelegate = object : NavigationDelegate { + @Suppress("OVERRIDE_DEPRECATION") override fun onLocationChange( session: GeckoSession, url: String?, @@ -1587,12 +1582,14 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat( "URL should be a data URL", url, equalTo(createDataUri(dataString, mimeType)), ) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1) @@ -1612,8 +1609,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should be a data URL", url, startsWith("data:")) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1) @@ -1641,8 +1640,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should match", url, equalTo(createDataUri(bytes, "text/html"))) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1) @@ -1683,8 +1684,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should match", url, equalTo(createDataUri(bytes, mimeType))) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1) @@ -1714,8 +1717,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("URI should match", request.uri, endsWith(HELLO_HTML_PATH)) assertThat( "Trigger URL should be null", @@ -1740,8 +1742,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should match", url, endsWith(HELLO_HTML_PATH)) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1, order = [2]) @@ -1774,8 +1778,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH)) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } }) @@ -1787,8 +1793,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "Load should not be direct", request.isDirectNavigation, @@ -1802,8 +1807,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should match", url, endsWith(HELLO_HTML_PATH)) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1, order = [2]) @@ -1830,8 +1837,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "Load should not be direct", request.isDirectNavigation, @@ -1845,8 +1851,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH)) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } @AssertCalled(count = 1, order = [2]) @@ -1872,8 +1880,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { if (request.uri.endsWith(HELLO_HTML_PATH)) { return GeckoResult.deny() } else { @@ -1913,8 +1920,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("URI should be correct", request.uri, endsWith(NEW_SESSION_CHILD_HTML_PATH)) assertThat( "Trigger URL should match", @@ -1969,8 +1975,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat("URI should be correct", request.uri, endsWith(NEW_SESSION_CHILD_HTML_PATH)) assertThat( "Trigger URL should be null", @@ -2080,8 +2085,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { // Pretend we handled the target="_blank" link click. if (request.uri.endsWith(NEW_SESSION_CHILD_HTML_PATH)) { return GeckoResult.deny() @@ -2102,8 +2106,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "URI must match", request.uri, @@ -2151,8 +2154,7 @@ class NavigationDelegateTest : BaseSessionTest() { mainSession.waitUntilCalled(object : NavigationDelegate { @AssertCalled(count = 1, order = [1]) - override fun onLoadRequest(session: GeckoSession, request: LoadRequest): - GeckoResult? { + override fun onLoadRequest(session: GeckoSession, request: LoadRequest): GeckoResult? { assertThat( "URL should be correct", request.uri, @@ -2172,8 +2174,7 @@ class NavigationDelegateTest : BaseSessionTest() { } @AssertCalled(count = 1, order = [2]) - override fun onNewSession(session: GeckoSession, uri: String): - GeckoResult? { + override fun onNewSession(session: GeckoSession, uri: String): GeckoResult? { assertThat("URL should be correct", uri, endsWith("form_blank.html?")) return null } @@ -2621,6 +2622,7 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { currentUrl = url } @@ -2702,8 +2704,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "Load should not be direct", request.isDirectNavigation, @@ -2717,8 +2718,10 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URI should match", url, endsWith("#test1")) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } }) @@ -2729,8 +2732,7 @@ class NavigationDelegateTest : BaseSessionTest() { override fun onLoadRequest( session: GeckoSession, request: LoadRequest, - ): - GeckoResult? { + ): GeckoResult? { return null } @@ -2739,13 +2741,20 @@ class NavigationDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URI should match", url, endsWith("#test2")) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) } }) } @Test fun purgeHistory() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) @@ -2830,6 +2839,54 @@ class NavigationDelegateTest : BaseSessionTest() { }) } + @WithDisplay(width = 100, height = 100) + @Test + fun locationReplaceOnUserGesture() { + mainSession.loadUri("$TEST_ENDPOINT$CLICK_TO_REPLACE_HTML_PATH") + mainSession.waitForPageStop() + + mainSession.synthesizeTap(50, 50) + + sessionRule.waitUntilCalled(object : NavigationDelegate { + @AssertCalled(count = 1) + override fun onLocationChange( + session: GeckoSession, + url: String?, + perms: MutableList, + hasUserGesture: Boolean, + ) { + assertThat("Should have a user gesture", hasUserGesture, equalTo(true)) + assertThat( + "Location should be replaced to replacedUrl", + url, + equalTo("replacedUrl"), + ) + } + }) + } + + @WithDisplay(width = 100, height = 100) + @Test + fun locationNotReplaceOnNoUserGesture() { + mainSession.loadUri("$TEST_ENDPOINT$HELLO_HTML_PATH") + sessionRule.waitForPageStop() + + sessionRule.forCallbacksDuringWait(object : NavigationDelegate { + @AssertCalled(count = 1, order = [2]) + override fun onLocationChange( + session: GeckoSession, + url: String?, + perms: MutableList, + hasUserGesture: Boolean, + ) { + assertThat("Session should not be null", session, notNullValue()) + assertThat("URL should not be null", url, notNullValue()) + assertThat("URL should match", url, endsWith(HELLO_HTML_PATH)) + assertThat("Should not have user gesture", hasUserGesture, equalTo(false)) + } + }) + } + @Test fun loadAfterLoad() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 2) @@ -3078,6 +3135,11 @@ class NavigationDelegateTest : BaseSessionTest() { } @Test fun goBackFromHistory() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) @@ -3119,6 +3181,7 @@ class NavigationDelegateTest : BaseSessionTest() { var lastTitle: String? = "" sessionRule.delegateDuringNextWait(object : NavigationDelegate, ContentDelegate { @AssertCalled(count = 1) + @Suppress("OVERRIDE_DEPRECATION") override fun onLocationChange( session: GeckoSession, url: String?, diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/OpenWindowTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/OpenWindowTest.kt index 335535bbb4..b7aed020b4 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/OpenWindowTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/OpenWindowTest.kt @@ -64,7 +64,7 @@ class OpenWindowTest : BaseSessionTest() { @NullDelegate(ServiceWorkerDelegate::class) fun openWindowNullDelegate() { sessionRule.delegateUntilTestEnd(object : ContentDelegate, NavigationDelegate { - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { // we should not open the target url assertThat("URL should notmatch", url, not(createTestUrl(OPEN_WINDOW_TARGET_PATH))) } @@ -76,7 +76,7 @@ class OpenWindowTest : BaseSessionTest() { @Test fun openWindowNullResult() { sessionRule.delegateUntilTestEnd(object : ContentDelegate, NavigationDelegate { - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { // we should not open the target url assertThat("URL should notmatch", url, not(createTestUrl(OPEN_WINDOW_TARGET_PATH))) } @@ -103,7 +103,7 @@ class OpenWindowTest : BaseSessionTest() { openPageClickNotification() sessionRule.waitUntilCalled(object : ContentDelegate, NavigationDelegate { @AssertCalled(count = 1, order = [1]) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { assertThat("Should be on the main session", session, equalTo(mainSession)) assertThat("URL should match", url, equalTo(createTestUrl(OPEN_WINDOW_TARGET_PATH))) } @@ -130,7 +130,7 @@ class OpenWindowTest : BaseSessionTest() { openPageClickNotification() sessionRule.waitUntilCalled(object : ContentDelegate, NavigationDelegate { @AssertCalled(count = 1, order = [1]) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { assertThat("Should be on the target session", session, equalTo(targetSession)) assertThat("URL should match", url, equalTo(createTestUrl(OPEN_WINDOW_TARGET_PATH))) } diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PdfCreationTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PdfCreationTest.kt index 627c076fc4..de9f282484 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PdfCreationTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PdfCreationTest.kt @@ -177,4 +177,16 @@ class PdfCreationTest : BaseSessionTest() { } } } + + @NullDelegate(Autofill.Delegate::class) + @Test + fun dontTryToOpenNullContent() { + // Bug 1881927. + assumeThat(sessionRule.env.isIsolatedProcess, equalTo(false)) + activityRule.scenario.onActivity { + TestContentProvider.setNullTestData("application/pdf") + mainSession.loadUri("content://org.mozilla.geckoview.test.provider/pdf") + mainSession.waitForPageStop() + } + } } diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PermissionDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PermissionDelegateTest.kt index 9ab2d2515f..6b39d410eb 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PermissionDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/PermissionDelegateTest.kt @@ -214,8 +214,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", @@ -275,7 +274,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_GEOLOCATION && @@ -302,8 +301,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { return GeckoResult.fromValue(ContentPermission.VALUE_DENY) } @@ -342,7 +340,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_GEOLOCATION && @@ -462,6 +460,7 @@ class PermissionDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_TRACKING) { @@ -501,6 +500,7 @@ class PermissionDelegateTest : BaseSessionTest() { assertTrackingProtectionPermission(null) mainSession.loadTestPath(HELLO_HTML_PATH) + mainSession.waitForPageStop() assertTrackingProtectionPermission(ContentPermission.VALUE_DENY) } @@ -515,8 +515,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", @@ -551,7 +550,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION && @@ -587,8 +586,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { return GeckoResult.fromValue(ContentPermission.VALUE_DENY) } }) @@ -617,7 +615,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION && @@ -649,8 +647,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.waitUntilCalled(object : PermissionDelegate { @AssertCalled(count = 2) - override fun onContentPermissionRequest(session: GeckoSession, perm: ContentPermission): - GeckoResult { + override fun onContentPermissionRequest(session: GeckoSession, perm: ContentPermission): GeckoResult { val expectedType = if (sessionRule.currentCall.counter == 1) PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE else PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE assertThat("Type should match", perm.permission, equalTo(expectedType)) return GeckoResult.fromValue(ContentPermission.VALUE_DENY) @@ -670,8 +667,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", @@ -707,7 +703,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION && @@ -736,8 +732,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", @@ -777,7 +772,7 @@ class PermissionDelegateTest : BaseSessionTest() { session2.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION && @@ -805,8 +800,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", @@ -841,7 +835,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION && @@ -876,8 +870,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", @@ -919,7 +912,7 @@ class PermissionDelegateTest : BaseSessionTest() { mainSession.delegateDuringNextWait(object : NavigationDelegate { @AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { var permFound2 = false for (perm in perms) { if (perm.permission == PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION && @@ -954,8 +947,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", @@ -1000,8 +992,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { return GeckoResult.fromValue(ContentPermission.VALUE_PROMPT) } }) @@ -1026,8 +1017,7 @@ class PermissionDelegateTest : BaseSessionTest() { override fun onContentPermissionRequest( session: GeckoSession, perm: ContentPermission, - ): - GeckoResult { + ): GeckoResult { assertThat("URI should match", perm.uri, endsWith(url)) assertThat( "Type should match", diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ProgressDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ProgressDelegateTest.kt index 3097452da8..f8046ed2ed 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ProgressDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ProgressDelegateTest.kt @@ -33,7 +33,7 @@ class ProgressDelegateTest : BaseSessionTest() { ProgressDelegate, NavigationDelegate { @AssertCalled - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { assertThat("LocationChange is called", url, endsWith(path)) } @@ -448,6 +448,11 @@ class ProgressDelegateTest : BaseSessionTest() { @WithDisplay(width = 400, height = 400) @Test fun saveAndRestoreStateNewSession() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) val helloUri = createTestUrl(HELLO_HTML_PATH) @@ -467,6 +472,7 @@ class ProgressDelegateTest : BaseSessionTest() { session: GeckoSession, url: String?, perms: MutableList, + hasUserGesture: Boolean, ) { assertThat("URI should match", url, equalTo(startUri)) } @@ -487,7 +493,7 @@ class ProgressDelegateTest : BaseSessionTest() { session.goBack() session.waitUntilCalled(object : NavigationDelegate { - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { assertThat("History should be preserved", url, equalTo(helloUri)) } }) @@ -511,7 +517,7 @@ class ProgressDelegateTest : BaseSessionTest() { sessionRule.forCallbacksDuringWait(object : NavigationDelegate { @AssertCalled - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { assertThat("URI should match", url, equalTo(startUri)) } }) @@ -532,6 +538,11 @@ class ProgressDelegateTest : BaseSessionTest() { @WithDisplay(width = 400, height = 400) @Test fun flushSessionState() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) val startUri = createTestUrl(SAVE_STATE_PATH) @@ -568,6 +579,11 @@ class ProgressDelegateTest : BaseSessionTest() { @NullDelegate(GeckoSession.HistoryDelegate::class) @Test fun noHistoryDelegateOnSessionStateChange() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) mainSession.loadTestPath(HELLO_HTML_PATH) diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/RuntimeSettingsTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/RuntimeSettingsTest.kt index 6504af8a4c..2b690726f3 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/RuntimeSettingsTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/RuntimeSettingsTest.kt @@ -277,8 +277,7 @@ class RuntimeSettingsTest : BaseSessionTest() { mainSession.loadUri("about:config") mainSession.waitUntilCalled(object : NavigationDelegate { @AssertCalled - override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): - GeckoResult? { + override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): GeckoResult? { assertThat("about:config should not load.", uri, equalTo("about:config")) return null } diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ScreenshotTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ScreenshotTest.kt index cee16f3f4c..f3141c661c 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ScreenshotTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ScreenshotTest.kt @@ -203,6 +203,11 @@ class ScreenshotTest : BaseSessionTest() { @WithDisplay(height = SCREEN_HEIGHT, width = SCREEN_WIDTH) @Test fun capturePixelsWhileSessionDeactivated() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) val screenshotFile = getComparisonScreenshot(SCREEN_WIDTH, SCREEN_HEIGHT) diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/SelectionActionDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/SelectionActionDelegateTest.kt index e5e8ec6ce2..d3e52cda6a 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/SelectionActionDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/SelectionActionDelegateTest.kt @@ -393,8 +393,7 @@ class SelectionActionDelegateTest : BaseSessionTest() { override fun onShowClipboardPermissionRequest( session: GeckoSession, perm: ClipboardPermission, - ): - GeckoResult { + ): GeckoResult { assertThat( "Type should match", perm.type, @@ -408,8 +407,7 @@ class SelectionActionDelegateTest : BaseSessionTest() { override fun onAlertPrompt( session: GeckoSession, prompt: PromptDelegate.AlertPrompt, - ): - GeckoResult { + ): GeckoResult { assertThat("Message should match", "allow", equalTo(prompt.message)) result.complete(null) return GeckoResult.fromValue(prompt.dismiss()) @@ -440,8 +438,7 @@ class SelectionActionDelegateTest : BaseSessionTest() { override fun onShowClipboardPermissionRequest( session: GeckoSession, perm: ClipboardPermission, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "Type should match", perm.type, @@ -454,8 +451,7 @@ class SelectionActionDelegateTest : BaseSessionTest() { override fun onAlertPrompt( session: GeckoSession, prompt: PromptDelegate.AlertPrompt, - ): - GeckoResult { + ): GeckoResult { assertThat("Message should match", "deny", equalTo(prompt.message)) result.complete(null) return GeckoResult.fromValue(prompt.dismiss()) @@ -486,8 +482,7 @@ class SelectionActionDelegateTest : BaseSessionTest() { override fun onShowClipboardPermissionRequest( session: GeckoSession, perm: ClipboardPermission, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "Type should match", perm.type, @@ -533,8 +528,7 @@ class SelectionActionDelegateTest : BaseSessionTest() { override fun onShowClipboardPermissionRequest( session: GeckoSession, perm: ClipboardPermission, - ): - GeckoResult? { + ): GeckoResult? { assertThat( "Type should match", perm.type, diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestContentProvider.java b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestContentProvider.java index 787448a859..b0591b693e 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestContentProvider.java +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestContentProvider.java @@ -18,6 +18,7 @@ public class TestContentProvider extends ContentProvider { private static final String LOGTAG = "TestContentProvider"; private static byte[] sTestData; private static String sMimeType; + private static boolean sAllowNullData = false; @Override public boolean onCreate() { @@ -62,7 +63,10 @@ public class TestContentProvider extends ContentProvider { public ParcelFileDescriptor openFile(final Uri uri, final String mode) throws FileNotFoundException { if (sTestData == null) { - throw new FileNotFoundException("No test data for: " + uri); + if (!sAllowNullData) { + throw new FileNotFoundException("No test data for: " + uri); + } + return null; } ParcelFileDescriptor[] pipe = null; @@ -98,6 +102,19 @@ public class TestContentProvider extends ContentProvider { */ public static void setTestData(final byte[] data, final String mimeType) { sTestData = data; + sAllowNullData = false; + sMimeType = mimeType; + } + + /** + * Set null that is used from content resolver but don't throw when calling openFile. + * + * @param data test data + * @param mimeType A mime type of test data. + */ + public static void setNullTestData(final String mimeType) { + sTestData = null; + sAllowNullData = true; sMimeType = mimeType; } } diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TextInputDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TextInputDelegateTest.kt index 7e4015a246..ca21d0a61d 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TextInputDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TextInputDelegateTest.kt @@ -537,7 +537,8 @@ class TextInputDelegateTest : BaseSessionTest() { "Can commit text (select before)", ic, "foobarfoo", - 5, /* checkGecko */ + 5, + /* checkGecko */ false, ) } @@ -641,7 +642,8 @@ class TextInputDelegateTest : BaseSessionTest() { "Can set new composing region text", ic, "frabar", - 6, /* checkGecko */ + 6, + /* checkGecko */ false, ) @@ -826,7 +828,13 @@ class TextInputDelegateTest : BaseSessionTest() { }.joinToString("") setupContent(content) val ic = mainSession.textInput.onCreateInputConnection(EditorInfo())!! - assertText("Can set large initial text", ic, content, /* checkGecko */ false) + assertText( + "Can set large initial text", + ic, + content, + /* checkGecko */ + false, + ) } @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N_MR1) @@ -1279,6 +1287,25 @@ class TextInputDelegateTest : BaseSessionTest() { assertText("commit abc", ic, "abc") } + // Bug 1837931 - When 2nd commitText uses -1 as newCursorPosition into batch mode, text + // cannot insert correct position. + @WithDisplay(width = 512, height = 512) + // Child process updates require having a display. + @Test + fun inputConnection_multiple_commitText_into_batchEdit() { + setupContent("") + val ic = mainSession.textInput.onCreateInputConnection(EditorInfo())!! + + // Emulate GBoard's InputConnection API calls + ic.beginBatchEdit() + ic.commitText("( ", 1) + ic.commitText(")", -1) + ic.endBatchEdit() + processChildEvents() + + assertText("commit ()", ic, "( )") + } + // Bug 1593683 - Cursor is jumping when using the arrow keys in input field on GBoard @WithDisplay(width = 512, height = 512) // Child process updates require having a display. @@ -1294,7 +1321,14 @@ class TextInputDelegateTest : BaseSessionTest() { pressKey(ic, KeyEvent.KEYCODE_DPAD_LEFT) pressKey(ic, KeyEvent.KEYCODE_DPAD_LEFT) pressKey(ic, KeyEvent.KEYCODE_DPAD_LEFT) - assertSelection("IME caret is moved to top", ic, 0, 0, /* checkGecko */ false) + assertSelection( + "IME caret is moved to top", + ic, + 0, + 0, + /* checkGecko */ + false, + ) setComposingText(ic, "bar", 1) finishComposingText(ic) diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TrackingPermissionService.java b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TrackingPermissionService.java index 141849589e..4b7bcabee5 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TrackingPermissionService.java +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TrackingPermissionService.java @@ -36,7 +36,8 @@ public class TrackingPermissionService extends TestRuntimeService { public void onLocationChange( final @NonNull GeckoSession session, final @Nullable String url, - final @NonNull List perms) { + final @NonNull List perms, + final @NonNull Boolean hasUserGesture) { for (ContentPermission perm : perms) { if (perm.permission == PermissionDelegate.PERMISSION_TRACKING) { mContentPermission = perm; diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VideoCaptureTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VideoCaptureTest.kt new file mode 100644 index 0000000000..7e1f8b1275 --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VideoCaptureTest.kt @@ -0,0 +1,58 @@ +package org.mozilla.geckoview.test + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.webrtc.CameraEnumerationAndroid.CaptureFormat +import org.webrtc.CameraEnumerator +import org.webrtc.CameraVideoCapturer +import org.webrtc.CameraVideoCapturer.CameraEventsHandler +import org.webrtc.videoengine.VideoCaptureAndroid + +@RunWith(AndroidJUnit4::class) +@SmallTest +class VideoCaptureTest { + // Always throw exception. + class BadCameraEnumerator : CameraEnumerator { + override fun getDeviceNames(): Array? { + throw java.lang.RuntimeException("") + } + + override fun isFrontFacing(deviceName: String?): Boolean { + throw java.lang.RuntimeException("") + } + + override fun isBackFacing(deviceName: String?): Boolean { + throw java.lang.RuntimeException("") + } + + override fun isInfrared(deviceName: String?): Boolean { + throw java.lang.RuntimeException("") + } + + override fun getSupportedFormats(deviceName: String?): List? { + throw java.lang.RuntimeException("") + } + + override fun createCapturer( + deviceName: String?, + eventsHandler: CameraEventsHandler?, + ): CameraVideoCapturer? { + throw java.lang.RuntimeException("") + } + } + + @Test + fun constructWithBadEnumerator() { + val ctr = VideoCaptureAndroid::class.java.getDeclaredConstructors()[0].apply { isAccessible = true } + val capture = ctr.newInstance( + InstrumentationRegistry.getInstrumentation().targetContext, + "my camera", + BadCameraEnumerator(), + ) as VideoCaptureAndroid + assertEquals(false, capture.canCapture()) + } +} diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExtensionTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExtensionTest.kt index 126e52da34..702ba4d23b 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExtensionTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExtensionTest.kt @@ -7,6 +7,7 @@ package org.mozilla.geckoview.test import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers import org.hamcrest.Matchers.greaterThan import org.hamcrest.core.IsEqual.equalTo import org.hamcrest.core.StringEndsWith.endsWith @@ -90,6 +91,14 @@ class WebExtensionTest : BaseSessionTest() { assertTrue(borderify.isBuiltIn) + assertArrayEquals( + arrayOf("*://developer.mozilla.org/*"), + borderify.metaData.optionalOrigins, + ) + assertArrayEquals( + arrayOf("clipboardRead"), + borderify.metaData.optionalPermissions, + ) mainSession.reload() sessionRule.waitForPageStop() @@ -109,6 +118,156 @@ class WebExtensionTest : BaseSessionTest() { assertBodyBorderEqualTo("") } + @Test + fun verifyOptionalAndOriginsPermissionsMV3() { + mainSession.loadUri("https://example.com") + sessionRule.waitForPageStop() + + // First let's check that the color of the border is empty before loading + // the WebExtension + assertBodyBorderEqualTo("") + + // Load the WebExtension that will add a border to the body + val borderify = sessionRule.waitForResult( + controller.installBuiltIn( + "resource://android/assets/web_extensions/borderify-mv3/", + ), + ) + + assertArrayEquals( + arrayOf("clipboardRead"), + borderify.metaData.optionalPermissions, + ) + + val expectedOptionalOrigins = arrayOf( + "*://*.example.com/*", + "*://opt-host-perm.example.com/*", + "*://host-perm.example.com/*", + ) + + expectedOptionalOrigins.sort() + borderify.metaData.optionalOrigins.sort() + + assertArrayEquals( + expectedOptionalOrigins, + borderify.metaData.optionalOrigins, + ) + + mainSession.reload() + sessionRule.waitForPageStop() + + // Check that the WebExtension was applied by checking the border color + assertBodyBorderEqualTo("red") + + // Uninstall WebExtension and check again + sessionRule.waitForResult(controller.uninstall(borderify)) + + mainSession.reload() + sessionRule.waitForPageStop() + + // Check that the WebExtension was not applied after being uninstalled + assertBodyBorderEqualTo("") + } + + @WithDisplay(width = 100, height = 100) + @Test + fun grantedOptionalPermissions() { + sessionRule.setPrefsUntilTestEnd( + mapOf( + "xpinstall.signatures.required" to false, + "extensions.install.requireBuiltInCerts" to false, + "extensions.update.requireBuiltInCerts" to false, + ), + ) + + val extension = sessionRule.waitForResult( + controller.ensureBuiltIn( + "resource://android/assets/web_extensions/optional-permission-request/", + "optional-permission-request@example.com", + ), + ) + + assertEquals("optional-permission-request@example.com", extension.id) + + mainSession.loadUri("${extension.metaData.baseUrl}clickToRequestPermission.html") + sessionRule.waitForPageStop() + + var grantedOptionalPermissions = extension.metaData.grantedOptionalPermissions + var grantedOptionalOrigins = extension.metaData.grantedOptionalOrigins + + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 0.", grantedOptionalOrigins.size, equalTo(0)) + + // click triggers permissions.request + mainSession.synthesizeTap(50, 50) + + sessionRule.delegateUntilTestEnd(object : WebExtensionController.PromptDelegate { + override fun onOptionalPrompt( + extension: WebExtension, + permissions: Array, + origins: Array, + ): GeckoResult { + return GeckoResult.allow() + } + }) + + var result = GeckoResult() + mainSession.webExtensionController.setMessageDelegate( + extension, + object : WebExtension.MessageDelegate { + override fun onMessage( + nativeApp: String, + message: Any, + sender: WebExtension.MessageSender, + ): GeckoResult? { + result.complete(message as String) + return null + } + }, + "browser", + ) + + result = GeckoResult() + val message = sessionRule.waitForResult(result) + assertThat("Permission request should be accepted.", message, equalTo("true")) + + val updatedExtension = sessionRule.waitForResult( + // Adds "internal:privateBrowsingAllowed" + controller.setAllowedInPrivateBrowsing(extension, true), + ) + + grantedOptionalPermissions = updatedExtension.metaData.grantedOptionalPermissions + grantedOptionalOrigins = updatedExtension.metaData.grantedOptionalOrigins + + assertThat( + "grantedOptionalPermissions must be 1.", + grantedOptionalPermissions.size, + equalTo(1), + ) + assertThat("grantedOptionalOrigins must be 1.", grantedOptionalOrigins.size, equalTo(1)) + assertThat( + "grantedOptionalOrigins must be *://example.com/*.", + grantedOptionalOrigins.first(), + equalTo("*://example.com/*"), + ) + + // geolocation is part of the manifest but not requested/granted. + assertFalse(grantedOptionalPermissions.contains("geolocation")) + + // "internal:privateBrowsingAllowed" must not be part of grantedOptionalPermissions. + assertThat( + "grantedOptionalPermissions must be activeTab.", + grantedOptionalPermissions.first(), + equalTo("activeTab"), + ) + + sessionRule.waitForResult(controller.uninstall(extension)) + } + private fun assertBodyBorderEqualTo(expected: String) { val color = mainSession.evaluateJS("document.body.style.borderColor") assertThat( @@ -1618,6 +1777,11 @@ class WebExtensionTest : BaseSessionTest() { // - verifies that the messages are received when restoring the tab in a fresh session @Test fun testRestoringExtensionPagePreservesMessages() { + // TODO: Bug 1884334 + val geckoPrefs = sessionRule.getPrefs( + "fission.disableSessionHistoryInParent", + ) + assumeThat(geckoPrefs[0] as Boolean, Matchers.equalTo(true)) // TODO: Bug 1837551 assumeThat(sessionRule.env.isFission, equalTo(false)) @@ -2138,7 +2302,7 @@ class WebExtensionTest : BaseSessionTest() { mainSession.waitUntilCalled(object : NavigationDelegate, ProgressDelegate { @GeckoSessionTestRule.AssertCalled(count = 1) - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { assertThat( "Url should load example.com first", url, @@ -2160,7 +2324,7 @@ class WebExtensionTest : BaseSessionTest() { val pageStop = GeckoResult() mainSession.delegateUntilTestEnd(object : NavigationDelegate, ProgressDelegate { - override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList) { + override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList, hasUserGesture: Boolean) { page = url } diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt index 469fd049ce..358134313a 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebNotificationTest.kt @@ -31,8 +31,7 @@ class WebNotificationTest : BaseSessionTest() { // Grant "desktop notification" permission mainSession.delegateUntilTestEnd(object : PermissionDelegate { - override fun onContentPermissionRequest(session: GeckoSession, perm: PermissionDelegate.ContentPermission): - GeckoResult? { + override fun onContentPermissionRequest(session: GeckoSession, perm: PermissionDelegate.ContentPermission): GeckoResult? { assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION)) return GeckoResult.fromValue(PermissionDelegate.ContentPermission.VALUE_ALLOW) } @@ -336,7 +335,11 @@ class WebNotificationTest : BaseSessionTest() { // Test that we can serialize a notification val parcel = Parcel.obtain() - notification.writeToParcel(parcel, /* ignored */ -1) + notification.writeToParcel( + parcel, + /* ignored */ + -1, + ) assertThat("Promise should have been resolved.", promiseResult.value as Double, equalTo(1.0)) } @@ -375,7 +378,11 @@ class WebNotificationTest : BaseSessionTest() { // Test that we can serialize a notification with an imageUrl.length >= 150 val parcel = Parcel.obtain() - notification.writeToParcel(parcel, /* ignored */ -1) + notification.writeToParcel( + parcel, + /* ignored */ + -1, + ) parcel.setDataPosition(0) val serializedNotification = WebNotification.CREATOR.createFromParcel(parcel) diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebPushTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebPushTest.kt index a2e6d58f3a..609275526c 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebPushTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebPushTest.kt @@ -60,8 +60,7 @@ class WebPushTest : BaseSessionTest() { sessionRule.setPrefsUntilTestEnd(mapOf("dom.webnotifications.requireuserinteraction" to false)) // Grant "desktop notification" permission mainSession.delegateUntilTestEnd(object : PermissionDelegate { - override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission): - GeckoResult? { + override fun onContentPermissionRequest(session: GeckoSession, perm: GeckoSession.PermissionDelegate.ContentPermission): GeckoResult? { assertThat("Should grant DESKTOP_NOTIFICATIONS permission", perm.permission, equalTo(GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION)) return GeckoResult.fromValue(GeckoSession.PermissionDelegate.ContentPermission.VALUE_ALLOW) } diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java index 9c9a9d6188..727f403931 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java @@ -831,7 +831,8 @@ public class GeckoSessionTestRule implements TestRule { public void onLocationChange( @NonNull GeckoSession session, @Nullable String url, - @NonNull List perms) {} + @NonNull List perms, + @NonNull Boolean hasUserGesture) {} @Override public void onShutdown() {} diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/AndroidGamepadManager.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/AndroidGamepadManager.java index 99be57fc12..3672428a98 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/AndroidGamepadManager.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/AndroidGamepadManager.java @@ -159,9 +159,9 @@ public class AndroidGamepadManager { /* package */ static void doStart(final Context context) { ThreadUtils.assertOnUiThread(); if (!sStarted) { + sStarted = true; scanForGamepads(); addDeviceListener(context); - sStarted = true; } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index 568fc3a0bb..bcd5762a92 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -46,7 +46,6 @@ import android.os.Looper; import android.os.PowerManager; import android.os.Vibrator; import android.provider.Settings; -import android.text.TextUtils; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.Display; @@ -1527,20 +1526,6 @@ public class GeckoAppShell { } } - private static String getLanguageTag(final Locale locale) { - final StringBuilder out = new StringBuilder(locale.getLanguage()); - final String country = locale.getCountry(); - final String variant = locale.getVariant(); - if (!TextUtils.isEmpty(country)) { - out.append('-').append(country); - } - if (!TextUtils.isEmpty(variant)) { - out.append('-').append(variant); - } - // e.g. "en", "en-US", or "en-US-POSIX". - return out.toString(); - } - @WrapForJNI public static String[] getDefaultLocales() { // XXX We may have to convert some language codes such as "id" vs "in". diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoDragAndDrop.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoDragAndDrop.java index 9c1473d4e7..d529449d5a 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoDragAndDrop.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoDragAndDrop.java @@ -42,7 +42,11 @@ public class GeckoDragAndDrop { private final Bitmap mBitmap; public DrawDragImage(final Bitmap bitmap) { - mBitmap = bitmap; + if (bitmap != null && bitmap.getWidth() > 0 && bitmap.getHeight() > 0) { + mBitmap = bitmap; + return; + } + mBitmap = null; } @Override diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/InputMethods.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/InputMethods.java index 120098a931..56fd0d9853 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/InputMethods.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/InputMethods.java @@ -6,11 +6,13 @@ package org.mozilla.gecko; import android.content.Context; +import android.os.Build; import android.provider.Settings.Secure; import android.view.View; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import java.util.Collection; +import java.util.Locale; public final class InputMethods { public static final String METHOD_ANDROID_LATINIME = "com.android.inputmethod.latin/.LatinIME"; @@ -99,6 +101,13 @@ public final class InputMethods { return METHOD_SONY.equals(inputMethod); } + // Workaround for bug 1818268 - Unexpected crash on Galaxy J7 + public static boolean dontOverrideCommitText() { + return Build.VERSION.SDK_INT == 23 + && Build.MANUFACTURER.toLowerCase(Locale.ROOT).equals("samsung") + && Build.MODEL.startsWith("SM-J700F"); + } + // TODO: Replace usages by definition in EditorInfoCompat once available (bug 1385726). public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000; } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/MediaDrmProxy.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/MediaDrmProxy.java index 1bfab37063..4ab8b10f9f 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/MediaDrmProxy.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/MediaDrmProxy.java @@ -23,6 +23,7 @@ public final class MediaDrmProxy { private static final String WIDEVINE_KEY_SYSTEM = "com.widevine.alpha"; @WrapForJNI private static final String AAC = "audio/mp4a-latm"; @WrapForJNI private static final String AVC = "video/avc"; + @WrapForJNI private static final String AV1 = "video/av01"; @WrapForJNI private static final String VORBIS = "audio/vorbis"; @WrapForJNI private static final String VP8 = "video/x-vnd.on2.vp8"; @WrapForJNI private static final String VP9 = "video/x-vnd.on2.vp9"; diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/LocaleUtils.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/LocaleUtils.java new file mode 100644 index 0000000000..8e4addc7b0 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/LocaleUtils.java @@ -0,0 +1,32 @@ +/* -*- Mode: Java; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*- */ +/* vim: set ts=2 et sw=2: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.util; + +import android.text.TextUtils; +import java.util.Locale; + +public class LocaleUtils { + // Locale.getLanguage() may return legacy language code until Java 17 + // https://developer.android.com/reference/java/util/Locale#legacy_language_codes + public static String getLanguageTagForAcceptLanguage(final Locale locale) { + String language = locale.getLanguage(); + if (language.equals("in")) { + language = "id"; + } else if (language.equals("iw")) { + language = "he"; + } else if (language.equals("ji")) { + language = "yi"; + } + final StringBuilder out = new StringBuilder(language); + final String country = locale.getCountry(); + if (!TextUtils.isEmpty(country)) { + out.append('-').append(country); + } + // e.g. "en", "en-US" + return out.toString(); + } +} diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentInputStream.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentInputStream.java index aa3f5c3174..bc9eff98f0 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentInputStream.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentInputStream.java @@ -37,6 +37,11 @@ import org.mozilla.gecko.annotation.WrapForJNI; try { mFd = cr.openAssetFileDescriptor(uri, "r"); + if (mFd == null) { + Log.e(LOGTAG, "Cannot open the uri: " + aUri + " (no file descriptor)"); + close(); + return; + } setInputStream(mFd.createInputStream()); if (!checkHeaders(HEADERS)) { @@ -127,7 +132,17 @@ import org.mozilla.gecko.annotation.WrapForJNI; || isExported(context, uri) || wasGrantedPermission(context, uri)) { final ContentResolver cr = context.getContentResolver(); - cr.openAssetFileDescriptor(uri, "r").close(); + if (cr == null) { + Log.e(LOGTAG, "No content resolver"); + return false; + } + final AssetFileDescriptor fd = cr.openAssetFileDescriptor(uri, "r"); + if (fd == null) { + // The descriptor can be null because the provider crashed. + Log.e(LOGTAG, "No asset file descriptor"); + return false; + } + fd.close(); Log.d(LOGTAG, "The uri is readable: " + uri); return true; } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoInputConnection.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoInputConnection.java index 5426adb501..2e8f2e55d7 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoInputConnection.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoInputConnection.java @@ -655,6 +655,53 @@ import org.mozilla.gecko.util.ThreadUtils; return replaceComposingSpanWithSelection() && mKeyInputConnection.commitText(text, newCursorPosition); } + + // Bug 1818268 - Unexpected crash on Galaxy J7 + if (InputMethods.dontOverrideCommitText()) { + return super.commitText(text, newCursorPosition); + } + + // Default implementation is + // 1. Set selection + // 2. Call Editable.replace + // 3. Set selection in Editable.replace + // + // However, this results in additional IPC in Gecko and unexpected selection before replacing + // text. + // When changing text in Gecko, the selection will be updated, so the default implementation is + // not compatible with Gecko's text handling. + // Therefore, we set the selection after replacing the text. However, if there is a composition, + // the selection may be an IME cursor, not a standard selection. In such cases, this step is not + // necessary. + final Editable content = getEditable(); + if (content != null) { + final int compositionStart = getComposingSpanStart(content); + final int compositionEnd = getComposingSpanEnd(content); + + if (compositionStart < 0 || compositionEnd < 0) { + // No composition + int selStart = Math.max(Selection.getSelectionStart(content), 0); + int selEnd = Math.max(Selection.getSelectionEnd(content), 0); + if (selStart > selEnd) { + final int tmp = selEnd; + selEnd = selStart; + selStart = tmp; + } + + beginBatchEdit(); + content.replace(selStart, selEnd, text); + + int cursorPosition = + newCursorPosition > 0 + ? selStart + text.length() + newCursorPosition - 1 + : selStart + newCursorPosition; + cursorPosition = Math.min(Math.max(0, cursorPosition), content.length()); + Selection.setSelection(content, cursorPosition); + endBatchEdit(); + return true; + } + } + return super.commitText(text, newCursorPosition); } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java index 3da044e603..0a80b02b04 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java @@ -27,6 +27,7 @@ import java.util.Locale; import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.GeckoSystemStateListener; import org.mozilla.gecko.util.GeckoBundle; +import org.mozilla.gecko.util.LocaleUtils; @AnyThread public final class GeckoRuntimeSettings extends RuntimeSettings { @@ -462,6 +463,8 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { * @param delegate the delegate that will handle telemetry * @return The builder instance. */ + @Deprecated + @DeprecationSchedule(id = "geckoview-gvst", version = 127) public @NonNull Builder telemetryDelegate(final @NonNull RuntimeTelemetry.Delegate delegate) { getSettings().mTelemetryProxy = new RuntimeTelemetry.Proxy(delegate); getSettings().mTelemetryEnabled.set(true); @@ -1054,7 +1057,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { } } // OS prefs come second: - for (final String locale : getDefaultLocales()) { + for (final String locale : getSystemLocalesForAcceptLanguage()) { final String localeLowerCase = locale.toLowerCase(Locale.ROOT); if (!locales.containsKey(localeLowerCase)) { locales.put(localeLowerCase, locale); @@ -1064,35 +1067,22 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { return TextUtils.join(",", locales.values()); } - private static String[] getDefaultLocales() { + private static String[] getSystemLocalesForAcceptLanguage() { if (VERSION.SDK_INT >= 24) { final LocaleList localeList = LocaleList.getDefault(); final String[] locales = new String[localeList.size()]; for (int i = 0; i < localeList.size(); i++) { - locales[i] = localeList.get(i).toLanguageTag(); + // accept-language should be language or language-region format. + locales[i] = LocaleUtils.getLanguageTagForAcceptLanguage(localeList.get(i)); } return locales; } final String[] locales = new String[1]; final Locale locale = Locale.getDefault(); - locales[0] = locale.toLanguageTag(); + locales[0] = LocaleUtils.getLanguageTagForAcceptLanguage(locale); return locales; } - private static String getLanguageTag(final Locale locale) { - final StringBuilder out = new StringBuilder(locale.getLanguage()); - final String country = locale.getCountry(); - final String variant = locale.getVariant(); - if (!TextUtils.isEmpty(country)) { - out.append('-').append(country); - } - if (!TextUtils.isEmpty(variant)) { - out.append('-').append(variant); - } - // e.g. "en", "en-US", or "en-US-POSIX". - return out.toString(); - } - /** * Sets whether Web Manifest processing support is enabled. * diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java index f8f7f858e3..85b3abf9a9 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java @@ -685,7 +685,11 @@ public class GeckoSession { final GeckoBundle[] perms = message.getBundleArray("permissions"); final List permList = PermissionDelegate.ContentPermission.fromBundleArray(perms); - delegate.onLocationChange(GeckoSession.this, message.getString("uri"), permList); + delegate.onLocationChange( + GeckoSession.this, + message.getString("uri"), + permList, + message.getBoolean("hasUserGesture")); } delegate.onCanGoBack(GeckoSession.this, message.getBoolean("canGoBack")); delegate.onCanGoForward(GeckoSession.this, message.getBoolean("canGoForward")); @@ -1928,7 +1932,7 @@ public class GeckoSession { // https://searchfox.org/mozilla-central/source/docshell/base/nsIWebNavigation.idl // // We do not use the same values directly in order to insulate ourselves from - // changes in Gecko. Instead, the flags are converted in GeckoViewNavigation.jsm. + // changes in Gecko. Instead, the flags are converted in GeckoViewNavigation.sys.mjs. /** Default load flag, no special considerations. */ public static final int LOAD_FLAGS_NONE = 0; @@ -4935,16 +4939,38 @@ public class GeckoSession { /** * A view has started loading content from the network. * + * @deprecated use {@link #onLocationChange(GeckoSession, String, + * List, Boolean) onLocationChange} instead * @param session The GeckoSession that initiated the callback. * @param url The resource being loaded. * @param perms The permissions currently associated with this url. */ @UiThread + @Deprecated + @DeprecationSchedule(id = "geckoview-onlocationchange", version = 127) default void onLocationChange( @NonNull GeckoSession session, @Nullable String url, final @NonNull List perms) {} + /** + * A view has started loading content from the network. + * + * @param session The GeckoSession that initiated the callback. + * @param url The resource being loaded. + * @param perms The permissions currently associated with this url. + * @param hasUserGesture Whether or not there was an active user gesture when the location + * change was requested. + */ + @UiThread + default void onLocationChange( + @NonNull GeckoSession session, + @Nullable String url, + final @NonNull List perms, + final @NonNull Boolean hasUserGesture) { + session.getNavigationDelegate().onLocationChange(session, url, perms); + } + /** * The view's ability to go back has changed. * diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java index 046f7a3072..14f6b14c47 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java @@ -203,7 +203,7 @@ public final class GeckoSessionSettings implements Parcelable { }) public @interface DisplayMode {} - // This needs to match GeckoViewSettings.jsm + // This needs to match GeckoViewSettings.sys.mjs /** "browser" value of the display member in Web App Manifests */ public static final int DISPLAY_MODE_BROWSER = 0; @@ -225,7 +225,7 @@ public final class GeckoSessionSettings implements Parcelable { }) public @interface UserAgentMode {} - // This needs to match GeckoViewSettingsChild.js and GeckoViewSettings.jsm + // This needs to match GeckoViewSettingsChild.js and GeckoViewSettings.sys.mjs /** The user agent mode is mobile device */ public static final int USER_AGENT_MODE_MOBILE = 0; diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java index 74eccaeb15..2271ff71f7 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java @@ -767,6 +767,9 @@ public class GeckoView extends FrameLayout implements GeckoDisplay.NewSurfacePro if (super.onKeyUp(keyCode, event)) { return true; } + if (AndroidGamepadManager.handleKeyEvent(event)) { + return true; + } return mSession != null && mSession.getTextInput().onKeyUp(keyCode, event); } @@ -775,6 +778,9 @@ public class GeckoView extends FrameLayout implements GeckoDisplay.NewSurfacePro if (super.onKeyDown(keyCode, event)) { return true; } + if (AndroidGamepadManager.handleKeyEvent(event)) { + return true; + } return mSession != null && mSession.getTextInput().onKeyDown(keyCode, event); } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java index d553a1aa3f..1caa5508ed 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java @@ -1688,7 +1688,7 @@ public class WebExtension { * in Firefox. */ public static class SignedStateFlags { - // Keep in sync with AddonManager.jsm + // Keep in sync with AddonManager.sys.mjs /** * This extension may be signed but by a certificate that doesn't chain to our our trusted * certificate. @@ -1819,6 +1819,50 @@ public class WebExtension { */ public final @NonNull String[] permissions; + /** + * API optional + * permissions requested or granted to this extension. + * + *

Permission identifiers match entries in the manifest, see + * API permissions . + */ + public final @NonNull String[] optionalPermissions; + + /** + * API optional + * permissions granted to this extension. + * + *

Permission identifiers match entries in the manifest, see + * API permissions . + */ + public final @NonNull String[] grantedOptionalPermissions; + + /** + * API + * optional origin permissions requested or granted to this extension. + * + *

Permission identifiers match entries in the manifest, see + * API permissions . + */ + public final @NonNull String[] optionalOrigins; + + /** + * API + * optional origin permissions granted to this extension. + * + *

Permission identifiers match entries in the manifest, see + * API permissions . + */ + public final @NonNull String[] grantedOptionalOrigins; + /** * Host permissions requested or granted to this extension. * @@ -1999,6 +2043,10 @@ public class WebExtension { protected MetaData() { icon = null; permissions = null; + optionalPermissions = null; + grantedOptionalPermissions = null; + grantedOptionalOrigins = null; + optionalOrigins = null; origins = null; name = null; description = null; @@ -2029,6 +2077,10 @@ public class WebExtension { /* package */ MetaData(final GeckoBundle bundle) { // We only expose permissions that the embedder should prompt for permissions = bundle.getStringArray("promptPermissions"); + optionalPermissions = bundle.getStringArray("optionalPermissions"); + grantedOptionalPermissions = bundle.getStringArray("grantedOptionalPermissions"); + optionalOrigins = bundle.getStringArray("optionalOrigins"); + grantedOptionalOrigins = bundle.getStringArray("grantedOptionalOrigins"); origins = bundle.getStringArray("origins"); description = bundle.getString("description"); version = bundle.getString("version"); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md index 10a6eb16cd..5776cf5afc 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md @@ -13,6 +13,27 @@ exclude: true ⚠️ breaking change and deprecation notices +## v125 +- ⚠️ Deprecated [`GeckoSession.NavigationDelegate.onLocationChange`][125.1], to be removed in v127. +([bug 1837601]({{bugzilla}}1837601)) +- Added [`GeckoSession.NavigationDelegate.onLocationChange#hasUserGesture`][125.2]. This indicates if a location change was requested +while a user gesture was active (e.g., a tap). +([bug 1837601]({{bugzilla}}1837601)) +- Added [`WebExtension.MetaData.optionalPermissions`][125.3] and [`WebExtension.MetaData.optionalOrigins`][125.4] which expose the optional and origin optional permissions of an extension ([bug 1811900]({{bugzilla}}1811900)). +- ⚠️ Deprecated [`RuntimeTelemetry`][125.5], [`GeckoRuntimeSettings.getTelemetryDelegate`][125.6] and [`GeckoRuntimeSettings.telemetryDelegate`][125.7], to be removed in v127. +([bug 1877836]({{bugzilla}}1877836)) +- Added [`WebExtension.MetaData.grantedOptionalPermissions`][125.8] and [`WebExtension.MetaData.grantedOptionalOrigins`][125.9] which expose the granted optional and origin optional permissions of an extension ([bug 1879543]({{bugzilla}}1879543)). + +[125.1]: {{javadoc_uri}}/GeckoSession.NavigationDelegate#onLocationChange(org.mozilla.geckoview.GeckoSession,java.lang.String,java.util.List) +[125.2]: {{javadoc_uri}}/GeckoSession.NavigationDelegate#onLocationChange(org.mozilla.geckoview.GeckoSession,java.lang.String,java.util.List,boolean) +[125.3]: {{javadoc_uri}}/WebExtension.MetaData.html#optionalPermissions +[125.4]: {{javadoc_uri}}/WebExtension.MetaData.html#optionalOrigins +[125.5]: {{javadoc_uri}}/RuntimeTelemetry.html +[125.6]: {{javadoc_uri}}/GeckoRuntimeSettings.html#getTelemetryDelegate +[125.7]: {{javadoc_uri}}/GeckoRuntimeSettings.html#telemetryDelegate +[125.8]: {{javadoc_uri}}/WebExtension.MetaData.html#grantedOptionalPermissions +[125.9]: {{javadoc_uri}}/WebExtension.MetaData.html#grantedOptionalOrigins + ## v124 - Added [`GeckoRuntimeSettings#setTrustedRecursiveResolverMode`][124.1] to enable DNS-over-HTTPS using different resolver modes ([bug 1591533]({{bugzilla}}1591533)). @@ -36,7 +57,7 @@ exclude: true [123.1]: {{javadoc_uri}}/TranslationsController.RuntimeTranslation.html#checkPairDownloadSize(java.lang.String,java.lang.String) [123.2]: {{javadoc_uri}}/TranslationsController.TranslationsException.html#ERROR_MODEL_LANGUAGE_REQUIRED -[121.3]: {{javadoc_uri}}/GeckoSession.html#sendPlacementAttributionEvent(String) +[123.3]: {{javadoc_uri}}/GeckoSession.html#sendPlacementAttributionEvent(String) ## v122 - ⚠️ Removed [`onGetNimbusFeature`][115.5], please use `ExperimentDelegate.onGetExperimentFeature` instead. @@ -1519,4 +1540,4 @@ to allow adding gecko profiler markers. [65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport(android.content.Context,android.os.Bundle,java.lang.String) [65.25]: {{javadoc_uri}}/GeckoResult.html -[api-version]: ff5a513251f19534bbf4ebe0084909665d00a227 +[api-version]: fc9fd590333bebf38058b7abddbb7a860cd6e4de diff --git a/mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/LocaleUtilsTest.java b/mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/LocaleUtilsTest.java new file mode 100644 index 0000000000..bc6dcc0ced --- /dev/null +++ b/mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/LocaleUtilsTest.java @@ -0,0 +1,47 @@ +/* Any copyright is dedicated to the Public Domain. +http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.gecko.util; + +import static org.junit.Assert.*; + +import android.test.suitebuilder.annotation.SmallTest; +import java.util.Locale; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +@SmallTest +public class LocaleUtilsTest { + @Test + public void languageTagForAcceptLanguage() { + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("zn-Hans-CN")), "zn-CN"); + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("zn-Hant-TW")), "zn-TW"); + + // If builder is Java 17+, Locale.getLanguage doesn't repelace with old language code. + // But we should keep this to make things understandable. + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("id-ID")), "id-ID"); + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("in-ID")), "id-ID"); + + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("yi-US")), "yi-US"); + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("ji-US")), "yi-US"); + + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("he-IL")), "he-IL"); + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage(Locale.forLanguageTag("iw-IL")), "he-IL"); + + // Android 14 may add extension (Bug 1873578) + assertEquals( + LocaleUtils.getLanguageTagForAcceptLanguage( + Locale.forLanguageTag("en-US-u-fw-mon-mu-celsius")), + "en-US"); + } +} -- cgit v1.2.3