From def92d1b8e9d373e2f6f27c366d578d97d8960c6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:34:50 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- .../geckoview/src/androidTest/AndroidManifest.xml | 3 +- .../assets/web_extensions/langpack_signed.xpi | Bin 4452 -> 7593 bytes .../options_page_alias/manifest.json | 12 + .../src/androidTest/assets/www/badVideoPath.html | 2 +- .../geckoview/src/androidTest/assets/www/ogg.html | 11 - .../src/androidTest/assets/www/videos/video.ogg | Bin 285310 -> 0 bytes .../mozilla/geckoview/test/AccessibilityTest.kt | 3 +- .../org/mozilla/geckoview/test/BaseSessionTest.kt | 1 - .../geckoview/test/ContentDelegateChildTest.kt | 196 ++++++++++++++++ .../geckoview/test/NavigationDelegateTest.kt | 24 ++ .../mozilla/geckoview/test/VerticalClippingTest.kt | 3 - .../org/mozilla/geckoview/test/WebExtensionTest.kt | 252 ++++++++++++++++++++- 12 files changed, 487 insertions(+), 20 deletions(-) create mode 100644 mobile/android/geckoview/src/androidTest/assets/web_extensions/options_page_alias/manifest.json delete mode 100644 mobile/android/geckoview/src/androidTest/assets/www/ogg.html delete mode 100644 mobile/android/geckoview/src/androidTest/assets/www/videos/video.ogg (limited to 'mobile/android/geckoview/src/androidTest') diff --git a/mobile/android/geckoview/src/androidTest/AndroidManifest.xml b/mobile/android/geckoview/src/androidTest/AndroidManifest.xml index 4dc4760d0f..2a6e47aa92 100644 --- a/mobile/android/geckoview/src/androidTest/AndroidManifest.xml +++ b/mobile/android/geckoview/src/androidTest/AndroidManifest.xml @@ -17,8 +17,7 @@ android:allowBackup="true" android:label="@string/app_name" android:supportsRtl="true" - android:theme="@style/AppTheme" - android:name="androidx.multidex.MultiDexApplication"> + android:theme="@style/AppTheme"> diff --git a/mobile/android/geckoview/src/androidTest/assets/www/ogg.html b/mobile/android/geckoview/src/androidTest/assets/www/ogg.html deleted file mode 100644 index dd478d3b3f..0000000000 --- a/mobile/android/geckoview/src/androidTest/assets/www/ogg.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - OGG Video - - - - - diff --git a/mobile/android/geckoview/src/androidTest/assets/www/videos/video.ogg b/mobile/android/geckoview/src/androidTest/assets/www/videos/video.ogg deleted file mode 100644 index ac7ece3519..0000000000 Binary files a/mobile/android/geckoview/src/androidTest/assets/www/videos/video.ogg and /dev/null differ diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt index 6e2d79e0b0..8e87c1d478 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt @@ -1071,7 +1071,8 @@ class AccessibilityTest : BaseSessionTest() { override fun onFocused(event: AccessibilityEvent) { nodeId = getSourceId(event) val node = createNodeInfo(nodeId) - assertThat("Focused outsideSelectable", node.text.toString(), equalTo("outside selectable")) + val nodeChild = createNodeInfo(node.getChildId(0)) + assertThat("Focused outsideSelectable", nodeChild.text.toString(), equalTo("outside selectable ")) } }) } 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 d57cd8f157..9bcba0f5b7 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 @@ -76,7 +76,6 @@ open class BaseSessionTest( const val TEST_GIF_PATH = "/assets/www/images/test.gif" const val TITLE_CHANGE_HTML_PATH = "/assets/www/titleChange.html" const val TRACKERS_PATH = "/assets/www/trackers.html" - const val VIDEO_OGG_PATH = "/assets/www/ogg.html" const val VIDEO_MP4_PATH = "/assets/www/mp4.html" const val VIDEO_WEBM_PATH = "/assets/www/webm.html" const val VIDEO_BAD_PATH = "/assets/www/badVideoPath.html" diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateChildTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateChildTest.kt index 511d58b5a6..a404935192 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateChildTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateChildTest.kt @@ -37,6 +37,88 @@ class ContentDelegateChildTest : BaseSessionTest() { mainSession.panZoomController.onTouchEvent(event) } + private fun sendRightClickDown(x: Float, y: Float) { + val downTime = SystemClock.uptimeMillis() + var eventTime = SystemClock.uptimeMillis() + + var pp = arrayOf(MotionEvent.PointerProperties()) + pp[0].id = 0 + pp[0].toolType = MotionEvent.TOOL_TYPE_MOUSE + + var pc = arrayOf(MotionEvent.PointerCoords()) + pc[0].x = x + pc[0].y = y + pc[0].pressure = 1.0f + pc[0].size = 1.0f + + var event = MotionEvent.obtain( + downTime, + eventTime, + MotionEvent.ACTION_DOWN, + /* pointerCount */ + 1, + pp, + pc, + /* metaState */ + 0, + MotionEvent.BUTTON_SECONDARY, + /* xPrecision */ + 1.0f, + /* yPrecision */ + 1.0f, + /* deviceId */ + 0, + /* edgeFlags */ + 0, + InputDevice.SOURCE_MOUSE, + /* flags */ + 0, + ) + mainSession.panZoomController.onTouchEvent(event) + } + + private fun sendRightClickUp(x: Float, y: Float) { + val downTime = SystemClock.uptimeMillis() + var eventTime = SystemClock.uptimeMillis() + + var pp = arrayOf(MotionEvent.PointerProperties()) + pp[0].id = 0 + pp[0].toolType = MotionEvent.TOOL_TYPE_MOUSE + + var pc = arrayOf(MotionEvent.PointerCoords()) + pc[0].x = x + pc[0].y = y + pc[0].pressure = 1.0f + pc[0].size = 1.0f + + var event = MotionEvent.obtain( + downTime, + eventTime, + MotionEvent.ACTION_UP, + /* pointerCount */ + 1, + pp, + pc, + /* metaState */ + 0, + // buttonState is unset in ACTION_UP + /* buttonState */ + 0, + /* xPrecision */ + 1.0f, + /* yPrecision */ + 1.0f, + /* deviceId */ + 0, + /* edgeFlags */ + 0, + InputDevice.SOURCE_MOUSE, + /* flags */ + 0, + ) + mainSession.panZoomController.onTouchEvent(event) + } + @WithDisplay(width = 100, height = 100) @Test fun requestContextMenuOnAudio() { @@ -276,6 +358,120 @@ class ContentDelegateChildTest : BaseSessionTest() { }) } + @WithDisplay(width = 100, height = 100) + @Test + fun requestContextMenuOnLinkRightClickMouseUp() { + sessionRule.setPrefsUntilTestEnd( + mapOf( + "ui.context_menus.after_mouseup" to true, + ), + ) + mainSession.loadTestPath(CONTEXT_MENU_LINK_HTML_PATH) + mainSession.waitForPageStop() + + sendRightClickDown(50f, 50f) + + mainSession.delegateDuringNextWait(object : ContentDelegate { + @AssertCalled(false) + override fun onContextMenu( + session: GeckoSession, + screenX: Int, + screenY: Int, + element: ContextElement, + ) {} + }) + + sendRightClickUp(50f, 50f) + + mainSession.delegateUntilTestEnd(object : ContentDelegate { + @AssertCalled(count = 1) + override fun onContextMenu( + session: GeckoSession, + screenX: Int, + screenY: Int, + element: ContextElement, + ) { + assertThat( + "Type should be none.", + element.type, + equalTo(ContextElement.TYPE_NONE), + ) + assertThat( + "The element link title should be the title of the anchor.", + element.title, + equalTo("Hello Link Title"), + ) + assertThat( + "The element link URI should be the href of the anchor.", + element.linkUri, + endsWith("hello.html"), + ) + assertThat( + "The element link text content should be the text content of the anchor.", + element.textContent, + equalTo("Hello World"), + ) + } + }) + } + + @WithDisplay(width = 100, height = 100) + @Test + fun requestContextMenuOnLinkRightClickMouseDown() { + sessionRule.setPrefsUntilTestEnd( + mapOf( + "ui.context_menus.after_mouseup" to false, + ), + ) + mainSession.loadTestPath(CONTEXT_MENU_LINK_HTML_PATH) + mainSession.waitForPageStop() + + sendRightClickDown(50f, 50f) + + mainSession.delegateDuringNextWait(object : ContentDelegate { + @AssertCalled(count = 1) + override fun onContextMenu( + session: GeckoSession, + screenX: Int, + screenY: Int, + element: ContextElement, + ) { + assertThat( + "Type should be none.", + element.type, + equalTo(ContextElement.TYPE_NONE), + ) + assertThat( + "The element link title should be the title of the anchor.", + element.title, + equalTo("Hello Link Title"), + ) + assertThat( + "The element link URI should be the href of the anchor.", + element.linkUri, + endsWith("hello.html"), + ) + assertThat( + "The element link text content should be the text content of the anchor.", + element.textContent, + equalTo("Hello World"), + ) + } + }) + + sendRightClickUp(50f, 50f) + + mainSession.delegateUntilTestEnd(object : ContentDelegate { + @AssertCalled(false) + override fun onContextMenu( + session: GeckoSession, + screenX: Int, + screenY: Int, + element: ContextElement, + ) {} + }) + } + @WithDisplay(width = 100, height = 100) @Test fun notRequestContextMenuWithPreventDefault() { 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 839ac4b468..4aec796d3e 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 @@ -2223,6 +2223,30 @@ class NavigationDelegateTest : BaseSessionTest() { ) } + @Test fun loadUriInPrivateSessionReferrerSession() { + val uri = "https://example.com/bar" + val referrer = "https://example.org/" + + mainSession.loadUri(referrer) + mainSession.waitForPageStop() + + val privateSettings = GeckoSessionSettings.Builder().usePrivateMode(true).build() + val newSession = sessionRule.createOpenSession(privateSettings) + newSession.load( + Loader() + .uri(uri) + .referrer(mainSession) + .flags(GeckoSession.LOAD_FLAGS_NONE), + ) + newSession.waitForPageStop() + + assertThat( + "Referrer should not sent", + newSession.evaluateJS("document.referrer") as String, + equalTo(""), + ) + } + @Test fun loadUriReferrerSessionFileUrl() { val uri = "file:///system/etc/fonts.xml" val referrer = "https://example.org" diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VerticalClippingTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VerticalClippingTest.kt index 2e340c09c2..5a3b1892ce 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VerticalClippingTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/VerticalClippingTest.kt @@ -11,7 +11,6 @@ import androidx.test.filters.MediumTest import org.hamcrest.Matchers import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.notNullValue -import org.junit.Assume.assumeThat import org.junit.Test import org.junit.runner.RunWith import org.mozilla.geckoview.GeckoResult @@ -71,8 +70,6 @@ class VerticalClippingTest : BaseSessionTest() { @WithDisplay(height = SCREEN_HEIGHT, width = SCREEN_WIDTH) @Test fun verticalClippingSucceeds() { - // Disable failing test on Webrender. Bug 1670267 - assumeThat(sessionRule.env.isWebrender, equalTo(false)) sessionRule.display?.setVerticalClipping(45) mainSession.loadTestPath(FIXED_BOTTOM) sessionRule.waitUntilCalled(object : ContentDelegate { 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 702ba4d23b..fa5caa8693 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 @@ -268,6 +268,220 @@ class WebExtensionTest : BaseSessionTest() { sessionRule.waitForResult(controller.uninstall(extension)) } + @Test + fun updateOptionalPermissions() { + var 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) + + var grantedOptionalPermissions = extension.metaData.grantedOptionalPermissions + var grantedOptionalOrigins = extension.metaData.grantedOptionalOrigins + + // Without adding any optional permissions. + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 0.", grantedOptionalOrigins.size, equalTo(0)) + + // Only adding an origin permission. + extension = sessionRule.waitForResult( + controller.addOptionalPermissions( + extension.id, + arrayOf(), + arrayOf("*://example.com/*"), + ), + ) + + grantedOptionalPermissions = extension.metaData.grantedOptionalPermissions + grantedOptionalOrigins = extension.metaData.grantedOptionalOrigins + + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 1.", grantedOptionalOrigins.size, equalTo(1)) + assertThat( + "grantedOptionalOrigins must be *://example.com/*.", + grantedOptionalOrigins.first(), + equalTo("*://example.com/*"), + ) + + // Adding "nothing" to verify that nothing gets changed. + extension = sessionRule.waitForResult( + controller.addOptionalPermissions( + extension.id, + arrayOf(), + arrayOf(), + ), + ) + + assertThat("grantedOptionalOrigins must be 1.", grantedOptionalOrigins.size, equalTo(1)) + assertThat( + "grantedOptionalOrigins must be *://example.com/*.", + grantedOptionalOrigins.first(), + equalTo("*://example.com/*"), + ) + + // Adding an optional permission. + extension = sessionRule.waitForResult( + controller.addOptionalPermissions( + extension.id, + arrayOf("activeTab"), + arrayOf(), + ), + ) + + grantedOptionalPermissions = extension.metaData.grantedOptionalPermissions + grantedOptionalOrigins = extension.metaData.grantedOptionalOrigins + + // Both optional and origin permissions must be granted. + assertThat( + "grantedOptionalPermissions must be 1.", + grantedOptionalPermissions.size, + equalTo(1), + ) + assertThat( + "grantedOptionalPermissions must be activeTab.", + grantedOptionalPermissions.first(), + equalTo("activeTab"), + ) + assertThat("grantedOptionalOrigins must be 1.", grantedOptionalOrigins.size, equalTo(1)) + assertThat( + "grantedOptionalOrigins must be *://example.com/*.", + grantedOptionalOrigins.first(), + equalTo("*://example.com/*"), + ) + + // Removing "nothing" to verify that nothing gets changed. + extension = sessionRule.waitForResult( + controller.removeOptionalPermissions( + extension.id, + arrayOf(), + arrayOf(), + ), + ) + + assertThat("grantedOptionalOrigins must be 1.", grantedOptionalOrigins.size, equalTo(1)) + assertThat( + "grantedOptionalOrigins must be *://example.com/*.", + grantedOptionalOrigins.first(), + equalTo("*://example.com/*"), + ) + + // Remove an activeTab optional permission. + extension = sessionRule.waitForResult( + controller.removeOptionalPermissions( + extension.id, + arrayOf("activeTab"), + arrayOf(), + ), + ) + + grantedOptionalPermissions = extension.metaData.grantedOptionalPermissions + grantedOptionalOrigins = extension.metaData.grantedOptionalOrigins + + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 1.", grantedOptionalOrigins.size, equalTo(1)) + assertThat( + "grantedOptionalOrigins must be *://example.com/*.", + grantedOptionalOrigins.first(), + equalTo("*://example.com/*"), + ) + + // Remove an `*://example.com/*` origin permission. + extension = sessionRule.waitForResult( + controller.removeOptionalPermissions( + extension.id, + arrayOf(), + arrayOf("*://example.com/*"), + ), + ) + + grantedOptionalPermissions = extension.metaData.grantedOptionalPermissions + grantedOptionalOrigins = extension.metaData.grantedOptionalOrigins + + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 0.", grantedOptionalOrigins.size, equalTo(0)) + + // Missing origins from the manifest. + // Must throw! + try { + extension = sessionRule.waitForResult( + controller.addOptionalPermissions( + extension.id, + arrayOf(), + arrayOf("*://missing-origins.com/*"), + ), + ) + fail() + } catch (_: Exception) { + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 0.", grantedOptionalOrigins.size, equalTo(0)) + } + + // Permission no in the manifest. + // Must throw! + try { + extension = sessionRule.waitForResult( + controller.addOptionalPermissions( + extension.id, + arrayOf("clipboardRead"), + arrayOf(), + ), + ) + fail() + } catch (_: Exception) { + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 0.", grantedOptionalOrigins.size, equalTo(0)) + } + + // Missing origins from the manifest. + // Must throw! + try { + extension = sessionRule.waitForResult( + controller.addOptionalPermissions( + extension.id, + arrayOf(), + arrayOf(""), + ), + ) + fail() + } catch (_: Exception) { + assertThat( + "grantedOptionalPermissions must be 0.", + grantedOptionalPermissions.size, + equalTo(0), + ) + assertThat("grantedOptionalOrigins must be 0.", grantedOptionalOrigins.size, equalTo(0)) + } + + sessionRule.waitForResult(controller.uninstall(extension)) + } + private fun assertBodyBorderEqualTo(expected: String) { val color = mainSession.evaluateJS("document.body.style.borderColor") assertThat( @@ -589,7 +803,7 @@ class WebExtensionTest : BaseSessionTest() { } @Test - fun optionsPageMetadata() { + fun optionsUIPageMetadata() { // dummy.xpi is not signed, but it could be sessionRule.setPrefsUntilTestEnd( mapOf( @@ -611,6 +825,7 @@ class WebExtensionTest : BaseSessionTest() { assertTrue(extension.metaData.baseUrl.matches("^moz-extension://[0-9a-f\\-]*/$".toRegex())) assertNotNull(extension.metaData.optionsPageUrl) assertTrue((extension.metaData.optionsPageUrl ?: "").matches("^moz-extension://[0-9a-f\\-]*/options.html$".toRegex())) + assertEquals(true, extension.metaData.openOptionsPageInTab) onReadyResult.complete(null) super.onReady(extension) } @@ -639,6 +854,41 @@ class WebExtensionTest : BaseSessionTest() { sessionRule.waitForResult(controller.uninstall(dummy)) } + @Test + fun optionsPageAliasMetadata() { + // NOTE: This test case tests options_page is considered an alternative alias for + // options_ui.page and the metadata to be set so that it is opened in a tab. + + // Wait for the onReady AddonManagerDelegate method to be called, and assert + // that the baseUrl and optionsPageUrl are both available as expected. + val onReadyResult = GeckoResult() + sessionRule.addExternalDelegateUntilTestEnd( + WebExtensionController.AddonManagerDelegate::class, + { delegate -> controller.setAddonManagerDelegate(delegate) }, + { controller.setAddonManagerDelegate(null) }, + object : WebExtensionController.AddonManagerDelegate { + @AssertCalled(count = 1) + override fun onReady(extension: WebExtension) { + assertNotNull(extension.metaData.baseUrl) + assertTrue(extension.metaData.baseUrl.matches("^moz-extension://[0-9a-f\\-]*/$".toRegex())) + assertEquals("${extension.metaData.baseUrl}dummy.html", extension.metaData.optionsPageUrl) + assertEquals(true, extension.metaData.openOptionsPageInTab) + onReadyResult.complete(null) + super.onReady(extension) + } + }, + ) + + val testExt = sessionRule.waitForResult( + controller.installBuiltIn( + "resource://android/assets/web_extensions/options_page_alias/", + ), + ) + + sessionRule.waitForResult(onReadyResult) + sessionRule.waitForResult(controller.uninstall(testExt)) + } + @Test fun installMultiple() { // dummy.xpi is not signed, but it could be -- cgit v1.2.3