[WebView Support Library] Add framework-ServiceWorker support.
Add WebView Support Library support for ServiceWorkers - using only the
framework android.webkit APIs for now. Hooking into the WebView APK code
directly will happen in a follow-up to avoid massive CLs.
Also include a test for ServiceWorkerClientCompat. This test
corresponds to the CTS test for ServiceWorkerClient.
We'll add feature flags for the ServiceWorker APIs in a follow-up.
Bug: 73151166
Test: run androidx.webkit tests.
Change-Id: Ie3042c0a95987e2864ec57c7cff0c30d4d974fd8
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
index 4dba759..36bc76b 100644
--- a/webkit/api/current.txt
+++ b/webkit/api/current.txt
@@ -1,5 +1,27 @@
package androidx.webkit {
+ public abstract class ServiceWorkerClientCompat {
+ ctor public ServiceWorkerClientCompat();
+ method public abstract android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
+ }
+
+ public abstract class ServiceWorkerControllerCompat {
+ method public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
+ method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+ method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat);
+ }
+
+ public abstract class ServiceWorkerWebSettingsCompat {
+ method public abstract boolean getAllowContentAccess();
+ method public abstract boolean getAllowFileAccess();
+ method public abstract boolean getBlockNetworkLoads();
+ method public abstract int getCacheMode();
+ method public abstract void setAllowContentAccess(boolean);
+ method public abstract void setAllowFileAccess(boolean);
+ method public abstract void setBlockNetworkLoads(boolean);
+ method public abstract void setCacheMode(int);
+ }
+
public class WebSettingsCompat {
method public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
method public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
diff --git a/webkit/src/androidTest/java/androidx/webkit/ServiceWorkerClientCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/ServiceWorkerClientCompatTest.java
new file mode 100644
index 0000000..aecbc34
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/ServiceWorkerClientCompatTest.java
@@ -0,0 +1,206 @@
+/*
+ * 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 android.os.Build;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebView;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ServiceWorkerClientCompatTest {
+
+ // The BASE_URL does not matter since the tests will intercept the load, but it should be https
+ // for the Service Worker registration to succeed.
+ private static final String BASE_URL = "https://www.example.com/";
+ private static final String INDEX_URL = BASE_URL + "index.html";
+ private static final String SW_URL = BASE_URL + "sw.js";
+ private static final String FETCH_URL = BASE_URL + "fetch.html";
+
+ private static final String JS_INTERFACE_NAME = "Android";
+ private static final int POLLING_TIMEOUT = 10 * 1000;
+
+ // static HTML page always injected instead of the url loaded.
+ private static final String INDEX_RAW_HTML =
+ "<!DOCTYPE html>\n"
+ + "<html>\n"
+ + " <body>\n"
+ + " <script>\n"
+ + " navigator.serviceWorker.register('sw.js').then(function(reg) {\n"
+ + " " + JS_INTERFACE_NAME + ".registrationSuccess();\n"
+ + " }).catch(function(err) {\n"
+ + " console.error(err);\n"
+ + " });\n"
+ + " </script>\n"
+ + " </body>\n"
+ + "</html>\n";
+ private static final String SW_RAW_HTML = "fetch('fetch.html');";
+ private static final String SW_UNREGISTER_RAW_JS =
+ "navigator.serviceWorker.getRegistration().then(function(r) {"
+ + " r.unregister().then(function(success) {"
+ + " if (success) " + JS_INTERFACE_NAME + ".unregisterSuccess();"
+ + " else console.error('unregister() was not successful');"
+ + " });"
+ + "}).catch(function(err) {"
+ + " console.error(err);"
+ + "});";
+
+ private JavascriptStatusReceiver mJavascriptStatusReceiver;
+ private WebViewOnUiThread mOnUiThread;
+
+ // Both this test and WebViewOnUiThread need to override some of the methods on WebViewClient,
+ // so this test subclasses the WebViewClient from WebViewOnUiThread.
+ private static class InterceptClient extends WebViewOnUiThread.WaitForLoadedClient {
+
+ InterceptClient(WebViewOnUiThread webViewOnUiThread) throws Exception {
+ super(webViewOnUiThread);
+ }
+
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view,
+ WebResourceRequest request) {
+ // Only return content for INDEX_URL, deny all other requests.
+ try {
+ if (request.getUrl().toString().equals(INDEX_URL)) {
+ return new WebResourceResponse("text/html", "utf-8",
+ new ByteArrayInputStream(INDEX_RAW_HTML.getBytes("UTF-8")));
+ }
+ } catch (java.io.UnsupportedEncodingException e) { }
+ return new WebResourceResponse("text/html", "UTF-8", null);
+ }
+ }
+
+ public static class InterceptServiceWorkerClient extends ServiceWorkerClientCompat {
+ private List<WebResourceRequest> mInterceptedRequests = new ArrayList<WebResourceRequest>();
+
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+ // Records intercepted requests and only return content for SW_URL.
+ mInterceptedRequests.add(request);
+ try {
+ if (request.getUrl().toString().equals(SW_URL)) {
+ return new WebResourceResponse("application/javascript", "utf-8",
+ new ByteArrayInputStream(SW_RAW_HTML.getBytes("UTF-8")));
+ }
+ } catch (java.io.UnsupportedEncodingException e) { }
+ return new WebResourceResponse("text/html", "UTF-8", null);
+ }
+
+ List<WebResourceRequest> getInterceptedRequests() {
+ return mInterceptedRequests;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mOnUiThread = new WebViewOnUiThread();
+ mOnUiThread.getSettings().setJavaScriptEnabled(true);
+
+ mJavascriptStatusReceiver = new JavascriptStatusReceiver();
+ mOnUiThread.addJavascriptInterface(mJavascriptStatusReceiver, JS_INTERFACE_NAME);
+ mOnUiThread.setWebViewClient(new InterceptClient(mOnUiThread));
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mOnUiThread != null) {
+ mOnUiThread.cleanUp();
+ }
+ }
+
+ // Test correct invocation of shouldInterceptRequest for Service Workers.
+ @Test
+ public void testServiceWorkerClientInterceptCallback() throws Exception {
+ // TODO(gsennton) activate this test for pre-N devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
+
+ final InterceptServiceWorkerClient mInterceptServiceWorkerClient =
+ new InterceptServiceWorkerClient();
+ ServiceWorkerControllerCompat swController = ServiceWorkerControllerCompat.getInstance();
+ swController.setServiceWorkerClient(mInterceptServiceWorkerClient);
+
+ mOnUiThread.loadUrlAndWaitForCompletion(INDEX_URL);
+
+ Callable<Boolean> registrationSuccess = new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return mJavascriptStatusReceiver.mRegistrationSuccess;
+ }
+ };
+ PollingCheck.check("JS could not register Service Worker", POLLING_TIMEOUT,
+ registrationSuccess);
+
+ Callable<Boolean> receivedRequest = new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return mInterceptServiceWorkerClient.getInterceptedRequests().size() >= 2;
+ }
+ };
+ PollingCheck.check("Service Worker intercept callbacks not invoked", POLLING_TIMEOUT,
+ receivedRequest);
+
+ List<WebResourceRequest> requests = mInterceptServiceWorkerClient.getInterceptedRequests();
+ assertEquals(2, requests.size());
+ assertEquals(SW_URL, requests.get(0).getUrl().toString());
+ assertEquals(FETCH_URL, requests.get(1).getUrl().toString());
+
+ // Clean-up, make sure to unregister the Service Worker.
+ mOnUiThread.evaluateJavascript(SW_UNREGISTER_RAW_JS, null);
+ Callable<Boolean> unregisterSuccess = new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return mJavascriptStatusReceiver.mUnregisterSuccess;
+ }
+ };
+ PollingCheck.check("JS could not unregister Service Worker", POLLING_TIMEOUT,
+ unregisterSuccess);
+ }
+
+ // Object added to the page via AddJavascriptInterface() that is used by the test Javascript to
+ // notify back to Java if the Service Worker registration was successful.
+ public static final class JavascriptStatusReceiver {
+ public volatile boolean mRegistrationSuccess = false;
+ public volatile boolean mUnregisterSuccess = false;
+
+ @JavascriptInterface
+ public void registrationSuccess() {
+ mRegistrationSuccess = true;
+ }
+
+ @JavascriptInterface
+ public void unregisterSuccess() {
+ mUnregisterSuccess = true;
+ }
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java
new file mode 100644
index 0000000..19aab8c
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java
@@ -0,0 +1,48 @@
+/*
+ * 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.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Base class for clients to capture Service Worker related callbacks,
+ * see {@link ServiceWorkerControllerCompat} for usage example.
+ */
+public abstract class ServiceWorkerClientCompat {
+ /**
+ *
+ * Notify the host application of a resource request and allow the
+ * application to return the data. If the return value is {@code null}, the
+ * Service Worker will continue to load the resource as usual.
+ * Otherwise, the return response and data will be used.
+ *
+ * <p class="note"><b>Note:</b> This method is called on a thread other than the UI thread so
+ * clients should exercise caution when accessing private data or the view system.
+ *
+ * @param request Object containing the details of the request.
+ * @return A {@link android.webkit.WebResourceResponse} containing the
+ * response information or {@code null} if the WebView should load the
+ * resource itself.
+ * @see android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView,
+ * WebResourceRequest)
+ *
+ */
+ public abstract WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request);
+}
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java
new file mode 100644
index 0000000..0a27cd0
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java
@@ -0,0 +1,105 @@
+/*
+ * 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.ServiceWorkerController;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.webkit.internal.FrameworkServiceWorkerController;
+
+// TODO(gsennton) guard APIs with isFeatureSupported(String)
+
+/**
+ * Manages Service Workers used by WebView.
+ *
+ * <p>Example usage:
+ * <pre class="prettyprint">
+ * ServiceWorkerControllerCompat swController = ServiceWorkerControllerCompat.getInstance();
+ * swController.setServiceWorkerClient(new ServiceWorkerClientCompat() {
+ * {@literal @}Override
+ * public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+ * // Capture request here and generate response or allow pass-through
+ * // by returning null.
+ * return null;
+ * }
+ * });
+ * </pre>
+ */
+public abstract class ServiceWorkerControllerCompat {
+ /**
+ *
+ * @hide Don't allow apps to sub-class this class.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public ServiceWorkerControllerCompat() {}
+
+ /**
+ * Returns the default ServiceWorkerController instance. At present there is
+ * only one ServiceWorkerController instance for all WebView instances,
+ * however this restriction may be relaxed in the future.
+ *
+ * @return the default ServiceWorkerController instance
+ */
+ @NonNull
+ public static ServiceWorkerControllerCompat getInstance() {
+ return LAZY_HOLDER.INSTANCE;
+ }
+
+ private static class LAZY_HOLDER {
+ static final ServiceWorkerControllerCompat INSTANCE =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
+ ? getFrameworkControllerCompat() : getSupportLibraryControllerCompat();
+ }
+
+ /**
+ * Return a version of {@link ServiceWorkerControllerCompat} that only uses framework APIs.
+ */
+ @RequiresApi(Build.VERSION_CODES.N)
+ private static ServiceWorkerControllerCompat getFrameworkControllerCompat() {
+ return new FrameworkServiceWorkerController(
+ ServiceWorkerController.getInstance());
+ }
+
+ private static ServiceWorkerControllerCompat getSupportLibraryControllerCompat() {
+ return null; // TODO(gsennton) implement this
+ }
+
+ /**
+ *
+ * Gets the settings for all service workers.
+ *
+ * @return the current {@link ServiceWorkerWebSettingsCompat}
+ *
+ */
+ @NonNull
+ public abstract ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+
+ /**
+ *
+ * Sets the client to capture service worker related callbacks.
+ *
+ * A {@link ServiceWorkerClientCompat} should be set before any service workers are
+ * active, e.g. a safe place is before any WebView instances are created or
+ * pages loaded.
+ *
+ */
+ public abstract void setServiceWorkerClient(@Nullable ServiceWorkerClientCompat client);
+}
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java
new file mode 100644
index 0000000..61c46c3
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java
@@ -0,0 +1,127 @@
+/*
+ * 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 androidx.annotation.IntDef;
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Manages settings state for all Service Workers. These settings are not tied to
+ * the lifetime of any WebView because service workers can outlive WebView instances.
+ * The settings are similar to {@link WebSettings} but only settings relevant to
+ * Service Workers are supported.
+ */
+public abstract class ServiceWorkerWebSettingsCompat {
+ /**
+ * @hide Don't allow apps to sub-class this class.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public ServiceWorkerWebSettingsCompat() {}
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @IntDef(value = {
+ WebSettings.LOAD_DEFAULT,
+ WebSettings.LOAD_CACHE_ELSE_NETWORK,
+ WebSettings.LOAD_NO_CACHE,
+ WebSettings.LOAD_CACHE_ONLY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CacheMode {}
+
+ /**
+ *
+ * Overrides the way the cache is used, see {@link WebSettings#setCacheMode}.
+ *
+ * @param mode the mode to use. One of {@link WebSettings#LOAD_DEFAULT},
+ * {@link WebSettings#LOAD_CACHE_ELSE_NETWORK}, {@link WebSettings#LOAD_NO_CACHE}
+ * or {@link WebSettings#LOAD_CACHE_ONLY}. The default value is
+ * {@link WebSettings#LOAD_DEFAULT}.
+ *
+ */
+ public abstract void setCacheMode(@CacheMode int mode);
+
+ /**
+ *
+ * Gets the current setting for overriding the cache mode.
+ *
+ * @return the current setting for overriding the cache mode
+ * @see #setCacheMode
+ *
+ */
+ public abstract @CacheMode int getCacheMode();
+
+ /**
+ *
+ * Enables or disables content URL access from Service Workers, see
+ * {@link WebSettings#setAllowContentAccess}.
+ *
+ */
+ public abstract void setAllowContentAccess(boolean allow);
+
+ /**
+ *
+ * Gets whether Service Workers support content URL access.
+ *
+ * @see #setAllowContentAccess
+ *
+ */
+ public abstract boolean getAllowContentAccess();
+
+ /**
+ *
+ * Enables or disables file access within Service Workers, see
+ * {@link WebSettings#setAllowFileAccess}.
+ *
+ */
+ public abstract void setAllowFileAccess(boolean allow);
+
+ /**
+ *
+ * Gets whether Service Workers support file access.
+ *
+ * @see #setAllowFileAccess
+ *
+ */
+ public abstract boolean getAllowFileAccess();
+
+ /**
+ *
+ * Sets whether Service Workers should not load resources from the network,
+ * see {@link WebSettings#setBlockNetworkLoads}.
+ *
+ * @param flag {@code true} means block network loads by the Service Workers
+ *
+ */
+ public abstract void setBlockNetworkLoads(boolean flag);
+
+ /**
+ *
+ * Gets whether Service Workers are prohibited from loading any resources from the network.
+ *
+ * @return {@code true} if the Service Workers are not allowed to load any resources from the
+ * network
+ * @see #setBlockNetworkLoads
+ *
+ */
+ public abstract boolean getBlockNetworkLoads();
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerClient.java b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerClient.java
new file mode 100644
index 0000000..c28346e
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerClient.java
@@ -0,0 +1,44 @@
+/*
+ * 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.os.Build;
+import android.webkit.ServiceWorkerClient;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+
+import androidx.annotation.RequiresApi;
+import androidx.webkit.ServiceWorkerClientCompat;
+
+/**
+ * A shim class that implements {@link ServiceWorkerClient} by delegating to a
+ * {@link ServiceWorkerClientCompat}.
+ * This class is used on up-to-date devices to avoid using reflection to call into WebView APK code.
+ */
+@RequiresApi(Build.VERSION_CODES.N)
+public class FrameworkServiceWorkerClient extends ServiceWorkerClient {
+ private final ServiceWorkerClientCompat mImpl;
+
+ public FrameworkServiceWorkerClient(ServiceWorkerClientCompat impl) {
+ mImpl = impl;
+ }
+
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+ return mImpl.shouldInterceptRequest(request);
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java
new file mode 100644
index 0000000..2e02777
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java
@@ -0,0 +1,53 @@
+/*
+ * 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.os.Build;
+import android.webkit.ServiceWorkerController;
+
+import androidx.annotation.RequiresApi;
+import androidx.webkit.ServiceWorkerClientCompat;
+import androidx.webkit.ServiceWorkerControllerCompat;
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+/**
+ * Implementation of {@link ServiceWorkerControllerCompat} meant for use on up-to-date platforms.
+ * This class does not use reflection to bypass framework APIs - instead it uses android.webkit
+ * APIs.
+ */
+@RequiresApi(Build.VERSION_CODES.N)
+public class FrameworkServiceWorkerController extends ServiceWorkerControllerCompat {
+ private final ServiceWorkerController mImpl;
+ private ServiceWorkerWebSettingsCompat mSettings;
+
+ public FrameworkServiceWorkerController(ServiceWorkerController impl) {
+ mImpl = impl;
+ }
+
+ @Override
+ public ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings() {
+ if (mSettings == null) {
+ mSettings = new FrameworksServiceWorkerWebSettings(mImpl.getServiceWorkerWebSettings());
+ }
+ return mSettings;
+ }
+
+ @Override
+ public void setServiceWorkerClient(ServiceWorkerClientCompat client) {
+ mImpl.setServiceWorkerClient(new FrameworkServiceWorkerClient(client));
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java b/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java
new file mode 100644
index 0000000..4373756
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java
@@ -0,0 +1,77 @@
+/*
+ * 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.os.Build;
+import android.webkit.ServiceWorkerWebSettings;
+
+import androidx.annotation.RequiresApi;
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+/**
+ * Implementation of {@link ServiceWorkerWebSettingsCompat} meant for use on up-to-date platforms.
+ * This class does not use reflection to bypass framework APIs - instead it uses android.webkit
+ * APIs.
+ */
+@RequiresApi(Build.VERSION_CODES.N)
+public class FrameworksServiceWorkerWebSettings extends ServiceWorkerWebSettingsCompat {
+ private final ServiceWorkerWebSettings mImpl;
+
+ public FrameworksServiceWorkerWebSettings(ServiceWorkerWebSettings impl) {
+ mImpl = impl;
+ }
+
+ @Override
+ public void setCacheMode(int mode) {
+ mImpl.setCacheMode(mode);
+ }
+
+ @Override
+ public int getCacheMode() {
+ return mImpl.getCacheMode();
+ }
+
+ @Override
+ public void setAllowContentAccess(boolean allow) {
+ mImpl.setAllowContentAccess(allow);
+ }
+
+ @Override
+ public boolean getAllowContentAccess() {
+ return mImpl.getAllowContentAccess();
+ }
+
+ @Override
+ public void setAllowFileAccess(boolean allow) {
+ mImpl.setAllowContentAccess(allow);
+ }
+
+ @Override
+ public boolean getAllowFileAccess() {
+ return mImpl.getAllowFileAccess();
+ }
+
+ @Override
+ public void setBlockNetworkLoads(boolean flag) {
+ mImpl.setAllowContentAccess(flag);
+ }
+
+ @Override
+ public boolean getBlockNetworkLoads() {
+ return mImpl.getBlockNetworkLoads();
+ }
+}