[WebView Support Library] Add support for WebSettingsCompat.

Add support for WebSettingsCompat in the form of

class WebSettingsCompat {
    static Foo method(WebSettings webSettings, Params params...);
}

APIs.

Bug: 73454029
Test: run androidx.webkit tests.

Change-Id: If8d63292c7c03001d5b5959236fa8733870d7ef0
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
index b0d66d6..7a3fe25 100644
--- a/webkit/api/current.txt
+++ b/webkit/api/current.txt
@@ -1,5 +1,14 @@
 package androidx.webkit {
 
+  public class WebSettingsCompat {
+    method public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+    method public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+    method public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+    method public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+    method public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+    method public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+  }
+
   public class WebViewCompat {
     method public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
   }
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
new file mode 100644
index 0000000..3fd1c1a
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.webkit.WebSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WebSettingsCompatTest {
+    WebViewOnUiThread mWebViewOnUiThread;
+
+    @Before
+    public void setUp() {
+        mWebViewOnUiThread = new androidx.webkit.WebViewOnUiThread();
+    }
+
+    @Test
+    public void testOffscreenPreRaster() {
+        assertFalse(WebSettingsCompat.getOffscreenPreRaster(mWebViewOnUiThread.getSettings()));
+
+        WebSettingsCompat.setOffscreenPreRaster(mWebViewOnUiThread.getSettings(), true);
+        assertTrue(WebSettingsCompat.getOffscreenPreRaster(mWebViewOnUiThread.getSettings()));
+    }
+
+    @Test
+    public void testEnableSafeBrowsing() throws Throwable {
+        WebSettingsCompat.setSafeBrowsingEnabled(mWebViewOnUiThread.getSettings(), false);
+        assertFalse(WebSettingsCompat.getSafeBrowsingEnabled(mWebViewOnUiThread.getSettings()));
+    }
+
+    @Test
+    public void testDisabledActionModeMenuItems() throws Throwable {
+        assertEquals(WebSettings.MENU_ITEM_NONE,
+                WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+
+        WebSettingsCompat.setDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings(),
+                WebSettings.MENU_ITEM_SHARE);
+        assertEquals(WebSettings.MENU_ITEM_SHARE,
+                WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+
+        WebSettingsCompat.setDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings(),
+                WebSettings.MENU_ITEM_PROCESS_TEXT | WebSettings.MENU_ITEM_WEB_SEARCH);
+        assertEquals(WebSettings.MENU_ITEM_PROCESS_TEXT | WebSettings.MENU_ITEM_WEB_SEARCH,
+                WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+    }
+}
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
index 6219bd3..a86775b 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
@@ -17,6 +17,7 @@
 package androidx.webkit;
 
 import android.support.test.InstrumentationRegistry;
+import android.webkit.WebSettings;
 import android.webkit.WebView;
 
 public class WebViewOnUiThread {
@@ -50,7 +51,36 @@
         });
     }
 
+    public WebSettings getSettings() {
+        return getValue(new ValueGetter<WebSettings>() {
+            @Override
+            public WebSettings capture() {
+                return mWebView.getSettings();
+            }
+        });
+    }
+
     public WebView getWebViewOnCurrentThread() {
         return mWebView;
     }
+
+    private <T> T getValue(ValueGetter<T> getter) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(getter);
+        return getter.getValue();
+    }
+
+    private abstract class ValueGetter<T> implements Runnable {
+        private T mValue;
+
+        @Override
+        public void run() {
+            mValue = capture();
+        }
+
+        protected abstract T capture();
+
+        public T getValue() {
+            return mValue;
+        }
+    }
 }
diff --git a/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
new file mode 100644
index 0000000..c73cda6
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -0,0 +1,134 @@
+/*
+ * 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.os.Build;
+import android.webkit.WebSettings;
+
+import androidx.webkit.internal.WebSettingsAdapter;
+import androidx.webkit.internal.WebViewGlueCommunicator;
+
+/**
+ * Compatibility version of {@link android.webkit.WebSettings}
+ */
+public class WebSettingsCompat {
+    private WebSettingsCompat() {}
+
+    // TODO(gsennton): add feature detection
+
+    /**
+     * 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>
+     */
+    public static void setOffscreenPreRaster(WebSettings webSettings, boolean enabled) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            webSettings.setOffscreenPreRaster(enabled);
+        } else {
+            getAdapter(webSettings).setOffscreenPreRaster(enabled);
+        }
+    }
+
+    /**
+     * Gets whether this WebView should raster tiles when it is
+     * offscreen but attached to a window.
+     * @return {@code true} if this WebView will raster tiles when it is
+     * offscreen but attached to a window.
+     */
+    public static boolean getOffscreenPreRaster(WebSettings webSettings) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return webSettings.getOffscreenPreRaster();
+        } else {
+            return getAdapter(webSettings).getOffscreenPreRaster();
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @param enabled Whether Safe Browsing is enabled.
+     */
+    public static void setSafeBrowsingEnabled(WebSettings webSettings, boolean enabled) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            webSettings.setSafeBrowsingEnabled(enabled);
+        } else {
+            getAdapter(webSettings).setSafeBrowsingEnabled(enabled);
+        }
+    }
+
+    /**
+     * Gets whether Safe Browsing is enabled.
+     * See {@link #setSafeBrowsingEnabled}.
+     *
+     * @return {@code true} if Safe Browsing is enabled and {@code false} otherwise.
+     */
+    public static boolean getSafeBrowsingEnabled(WebSettings webSettings) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            return webSettings.getSafeBrowsingEnabled();
+        } else {
+            return getAdapter(webSettings).getSafeBrowsingEnabled();
+        }
+    }
+
+    /**
+     * Disables the action mode menu items according to {@code menuItems} flag.
+     * @param menuItems an integer field flag for the menu items to be disabled.
+     */
+    public static void setDisabledActionModeMenuItems(WebSettings webSettings, int menuItems) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            webSettings.setDisabledActionModeMenuItems(menuItems);
+        } else {
+            getAdapter(webSettings).setDisabledActionModeMenuItems(menuItems);
+        }
+    }
+
+    /**
+     * Gets the action mode menu items that are disabled, expressed in an integer field flag.
+     * The default value is {@link WebSettings#MENU_ITEM_NONE}
+     *
+     * @return all the disabled menu item flags combined with bitwise OR.
+     */
+    public static int getDisabledActionModeMenuItems(WebSettings webSettings) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            return webSettings.getDisabledActionModeMenuItems();
+        } else {
+            return getAdapter(webSettings).getDisabledActionModeMenuItems();
+        }
+    }
+
+    private static WebSettingsAdapter getAdapter(WebSettings webSettings) {
+        return WebViewGlueCommunicator.getCompatConverter().convertSettings(webSettings);
+    }
+}
+
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java
new file mode 100644
index 0000000..091879c
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java
@@ -0,0 +1,75 @@
+/*
+ * 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.internal;
+
+import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
+
+/**
+ * Adapter between WebSettingsCompat and
+ * {@link org.chromium.support_lib_boundary.WebSettingsBoundaryInterface} (the
+ * corresponding interface shared with the support library glue in the WebView APK).
+ */
+public class WebSettingsAdapter {
+    private WebSettingsBoundaryInterface mBoundaryInterface;
+
+    public WebSettingsAdapter(WebSettingsBoundaryInterface boundaryInterface) {
+        mBoundaryInterface = boundaryInterface;
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#setOffscreenPreRaster}.
+     */
+    public void setOffscreenPreRaster(boolean enabled) {
+        mBoundaryInterface.setOffscreenPreRaster(enabled);
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#getOffscreenPreRaster}.
+     */
+    public boolean getOffscreenPreRaster() {
+        return mBoundaryInterface.getOffscreenPreRaster();
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#setSafeBrowsingEnabled}.
+     */
+    public void setSafeBrowsingEnabled(boolean enabled) {
+        mBoundaryInterface.setSafeBrowsingEnabled(enabled);
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#getSafeBrowsingEnabled}.
+     */
+    public boolean getSafeBrowsingEnabled() {
+        return mBoundaryInterface.getSafeBrowsingEnabled();
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#setDisabledActionModeMenuItems}.
+     */
+    public void setDisabledActionModeMenuItems(int menuItems) {
+        mBoundaryInterface.setDisabledActionModeMenuItems(menuItems);
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#getDisabledActionModeMenuItems}.
+     */
+    public int getDisabledActionModeMenuItems() {
+        return mBoundaryInterface.getDisabledActionModeMenuItems();
+    }
+
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
index f97b2d8..24bb2d1 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
@@ -42,10 +42,17 @@
         return LAZY_FACTORY_HOLDER.INSTANCE;
     }
 
+    public static WebkitToCompatConverter getCompatConverter() {
+        return LAZY_FACTORY_HOLDER.COMPAT_CONVERTER;
+    }
+
     private static class LAZY_FACTORY_HOLDER {
         static final WebViewProviderFactoryAdapter INSTANCE =
                 new WebViewProviderFactoryAdapter(
                         WebViewGlueCommunicator.createGlueProviderFactory());
+        static final WebkitToCompatConverter COMPAT_CONVERTER =
+                new WebkitToCompatConverter(
+                        INSTANCE.getWebkitToCompatConverter());
     }
 
     private static InvocationHandler fetchGlueProviderFactoryImpl() {
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
index d961c09..fe98a56 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
@@ -21,6 +21,7 @@
 import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
 import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
 import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
 
 /**
  * Adapter for WebViewProviderFactoryBoundaryInterface providing static WebView functionality
@@ -42,4 +43,14 @@
         return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
                 WebViewProviderBoundaryInterface.class, mImpl.createWebView(webview));
     }
+
+    /**
+     * Adapter method for creating a new support library version of
+     * {@link androidx.webkit.internal.WebkitToCompatConverter}, which converts android.webkit
+     * classes into their corresponding support library classes.
+     */
+    public WebkitToCompatConverterBoundaryInterface getWebkitToCompatConverter() {
+        return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                WebkitToCompatConverterBoundaryInterface.class, mImpl.getWebkitToCompatConverter());
+    }
 }
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
new file mode 100644
index 0000000..cb40530
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
@@ -0,0 +1,45 @@
+/*
+ * 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.internal;
+
+import android.webkit.WebSettings;
+
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
+
+/**
+ * A class providing functionality for converting android.webkit classes into support library
+ * classes.
+ */
+public class WebkitToCompatConverter {
+    private final WebkitToCompatConverterBoundaryInterface mImpl;
+
+    public WebkitToCompatConverter(WebkitToCompatConverterBoundaryInterface impl) {
+        mImpl = impl;
+    }
+
+    /**
+     * Return a WebSettingsAdapter linked to webSettings such that calls on either of those
+     * objects affect the other object. That WebSettingsAdapter can be used to implement
+     * {@link androidx.webkit.WebSettingsCompat}.
+     */
+    public WebSettingsAdapter convertSettings(WebSettings webSettings) {
+        return new WebSettingsAdapter(BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                WebSettingsBoundaryInterface.class, mImpl.convertSettings(webSettings)));
+    }
+}