Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* vim: ts=4 sw=4 expandtab:
* 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.geckoview;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.AnyThread;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collection;
import org.mozilla.gecko.util.GeckoBundle;
@AnyThread
public final class GeckoSessionSettings implements Parcelable {
/** Settings builder used to construct the settings object. */
@AnyThread
public static final class Builder {
private final GeckoSessionSettings mSettings;
@SuppressWarnings("checkstyle:javadocmethod")
public Builder() {
mSettings = new GeckoSessionSettings();
}
@SuppressWarnings("checkstyle:javadocmethod")
public Builder(final GeckoSessionSettings settings) {
mSettings = new GeckoSessionSettings(settings);
}
/**
* Finalize and return the settings.
*
* @return The constructed settings.
*/
public @NonNull GeckoSessionSettings build() {
return new GeckoSessionSettings(mSettings);
}
/**
* Set the chrome URI.
*
* @param uri The URI to set the Chrome URI to.
* @return This Builder instance.
*/
public @NonNull Builder chromeUri(final @NonNull String uri) {
mSettings.setChromeUri(uri);
return this;
}
/**
* Set the screen id.
*
* @param id The screen id.
* @return This Builder instance.
*/
public @NonNull Builder screenId(final int id) {
mSettings.setScreenId(id);
return this;
}
/**
* Set the privacy mode for this instance.
*
* @param flag A flag determining whether Private Mode should be enabled. Default is false.
* @return This Builder instance.
*/
public @NonNull Builder usePrivateMode(final boolean flag) {
mSettings.setUsePrivateMode(flag);
return this;
}
/**
* Set the session context ID for this instance. Setting a context ID partitions the cookie jars
* based on the provided IDs. This isolates the browser storage like cookies and localStorage
* between sessions, only sessions that share the same ID share storage data.
*
* <p>Warning: Storage data is collected persistently for each context, to delete context data,
* call {@link StorageController#clearDataForSessionContext} for the given context.
*
* @param value The custom context ID. The default ID is null, which removes isolation for this
* instance.
* @return This Builder instance.
*/
public @NonNull Builder contextId(final @Nullable String value) {
mSettings.setContextId(value);
return this;
}
/**
* Set whether tracking protection should be enabled.
*
* @param flag A flag determining whether tracking protection should be enabled. Default is
* false.
* @return This Builder instance.
*/
public @NonNull Builder useTrackingProtection(final boolean flag) {
mSettings.setUseTrackingProtection(flag);
return this;
}
/**
* Set the user agent mode.
*
* @param mode The mode to set the user agent to. Use one or more of the {@link
* GeckoSessionSettings#USER_AGENT_MODE_MOBILE GeckoSessionSettings.USER_AGENT_MODE_*}
* flags.
* @return This Builder instance.
*/
public @NonNull Builder userAgentMode(@UserAgentMode final int mode) {
mSettings.setUserAgentMode(mode);
return this;
}
/**
* Override the user agent.
*
* @param agent The user agent to use.
* @return This Builder instance.
*/
public @NonNull Builder userAgentOverride(final @NonNull String agent) {
mSettings.setUserAgentOverride(agent);
return this;
}
/**
* Specify which display-mode to use.
*
* @param mode The mode to set the display to. Use one or more of the {@link
* GeckoSessionSettings#DISPLAY_MODE_BROWSER GeckoSessionSettings.DISPLAY_MODE_*} flags.
* @return This Builder instance.
*/
public @NonNull Builder displayMode(@DisplayMode final int mode) {
mSettings.setDisplayMode(mode);
return this;
}
/**
* Set whether to suspend the playing of media when the session is inactive.
*
* @param flag A flag determining whether media should be suspended. Default is false.
* @return This Builder instance.
*/
public @NonNull Builder suspendMediaWhenInactive(final boolean flag) {
mSettings.setSuspendMediaWhenInactive(flag);
return this;
}
/**
* Set whether JavaScript support should be enabled.
*
* @param flag A flag determining whether JavaScript should be enabled. Default is true.
* @return This Builder instance.
*/
public @NonNull Builder allowJavascript(final boolean flag) {
mSettings.setAllowJavascript(flag);
return this;
}
/**
* Set whether the entire accessible tree should be exposed with no caching.
*
* @param flag A flag determining if the entire accessible tree should be exposed. Default is
* false.
* @return This Builder instance.
*/
public @NonNull Builder fullAccessibilityTree(final boolean flag) {
mSettings.setFullAccessibilityTree(flag);
return this;
}
/**
* Specify which viewport mode to use.
*
* @param mode The mode to set the viewport to. Use one or more of the {@link
* GeckoSessionSettings#VIEWPORT_MODE_MOBILE GeckoSessionSettings.VIEWPORT_MODE_*} flags.
* @return This Builder instance.
*/
public @NonNull Builder viewportMode(@ViewportMode final int mode) {
mSettings.setViewportMode(mode);
return this;
}
}
private static final String LOGTAG = "GeckoSessionSettings";
private static final boolean DEBUG = false;
/** This value is for the display member of Web App Manifests */
@Retention(RetentionPolicy.SOURCE)
@IntDef({
DISPLAY_MODE_BROWSER,
DISPLAY_MODE_MINIMAL_UI,
DISPLAY_MODE_STANDALONE,
DISPLAY_MODE_FULLSCREEN
})
public @interface DisplayMode {}
// 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;
/** "minimal-ui" value of the display member in Web App Manifests */
public static final int DISPLAY_MODE_MINIMAL_UI = 1;
/** "standalone" value of the display member in Web App Manifests */
public static final int DISPLAY_MODE_STANDALONE = 2;
/** "fullscreen" value of the display member in Web App Manifests */
public static final int DISPLAY_MODE_FULLSCREEN = 3;
/** The user agent string mode */
@Retention(RetentionPolicy.SOURCE)
@IntDef({
USER_AGENT_MODE_MOBILE,
USER_AGENT_MODE_DESKTOP,
USER_AGENT_MODE_VR,
})
public @interface UserAgentMode {}
// 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;
/** The user agent mobe is desktop device */
public static final int USER_AGENT_MODE_DESKTOP = 1;
/** The user agent mode is VR device */
public static final int USER_AGENT_MODE_VR = 2;
/** The view port mode */
@Retention(RetentionPolicy.SOURCE)
@IntDef({VIEWPORT_MODE_MOBILE, VIEWPORT_MODE_DESKTOP})
public @interface ViewportMode {}
// This needs to match GeckoViewSettingsChild.js
/**
* Mobile-friendly pages will be rendered using a viewport based on their &lt;meta&gt; viewport
* tag. All other pages will be rendered using a special desktop mode viewport, which has a width
* of 980 CSS px.
*/
public static final int VIEWPORT_MODE_MOBILE = 0;
/**
* All pages will be rendered using the special desktop mode viewport, which has a width of 980
* CSS px, regardless of whether the page has a &lt;meta&gt; viewport tag specified or not.
*/
public static final int VIEWPORT_MODE_DESKTOP = 1;
public static class Key<T> {
/* package */ final String name;
/* package */ final boolean initOnly;
/* package */ final Collection<T> values;
/* package */ Key(final String name) {
this(name, /* initOnly */ false, /* values */ null);
}
/* package */ Key(final String name, final boolean initOnly, final Collection<T> values) {
this.name = name;
this.initOnly = initOnly;
this.values = values;
}
}
/**
* Key to set the chrome window URI, or null to use default URI. Read-only once session is open.
*/
private static final Key<String> CHROME_URI =
new Key<String>("chromeUri", /* initOnly */ true, /* values */ null);
/** Key to set the window screen ID, or 0 to use default ID. Read-only once session is open. */
private static final Key<Integer> SCREEN_ID =
new Key<Integer>("screenId", /* initOnly */ true, /* values */ null);
/** Key to enable and disable tracking protection. */
private static final Key<Boolean> USE_TRACKING_PROTECTION =
new Key<Boolean>("useTrackingProtection");
/** Key to enable and disable private mode browsing. Read-only once session is open. */
private static final Key<Boolean> USE_PRIVATE_MODE =
new Key<Boolean>("usePrivateMode", /* initOnly */ true, /* values */ null);
/** Key to specify which user agent mode we should use. */
private static final Key<Integer> USER_AGENT_MODE =
new Key<Integer>(
"userAgentMode", /* initOnly */
false,
Arrays.asList(USER_AGENT_MODE_MOBILE, USER_AGENT_MODE_DESKTOP, USER_AGENT_MODE_VR));
/**
* Key to specify the user agent override string. Set value to null to use the user agent
* specified by USER_AGENT_MODE.
*/
private static final Key<String> USER_AGENT_OVERRIDE =
new Key<String>("userAgentOverride", /* initOnly */ false, /* values */ null);
/** Key to specify which viewport mode we should use. */
private static final Key<Integer> VIEWPORT_MODE =
new Key<Integer>(
"viewportMode", /* initOnly */
false,
Arrays.asList(VIEWPORT_MODE_MOBILE, VIEWPORT_MODE_DESKTOP));
/** Key to specify which display-mode we should use. */
private static final Key<Integer> DISPLAY_MODE =
new Key<Integer>(
"displayMode", /* initOnly */
false,
Arrays.asList(
DISPLAY_MODE_BROWSER, DISPLAY_MODE_MINIMAL_UI,
DISPLAY_MODE_STANDALONE, DISPLAY_MODE_FULLSCREEN));
/** Key to specify if media should be suspended when the session is inactive. */
private static final Key<Boolean> SUSPEND_MEDIA_WHEN_INACTIVE =
new Key<Boolean>("suspendMediaWhenInactive", /* initOnly */ false, /* values */ null);
/** Key to specify if JavaScript should be allowed on this session. */
private static final Key<Boolean> ALLOW_JAVASCRIPT =
new Key<Boolean>("allowJavascript", /* initOnly */ false, /* values */ null);
/** Key to specify if entire accessible tree should be exposed with no caching. */
private static final Key<Boolean> FULL_ACCESSIBILITY_TREE =
new Key<Boolean>("fullAccessibilityTree", /* initOnly */ false, /* values */ null);
/**
* Key to specify if this GeckoSession is a Popup or not. Popup sessions can paint over other
* sessions and are not exposed to the tabs WebExtension API.
*/
private static final Key<Boolean> IS_POPUP =
new Key<Boolean>("isPopup", /* initOnly */ false, /* values */ null);
/** Internal Gecko key to specify the session context ID. Derived from `UNSAFE_CONTEXT_ID`. */
private static final Key<String> CONTEXT_ID =
new Key<String>("sessionContextId", /* initOnly */ true, /* values */ null);
/** User-provided key to specify the session context ID. */
private static final Key<String> UNSAFE_CONTEXT_ID =
new Key<String>("unsafeSessionContextId", /* initOnly */ true, /* values */ null);
private final GeckoSession mSession;
private final GeckoBundle mBundle;
@SuppressWarnings("checkstyle:javadocmethod")
public GeckoSessionSettings() {
this(null, null);
}
@SuppressWarnings("checkstyle:javadocmethod")
public GeckoSessionSettings(final @NonNull GeckoSessionSettings settings) {
this(settings, null);
}
/* package */ GeckoSessionSettings(
final @Nullable GeckoSessionSettings settings, final @Nullable GeckoSession session) {
mSession = session;
if (settings != null) {
mBundle = new GeckoBundle(settings.mBundle);
return;
}
mBundle = new GeckoBundle();
mBundle.putString(CHROME_URI.name, null);
mBundle.putInt(SCREEN_ID.name, 0);
mBundle.putBoolean(USE_TRACKING_PROTECTION.name, false);
mBundle.putBoolean(USE_PRIVATE_MODE.name, false);
mBundle.putBoolean(SUSPEND_MEDIA_WHEN_INACTIVE.name, false);
mBundle.putBoolean(ALLOW_JAVASCRIPT.name, true);
mBundle.putBoolean(FULL_ACCESSIBILITY_TREE.name, false);
mBundle.putBoolean(IS_POPUP.name, false);
mBundle.putInt(USER_AGENT_MODE.name, USER_AGENT_MODE_MOBILE);
mBundle.putString(USER_AGENT_OVERRIDE.name, null);
mBundle.putInt(VIEWPORT_MODE.name, VIEWPORT_MODE_MOBILE);
mBundle.putInt(DISPLAY_MODE.name, DISPLAY_MODE_BROWSER);
mBundle.putString(CONTEXT_ID.name, null);
mBundle.putString(UNSAFE_CONTEXT_ID.name, null);
}
/**
* Set whether tracking protection should be enabled.
*
* @param value A flag determining whether tracking protection should be enabled. Default is
* false.
*/
public void setUseTrackingProtection(final boolean value) {
setBoolean(USE_TRACKING_PROTECTION, value);
}
/**
* Set the privacy mode for this instance.
*
* @param value A flag determining whether Private Mode should be enabled. Default is false.
*/
private void setUsePrivateMode(final boolean value) {
setBoolean(USE_PRIVATE_MODE, value);
}
/**
* Set whether to suspend the playing of media when the session is inactive.
*
* @param value A flag determining whether media should be suspended. Default is false.
*/
public void setSuspendMediaWhenInactive(final boolean value) {
setBoolean(SUSPEND_MEDIA_WHEN_INACTIVE, value);
}
/**
* Set whether JavaScript support should be enabled.
*
* @param value A flag determining whether JavaScript should be enabled. Default is true.
*/
public void setAllowJavascript(final boolean value) {
setBoolean(ALLOW_JAVASCRIPT, value);
}
/**
* Set whether the entire accessible tree should be exposed with no caching.
*
* @param value A flag determining full accessibility tree should be exposed. Default is false.
*/
public void setFullAccessibilityTree(final boolean value) {
setBoolean(FULL_ACCESSIBILITY_TREE, value);
}
/* package */ void setIsPopup(final boolean value) {
setBoolean(IS_POPUP, value);
}
private void setBoolean(final Key<Boolean> key, final boolean value) {
synchronized (mBundle) {
if (valueChangedLocked(key, value)) {
mBundle.putBoolean(key.name, value);
dispatchUpdate();
}
}
}
/**
* Whether tracking protection is enabled.
*
* @return true if tracking protection is enabled, false if not.
*/
public boolean getUseTrackingProtection() {
return getBoolean(USE_TRACKING_PROTECTION);
}
/**
* Whether private mode is enabled.
*
* @return true if private mode is enabled, false if not.
*/
public boolean getUsePrivateMode() {
return getBoolean(USE_PRIVATE_MODE);
}
/**
* The context ID for this session.
*
* @return The context ID for this session.
*/
public @Nullable String getContextId() {
// Return the user-provided unsafe string.
return getString(UNSAFE_CONTEXT_ID);
}
/**
* Whether media will be suspended when the session is inactice.
*
* @return true if media will be suspended, false if not.
*/
public boolean getSuspendMediaWhenInactive() {
return getBoolean(SUSPEND_MEDIA_WHEN_INACTIVE);
}
/**
* Whether javascript execution is allowed.
*
* @return true if javascript execution is allowed, false if not.
*/
public boolean getAllowJavascript() {
return getBoolean(ALLOW_JAVASCRIPT);
}
/**
* Whether entire accessible tree is exposed with no caching.
*
* @return true if accessibility tree is exposed, false if not.
*/
public boolean getFullAccessibilityTree() {
return getBoolean(FULL_ACCESSIBILITY_TREE);
}
/* package */ boolean getIsPopup() {
return getBoolean(IS_POPUP);
}
private boolean getBoolean(final Key<Boolean> key) {
synchronized (mBundle) {
return mBundle.getBoolean(key.name);
}
}
/**
* Set the screen id.
*
* @param value The screen id.
*/
private void setScreenId(final int value) {
setInt(SCREEN_ID, value);
}
/**
* Specify which user agent mode we should use
*
* @param value One or more of the {@link GeckoSessionSettings#USER_AGENT_MODE_MOBILE
* GeckoSessionSettings.USER_AGENT_MODE_*} flags.
*/
public void setUserAgentMode(@UserAgentMode final int value) {
setInt(USER_AGENT_MODE, value);
}
/**
* Set the display mode.
*
* @param value The mode to set the display to. Use one or more of the {@link
* GeckoSessionSettings#DISPLAY_MODE_BROWSER GeckoSessionSettings.DISPLAY_MODE_*} flags.
*/
public void setDisplayMode(@DisplayMode final int value) {
setInt(DISPLAY_MODE, value);
}
/**
* Specify which viewport mode we should use
*
* @param value One or more of the {@link GeckoSessionSettings#VIEWPORT_MODE_MOBILE
* GeckoSessionSettings.VIEWPORT_MODE_*} flags.
*/
public void setViewportMode(@ViewportMode final int value) {
setInt(VIEWPORT_MODE, value);
}
private void setInt(final Key<Integer> key, final int value) {
synchronized (mBundle) {
if (valueChangedLocked(key, value)) {
mBundle.putInt(key.name, value);
dispatchUpdate();
}
}
}
/**
* Set the window screen ID. Read-only once session is open. Use the {@link Builder} to set on
* session open.
*
* @return Key to set the window screen ID. 0 is the default ID.
*/
public int getScreenId() {
return getInt(SCREEN_ID);
}
/**
* The current user agent Mode
*
* @return One or more of the {@link GeckoSessionSettings#USER_AGENT_MODE_MOBILE
* GeckoSessionSettings.USER_AGENT_MODE_*} flags.
*/
public @UserAgentMode int getUserAgentMode() {
return getInt(USER_AGENT_MODE);
}
/**
* The current display mode.
*
* @return One or more of the {@link GeckoSessionSettings#DISPLAY_MODE_BROWSER
* GeckoSessionSettings.DISPLAY_MODE_*} flags.
*/
public @DisplayMode int getDisplayMode() {
return getInt(DISPLAY_MODE);
}
/**
* The current viewport Mode
*
* @return One or more of the {@link GeckoSessionSettings#VIEWPORT_MODE
* GeckoSessionSettings.VIEWPORT_MODE_*} flags.
*/
public @ViewportMode int getViewportMode() {
return getInt(VIEWPORT_MODE);
}
private int getInt(final Key<Integer> key) {
synchronized (mBundle) {
return mBundle.getInt(key.name);
}
}
/**
* Set the chrome URI.
*
* @param value The URI to set the Chrome URI to.
*/
private void setChromeUri(final @NonNull String value) {
setString(CHROME_URI, value);
}
/**
* Specify the user agent override string. Set value to null to use the user agent specified by
* USER_AGENT_MODE.
*
* @param value The string to override the user agent with.
*/
public void setUserAgentOverride(final @Nullable String value) {
setString(USER_AGENT_OVERRIDE, value);
}
private void setContextId(final @Nullable String value) {
setString(UNSAFE_CONTEXT_ID, value);
setString(CONTEXT_ID, StorageController.createSafeSessionContextId(value));
}
private void setString(final Key<String> key, final String value) {
synchronized (mBundle) {
if (valueChangedLocked(key, value)) {
mBundle.putString(key.name, value);
dispatchUpdate();
}
}
}
/**
* Set the chrome window URI. Read-only once session is open. Use the {@link Builder} to set on
* session open.
*
* @return Key to set the chrome window URI, or null to use default URI.
*/
public @Nullable String getChromeUri() {
return getString(CHROME_URI);
}
/**
* The user agent override string.
*
* @return The current user agent string or null if the agent is specified by {@link
* GeckoSessionSettings#USER_AGENT_MODE}
*/
public @Nullable String getUserAgentOverride() {
return getString(USER_AGENT_OVERRIDE);
}
private String getString(final Key<String> key) {
synchronized (mBundle) {
return mBundle.getString(key.name);
}
}
/* package */ @NonNull
GeckoBundle toBundle() {
return new GeckoBundle(mBundle);
}
@Override
public String toString() {
return mBundle.toString();
}
@Override
public boolean equals(final Object other) {
return other instanceof GeckoSessionSettings
&& mBundle.equals(((GeckoSessionSettings) other).mBundle);
}
@Override
public int hashCode() {
return mBundle.hashCode();
}
private <T> boolean valueChangedLocked(final Key<T> key, final T value) {
if (key.initOnly && mSession != null) {
throw new IllegalStateException("Read-only property");
} else if (key.values != null && !key.values.contains(value)) {
throw new IllegalArgumentException("Invalid value");
}
final Object old = mBundle.get(key.name);
return (old != value) && (old == null || !old.equals(value));
}
private void dispatchUpdate() {
if (mSession != null) {
mSession.getEventDispatcher().dispatch("GeckoView:UpdateSettings", toBundle());
}
}
@Override // Parcelable
public int describeContents() {
return 0;
}
@Override // Parcelable
public void writeToParcel(final @NonNull Parcel out, final int flags) {
mBundle.writeToParcel(out, flags);
}
// AIDL code may call readFromParcel even though it's not part of Parcelable.
@SuppressWarnings("checkstyle:javadocmethod")
public void readFromParcel(final @NonNull Parcel source) {
mBundle.readFromParcel(source);
}
public static final Parcelable.Creator<GeckoSessionSettings> CREATOR =
new Parcelable.Creator<GeckoSessionSettings>() {
@Override
public GeckoSessionSettings createFromParcel(final Parcel in) {
final GeckoSessionSettings settings = new GeckoSessionSettings();
settings.readFromParcel(in);
return settings;
}
@Override
public GeckoSessionSettings[] newArray(final int size) {
return new GeckoSessionSettings[size];
}
};
}