// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.android_webview; import android.content.Context; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Message; import android.os.Process; import android.provider.Settings; import android.util.Log; import android.webkit.WebSettings; import android.webkit.WebSettings.PluginState; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import org.chromium.base.ThreadUtils; /** * Stores Android WebView specific settings that does not need to be synced to WebKit. * Use {@link org.chromium.content.browser.ContentSettings} for WebKit settings. * * Methods in this class can be called from any thread, including threads created by * the client of WebView. */ @JNINamespace("android_webview") public class AwSettings { // This enum corresponds to WebSettings.LayoutAlgorithm. We use our own to be // able to extend it. public enum LayoutAlgorithm { NORMAL, SINGLE_COLUMN, NARROW_COLUMNS, TEXT_AUTOSIZING, } private static final String TAG = "AwSettings"; // This class must be created on the UI thread. Afterwards, it can be // used from any thread. Internally, the class uses a message queue // to call native code on the UI thread only. // Values passed in on construction. private final boolean mHasInternetPermission; private ZoomSupportChangeListener mZoomChangeListener; private double mDIPScale = 1.0; // Lock to protect all settings. private final Object mAwSettingsLock = new Object(); private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS; private int mTextSizePercent = 100; private String mStandardFontFamily = "sans-serif"; private String mFixedFontFamily = "monospace"; private String mSansSerifFontFamily = "sans-serif"; private String mSerifFontFamily = "serif"; private String mCursiveFontFamily = "cursive"; private String mFantasyFontFamily = "fantasy"; private String mDefaultTextEncoding; private String mUserAgent; private int mMinimumFontSize = 8; private int mMinimumLogicalFontSize = 8; private int mDefaultFontSize = 16; private int mDefaultFixedFontSize = 13; private boolean mLoadsImagesAutomatically = true; private boolean mImagesEnabled = true; private boolean mJavaScriptEnabled = false; private boolean mAllowUniversalAccessFromFileURLs = false; private boolean mAllowFileAccessFromFileURLs = false; private boolean mJavaScriptCanOpenWindowsAutomatically = false; private boolean mSupportMultipleWindows = false; private PluginState mPluginState = PluginState.OFF; private boolean mAppCacheEnabled = false; private boolean mDomStorageEnabled = false; private boolean mDatabaseEnabled = false; private boolean mUseWideViewport = false; private boolean mLoadWithOverviewMode = false; private boolean mMediaPlaybackRequiresUserGesture = true; private String mDefaultVideoPosterURL; private float mInitialPageScalePercent = 0; private boolean mSpatialNavigationEnabled; // Default depends on device features. private boolean mEnableSupportedHardwareAcceleratedFeatures = false; private final boolean mSupportLegacyQuirks; private final boolean mPasswordEchoEnabled; // Not accessed by the native side. private boolean mBlockNetworkLoads; // Default depends on permission of embedding APK. private boolean mAllowContentUrlAccess = true; private boolean mAllowFileUrlAccess = true; private int mCacheMode = WebSettings.LOAD_DEFAULT; private boolean mShouldFocusFirstNode = true; private boolean mGeolocationEnabled = true; private boolean mAutoCompleteEnabled = true; private boolean mSupportZoom = true; private boolean mBuiltInZoomControls = false; private boolean mDisplayZoomControls = true; static class LazyDefaultUserAgent{ // Lazy Holder pattern private static final String sInstance = nativeGetDefaultUserAgent(); } // Protects access to settings global fields. private static final Object sGlobalContentSettingsLock = new Object(); // For compatibility with the legacy WebView, we can only enable AppCache when the path is // provided. However, we don't use the path, so we just check if we have received it from the // client. private static boolean sAppCachePathIsSet = false; // The native side of this object. It's lifetime is bounded by the WebContent it is attached to. private long mNativeAwSettings = 0; // Custom handler that queues messages to call native code on the UI thread. private final EventHandler mEventHandler; private static final int MINIMUM_FONT_SIZE = 1; private static final int MAXIMUM_FONT_SIZE = 72; // Class to handle messages to be processed on the UI thread. private class EventHandler { // Message id for running a Runnable with mAwSettingsLock held. private static final int RUN_RUNNABLE_BLOCKING = 0; // Actual UI thread handler private Handler mHandler; // Synchronization flag. private boolean mSynchronizationPending = false; EventHandler() { } void bindUiThread() { if (mHandler != null) return; mHandler = new Handler(ThreadUtils.getUiThreadLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case RUN_RUNNABLE_BLOCKING: synchronized (mAwSettingsLock) { if (mNativeAwSettings != 0) { ((Runnable)msg.obj).run(); } mSynchronizationPending = false; mAwSettingsLock.notifyAll(); } break; } } }; } void runOnUiThreadBlockingAndLocked(Runnable r) { assert Thread.holdsLock(mAwSettingsLock); if (mHandler == null) return; if (ThreadUtils.runningOnUiThread()) { r.run(); } else { assert !mSynchronizationPending; mSynchronizationPending = true; mHandler.sendMessage(Message.obtain(null, RUN_RUNNABLE_BLOCKING, r)); try { while (mSynchronizationPending) { mAwSettingsLock.wait(); } } catch (InterruptedException e) { Log.e(TAG, "Interrupted waiting a Runnable to complete", e); mSynchronizationPending = false; } } } void maybePostOnUiThread(Runnable r) { if (mHandler != null) { mHandler.post(r); } } void updateWebkitPreferencesLocked() { runOnUiThreadBlockingAndLocked(new Runnable() { @Override public void run() { updateWebkitPreferencesOnUiThreadLocked(); } }); } } interface ZoomSupportChangeListener { public void onGestureZoomSupportChanged( boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom); } public AwSettings(Context context, boolean isAccessFromFileURLsGrantedByDefault, boolean supportsLegacyQuirks) { boolean hasInternetPermission = context.checkPermission( android.Manifest.permission.INTERNET, Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED; synchronized (mAwSettingsLock) { mHasInternetPermission = hasInternetPermission; mBlockNetworkLoads = !hasInternetPermission; mEventHandler = new EventHandler(); if (isAccessFromFileURLsGrantedByDefault) { mAllowUniversalAccessFromFileURLs = true; mAllowFileAccessFromFileURLs = true; } mDefaultTextEncoding = AwResource.getDefaultTextEncoding(); mUserAgent = LazyDefaultUserAgent.sInstance; // Best-guess a sensible initial value based on the features supported on the device. mSpatialNavigationEnabled = !context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TOUCHSCREEN); // Respect the system setting for password echoing. mPasswordEchoEnabled = Settings.System.getInt(context.getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1) == 1; // By default, scale the text size by the system font scale factor. Embedders // may override this by invoking setTextZoom(). mTextSizePercent *= context.getResources().getConfiguration().fontScale; mSupportLegacyQuirks = supportsLegacyQuirks; } // Defer initializing the native side until a native WebContents instance is set. } @CalledByNative private void nativeAwSettingsGone(long nativeAwSettings) { assert mNativeAwSettings != 0 && mNativeAwSettings == nativeAwSettings; mNativeAwSettings = 0; } @CalledByNative private double getDIPScaleLocked() { assert Thread.holdsLock(mAwSettingsLock); return mDIPScale; } void setDIPScale(double dipScale) { synchronized (mAwSettingsLock) { mDIPScale = dipScale; // TODO(joth): This should also be synced over to native side, but right now // the setDIPScale call is always followed by a setWebContents() which covers this. } } void setZoomListener(ZoomSupportChangeListener zoomChangeListener) { synchronized (mAwSettingsLock) { mZoomChangeListener = zoomChangeListener; } } void setWebContents(int nativeWebContents) { synchronized (mAwSettingsLock) { if (mNativeAwSettings != 0) { nativeDestroy(mNativeAwSettings); assert mNativeAwSettings == 0; // nativeAwSettingsGone should have been called. } if (nativeWebContents != 0) { mEventHandler.bindUiThread(); mNativeAwSettings = nativeInit(nativeWebContents); nativeUpdateEverythingLocked(mNativeAwSettings); onGestureZoomSupportChanged( supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked()); } } } /** * See {@link android.webkit.WebSettings#setBlockNetworkLoads}. */ public void setBlockNetworkLoads(boolean flag) { synchronized (mAwSettingsLock) { if (!flag && !mHasInternetPermission) { throw new SecurityException("Permission denied - " + "application missing INTERNET permission"); } mBlockNetworkLoads = flag; } } /** * See {@link android.webkit.WebSettings#getBlockNetworkLoads}. */ public boolean getBlockNetworkLoads() { synchronized (mAwSettingsLock) { return mBlockNetworkLoads; } } /** * See {@link android.webkit.WebSettings#setAllowFileAccess}. */ public void setAllowFileAccess(boolean allow) { synchronized (mAwSettingsLock) { if (mAllowFileUrlAccess != allow) { mAllowFileUrlAccess = allow; } } } /** * See {@link android.webkit.WebSettings#getAllowFileAccess}. */ public boolean getAllowFileAccess() { synchronized (mAwSettingsLock) { return mAllowFileUrlAccess; } } /** * See {@link android.webkit.WebSettings#setAllowContentAccess}. */ public void setAllowContentAccess(boolean allow) { synchronized (mAwSettingsLock) { if (mAllowContentUrlAccess != allow) { mAllowContentUrlAccess = allow; } } } /** * See {@link android.webkit.WebSettings#getAllowContentAccess}. */ public boolean getAllowContentAccess() { synchronized (mAwSettingsLock) { return mAllowContentUrlAccess; } } /** * See {@link android.webkit.WebSettings#setCacheMode}. */ public void setCacheMode(int mode) { synchronized (mAwSettingsLock) { if (mCacheMode != mode) { mCacheMode = mode; } } } /** * See {@link android.webkit.WebSettings#getCacheMode}. */ public int getCacheMode() { synchronized (mAwSettingsLock) { return mCacheMode; } } /** * See {@link android.webkit.WebSettings#setNeedInitialFocus}. */ public void setShouldFocusFirstNode(boolean flag) { synchronized (mAwSettingsLock) { mShouldFocusFirstNode = flag; } } /** * See {@link android.webkit.WebView#setInitialScale}. */ public void setInitialPageScale(final float scaleInPercent) { synchronized (mAwSettingsLock) { if (mInitialPageScalePercent != scaleInPercent) { mInitialPageScalePercent = scaleInPercent; mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() { @Override public void run() { nativeUpdateInitialPageScaleLocked(mNativeAwSettings); } }); } } } @CalledByNative private float getInitialPageScalePercentLocked() { assert Thread.holdsLock(mAwSettingsLock); return mInitialPageScalePercent; } void setSpatialNavigationEnabled(boolean enable) { synchronized (mAwSettingsLock) { if (mSpatialNavigationEnabled != enable) { mSpatialNavigationEnabled = enable; mEventHandler.updateWebkitPreferencesLocked(); } } } @CalledByNative private boolean getSpatialNavigationLocked() { assert Thread.holdsLock(mAwSettingsLock); return mSpatialNavigationEnabled; } void setEnableSupportedHardwareAcceleratedFeatures(boolean enable) { synchronized (mAwSettingsLock) { if (mEnableSupportedHardwareAcceleratedFeatures != enable) { mEnableSupportedHardwareAcceleratedFeatures = enable; mEventHandler.updateWebkitPreferencesLocked(); } } } @CalledByNative private boolean getEnableSupportedHardwareAcceleratedFeaturesLocked() { assert Thread.holdsLock(mAwSettingsLock); return mEnableSupportedHardwareAcceleratedFeatures; } /** * See {@link android.webkit.WebSettings#setNeedInitialFocus}. */ public boolean shouldFocusFirstNode() { synchronized (mAwSettingsLock) { return mShouldFocusFirstNode; } } /** * See {@link android.webkit.WebSettings#setGeolocationEnabled}. */ public void setGeolocationEnabled(boolean flag) { synchronized (mAwSettingsLock) { if (mGeolocationEnabled != flag) { mGeolocationEnabled = flag; } } } /** * @return Returns if geolocation is currently enabled. */ boolean getGeolocationEnabled() { synchronized (mAwSettingsLock) { return mGeolocationEnabled; } } /** * See {@link android.webkit.WebSettings#setSaveFormData}. */ public void setSaveFormData(final boolean enable) { synchronized (mAwSettingsLock) { if (mAutoCompleteEnabled != enable) { mAutoCompleteEnabled = enable; mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() { @Override public void run() { nativeUpdateFormDataPreferencesLocked(mNativeAwSettings); } }); } } } /** * See {@link android.webkit.WebSettings#getSaveFormData}. */ public boolean getSaveFormData() { synchronized (mAwSettingsLock) { return getSaveFormDataLocked(); } } @CalledByNative private boolean getSaveFormDataLocked() { assert Thread.holdsLock(mAwSettingsLock); return mAutoCompleteEnabled; } /** * @returns the default User-Agent used by each ContentViewCore instance, i.e. unless * overridden by {@link #setUserAgentString()} */ public static String getDefaultUserAgent() { return LazyDefaultUserAgent.sInstance; } /** * See {@link android.webkit.WebSettings#setUserAgentString}. */ public void setUserAgentString(String ua) { synchronized (mAwSettingsLock) { final String oldUserAgent = mUserAgent; if (ua == null || ua.length() == 0) { mUserAgent = LazyDefaultUserAgent.sInstance; } else { mUserAgent = ua; } if (!oldUserAgent.equals(mUserAgent)) { mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() { @Override public void run() { nativeUpdateUserAgentLocked(mNativeAwSettings); } }); } } } /** * See {@link android.webkit.WebSettings#getUserAgentString}. */ public String getUserAgentString() { synchronized (mAwSettingsLock) { return mUserAgent; } } @CalledByNative private String getUserAgentLocked() { assert Thread.holdsLock(mAwSettingsLock); return mUserAgent; } /** * See {@link android.webkit.WebSettings#setLoadWithOverviewMode}. */ public void setLoadWithOverviewMode(boolean overview) { synchronized (mAwSettingsLock) { if (mLoadWithOverviewMode != overview) { mLoadWithOverviewMode = overview; mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() { @Override public void run() { updateWebkitPreferencesOnUiThreadLocked(); nativeResetScrollAndScaleState(mNativeAwSettings); } }); } } } /** * See {@link android.webkit.WebSettings#getLoadWithOverviewMode}. */ public boolean getLoadWithOverviewMode() { synchronized (mAwSettingsLock) { return mLoadWithOverviewMode; } } @CalledByNative private boolean getLoadWithOverviewModeLocked() { assert Thread.holdsLock(mAwSettingsLock); return mLoadWithOverviewMode; } /** * See {@link android.webkit.WebSettings#setTextZoom}. */ public void setTextZoom(final int textZoom) { synchronized (mAwSettingsLock) { if (mTextSizePercent != textZoom) { mTextSizePercent = textZoom; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getTextZoom}. */ public int getTextZoom() { synchronized (mAwSettingsLock) { return mTextSizePercent; } } @CalledByNative private int getTextSizePercentLocked() { assert Thread.holdsLock(mAwSettingsLock); return mTextSizePercent; } /** * See {@link android.webkit.WebSettings#setStandardFontFamily}. */ public void setStandardFontFamily(String font) { synchronized (mAwSettingsLock) { if (font != null && !mStandardFontFamily.equals(font)) { mStandardFontFamily = font; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getStandardFontFamily}. */ public String getStandardFontFamily() { synchronized (mAwSettingsLock) { return mStandardFontFamily; } } @CalledByNative private String getStandardFontFamilyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mStandardFontFamily; } /** * See {@link android.webkit.WebSettings#setFixedFontFamily}. */ public void setFixedFontFamily(String font) { synchronized (mAwSettingsLock) { if (font != null && !mFixedFontFamily.equals(font)) { mFixedFontFamily = font; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getFixedFontFamily}. */ public String getFixedFontFamily() { synchronized (mAwSettingsLock) { return mFixedFontFamily; } } @CalledByNative private String getFixedFontFamilyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mFixedFontFamily; } /** * See {@link android.webkit.WebSettings#setSansSerifFontFamily}. */ public void setSansSerifFontFamily(String font) { synchronized (mAwSettingsLock) { if (font != null && !mSansSerifFontFamily.equals(font)) { mSansSerifFontFamily = font; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getSansSerifFontFamily}. */ public String getSansSerifFontFamily() { synchronized (mAwSettingsLock) { return mSansSerifFontFamily; } } @CalledByNative private String getSansSerifFontFamilyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mSansSerifFontFamily; } /** * See {@link android.webkit.WebSettings#setSerifFontFamily}. */ public void setSerifFontFamily(String font) { synchronized (mAwSettingsLock) { if (font != null && !mSerifFontFamily.equals(font)) { mSerifFontFamily = font; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getSerifFontFamily}. */ public String getSerifFontFamily() { synchronized (mAwSettingsLock) { return mSerifFontFamily; } } @CalledByNative private String getSerifFontFamilyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mSerifFontFamily; } /** * See {@link android.webkit.WebSettings#setCursiveFontFamily}. */ public void setCursiveFontFamily(String font) { synchronized (mAwSettingsLock) { if (font != null && !mCursiveFontFamily.equals(font)) { mCursiveFontFamily = font; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getCursiveFontFamily}. */ public String getCursiveFontFamily() { synchronized (mAwSettingsLock) { return mCursiveFontFamily; } } @CalledByNative private String getCursiveFontFamilyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mCursiveFontFamily; } /** * See {@link android.webkit.WebSettings#setFantasyFontFamily}. */ public void setFantasyFontFamily(String font) { synchronized (mAwSettingsLock) { if (font != null && !mFantasyFontFamily.equals(font)) { mFantasyFontFamily = font; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getFantasyFontFamily}. */ public String getFantasyFontFamily() { synchronized (mAwSettingsLock) { return mFantasyFontFamily; } } @CalledByNative private String getFantasyFontFamilyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mFantasyFontFamily; } /** * See {@link android.webkit.WebSettings#setMinimumFontSize}. */ public void setMinimumFontSize(int size) { synchronized (mAwSettingsLock) { size = clipFontSize(size); if (mMinimumFontSize != size) { mMinimumFontSize = size; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getMinimumFontSize}. */ public int getMinimumFontSize() { synchronized (mAwSettingsLock) { return mMinimumFontSize; } } @CalledByNative private int getMinimumFontSizeLocked() { assert Thread.holdsLock(mAwSettingsLock); return mMinimumFontSize; } /** * See {@link android.webkit.WebSettings#setMinimumLogicalFontSize}. */ public void setMinimumLogicalFontSize(int size) { synchronized (mAwSettingsLock) { size = clipFontSize(size); if (mMinimumLogicalFontSize != size) { mMinimumLogicalFontSize = size; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getMinimumLogicalFontSize}. */ public int getMinimumLogicalFontSize() { synchronized (mAwSettingsLock) { return mMinimumLogicalFontSize; } } @CalledByNative private int getMinimumLogicalFontSizeLocked() { assert Thread.holdsLock(mAwSettingsLock); return mMinimumLogicalFontSize; } /** * See {@link android.webkit.WebSettings#setDefaultFontSize}. */ public void setDefaultFontSize(int size) { synchronized (mAwSettingsLock) { size = clipFontSize(size); if (mDefaultFontSize != size) { mDefaultFontSize = size; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getDefaultFontSize}. */ public int getDefaultFontSize() { synchronized (mAwSettingsLock) { return mDefaultFontSize; } } @CalledByNative private int getDefaultFontSizeLocked() { assert Thread.holdsLock(mAwSettingsLock); return mDefaultFontSize; } /** * See {@link android.webkit.WebSettings#setDefaultFixedFontSize}. */ public void setDefaultFixedFontSize(int size) { synchronized (mAwSettingsLock) { size = clipFontSize(size); if (mDefaultFixedFontSize != size) { mDefaultFixedFontSize = size; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getDefaultFixedFontSize}. */ public int getDefaultFixedFontSize() { synchronized (mAwSettingsLock) { return mDefaultFixedFontSize; } } @CalledByNative private int getDefaultFixedFontSizeLocked() { assert Thread.holdsLock(mAwSettingsLock); return mDefaultFixedFontSize; } /** * See {@link android.webkit.WebSettings#setJavaScriptEnabled}. */ public void setJavaScriptEnabled(boolean flag) { synchronized (mAwSettingsLock) { if (mJavaScriptEnabled != flag) { mJavaScriptEnabled = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs}. */ public void setAllowUniversalAccessFromFileURLs(boolean flag) { synchronized (mAwSettingsLock) { if (mAllowUniversalAccessFromFileURLs != flag) { mAllowUniversalAccessFromFileURLs = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#setAllowFileAccessFromFileURLs}. */ public void setAllowFileAccessFromFileURLs(boolean flag) { synchronized (mAwSettingsLock) { if (mAllowFileAccessFromFileURLs != flag) { mAllowFileAccessFromFileURLs = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#setLoadsImagesAutomatically}. */ public void setLoadsImagesAutomatically(boolean flag) { synchronized (mAwSettingsLock) { if (mLoadsImagesAutomatically != flag) { mLoadsImagesAutomatically = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getLoadsImagesAutomatically}. */ public boolean getLoadsImagesAutomatically() { synchronized (mAwSettingsLock) { return mLoadsImagesAutomatically; } } @CalledByNative private boolean getLoadsImagesAutomaticallyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mLoadsImagesAutomatically; } /** * See {@link android.webkit.WebSettings#setImagesEnabled}. */ public void setImagesEnabled(boolean flag) { synchronized (mAwSettingsLock) { if (mImagesEnabled != flag) { mImagesEnabled = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getImagesEnabled}. */ public boolean getImagesEnabled() { synchronized (mAwSettingsLock) { return mImagesEnabled; } } @CalledByNative private boolean getImagesEnabledLocked() { assert Thread.holdsLock(mAwSettingsLock); return mImagesEnabled; } /** * See {@link android.webkit.WebSettings#getJavaScriptEnabled}. */ public boolean getJavaScriptEnabled() { synchronized (mAwSettingsLock) { return mJavaScriptEnabled; } } @CalledByNative private boolean getJavaScriptEnabledLocked() { assert Thread.holdsLock(mAwSettingsLock); return mJavaScriptEnabled; } /** * See {@link android.webkit.WebSettings#getAllowUniversalAccessFromFileURLs}. */ public boolean getAllowUniversalAccessFromFileURLs() { synchronized (mAwSettingsLock) { return mAllowUniversalAccessFromFileURLs; } } @CalledByNative private boolean getAllowUniversalAccessFromFileURLsLocked() { assert Thread.holdsLock(mAwSettingsLock); return mAllowUniversalAccessFromFileURLs; } /** * See {@link android.webkit.WebSettings#getAllowFileAccessFromFileURLs}. */ public boolean getAllowFileAccessFromFileURLs() { synchronized (mAwSettingsLock) { return mAllowFileAccessFromFileURLs; } } @CalledByNative private boolean getAllowFileAccessFromFileURLsLocked() { assert Thread.holdsLock(mAwSettingsLock); return mAllowFileAccessFromFileURLs; } /** * See {@link android.webkit.WebSettings#setPluginsEnabled}. */ public void setPluginsEnabled(boolean flag) { setPluginState(flag ? PluginState.ON : PluginState.OFF); } /** * See {@link android.webkit.WebSettings#setPluginState}. */ public void setPluginState(PluginState state) { synchronized (mAwSettingsLock) { if (mPluginState != state) { mPluginState = state; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getPluginsEnabled}. */ public boolean getPluginsEnabled() { synchronized (mAwSettingsLock) { return mPluginState == PluginState.ON; } } /** * Return true if plugins are disabled. * @return True if plugins are disabled. */ @CalledByNative private boolean getPluginsDisabledLocked() { assert Thread.holdsLock(mAwSettingsLock); return mPluginState == PluginState.OFF; } /** * See {@link android.webkit.WebSettings#getPluginState}. */ public PluginState getPluginState() { synchronized (mAwSettingsLock) { return mPluginState; } } /** * See {@link android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically}. */ public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) { synchronized (mAwSettingsLock) { if (mJavaScriptCanOpenWindowsAutomatically != flag) { mJavaScriptCanOpenWindowsAutomatically = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically}. */ public boolean getJavaScriptCanOpenWindowsAutomatically() { synchronized (mAwSettingsLock) { return mJavaScriptCanOpenWindowsAutomatically; } } @CalledByNative private boolean getJavaScriptCanOpenWindowsAutomaticallyLocked() { assert Thread.holdsLock(mAwSettingsLock); return mJavaScriptCanOpenWindowsAutomatically; } /** * See {@link android.webkit.WebSettings#setLayoutAlgorithm}. */ public void setLayoutAlgorithm(LayoutAlgorithm l) { synchronized (mAwSettingsLock) { if (mLayoutAlgorithm != l) { mLayoutAlgorithm = l; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getLayoutAlgorithm}. */ public LayoutAlgorithm getLayoutAlgorithm() { synchronized (mAwSettingsLock) { return mLayoutAlgorithm; } } /** * Gets whether Text Auto-sizing layout algorithm is enabled. * * @return true if Text Auto-sizing layout algorithm is enabled */ @CalledByNative private boolean getTextAutosizingEnabledLocked() { assert Thread.holdsLock(mAwSettingsLock); return mLayoutAlgorithm == LayoutAlgorithm.TEXT_AUTOSIZING; } /** * See {@link android.webkit.WebSettings#setSupportMultipleWindows}. */ public void setSupportMultipleWindows(boolean support) { synchronized (mAwSettingsLock) { if (mSupportMultipleWindows != support) { mSupportMultipleWindows = support; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#supportMultipleWindows}. */ public boolean supportMultipleWindows() { synchronized (mAwSettingsLock) { return mSupportMultipleWindows; } } @CalledByNative private boolean getSupportMultipleWindowsLocked() { assert Thread.holdsLock(mAwSettingsLock); return mSupportMultipleWindows; } @CalledByNative private boolean getSupportLegacyQuirksLocked() { assert Thread.holdsLock(mAwSettingsLock); return mSupportLegacyQuirks; } /** * See {@link android.webkit.WebSettings#setUseWideViewPort}. */ public void setUseWideViewPort(boolean use) { synchronized (mAwSettingsLock) { if (mUseWideViewport != use) { mUseWideViewport = use; onGestureZoomSupportChanged( supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked()); mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getUseWideViewPort}. */ public boolean getUseWideViewPort() { synchronized (mAwSettingsLock) { return mUseWideViewport; } } @CalledByNative private boolean getUseWideViewportLocked() { assert Thread.holdsLock(mAwSettingsLock); return mUseWideViewport; } @CalledByNative private boolean getPasswordEchoEnabledLocked() { assert Thread.holdsLock(mAwSettingsLock); return mPasswordEchoEnabled; } /** * See {@link android.webkit.WebSettings#setAppCacheEnabled}. */ public void setAppCacheEnabled(boolean flag) { synchronized (mAwSettingsLock) { if (mAppCacheEnabled != flag) { mAppCacheEnabled = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#setAppCachePath}. */ public void setAppCachePath(String path) { boolean needToSync = false; synchronized (sGlobalContentSettingsLock) { // AppCachePath can only be set once. if (!sAppCachePathIsSet && path != null && !path.isEmpty()) { sAppCachePathIsSet = true; needToSync = true; } } // The obvious problem here is that other WebViews will not be updated, // until they execute synchronization from Java to the native side. // But this is the same behaviour as it was in the legacy WebView. if (needToSync) { synchronized (mAwSettingsLock) { mEventHandler.updateWebkitPreferencesLocked(); } } } /** * Gets whether Application Cache is enabled. * * @return true if Application Cache is enabled */ @CalledByNative private boolean getAppCacheEnabledLocked() { assert Thread.holdsLock(mAwSettingsLock); if (!mAppCacheEnabled) { return false; } synchronized (sGlobalContentSettingsLock) { return sAppCachePathIsSet; } } /** * See {@link android.webkit.WebSettings#setDomStorageEnabled}. */ public void setDomStorageEnabled(boolean flag) { synchronized (mAwSettingsLock) { if (mDomStorageEnabled != flag) { mDomStorageEnabled = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getDomStorageEnabled}. */ public boolean getDomStorageEnabled() { synchronized (mAwSettingsLock) { return mDomStorageEnabled; } } @CalledByNative private boolean getDomStorageEnabledLocked() { assert Thread.holdsLock(mAwSettingsLock); return mDomStorageEnabled; } /** * See {@link android.webkit.WebSettings#setDatabaseEnabled}. */ public void setDatabaseEnabled(boolean flag) { synchronized (mAwSettingsLock) { if (mDatabaseEnabled != flag) { mDatabaseEnabled = flag; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getDatabaseEnabled}. */ public boolean getDatabaseEnabled() { synchronized (mAwSettingsLock) { return mDatabaseEnabled; } } @CalledByNative private boolean getDatabaseEnabledLocked() { assert Thread.holdsLock(mAwSettingsLock); return mDatabaseEnabled; } /** * See {@link android.webkit.WebSettings#setDefaultTextEncodingName}. */ public void setDefaultTextEncodingName(String encoding) { synchronized (mAwSettingsLock) { if (encoding != null && !mDefaultTextEncoding.equals(encoding)) { mDefaultTextEncoding = encoding; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getDefaultTextEncodingName}. */ public String getDefaultTextEncodingName() { synchronized (mAwSettingsLock) { return mDefaultTextEncoding; } } @CalledByNative private String getDefaultTextEncodingLocked() { assert Thread.holdsLock(mAwSettingsLock); return mDefaultTextEncoding; } /** * See {@link android.webkit.WebSettings#setMediaPlaybackRequiresUserGesture}. */ public void setMediaPlaybackRequiresUserGesture(boolean require) { synchronized (mAwSettingsLock) { if (mMediaPlaybackRequiresUserGesture != require) { mMediaPlaybackRequiresUserGesture = require; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getMediaPlaybackRequiresUserGesture}. */ public boolean getMediaPlaybackRequiresUserGesture() { synchronized (mAwSettingsLock) { return mMediaPlaybackRequiresUserGesture; } } @CalledByNative private boolean getMediaPlaybackRequiresUserGestureLocked() { assert Thread.holdsLock(mAwSettingsLock); return mMediaPlaybackRequiresUserGesture; } /** * See {@link android.webkit.WebSettings#setDefaultVideoPosterURL}. */ public void setDefaultVideoPosterURL(String url) { synchronized (mAwSettingsLock) { if (mDefaultVideoPosterURL != null && !mDefaultVideoPosterURL.equals(url) || mDefaultVideoPosterURL == null && url != null) { mDefaultVideoPosterURL = url; mEventHandler.updateWebkitPreferencesLocked(); } } } /** * See {@link android.webkit.WebSettings#getDefaultVideoPosterURL}. */ public String getDefaultVideoPosterURL() { synchronized (mAwSettingsLock) { return mDefaultVideoPosterURL; } } @CalledByNative private String getDefaultVideoPosterURLLocked() { assert Thread.holdsLock(mAwSettingsLock); return mDefaultVideoPosterURL; } private void onGestureZoomSupportChanged( final boolean supportsDoubleTapZoom, final boolean supportsMultiTouchZoom) { // Always post asynchronously here, to avoid doubling back onto the caller. mEventHandler.maybePostOnUiThread(new Runnable() { @Override public void run() { synchronized (mAwSettingsLock) { if (mZoomChangeListener != null) { mZoomChangeListener.onGestureZoomSupportChanged( supportsDoubleTapZoom, supportsMultiTouchZoom); } } } }); } /** * See {@link android.webkit.WebSettings#setSupportZoom}. */ public void setSupportZoom(boolean support) { synchronized (mAwSettingsLock) { if (mSupportZoom != support) { mSupportZoom = support; onGestureZoomSupportChanged( supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked()); } } } /** * See {@link android.webkit.WebSettings#supportZoom}. */ public boolean supportZoom() { synchronized (mAwSettingsLock) { return mSupportZoom; } } /** * See {@link android.webkit.WebSettings#setBuiltInZoomControls}. */ public void setBuiltInZoomControls(boolean enabled) { synchronized (mAwSettingsLock) { if (mBuiltInZoomControls != enabled) { mBuiltInZoomControls = enabled; onGestureZoomSupportChanged( supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked()); } } } /** * See {@link android.webkit.WebSettings#getBuiltInZoomControls}. */ public boolean getBuiltInZoomControls() { synchronized (mAwSettingsLock) { return mBuiltInZoomControls; } } /** * See {@link android.webkit.WebSettings#setDisplayZoomControls}. */ public void setDisplayZoomControls(boolean enabled) { synchronized (mAwSettingsLock) { mDisplayZoomControls = enabled; } } /** * See {@link android.webkit.WebSettings#getDisplayZoomControls}. */ public boolean getDisplayZoomControls() { synchronized (mAwSettingsLock) { return mDisplayZoomControls; } } @CalledByNative private boolean supportsDoubleTapZoomLocked() { assert Thread.holdsLock(mAwSettingsLock); return mSupportZoom && mBuiltInZoomControls && mUseWideViewport; } private boolean supportsMultiTouchZoomLocked() { assert Thread.holdsLock(mAwSettingsLock); return mSupportZoom && mBuiltInZoomControls; } boolean supportsMultiTouchZoom() { synchronized (mAwSettingsLock) { return supportsMultiTouchZoomLocked(); } } boolean shouldDisplayZoomControls() { synchronized (mAwSettingsLock) { return supportsMultiTouchZoomLocked() && mDisplayZoomControls; } } private int clipFontSize(int size) { if (size < MINIMUM_FONT_SIZE) { return MINIMUM_FONT_SIZE; } else if (size > MAXIMUM_FONT_SIZE) { return MAXIMUM_FONT_SIZE; } return size; } @CalledByNative private void updateEverything() { synchronized (mAwSettingsLock) { nativeUpdateEverythingLocked(mNativeAwSettings); } } @CalledByNative private void populateWebPreferences(long webPrefsPtr) { synchronized (mAwSettingsLock) { nativePopulateWebPreferencesLocked(mNativeAwSettings, webPrefsPtr); } } private void updateWebkitPreferencesOnUiThreadLocked() { assert mEventHandler.mHandler != null; ThreadUtils.assertOnUiThread(); nativeUpdateWebkitPreferencesLocked(mNativeAwSettings); } private native long nativeInit(long webContentsPtr); private native void nativeDestroy(long nativeAwSettings); private native void nativePopulateWebPreferencesLocked(long nativeAwSettings, long webPrefsPtr); private native void nativeResetScrollAndScaleState(long nativeAwSettings); private native void nativeUpdateEverythingLocked(long nativeAwSettings); private native void nativeUpdateInitialPageScaleLocked(long nativeAwSettings); private native void nativeUpdateUserAgentLocked(long nativeAwSettings); private native void nativeUpdateWebkitPreferencesLocked(long nativeAwSettings); private static native String nativeGetDefaultUserAgent(); private native void nativeUpdateFormDataPreferencesLocked(long nativeAwSettings); }