/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.webkit;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
import androidx.webkit.internal.ApiFeature;
import androidx.webkit.internal.ApiHelperForM;
import androidx.webkit.internal.ApiHelperForN;
import androidx.webkit.internal.ApiHelperForO;
import androidx.webkit.internal.ApiHelperForQ;
import androidx.webkit.internal.WebSettingsAdapter;
import androidx.webkit.internal.WebViewFeatureInternal;
import androidx.webkit.internal.WebViewGlueCommunicator;
import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Set;
/**
* Compatibility version of {@link android.webkit.WebSettings}
*/
public class WebSettingsCompat {
private WebSettingsCompat() {}
/**
* Sets whether this WebView should raster tiles when it is
* offscreen but attached to a window. Turning this on can avoid
* rendering artifacts when animating an offscreen WebView on-screen.
* Offscreen WebViews in this mode use more memory. The default value is
* false.<br>
* Please follow these guidelines to limit memory usage:
* <ul>
* <li> WebView size should be not be larger than the device screen size.
* <li> Limit use of this mode to a small number of WebViews. Use it for
* visible WebViews and WebViews about to be animated to visible.
* </ul>
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#OFF_SCREEN_PRERASTER}.
*/
@RequiresFeature(name = WebViewFeature.OFF_SCREEN_PRERASTER,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setOffscreenPreRaster(@NonNull WebSettings settings, boolean enabled) {
ApiFeature.M feature = WebViewFeatureInternal.OFF_SCREEN_PRERASTER;
if (feature.isSupportedByFramework()) {
ApiHelperForM.setOffscreenPreRaster(settings, enabled);
} else if (feature.isSupportedByWebView()) {
getAdapter(settings).setOffscreenPreRaster(enabled);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Gets whether this WebView should raster tiles when it is
* offscreen but attached to a window.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#OFF_SCREEN_PRERASTER}.
*
* @return {@code true} if this WebView will raster tiles when it is
* offscreen but attached to a window.
*/
@RequiresFeature(name = WebViewFeature.OFF_SCREEN_PRERASTER,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static boolean getOffscreenPreRaster(@NonNull WebSettings settings) {
ApiFeature.M feature = WebViewFeatureInternal.OFF_SCREEN_PRERASTER;
if (feature.isSupportedByFramework()) {
return ApiHelperForM.getOffscreenPreRaster(settings);
} else if (feature.isSupportedByWebView()) {
return getAdapter(settings).getOffscreenPreRaster();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Sets whether Safe Browsing is enabled. Safe Browsing allows WebView to
* protect against malware and phishing attacks by verifying the links.
*
* <p>
* Safe Browsing can be disabled for all WebViews using a manifest tag (read <a
* href="{@docRoot}reference/android/webkit/WebView.html">general Safe Browsing info</a>). The
* manifest tag has a lower precedence than this API.
*
* <p>
* Safe Browsing is enabled by default for devices which support it.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#SAFE_BROWSING_ENABLE}.
*
* @param enabled Whether Safe Browsing is enabled.
*/
@RequiresFeature(name = WebViewFeature.SAFE_BROWSING_ENABLE,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setSafeBrowsingEnabled(@NonNull WebSettings settings, boolean enabled) {
ApiFeature.O feature = WebViewFeatureInternal.SAFE_BROWSING_ENABLE;
if (feature.isSupportedByFramework()) {
ApiHelperForO.setSafeBrowsingEnabled(settings, enabled);
} else if (feature.isSupportedByWebView()) {
getAdapter(settings).setSafeBrowsingEnabled(enabled);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Gets whether Safe Browsing is enabled.
* See {@link #setSafeBrowsingEnabled}.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#SAFE_BROWSING_ENABLE}.
*
* @return {@code true} if Safe Browsing is enabled and {@code false} otherwise.
*/
@RequiresFeature(name = WebViewFeature.SAFE_BROWSING_ENABLE,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static boolean getSafeBrowsingEnabled(@NonNull WebSettings settings) {
ApiFeature.O feature = WebViewFeatureInternal.SAFE_BROWSING_ENABLE;
if (feature.isSupportedByFramework()) {
return ApiHelperForO.getSafeBrowsingEnabled(settings);
} else if (feature.isSupportedByWebView()) {
return getAdapter(settings).getSafeBrowsingEnabled();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef(flag = true, value = {
WebSettings.MENU_ITEM_NONE,
WebSettings.MENU_ITEM_SHARE,
WebSettings.MENU_ITEM_WEB_SEARCH,
WebSettings.MENU_ITEM_PROCESS_TEXT
})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface MenuItemFlags {}
/**
* Disables the action mode menu items according to {@code menuItems} flag.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#DISABLED_ACTION_MODE_MENU_ITEMS}.
*
* @param menuItems an integer field flag for the menu items to be disabled.
*/
@RequiresFeature(name = WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setDisabledActionModeMenuItems(@NonNull WebSettings settings,
@MenuItemFlags int menuItems) {
ApiFeature.N feature = WebViewFeatureInternal.DISABLED_ACTION_MODE_MENU_ITEMS;
if (feature.isSupportedByFramework()) {
ApiHelperForN.setDisabledActionModeMenuItems(settings, menuItems);
} else if (feature.isSupportedByWebView()) {
getAdapter(settings).setDisabledActionModeMenuItems(menuItems);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Gets the action mode menu items that are disabled, expressed in an integer field flag.
* The default value is {@link WebSettings#MENU_ITEM_NONE}
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#DISABLED_ACTION_MODE_MENU_ITEMS}.
*
* @return all the disabled menu item flags combined with bitwise OR.
*/
@RequiresFeature(name = WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static @MenuItemFlags int getDisabledActionModeMenuItems(@NonNull WebSettings settings) {
ApiFeature.N feature = WebViewFeatureInternal.DISABLED_ACTION_MODE_MENU_ITEMS;
if (feature.isSupportedByFramework()) {
return ApiHelperForN.getDisabledActionModeMenuItems(settings);
} else if (feature.isSupportedByWebView()) {
return getAdapter(settings).getDisabledActionModeMenuItems();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Disable force dark, irrespective of the force dark mode of the WebView parent. In this mode,
* WebView content will always be rendered as-is, regardless of whether native views are being
* automatically darkened.
*
* @see #setForceDark
* @deprecated refer to {@link #setForceDark}
*/
@Deprecated
public static final int FORCE_DARK_OFF = WebSettings.FORCE_DARK_OFF;
/**
* Enable force dark dependent on the state of the WebView parent view. If the WebView parent
* view is being automatically force darkened
* (@see android.view.View#setForceDarkAllowed), then WebView content will be rendered
* so as to emulate a dark theme. WebViews that are not attached to the view hierarchy will not
* be inverted.
*
* <p class="note"> If your app uses a dark theme, WebView will not be inverted. Similarly, if
* your app's theme inherits from a {@code DayNight} theme, WebView will not be inverted.
* In either of these cases, you should control the mode manually with
* {@link ForceDark#FORCE_DARK_ON} or {@link ForceDark#FORCE_DARK_OFF}.
*
* <p> See <a href="https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#force_dark">
* Force Dark documentation</a> for more information.
*
* @see #setForceDark
* @deprecated refer to {@link #setForceDark}
*/
@Deprecated
public static final int FORCE_DARK_AUTO = WebSettings.FORCE_DARK_AUTO;
/**
* Unconditionally enable force dark. In this mode WebView content will always be rendered so
* as to emulate a dark theme.
*
* @see #setForceDark
* @deprecated refer to {@link #setForceDark}
*/
@Deprecated
public static final int FORCE_DARK_ON = WebSettings.FORCE_DARK_ON;
/**
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef(value = {
FORCE_DARK_OFF,
FORCE_DARK_AUTO,
FORCE_DARK_ON,
})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface ForceDark {}
/**
* Set the force dark mode for this WebView.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#FORCE_DARK}.
*
* <p>
* If equals to {@link ForceDark#FORCE_DARK_ON} then {@link #setForceDarkStrategy} is used to
* specify darkening strategy.
*
* @param forceDarkMode the force dark mode to set.
* @see #getForceDark
* @deprecated The "force dark" model previously implemented by WebView was complex
* and didn't interoperate well with current Web standards for
* {@code prefers-color-scheme} and {@code color-scheme}. In apps with
* {@code targetSdkVersion} ≥ {@link android.os.Build.VERSION_CODES#TIRAMISU}
* this API is a no-op and WebView will always use the dark style defined by web content
* authors if the app's theme is dark. To customize the behavior, refer to
* {@link #setAlgorithmicDarkeningAllowed}.
*/
@Deprecated
@RequiresFeature(name = WebViewFeature.FORCE_DARK,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setForceDark(@NonNull WebSettings settings,
@ForceDark int forceDarkMode) {
ApiFeature.Q feature = WebViewFeatureInternal.FORCE_DARK;
if (feature.isSupportedByFramework()) {
ApiHelperForQ.setForceDark(settings, forceDarkMode);
} else if (feature.isSupportedByWebView()) {
getAdapter(settings).setForceDark(forceDarkMode);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Get the force dark mode for this WebView.
*
* <p>
* The default force dark mode is {@link #FORCE_DARK_AUTO}.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#FORCE_DARK}.
*
* @return the currently set force dark mode.
* @see #setForceDark
* @deprecated refer to {@link #setForceDark}
*/
@Deprecated
@RequiresFeature(name = WebViewFeature.FORCE_DARK,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static @ForceDark int getForceDark(@NonNull WebSettings settings) {
ApiFeature.Q feature = WebViewFeatureInternal.FORCE_DARK;
if (feature.isSupportedByFramework()) {
return ApiHelperForQ.getForceDark(settings);
} else if (feature.isSupportedByWebView()) {
return getAdapter(settings).getForceDark();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Control whether algorithmic darkening is allowed.
*
* <p class="note">
* <b>Note:</b> This API and the behaviour described only apply to apps with
* {@code targetSdkVersion} ≥ {@link android.os.Build.VERSION_CODES#TIRAMISU}.
*
* <p>
* WebView always sets the media query {@code prefers-color-scheme} according to the app's
* theme attribute {@link android.R.styleable#Theme_isLightTheme isLightTheme}, i.e.
* {@code prefers-color-scheme} is {@code light} if isLightTheme is true or not specified,
* otherwise it is {@code dark}. This means that the web content's light or dark style will
* be applied automatically to match the app's theme if the content supports it.
*
* <p>
* Algorithmic darkening is disallowed by default.
* <p>
* If the app's theme is dark and it allows algorithmic darkening, WebView will attempt to
* darken web content using an algorithm, if the content doesn't define its own dark styles
* and doesn't explicitly disable darkening.
*
* <p>
* If Android is applying Force Dark to WebView then WebView will ignore the value of
* this setting and behave as if it were set to true.
*
* <p>
* The deprecated {@link #setForceDark} and related API are no-ops in apps with
* {@code targetSdkVersion} ≥ {@link android.os.Build.VERSION_CODES#TIRAMISU},
* but they still apply to apps with
* {@code targetSdkVersion} < {@link android.os.Build.VERSION_CODES#TIRAMISU}.
*
* <p>
* The below table summarizes how APIs work with different apps.
*
* <table border="2" width="85%" align="center" cellpadding="5">
* <thead>
* <tr>
* <th>App</th>
* <th>Web content which uses prefers-color-scheme</th>
* <th>Web content which does not use prefers-color-scheme</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>App with {@code isLightTheme} True or not set</td>
* <td>Renders with the light theme defined by the content author.</td>
* <td>Renders with the default styling defined by the content author.</td>
* </tr>
* <tr>
* <td>App with Android forceDark in effect</td>
* <td>Renders with the dark theme defined by the content author.</td>
* <td>Renders with the styling modified to dark colors by an algorithm
* if allowed by the content author.</td>
* </tr>
* <tr>
* <td>App with {@code isLightTheme} False,
* {@code targetSdkVersion} < {@link android.os.Build.VERSION_CODES#TIRAMISU},
* and has {@code FORCE_DARK_AUTO}</td>
* <td>Renders with the dark theme defined by the content author.</td>
* <td>Renders with the default styling defined by the content author.</td>
* </tr>
* <tr>
* <td>App with {@code isLightTheme} False,
* {@code targetSdkVersion} ≥ {@link android.os.Build.VERSION_CODES#TIRAMISU},
* and {@code setAlgorithmicDarkening(false)}</td>
* <td>Renders with the dark theme defined by the content author.</td>
* <td>Renders with the default styling defined by the content author.</td>
* </tr>
* <tr>
* <td>App with {@code isLightTheme} False,
* {@code targetSdkVersion} ≥ {@link android.os.Build.VERSION_CODES#TIRAMISU},
* and {@code setAlgorithmicDarkening(true)}</td>
* <td>Renders with the dark theme defined by the content author.</td>
* <td>Renders with the styling modified to dark colors by an algorithm if allowed
* by the content author.</td>
* </tr>
* </tbody>
* </table>
* </p>
*
* <p>
* To check if {@code WebViewFeature.ALGORITHMIC_DARKENING} is supported,
* {@link androidx.webkit.WebViewFeature#isFeatureSupported} should be called after WebView
* is created.
*
* <p>
* @param allow allow algorithmic darkening or not.
*
*/
@RequiresFeature(name = WebViewFeature.ALGORITHMIC_DARKENING,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setAlgorithmicDarkeningAllowed(@NonNull WebSettings settings,
boolean allow) {
ApiFeature.T feature = WebViewFeatureInternal.ALGORITHMIC_DARKENING;
if (feature.isSupportedByWebView()) {
getAdapter(settings).setAlgorithmicDarkeningAllowed(allow);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Get if algorithmic darkening is allowed or not for this WebView.
* The default is false.
*
* @return if the algorithmic darkening is allowed or not.
* @see #setAlgorithmicDarkeningAllowed
*/
@RequiresFeature(name = WebViewFeature.ALGORITHMIC_DARKENING,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static boolean isAlgorithmicDarkeningAllowed(@NonNull WebSettings settings) {
ApiFeature.T feature = WebViewFeatureInternal.ALGORITHMIC_DARKENING;
if (feature.isSupportedByWebView()) {
return getAdapter(settings).isAlgorithmicDarkeningAllowed();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* In this mode WebView content will be darkened by a user agent and it will ignore the
* web page's dark theme if it exists. To avoid mixing two different darkening strategies,
* the {@code prefers-color-scheme} media query will evaluate to light.
*
* <p> See <a href="https://drafts.csswg.org/css-color-adjust-1/">specification</a>
* for more information.
*
* @see #setForceDarkStrategy
* @deprecated refer to {@link #setForceDark}
*/
@Deprecated
public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY =
WebSettingsBoundaryInterface.ForceDarkBehavior.FORCE_DARK_ONLY;
/**
* In this mode WebView content will always be darkened using dark theme provided by web page.
* If web page does not provide dark theme support WebView content will be rendered with a
* default theme.
*
* <p> See <a href="https://drafts.csswg.org/css-color-adjust-1/">specification</a>
* for more information.
*
* @see #setForceDarkStrategy
* @deprecated refer to {@link #setForceDark}
*/
@Deprecated
public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY =
WebSettingsBoundaryInterface.ForceDarkBehavior.MEDIA_QUERY_ONLY;
/**
* In this mode WebView content will be darkened by a user agent unless web page supports dark
* theme. WebView determines whether web pages supports dark theme by the presence of
* {@code color-scheme} metadata containing "dark" value. For example,
* {@code <meta name="color-scheme" content="dark light">}.
* If the metadata is not presented WebView content will be darkened by a user agent and
* {@code prefers-color-scheme} media query will evaluate to light.
*
* <p> See <a href="https://drafts.csswg.org/css-color-adjust-1/">specification</a>
* for more information.
*
* @see #setForceDarkStrategy
* @deprecated refer to {@link #setForceDark}
*/
@Deprecated
public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING =
WebSettingsBoundaryInterface.ForceDarkBehavior.PREFER_MEDIA_QUERY_OVER_FORCE_DARK;
/**
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef(value = {
DARK_STRATEGY_USER_AGENT_DARKENING_ONLY,
DARK_STRATEGY_WEB_THEME_DARKENING_ONLY,
DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING,
})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface ForceDarkStrategy {}
/**
* Set how WebView content should be darkened.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#FORCE_DARK_STRATEGY}.
*
* <p>
* The specified strategy is only used if force dark mode is on.
* See {@link #setForceDark}.
*
* @param forceDarkBehavior the force dark strategy to set.
* @see #getForceDarkStrategy
* @deprecated refer to {@link #setForceDark}
*/
@RequiresFeature(name = WebViewFeature.FORCE_DARK_STRATEGY,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
@Deprecated
public static void setForceDarkStrategy(@NonNull WebSettings settings,
@ForceDarkStrategy int forceDarkBehavior) {
ApiFeature.NoFramework feature = WebViewFeatureInternal.FORCE_DARK_STRATEGY;
if (feature.isSupportedByWebView()) {
getAdapter(settings).setForceDarkStrategy(forceDarkBehavior);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Get how content is darkened for this WebView.
*
* <p>
* The default force dark strategy is
* {@link #DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING}
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#FORCE_DARK_STRATEGY}.
*
* @return the currently set force dark strategy.
* @see #setForceDarkStrategy
* @deprecated refer to {@link #setForceDark}
*/
@RequiresFeature(name = WebViewFeature.FORCE_DARK_STRATEGY,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
@Deprecated
public static @ForceDarkStrategy int getForceDarkStrategy(@NonNull WebSettings settings) {
ApiFeature.NoFramework feature = WebViewFeatureInternal.FORCE_DARK_STRATEGY;
if (feature.isSupportedByWebView()) {
return getAdapter(settings).getForceDark();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Sets whether EnterpriseAuthenticationAppLinkPolicy if set by admin is allowed to have any
* effect on WebView.
* <p>
* EnterpriseAuthenticationAppLinkPolicy in WebView allows admins to specify authentication
* urls. When WebView is redirected to authentication url, and an app on the device has
* registered as the default handler for the url, that app is launched.
* <p>
* EnterpriseAuthenticationAppLinkPolicy is enabled by default.
*
* <p> See <a href="https://source.chromium.org/chromium/chromium/src/+/main:components/policy/resources/policy_templates.json;l=32321?q=EnterpriseAuthenticationAppLinkPolicy%20file:policy_templates.json">
* this</a> for more information on EnterpriseAuthenticationAppLinkPolicy.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY}.
*
* @param enabled Whether EnterpriseAuthenticationAppLinkPolicy should be enabled.
*/
@RequiresFeature(name = WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(
@NonNull WebSettings settings,
boolean enabled) {
ApiFeature.NoFramework feature =
WebViewFeatureInternal.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY;
if (feature.isSupportedByWebView()) {
getAdapter(settings).setEnterpriseAuthenticationAppLinkPolicyEnabled(enabled);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Gets whether EnterpriseAuthenticationAppLinkPolicy is allowed to have any effect on WebView.
*
* <p> See <a href="https://source.chromium.org/chromium/chromium/src/+/main:components/policy/resources/policy_templates.json;l=32321?q=EnterpriseAuthenticationAppLinkPolicy%20file:policy_templates.json">
* this</a> for more information on EnterpriseAuthenticationAppLinkPolicy.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY}.
*
* @return {@code true} if EnterpriseAuthenticationAppLinkPolicy is enabled and {@code false}
* otherwise.
*/
@RequiresFeature(name = WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(
@NonNull WebSettings settings) {
ApiFeature.NoFramework feature =
WebViewFeatureInternal.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY;
if (feature.isSupportedByWebView()) {
return getAdapter(settings).getEnterpriseAuthenticationAppLinkPolicyEnabled();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Get the currently configured allow-list of origins, which is guaranteed to receive the
* {@code X-Requested-With} HTTP header on requests from the {@link WebView} owning the passed
* {@link WebSettings}.
* <p>
* Any origin <em>not</em> on this allow-list may not receive the header, depending on the
* current installed WebView provider.
* <p>
* The format of the strings in the allow-list follows the origin rules of
* {@link WebViewCompat#addWebMessageListener(WebView, String, Set, WebViewCompat.WebMessageListener)}.
*
* @param settings Settings retrieved from {@link WebView#getSettings()}.
* @return The configured set of allow-listed origins.
* @see #setRequestedWithHeaderOriginAllowList(WebSettings, Set)
*/
@RequiresFeature(name = WebViewFeature.REQUESTED_WITH_HEADER_ALLOW_LIST,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
@NonNull
public static Set<String> getRequestedWithHeaderOriginAllowList(@NonNull WebSettings settings) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.REQUESTED_WITH_HEADER_ALLOW_LIST;
if (feature.isSupportedByWebView()) {
return getAdapter(settings).getRequestedWithHeaderOriginAllowList();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Set an allow-list of origins to receive the {@code X-Requested-With} HTTP header from the
* WebView owning the passed {@link WebSettings}.
* <p>
* Historically, this header was sent on all requests from WebView, containing the
* app package name of the embedding app. Depending on the version of installed WebView, this
* may no longer be the case, as the header was deprecated in late 2022, and its use
* discontinued.
* <p>
* Apps can use this method to restore the legacy behavior for servers that still rely on
* the deprecated header, but it should not be used to identify the webview to first-party
* servers under the control of the app developer.
* <p>
* The format of the strings in the allow-list follows the origin rules of
* {@link WebViewCompat#addWebMessageListener(WebView, String, Set, WebViewCompat.WebMessageListener)}.
*
* @param settings Settings retrieved from {@link WebView#getSettings()}.
* @param allowList Set of origins to allow-list.
* @throws IllegalArgumentException if the allow-list contains a malformed origin.
*/
@RequiresFeature(name = WebViewFeature.REQUESTED_WITH_HEADER_ALLOW_LIST,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setRequestedWithHeaderOriginAllowList(@NonNull WebSettings settings,
@NonNull Set<String> allowList) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.REQUESTED_WITH_HEADER_ALLOW_LIST;
if (feature.isSupportedByWebView()) {
getAdapter(settings).setRequestedWithHeaderOriginAllowList(allowList);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Sets the WebView's user-agent metadata to generate user-agent client hints.
* <p>
* UserAgentMetadata in WebView is used to populate user-agent client hints, they can provide
* the client’s branding and version information, the underlying operating system’s branding
* and major version, as well as details about the underlying device.
* <p>
* The user-agent string can be set with {@link WebSettings#setUserAgentString(String)}, here
* are the details on how this API interacts it to generate user-agent client hints.
* <p>
* If the UserAgentMetadata is null and the overridden user-agent contains the system default
* user-agent, the system default value will be used.
* <p>
* If the UserAgentMetadata is null but the overridden user-agent doesn't contain the system
* default user-agent, only the
* <a href="https://wicg.github.io/client-hints-infrastructure/#low-entropy-hint-table">low-entry user-agent client hints</a> will be generated.
*
* <p> See <a href="https://wicg.github.io/ua-client-hints/">
* this</a> for more information about User-Agent Client Hints.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#USER_AGENT_METADATA}.
*
* @param settings Settings retrieved from {@link WebView#getSettings()}.
* @param metadata the WebView's user-agent metadata.
*/
@RequiresFeature(name = WebViewFeature.USER_AGENT_METADATA,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setUserAgentMetadata(@NonNull WebSettings settings,
@NonNull UserAgentMetadata metadata) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.USER_AGENT_METADATA;
if (feature.isSupportedByWebView()) {
getAdapter(settings).setUserAgentMetadata(metadata);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Get the WebView's user-agent metadata which used to generate user-agent client hints.
*
* <p> See <a href="https://wicg.github.io/ua-client-hints/"> this</a> for more information
* about User-Agent Client Hints.
*
* <p>
* This method should only be called if
* {@link WebViewFeature#isFeatureSupported(String)}
* returns true for {@link WebViewFeature#USER_AGENT_METADATA}.
*
* @param settings Settings retrieved from {@link WebView#getSettings()}.
*/
@RequiresFeature(name = WebViewFeature.USER_AGENT_METADATA,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
@NonNull
public static UserAgentMetadata getUserAgentMetadata(@NonNull WebSettings settings) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.USER_AGENT_METADATA;
if (feature.isSupportedByWebView()) {
return getAdapter(settings).getUserAgentMetadata();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* @hide
*/
@IntDef({ATTRIBUTION_BEHAVIOR_DISABLED,
ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER,
ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER,
ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER})
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Retention(RetentionPolicy.SOURCE)
@interface AttributionRegistrationBehavior {
}
/**
* AttributionRegistrationBehavior that disables source and trigger registration from WebView.
* <p>
* Note that the initial network call to the Attribution Source or Trigger URIs may still
* happen depending on the installed version of WebView, but any response is discarded and
* nothing will be stored on the device.
*/
public static final int ATTRIBUTION_BEHAVIOR_DISABLED =
WebSettingsBoundaryInterface.AttributionBehavior.DISABLED;
/**
* AttributionRegistrationBehavior that allows apps to register app sources (sources
* associated with the app package name) and web triggers (triggers associated with the
* eTLD+1) from WebView.
* <p>
* This is the default behavior.
*/
public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER =
WebSettingsBoundaryInterface.AttributionBehavior.APP_SOURCE_AND_WEB_TRIGGER;
/**
* AttributionRegistrationBehavior that allows apps to register web sources and web triggers
* from WebView.
* <p>
* This option should only be used after applying to
* <a href="https://developer.android.com/design-for-safety/privacy-sandbox/attribution-app-to-web#register-attribution">
* use web sources</a>.
*/
public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER =
WebSettingsBoundaryInterface.AttributionBehavior.WEB_SOURCE_AND_WEB_TRIGGER;
/**
* AttributionRegistrationBehavior that allows apps to register app sources and app triggers
* from WebView.
*/
public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER =
WebSettingsBoundaryInterface.AttributionBehavior.APP_SOURCE_AND_APP_TRIGGER;
/**
* Control how WebView interacts with
* <a href="https://developer.android.com/design-for-safety/privacy-sandbox/attribution">Attribution Reporting</a>.
* <p>
* WebView supports
* <a href="https://github.com/WICG/attribution-reporting-api">Attribution Reporting</a> across
* <a href="https://developer.android.com/design-for-safety/privacy-sandbox/attribution-app-to-web">apps and web pages</a>
* by enabling the web content to register sources and triggers.
* <p>
* By default, attribution sources will be registered as attributed to the app, while
* triggers are attributed to the loaded web content
* ({@link #ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER}). Apps should only need to
* change this default if they have a specific semantic for how they use WebView. In
* particular, in-app browsers should follow the steps to apply to the
* <a href="https://developer.android.com/design-for-safety/privacy-sandbox/attribution-app-to-web#register-attribution">
* allowlist for registering web sources</a> and then set the
* {@link #ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER} behavior.
*
* @see
* <a href="https://developer.android.com/design-for-safety/privacy-sandbox/attribution-app-to-web#register-attribution">How to apply to use web source</a>
* @see #ATTRIBUTION_BEHAVIOR_DISABLED
* @see #ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER
* @see #ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER
* @see #ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER
* @param settings Settings retrieved from {@link WebView#getSettings()}.
* @param behavior New behavior to use.
*/
@RequiresFeature(name = WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setAttributionRegistrationBehavior(@NonNull WebSettings settings,
@AttributionRegistrationBehavior int behavior) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.ATTRIBUTION_REGISTRATION_BEHAVIOR;
if (feature.isSupportedByWebView()) {
getAdapter(settings).setAttributionRegistrationBehavior(behavior);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Read the current behavior for attribution registration.
*
* @see #setAttributionRegistrationBehavior(WebSettings, int)
* @see #ATTRIBUTION_BEHAVIOR_DISABLED
* @see #ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER
* @see #ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER
* @see #ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER
* @param settings Settings retrieved from {@link WebView#getSettings()}.
*/
@RequiresFeature(name = WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
@AttributionRegistrationBehavior
public static int getAttributionRegistrationBehavior(@NonNull WebSettings settings) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.ATTRIBUTION_REGISTRATION_BEHAVIOR;
if (feature.isSupportedByWebView()) {
return getAdapter(settings).getAttributionRegistrationBehavior();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Sets permissions provided through
* {@link WebViewMediaIntegrityApiStatusConfig} for using the
* WebView Integrity API.
*/
@RequiresFeature(name = WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setWebViewMediaIntegrityApiStatus(
@NonNull WebSettings settings,
@NonNull WebViewMediaIntegrityApiStatusConfig permissionConfig) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.WEBVIEW_MEDIA_INTEGRITY_API_STATUS;
if (feature.isSupportedByWebView()) {
getAdapter(settings).setWebViewMediaIntegrityApiStatus(permissionConfig);
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
/**
* Returns the {@link WebViewMediaIntegrityApiStatusConfig} currently in use.
*/
@RequiresFeature(name = WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS,
enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
@NonNull
public static WebViewMediaIntegrityApiStatusConfig getWebViewMediaIntegrityApiStatus(
@NonNull WebSettings settings) {
final ApiFeature.NoFramework feature =
WebViewFeatureInternal.WEBVIEW_MEDIA_INTEGRITY_API_STATUS;
if (feature.isSupportedByWebView()) {
return getAdapter(settings).getWebViewMediaIntegrityApiStatus();
} else {
throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
private static WebSettingsAdapter getAdapter(WebSettings settings) {
return WebViewGlueCommunicator.getCompatConverter().convertSettings(settings);
}
}