Merge "[WebView Support Library] Implement onReceivedError" into pi-androidx-dev
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
index 08c6a55..5271a24 100644
--- a/webkit/api/current.txt
+++ b/webkit/api/current.txt
@@ -22,6 +22,11 @@
     method public abstract void setCacheMode(int);
   }
 
+  public abstract class WebResourceErrorCompat {
+    method public abstract java.lang.CharSequence getDescription();
+    method public abstract int getErrorCode();
+  }
+
   public class WebSettingsCompat {
     method public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
     method public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
@@ -33,6 +38,8 @@
 
   public class WebViewClientCompat extends android.webkit.WebViewClient {
     ctor public WebViewClientCompat();
+    method public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+    method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
   }
 
   public class WebViewCompat {
diff --git a/webkit/src/main/java/androidx/webkit/WebResourceErrorCompat.java b/webkit/src/main/java/androidx/webkit/WebResourceErrorCompat.java
new file mode 100644
index 0000000..32ea840
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebResourceErrorCompat.java
@@ -0,0 +1,133 @@
+/*
+ * 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.WebResourceError;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+
+import org.chromium.support_lib_boundary.WebResourceErrorBoundaryInterface;
+import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * Compatibility version of {@link WebResourceError}.
+ */
+public abstract class WebResourceErrorCompat {
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @IntDef(value = {
+            WebViewClient.ERROR_UNKNOWN,
+            WebViewClient.ERROR_HOST_LOOKUP,
+            WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME,
+            WebViewClient.ERROR_AUTHENTICATION,
+            WebViewClient.ERROR_PROXY_AUTHENTICATION,
+            WebViewClient.ERROR_CONNECT,
+            WebViewClient.ERROR_IO,
+            WebViewClient.ERROR_TIMEOUT,
+            WebViewClient.ERROR_REDIRECT_LOOP,
+            WebViewClient.ERROR_UNSUPPORTED_SCHEME,
+            WebViewClient.ERROR_FAILED_SSL_HANDSHAKE,
+            WebViewClient.ERROR_BAD_URL,
+            WebViewClient.ERROR_FILE,
+            WebViewClient.ERROR_FILE_NOT_FOUND,
+            WebViewClient.ERROR_TOO_MANY_REQUESTS,
+            WebViewClient.ERROR_UNSAFE_RESOURCE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NetErrorCode {}
+
+    /**
+     * Gets the error code of the error. The code corresponds to one
+     * of the {@code ERROR_*} constants in {@link WebViewClient}.
+     *
+     * @return The error code of the error
+     */
+    public abstract @NetErrorCode int getErrorCode();
+
+    /**
+     * Gets the string describing the error. Descriptions are localized,
+     * and thus can be used for communicating the problem to the user.
+     *
+     * @return The description of the error
+     */
+    @NonNull
+    public abstract CharSequence getDescription();
+
+    /**
+     * This class cannot be created by applications. The support library should instantiate this
+     * with {@link #fromInvocationHandler} or {@link #fromWebResourceError}.
+     */
+    private WebResourceErrorCompat() {
+    }
+
+    /**
+     * Conversion helper to create a WebResourceErrorCompat which delegates calls to {@param
+     * handler}. The InvocationHandler must be created by {@link
+     * BoundaryInterfaceReflectionUtil#createInvocationHandlerFor} using {@link
+     * WebResourceErrorBoundaryInterface}.
+     *
+     * @param handler The InvocationHandler that chromium passed in the callback.
+     */
+    @NonNull
+    /* package */ static WebResourceErrorCompat fromInvocationHandler(InvocationHandler handler) {
+        final WebResourceErrorBoundaryInterface errorDelegate =
+                BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                        WebResourceErrorBoundaryInterface.class, handler);
+        return new WebResourceErrorCompat() {
+            @Override
+            public @NetErrorCode int getErrorCode() {
+                return errorDelegate.getErrorCode();
+            }
+
+            @Override
+            @NonNull
+            public CharSequence getDescription() {
+                return errorDelegate.getDescription();
+            }
+        };
+    }
+
+    /**
+     * Conversion helper to create a WebResourceErrorCompat which delegates calls to {@param error}.
+     *
+     * @param error The WebResourceError that chromium passed in the callback.
+     */
+    @NonNull
+    @RequiresApi(23)
+    /* package */ static WebResourceErrorCompat fromWebResourceError(final WebResourceError error) {
+        return new WebResourceErrorCompat() {
+            @Override
+            public @NetErrorCode int getErrorCode() {
+                return error.getErrorCode();
+            }
+
+            @Override
+            @NonNull
+            public CharSequence getDescription() {
+                return error.getDescription();
+            }
+        };
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java b/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java
index 8c690f9..22a19fa 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java
@@ -17,6 +17,7 @@
 package androidx.webkit;
 
 import android.os.Build;
+import android.webkit.WebResourceError;
 import android.webkit.WebResourceRequest;
 import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
@@ -57,17 +58,56 @@
     }
 
     /**
-     * Invoked by chromium for the {@code onReceivedError} event. Applications are not meant to
-     * override this, and should instead override the non-final {@code onReceivedError} method.
-     * TODO(ntfschr): link to that method once it's implemented.
+     * Invoked by chromium (for up-to-date WebView APKs) for the {@code onReceivedError} event.
+     * Applications are not meant to override this, and should instead override the non-final {@link
+     * onReceivedError(WebView, WebResourceRequest, WebResourceErrorCompat)} method.
      *
      * @hide
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @Override
+    @RequiresApi(21)
     public final void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request,
-            /* WebResourceError */ @NonNull InvocationHandler error) {
-        // TODO(ntfschr): implement this (b/73151460).
+            /* WebResourceError */ @NonNull InvocationHandler handler) {
+        onReceivedError(view, request, WebResourceErrorCompat.fromInvocationHandler(handler));
+    }
+
+    /**
+     * Invoked by chromium (in legacy WebView APKs) for the {@code onReceivedError} event on {@link
+     * Build.VERSION_CODES.M} and above. Applications are not meant to override this, and should
+     * instead override the non-final {@link onReceivedError(WebView, WebResourceRequest,
+     * WebResourceErrorCompat)} method.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Override
+    @RequiresApi(23)
+    public final void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request,
+            @NonNull WebResourceError error) {
+        if (Build.VERSION.SDK_INT < 23) return;
+        onReceivedError(view, request, WebResourceErrorCompat.fromWebResourceError(error));
+    }
+
+    /**
+     * Report web resource loading error to the host application. These errors usually indicate
+     * inability to connect to the server. Note that unlike the deprecated version of the callback,
+     * the new version will be called for any resource (iframe, image, etc.), not just for the main
+     * page. Thus, it is recommended to perform minimum required work in this callback.
+     * @param view The WebView that is initiating the callback.
+     * @param request The originating request.
+     * @param error Information about the error occurred.
+     */
+    @SuppressWarnings("deprecation") // for invoking the old onReceivedError.
+    @RequiresApi(21)
+    public void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request,
+            @NonNull WebResourceErrorCompat error) {
+        if (Build.VERSION.SDK_INT < 21) return;
+        if (request.isForMainFrame()) {
+            onReceivedError(view,
+                    error.getErrorCode(), error.getDescription().toString(),
+                    request.getUrl().toString());
+        }
     }
 
     @Override
@@ -90,10 +130,8 @@
         // TODO(ntfschr): implement this (b/73151460).
     }
 
-    // Default behavior in WebViewClient is to invoke the other (deprecated)
-    // shouldOverrideUrlLoading method.
     @Override
-    @SuppressWarnings("deprecation")
+    @SuppressWarnings("deprecation") // for invoking the old shouldOverrideUrlLoading.
     @RequiresApi(21)
     public boolean shouldOverrideUrlLoading(@NonNull WebView view,
             @NonNull WebResourceRequest request) {