Bug 1667471 - Add builder-like replacement for loadUri. r=snorp,owlish

This introduces a new way of loading URIs in GeckoSession, using a builder-like
method `loader()` which deprecates the existing `loadUri`.

This change improves readability of long `loadUri` calls and allows us to add
more parameters without compromising usability.

It also fixes a bug where we were not short-circuiting the `onLoadRequest` call
in some cases.

Differential Revision: https://phabricator.services.mozilla.com/D91982
This commit is contained in:
Agi Sferro 2020-10-15 00:43:21 +00:00
parent 05cc37d7c1
commit be384731dd
6 changed files with 407 additions and 125 deletions

View File

@ -697,8 +697,8 @@ package org.mozilla.geckoview {
method @UiThread @NonNull public GeckoDisplay acquireDisplay();
method @UiThread public void autofill(@NonNull SparseArray<CharSequence>);
method @UiThread public void close();
method @AnyThread @NonNull public static String createDataUri(@NonNull byte[], @Nullable String);
method @AnyThread @NonNull public static String createDataUri(@NonNull String, @Nullable String);
method @AnyThread @Deprecated @NonNull public static String createDataUri(@NonNull byte[], @Nullable String);
method @AnyThread @Deprecated @NonNull public static String createDataUri(@NonNull String, @Nullable String);
method @AnyThread public void exitFullScreen();
method @UiThread @NonNull public SessionAccessibility getAccessibility();
method @UiThread @Nullable public Autofill.Delegate getAutofillDelegate();
@ -733,20 +733,21 @@ package org.mozilla.geckoview {
method @AnyThread public void goForward();
method @AnyThread public void gotoHistoryIndex(int);
method @AnyThread public boolean isOpen();
method @AnyThread public void loadData(@NonNull byte[], @Nullable String);
method @AnyThread public void loadString(@NonNull String, @Nullable String);
method @AnyThread public void load(@NonNull GeckoSession.Loader);
method @AnyThread @Deprecated public void loadData(@NonNull byte[], @Nullable String);
method @AnyThread @Deprecated public void loadString(@NonNull String, @Nullable String);
method @AnyThread public void loadUri(@NonNull String);
method @AnyThread public void loadUri(@NonNull String, @Nullable Map<String,String>);
method @AnyThread public void loadUri(@NonNull String, int);
method @AnyThread public void loadUri(@NonNull String, @Nullable String, int);
method @AnyThread public void loadUri(@NonNull String, @Nullable String, int, @Nullable Map<String,String>);
method @AnyThread public void loadUri(@NonNull String, @Nullable GeckoSession, int);
method @AnyThread public void loadUri(@NonNull String, @Nullable GeckoSession, int, @Nullable Map<String,String>);
method @AnyThread public void loadUri(@NonNull Uri);
method @AnyThread public void loadUri(@NonNull Uri, @Nullable Map<String,String>);
method @AnyThread public void loadUri(@NonNull Uri, int);
method @AnyThread public void loadUri(@NonNull Uri, @Nullable Uri, int);
method @AnyThread public void loadUri(@NonNull Uri, @Nullable Uri, int, @Nullable Map<String,String>);
method @AnyThread @Deprecated public void loadUri(@NonNull String, @Nullable Map<String,String>);
method @AnyThread @Deprecated public void loadUri(@NonNull String, int);
method @AnyThread @Deprecated public void loadUri(@NonNull String, @Nullable String, int);
method @AnyThread @Deprecated public void loadUri(@NonNull String, @Nullable String, int, @Nullable Map<String,String>);
method @AnyThread @Deprecated public void loadUri(@NonNull String, @Nullable GeckoSession, int);
method @AnyThread @Deprecated public void loadUri(@NonNull String, @Nullable GeckoSession, int, @Nullable Map<String,String>);
method @AnyThread @Deprecated public void loadUri(@NonNull Uri);
method @AnyThread @Deprecated public void loadUri(@NonNull Uri, @Nullable Map<String,String>);
method @AnyThread @Deprecated public void loadUri(@NonNull Uri, int);
method @AnyThread @Deprecated public void loadUri(@NonNull Uri, @Nullable Uri, int);
method @AnyThread @Deprecated public void loadUri(@NonNull Uri, @Nullable Uri, int, @Nullable Map<String,String>);
method @UiThread public void open(@NonNull GeckoRuntime);
method @AnyThread public void purgeHistory();
method @UiThread public void releaseDisplay(@NonNull GeckoDisplay);
@ -852,6 +853,19 @@ package org.mozilla.geckoview {
method @AnyThread default public int getCurrentIndex();
}
@AnyThread public static class GeckoSession.Loader {
ctor public Loader();
method @NonNull public GeckoSession.Loader additionalHeaders(@NonNull Map<String,String>);
method @NonNull public GeckoSession.Loader data(@NonNull byte[], @Nullable String);
method @NonNull public GeckoSession.Loader data(@NonNull String, @Nullable String);
method @NonNull public GeckoSession.Loader flags(int);
method @NonNull public GeckoSession.Loader referrer(@NonNull GeckoSession);
method @NonNull public GeckoSession.Loader referrer(@NonNull Uri);
method @NonNull public GeckoSession.Loader referrer(@NonNull String);
method @NonNull public GeckoSession.Loader uri(@NonNull String);
method @NonNull public GeckoSession.Loader uri(@NonNull Uri);
}
public static interface GeckoSession.MediaDelegate {
method @UiThread default public void onMediaAdd(@NonNull GeckoSession, @NonNull MediaElement);
method @UiThread default public void onMediaRemove(@NonNull GeckoSession, @NonNull MediaElement);

View File

@ -4,26 +4,21 @@
package org.mozilla.geckoview.test
import org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.NullDelegate
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.Setting
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
import org.mozilla.geckoview.test.util.Callbacks
import androidx.test.filters.MediumTest
import android.util.Base64
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.MatcherAssert
import androidx.test.filters.MediumTest
import org.hamcrest.Matchers.*
import org.json.JSONObject
import org.junit.Assert
import org.junit.Assume.assumeThat
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.geckoview.*
import org.mozilla.geckoview.GeckoSession.Loader
import org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.*
import org.mozilla.geckoview.test.util.Callbacks
import org.mozilla.geckoview.test.util.UiThreadUtils
@RunWith(AndroidJUnit4::class)
@ -467,8 +462,9 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.runtime.settings.contentBlocking.setSafeBrowsing(category)
sessionRule.session.loadUri(phishingUri + "?bypass=true",
GeckoSession.LOAD_FLAGS_BYPASS_CLASSIFIER)
sessionRule.session.load(Loader()
.uri(phishingUri + "?bypass=true")
.flags(GeckoSession.LOAD_FLAGS_BYPASS_CLASSIFIER))
sessionRule.session.waitForPageStop()
sessionRule.forCallbacksDuringWait(
@ -863,7 +859,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@Test fun loadString() {
val dataString = "<html><head><title>TheTitle</title></head><body>TheBody</body></html>"
val mimeType = "text/html"
sessionRule.session.loadString(dataString, mimeType)
sessionRule.session.load(Loader().data(dataString, mimeType))
sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate, Callbacks.ProgressDelegate, Callbacks.ContentDelegate {
@ -875,7 +871,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(count = 1)
override fun onLocationChange(session: GeckoSession, url: String?) {
assertThat("URL should be a data URL", url,
equalTo(GeckoSession.createDataUri(dataString, mimeType)))
equalTo(createDataUri(dataString, mimeType)))
}
@AssertCalled(count = 1)
@ -886,7 +882,7 @@ class NavigationDelegateTest : BaseSessionTest() {
}
@Test fun loadString_noMimeType() {
sessionRule.session.loadString("Hello, World!", null)
sessionRule.session.load(Loader().data("Hello, World!", null))
sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate, Callbacks.ProgressDelegate {
@ -906,7 +902,7 @@ class NavigationDelegateTest : BaseSessionTest() {
val bytes = getTestBytes(HELLO_HTML_PATH)
assertThat("test html should have data", bytes.size, greaterThan(0))
sessionRule.session.loadData(bytes, "text/html")
sessionRule.session.load(Loader().data(bytes, "text/html"))
sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate, Callbacks.ProgressDelegate, Callbacks.ContentDelegate {
@ -917,7 +913,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(count = 1)
override fun onLocationChange(session: GeckoSession, url: String?) {
assertThat("URL should match", url, equalTo(GeckoSession.createDataUri(bytes, "text/html")))
assertThat("URL should match", url, equalTo(createDataUri(bytes, "text/html")))
}
@AssertCalled(count = 1)
@ -927,17 +923,28 @@ class NavigationDelegateTest : BaseSessionTest() {
})
}
private fun createDataUri(data: String,
mimeType: String?): String {
return String.format("data:%s,%s", mimeType ?: "", data)
}
private fun createDataUri(bytes: ByteArray,
mimeType: String?): String {
return String.format("data:%s;base64,%s", mimeType ?: "",
Base64.encodeToString(bytes, Base64.NO_WRAP))
}
fun loadDataHelper(assetPath: String, mimeType: String? = null) {
val bytes = getTestBytes(assetPath)
assertThat("test data should have bytes", bytes.size, greaterThan(0))
sessionRule.session.loadData(bytes, mimeType)
sessionRule.session.load(Loader().data(bytes, mimeType))
sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate, Callbacks.ProgressDelegate {
@AssertCalled(count = 1)
override fun onLocationChange(session: GeckoSession, url: String?) {
assertThat("URL should match", url, equalTo(GeckoSession.createDataUri(bytes, mimeType)))
assertThat("URL should match", url, equalTo(createDataUri(bytes, mimeType)))
}
@AssertCalled(count = 1)
@ -1314,7 +1321,10 @@ class NavigationDelegateTest : BaseSessionTest() {
val uri = "https://example.com"
val referrer = "https://foo.org/"
sessionRule.session.loadUri(uri, referrer, GeckoSession.LOAD_FLAGS_NONE)
sessionRule.session.load(Loader()
.uri(uri)
.referrer(referrer)
.flags(GeckoSession.LOAD_FLAGS_NONE))
sessionRule.session.waitForPageStop()
assertThat("Referrer should match",
@ -1330,7 +1340,10 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.session.waitForPageStop()
val newSession = sessionRule.createOpenSession()
newSession.loadUri(uri, sessionRule.session, GeckoSession.LOAD_FLAGS_NONE)
newSession.load(Loader()
.uri(uri)
.referrer(sessionRule.session)
.flags(GeckoSession.LOAD_FLAGS_NONE))
newSession.waitForPageStop()
assertThat("Referrer should match",
@ -1346,7 +1359,10 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.session.waitForPageStop()
val newSession = sessionRule.createOpenSession()
newSession.loadUri(uri, sessionRule.session, GeckoSession.LOAD_FLAGS_NONE)
newSession.load(Loader()
.uri(uri)
.referrer(sessionRule.session)
.flags(GeckoSession.LOAD_FLAGS_NONE))
newSession.waitUntilCalled(object : Callbacks.NavigationDelegate {
@AssertCalled
override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): GeckoResult<String>? {
@ -1368,7 +1384,9 @@ class NavigationDelegateTest : BaseSessionTest() {
val expected = defaultHeaders.plus(additional)
// Now load the page with the header override
sessionRule.session.loadUri("$TEST_ENDPOINT/anything", headers)
sessionRule.session.load(Loader()
.uri("$TEST_ENDPOINT/anything")
.additionalHeaders(headers))
sessionRule.session.waitForPageStop()
val content = sessionRule.session.evaluateJS("document.body.children[0].innerHTML") as String

View File

@ -4,6 +4,7 @@
package org.mozilla.geckoview.test
import android.util.Base64
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.MediumTest
@ -428,6 +429,12 @@ class ProgressDelegateTest : BaseSessionTest() {
})
}
private fun createDataUri(bytes: ByteArray,
mimeType: String?): String {
return String.format("data:%s;base64,%s", mimeType ?: "",
Base64.encodeToString(bytes, Base64.NO_WRAP))
}
@Test(expected = UiThreadUtils.TimeoutException::class)
fun handlingLargeDataURIs() {
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
@ -437,7 +444,7 @@ class ProgressDelegateTest : BaseSessionTest() {
});
val dataBytes = ByteArray(3 * 1024 * 1024)
val uri = GeckoSession.createDataUri(dataBytes, "*/*")
val uri = createDataUri(dataBytes, "*/*")
sessionRule.session.loadTestPath(DATA_URI_PATH)
sessionRule.session.waitForPageStop()
@ -455,7 +462,7 @@ class ProgressDelegateTest : BaseSessionTest() {
});
val dataBytes = this.getTestBytes("/assets/www/images/test.gif")
val uri = GeckoSession.createDataUri(dataBytes, "image/*")
val uri = createDataUri(dataBytes, "image/*")
sessionRule.session.loadTestPath(DATA_URI_PATH)
sessionRule.session.waitForPageStop()

View File

@ -1460,35 +1460,268 @@ public class GeckoSession {
*/
public static final int LOAD_FLAGS_REPLACE_HISTORY = 1 << 6;
private GeckoBundle additionalHeadersToBundle(final Map<String, String> additionalHeaders) {
final GeckoBundle bundle = new GeckoBundle(additionalHeaders.size());
for (Map.Entry<String, String> entry : additionalHeaders.entrySet()) {
if (entry.getKey() == null) {
// Ignore null keys
continue;
}
bundle.putString(entry.getKey(), entry.getValue());
/**
* Main entry point for loading URIs into a {@link GeckoSession}.
*
* The simplest use case is loading a URIs with no extra options, this can
* be accomplished by specifying the URI in {@link #uri} and then calling
* {@link #load}, e.g.
*
* <pre><code>
* session.load(new Loader().uri("http://mozilla.org"));
* </code></pre>
*
* This class can also be used to load <code>data:</code> URIs, either from
* a <code>byte[]</code> array or a <code>String</code> using {@link
* #data}, e.g.
*
* <pre><code>
* session.load(new Loader().data("the data:1234,5678", "text/plain"));
* </code></pre>
*
* This class also allows you to specify some extra data, e.g. you can set
* a referrer using {@link #referrer} which can either be a {@link
* GeckoSession} or a plain URL string. You can also specify some Load
* Flags using {@link #flags}.
*
* The class is structured as a Builder, so method calls can be easily
* chained, e.g.
*
* <pre><code>
* session.load(new Loader()
* .url("http://mozilla.org")
* .referrer("http://my-referrer.com")
* .flags(...));
* </code></pre>
*/
@AnyThread
public static class Loader {
private String mUri;
private GeckoSession mReferrerSession;
private String mReferrerUri;
private GeckoBundle mHeaders;
private @LoadFlags int mLoadFlags = LOAD_FLAGS_NONE;
private boolean mIsDataUri;
private static @NonNull String createDataUri(@NonNull final byte[] bytes,
@Nullable final String mimeType) {
return String.format("data:%s;base64,%s", mimeType != null ? mimeType : "",
Base64.encodeToString(bytes, Base64.NO_WRAP));
}
return bundle;
private static @NonNull String createDataUri(@NonNull final String data,
@Nullable final String mimeType) {
return String.format("data:%s,%s", mimeType != null ? mimeType : "", data);
}
/**
* Set the URI of the resource to load.
* @param uri a String containg the URI
* @return this {@link Loader} instance.
*/
@NonNull
public Loader uri(final @NonNull String uri) {
mUri = uri;
mIsDataUri = false;
return this;
}
/**
* Set the URI of the resource to load.
* @param uri a {@link Uri} instance
* @return this {@link Loader} instance.
*/
@NonNull
public Loader uri(final @NonNull Uri uri) {
mUri = uri.toString();
mIsDataUri = false;
return this;
}
/**
* Set the data URI of the resource to load.
* @param bytes a <code>byte</code> array containing the data to load.
* @param mimeType a <code>String</code> containing the mime type for this
* data URI, e.g. "text/plain"
* @return this {@link Loader} instance.
*/
@NonNull
public Loader data(final @NonNull byte[] bytes, final @Nullable String mimeType) {
mUri = createDataUri(bytes, mimeType);
mIsDataUri = true;
return this;
}
/**
* Set the data URI of the resource to load.
* @param data a <code>String</code> array containing the data to load.
* @param mimeType a <code>String</code> containing the mime type for this
* data URI, e.g. "text/plain"
* @return this {@link Loader} instance.
*/
@NonNull
public Loader data(final @NonNull String data, final @Nullable String mimeType) {
mUri = createDataUri(data, mimeType);
mIsDataUri = true;
return this;
}
/**
* Set the referrer for this load.
* @param referrer a <code>GeckoSession</code> that will be used as the referrer
* @return this {@link Loader} instance.
*/
@NonNull
public Loader referrer(final @NonNull GeckoSession referrer) {
mReferrerSession = referrer;
return this;
}
/**
* Set the referrer for this load.
* @param referrerUri a {@link Uri} that will be used as the referrer
* @return this {@link Loader} instance.
*/
@NonNull
public Loader referrer(final @NonNull Uri referrerUri) {
mReferrerUri = referrerUri != null ? referrerUri.toString() : null;
return this;
}
/**
* Set the referrer for this load.
* @param referrerUri a <code>String</code> containing the URI
* that will be used as the referrer
* @return this {@link Loader} instance.
*/
@NonNull
public Loader referrer(final @NonNull String referrerUri) {
mReferrerUri = referrerUri;
return this;
}
/**
* Add headers for this load.
*
* Note: the <code>Host</code> and <code>Connection</code>
* headers are ignored.
*
* @param headers a <code>Map</code> containing headers that will
* be added to this load.
* @return this {@link Loader} instance.
*/
@NonNull
public Loader additionalHeaders(final @NonNull Map<String, String> headers) {
final GeckoBundle bundle = new GeckoBundle(headers.size());
for (Map.Entry<String, String> entry : headers.entrySet()) {
if (entry.getKey() == null) {
// Ignore null keys
continue;
}
bundle.putString(entry.getKey(), entry.getValue());
}
mHeaders = bundle;
return this;
}
/**
* Set the load flags for this load.
* @param flags the load flags to use, an OR-ed value of
* {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*} that will be used as the referrer
* @return this {@link Loader} instance.
*/
@NonNull
public Loader flags(final @LoadFlags int flags) {
mLoadFlags = flags;
return this;
}
}
/**
* Load page using the {@link Loader} specified.
*
* @param request Loader for this request.
* @see Loader
*/
@AnyThread
public void load(final @NonNull Loader request) {
if (request.mUri == null) {
throw new IllegalArgumentException(
"You need to specify at least one between `uri` and `data`.");
}
if (request.mReferrerUri != null && request.mReferrerSession != null) {
throw new IllegalArgumentException(
"Cannot specify both a referrer session and a referrer URI.");
}
final int loadFlags = request.mIsDataUri
// If this is a data: load then we need to force allow it.
? request.mLoadFlags | LOAD_FLAGS_FORCE_ALLOW_DATA_URI
: request.mLoadFlags;
// For performance reasons we short-circuit the delegate here
// instead of making Gecko call it for direct loadUri calls.
final NavigationDelegate.LoadRequest loadRequest =
new NavigationDelegate.LoadRequest(
request.mUri,
null, /* triggerUri */
1, /* geckoTarget: OPEN_CURRENTWINDOW */
0, /* flags */
false, /* hasUserGesture */
true /* isDirectNavigation */);
shouldLoadUri(loadRequest).getOrAccept(allowOrDeny -> {
if (allowOrDeny == AllowOrDeny.DENY) {
return;
}
final GeckoBundle msg = new GeckoBundle();
msg.putString("uri", request.mUri);
msg.putInt("flags", loadFlags);
if (request.mReferrerUri != null) {
msg.putString("referrerUri", request.mReferrerUri);
}
if (request.mReferrerSession != null) {
msg.putString("referrerSessionId", request.mReferrerSession.mId);
}
if (request.mHeaders != null) {
msg.putBundle("headers", request.mHeaders);
}
mEventDispatcher.dispatch("GeckoView:LoadUri", msg);
});
}
/**
* Load the given URI.
*
* Convenience method for <pre><code>
* session.load(new Loader().uri(uri));
* </code></pre>
*
* @param uri The URI of the resource to load.
*/
@AnyThread
public void loadUri(final @NonNull String uri) {
loadUri(uri, (GeckoSession)null, LOAD_FLAGS_NONE, (Map<String, String>) null);
load(new Loader().uri(uri));
}
/**
* Load the given URI with specified HTTP request headers.
* @param uri The URI of the resource to load.
* @param additionalHeaders any additional request headers used with the load
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull String uri, final @Nullable Map<String, String> additionalHeaders) {
loadUri(uri, (GeckoSession)null, LOAD_FLAGS_NONE, additionalHeaders);
load(new Loader()
.uri(uri)
.additionalHeaders(additionalHeaders));
}
/**
@ -1496,10 +1729,14 @@ public class GeckoSession {
*
* @param uri the URI to load
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull String uri, final @LoadFlags int flags) {
loadUri(uri, (GeckoSession)null, flags, (Map<String, String>) null);
load(new Loader()
.uri(uri)
.flags(flags));
}
/**
@ -1508,11 +1745,16 @@ public class GeckoSession {
* @param uri the URI to load
* @param referrer the referrer, may be null
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull String uri, final @Nullable String referrer,
final @LoadFlags int flags) {
loadUri(uri, referrer, flags, (Map<String, String>) null);
load(new Loader()
.uri(uri)
.referrer(referrer)
.flags(flags));
}
/**
@ -1522,22 +1764,17 @@ public class GeckoSession {
* @param referrer the referrer, may be null
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @param additionalHeaders any additional request headers used with the load
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull String uri, final @Nullable String referrer,
final @LoadFlags int flags, final @Nullable Map<String, String> additionalHeaders) {
final GeckoBundle msg = new GeckoBundle();
msg.putString("uri", uri);
msg.putInt("flags", flags);
if (referrer != null) {
msg.putString("referrerUri", referrer);
}
if (additionalHeaders != null) {
msg.putBundle("headers", additionalHeadersToBundle(additionalHeaders));
}
mEventDispatcher.dispatch("GeckoView:LoadUri", msg);
load(new Loader()
.uri(uri)
.referrer(referrer)
.flags(flags)
.additionalHeaders(additionalHeaders));
}
/**
@ -1548,11 +1785,16 @@ public class GeckoSession {
* @param uri the URI to load
* @param referrer the referring GeckoSession, may be null
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull String uri, final @Nullable GeckoSession referrer,
final @LoadFlags int flags) {
loadUri(uri, referrer, flags, (Map<String, String>) null);
load(new Loader()
.uri(uri)
.referrer(referrer)
.flags(flags));
}
/**
@ -1564,40 +1806,17 @@ public class GeckoSession {
* @param referrer the referring GeckoSession, may be null
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @param additionalHeaders any additional request headers used with the load
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull String uri, final @Nullable GeckoSession referrer,
final @LoadFlags int flags, final @Nullable Map<String, String> additionalHeaders) {
// For performance reasons we short-circuit the delegate here
// instead of making Gecko call it for direct loadUri calls.
final NavigationDelegate.LoadRequest request =
new NavigationDelegate.LoadRequest(
uri,
null, /* triggerUri */
1, /* geckoTarget: OPEN_CURRENTWINDOW */
0, /* flags */
false, /* hasUserGesture */
true /* isDirectNavigation */);
shouldLoadUri(request).getOrAccept(allowOrDeny -> {
if (allowOrDeny == AllowOrDeny.DENY) {
return;
}
final GeckoBundle msg = new GeckoBundle();
msg.putString("uri", uri);
msg.putInt("flags", flags);
if (referrer != null) {
msg.putString("referrerSessionId", referrer.mId);
}
if (additionalHeaders != null) {
msg.putBundle("headers", additionalHeadersToBundle(additionalHeaders));
}
mEventDispatcher.dispatch("GeckoView:LoadUri", msg);
});
load(new Loader()
.uri(uri)
.referrer(referrer)
.additionalHeaders(additionalHeaders)
.flags(flags));
}
private GeckoResult<AllowOrDeny> shouldLoadUri(final NavigationDelegate.LoadRequest request) {
@ -1628,30 +1847,41 @@ public class GeckoSession {
/**
* Load the given URI.
* @param uri The URI of the resource to load.
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull Uri uri) {
loadUri(uri.toString(), (GeckoSession)null, LOAD_FLAGS_NONE, (Map<String, String>) null);
load(new Loader()
.uri(uri));
}
/**
* Load the given URI with specified HTTP request headers.
* @param uri The URI of the resource to load.
* @param additionalHeaders any additional request headers used with the load
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull Uri uri, final @Nullable Map<String, String> additionalHeaders) {
loadUri(uri.toString(), (GeckoSession)null, LOAD_FLAGS_NONE, additionalHeaders);
load(new Loader()
.uri(uri)
.additionalHeaders(additionalHeaders));
}
/**
* Load the given URI with the specified referrer and load type.
* @param uri the URI to load
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull Uri uri, final @LoadFlags int flags) {
loadUri(uri.toString(), (GeckoSession)null, flags, (Map<String, String>) null);
load(new Loader()
.uri(uri)
.flags(flags));
}
/**
@ -1659,11 +1889,16 @@ public class GeckoSession {
* @param uri the URI to load
* @param referrer the Uri to use as the referrer
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull Uri uri, final @Nullable Uri referrer,
final @LoadFlags int flags) {
loadUri(uri.toString(), referrer != null ? referrer.toString() : null, flags, (Map<String, String>) null);
load(new Loader()
.uri(uri)
.referrer(referrer)
.flags(flags));
}
/**
@ -1672,11 +1907,17 @@ public class GeckoSession {
* @param referrer the Uri to use as the referrer
* @param flags the load flags to use, an OR-ed value of {@link #LOAD_FLAGS_NONE LOAD_FLAGS_*}
* @param additionalHeaders any additional request headers used with the load
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadUri(final @NonNull Uri uri, final @Nullable Uri referrer,
final @LoadFlags int flags, final @Nullable Map<String, String> additionalHeaders) {
loadUri(uri.toString(), referrer != null ? referrer.toString() : null, flags, additionalHeaders);
load(new Loader()
.uri(uri)
.referrer(referrer)
.flags(flags)
.additionalHeaders(additionalHeaders));
}
/**
@ -1685,15 +1926,12 @@ public class GeckoSession {
* @param data a String representing the data
* @param mimeType the mime type of the data, e.g. "text/plain". Maybe be null, in
* which case the type is guessed.
*
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadString(@NonNull final String data, @Nullable final String mimeType) {
if (data == null) {
throw new IllegalArgumentException("data cannot be null");
}
loadUri(createDataUri(data, mimeType), (GeckoSession)null, LOAD_FLAGS_NONE);
load(new Loader().data(data, mimeType));
}
/**
@ -1702,14 +1940,12 @@ public class GeckoSession {
* @param bytes the data to load
* @param mimeType the mime type of the data, e.g. video/mp4. May be null, in which
* case the type is guessed.
* @deprecated Use {@link #load} instead.
*/
@AnyThread
@Deprecated
public void loadData(@NonNull final byte[] bytes, @Nullable final String mimeType) {
if (bytes == null) {
throw new IllegalArgumentException("data cannot be null");
}
loadUri(createDataUri(bytes, mimeType), (GeckoSession)null, LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
load(new Loader().data(bytes, mimeType));
}
/**
@ -1719,10 +1955,10 @@ public class GeckoSession {
* @return a URI String
*/
@AnyThread
@Deprecated
public static @NonNull String createDataUri(@NonNull final byte[] bytes,
@Nullable final String mimeType) {
return String.format("data:%s;base64,%s", mimeType != null ? mimeType : "",
Base64.encodeToString(bytes, Base64.NO_WRAP));
return Loader.createDataUri(bytes, mimeType);
}
/**
@ -1732,9 +1968,10 @@ public class GeckoSession {
* @return a URI String
*/
@AnyThread
@Deprecated
public static @NonNull String createDataUri(@NonNull final String data,
@Nullable final String mimeType) {
return String.format("data:%s,%s", mimeType != null ? mimeType : "", data);
return Loader.createDataUri(data, mimeType);
}
/**

View File

@ -478,10 +478,10 @@ public class WebExtension {
public final Boolean pinned;
/**
* The url that the tab will be navigated to. This url is provided just
* for informational purposes, there is no need to call
* <code>loadUri</code> on it. The corresponding {@link GeckoSession} will be
* navigated to the right URL after returning
* <code>GeckoResult.ALLOW</code> from {@link SessionTabDelegate#onUpdateTab}
* for informational purposes, there is no need to load the URL manually.
* The corresponding {@link GeckoSession} will be navigated to the
* right URL after returning <code>GeckoResult.ALLOW</code> from {@link
* SessionTabDelegate#onUpdateTab}
*/
@Nullable
public final String url;
@ -553,10 +553,10 @@ public class WebExtension {
public final Boolean pinned;
/**
* The url that the tab will be navigated to. This url is provided just
* for informational purposes, there is no need to call
* <code>loadUri</code> on it. The corresponding {@link GeckoSession} will be
* navigated to the right URL after returning
* <code>GeckoResult.ALLOW</code> from {@link TabDelegate#onNewTab}
* for informational purposes, there is no need to load the URL
* manually. The corresponding {@link GeckoSession} will be navigated
* to the right URL after returning <code>GeckoResult.ALLOW</code> from
* {@link TabDelegate#onNewTab}
*/
@Nullable
public final String url;

View File

@ -31,12 +31,18 @@ exclude: true
FIDO support for WebAuthn.
- Added ['GeckoWebExecutor#FETCH_FLAG_PRIVATE'][83.5]. This new flag allows for private browsing downloads using WebExecutor.
([bug 1665426]({{bugzilla}}1665426))
- ⚠️ Deprecated [`GeckoSession#loadUri`][83.6] variants in favor of
[`GeckoSession#load`][83.7]. See docs for [`Loader`][83.8].
([bug 1667471]({{bugzilla}}1667471))
[83.1]: {{javadoc_uri}}/WebExtension.MetaData.html#temporary
[83.2]: {{javadoc_uri}}/MediaSession.Delegate.html#onMetadata-org.mozilla.geckoview.GeckoSession-org.mozilla.geckoview.MediaSession-org.mozilla.geckoview.MediaSession.Metadata-
[83.3]: {{javadoc_uri}}/ContentBlocking.SafeBrowsingProvider.html
[83.4]: {{javadoc_uri}}/GeckoRuntime.ActivityDelegate.html
[83.5]: {{javadoc_uri}}/GeckoWebExecutor.html#FETCH_FLAG_PRIVATE
[83.6]: {{javadoc_uri}}/GeckoSession.html#loadUri-java.lang.String-org.mozilla.geckoview.GeckoSession-int-java.util.Map-
[83.7]: {{javadoc_uri}}/GeckoSession.html#load-org.mozilla.geckoview.GeckoSession.Loader-
[83.8]: {{javadoc_uri}}/GeckoSession.Loader.html
## v82
- ⚠️ [`WebNotification.source`][79.2] is now `@Nullable` to account for
@ -826,4 +832,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]: a2b63f41870a698bfe884cc415427dfb8c6fb471
[api-version]: 0abbabc4fa9445edc2f37ba174b189be25c2b2fa