diff options
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java')
-rw-r--r-- | mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java | 732 |
1 files changed, 732 insertions, 0 deletions
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 new file mode 100644 index 0000000000..046f7a3072 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java @@ -0,0 +1,732 @@ +/* -*- 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.jsm + /** "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.jsm + /** 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 <meta> 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 <meta> 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]; + } + }; +} |