| // 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.pm.ActivityInfo; |
| import android.graphics.Bitmap; |
| import android.graphics.Picture; |
| import android.net.http.SslError; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.webkit.ConsoleMessage; |
| import android.webkit.GeolocationPermissions; |
| import android.webkit.ValueCallback; |
| import android.webkit.WebChromeClient; |
| |
| import org.chromium.content.browser.ContentViewCore; |
| import org.chromium.content.browser.WebContentsObserverAndroid; |
| import org.chromium.net.NetError; |
| |
| /** |
| * Base-class that an AwContents embedder derives from to receive callbacks. |
| * This extends ContentViewClient, as in many cases we want to pass-thru ContentViewCore |
| * callbacks right to our embedder, and this setup facilities that. |
| * For any other callbacks we need to make transformations of (e.g. adapt parameters |
| * or perform filtering) we can provide final overrides for methods here, and then introduce |
| * new abstract methods that the our own client must implement. |
| * i.e.: all methods in this class should either be final, or abstract. |
| */ |
| public abstract class AwContentsClient { |
| |
| private final AwContentsClientCallbackHelper mCallbackHelper; |
| |
| private AwWebContentsObserver mWebContentsObserver; |
| |
| // Last background color reported from the renderer. Holds the sentinal value INVALID_COLOR |
| // if not valid. |
| private int mCachedRendererBackgroundColor = INVALID_COLOR; |
| |
| private static final int INVALID_COLOR = 0; |
| |
| public AwContentsClient() { |
| this(Looper.myLooper()); |
| } |
| |
| // Alllow injection of the callback thread, for testing. |
| public AwContentsClient(Looper looper) { |
| mCallbackHelper = new AwContentsClientCallbackHelper(looper, this); |
| } |
| |
| class AwWebContentsObserver extends WebContentsObserverAndroid { |
| public AwWebContentsObserver(ContentViewCore contentViewCore) { |
| super(contentViewCore); |
| } |
| |
| @Override |
| public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { |
| if (isMainFrame) { |
| AwContentsClient.this.onPageFinished(validatedUrl); |
| } |
| } |
| |
| @Override |
| public void didFailLoad(boolean isProvisionalLoad, |
| boolean isMainFrame, int errorCode, String description, String failingUrl) { |
| if (isMainFrame) { |
| if (errorCode != NetError.ERR_ABORTED) { |
| // This error code is generated for the following reasons: |
| // - WebView.stopLoading is called, |
| // - the navigation is intercepted by the embedder via shouldOverrideNavigation. |
| // |
| // The Android WebView does not notify the embedder of these situations using |
| // this error code with the WebViewClient.onReceivedError callback. |
| AwContentsClient.this.onReceivedError( |
| ErrorCodeConversionHelper.convertErrorCode(errorCode), description, |
| failingUrl); |
| } |
| // Need to call onPageFinished after onReceivedError (if there is an error) for |
| // backwards compatibility with the classic webview. |
| AwContentsClient.this.onPageFinished(failingUrl); |
| } |
| } |
| |
| @Override |
| public void didNavigateMainFrame(String url, String baseUrl, |
| boolean isNavigationToDifferentPage, boolean isNavigationInPage) { |
| // This is here to emulate the Classic WebView firing onPageFinished for main frame |
| // navigations where only the hash fragment changes. |
| if (isNavigationInPage) { |
| AwContentsClient.this.onPageFinished(url); |
| } |
| } |
| |
| @Override |
| public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) { |
| AwContentsClient.this.doUpdateVisitedHistory(url, isReload); |
| } |
| |
| } |
| |
| final void installWebContentsObserver(ContentViewCore contentViewCore) { |
| if (mWebContentsObserver != null) { |
| mWebContentsObserver.detachFromWebContents(); |
| } |
| mWebContentsObserver = new AwWebContentsObserver(contentViewCore); |
| } |
| |
| final AwContentsClientCallbackHelper getCallbackHelper() { |
| return mCallbackHelper; |
| } |
| |
| final int getCachedRendererBackgroundColor() { |
| assert isCachedRendererBackgroundColorValid(); |
| return mCachedRendererBackgroundColor; |
| } |
| |
| final boolean isCachedRendererBackgroundColorValid() { |
| return mCachedRendererBackgroundColor != INVALID_COLOR; |
| } |
| |
| final void onBackgroundColorChanged(int color) { |
| // Avoid storing the sentinal INVALID_COLOR (note that both 0 and 1 are both |
| // fully transparent so this transpose makes no visible difference). |
| mCachedRendererBackgroundColor = color == INVALID_COLOR ? 1 : color; |
| } |
| |
| //-------------------------------------------------------------------------------------------- |
| // WebView specific methods that map directly to WebViewClient / WebChromeClient |
| //-------------------------------------------------------------------------------------------- |
| |
| /** |
| * Parameters for the {@link AwContentsClient#showFileChooser} method. |
| */ |
| public static class FileChooserParams { |
| public int mode; |
| public String acceptTypes; |
| public String title; |
| public String defaultFilename; |
| public boolean capture; |
| } |
| |
| public abstract void getVisitedHistory(ValueCallback<String[]> callback); |
| |
| public abstract void doUpdateVisitedHistory(String url, boolean isReload); |
| |
| public abstract void onProgressChanged(int progress); |
| |
| public abstract InterceptedRequestData shouldInterceptRequest(String url); |
| |
| public abstract boolean shouldOverrideKeyEvent(KeyEvent event); |
| |
| public abstract boolean shouldOverrideUrlLoading(String url); |
| |
| public abstract void onLoadResource(String url); |
| |
| public abstract void onUnhandledKeyEvent(KeyEvent event); |
| |
| public abstract boolean onConsoleMessage(ConsoleMessage consoleMessage); |
| |
| public abstract void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, |
| String host, String realm); |
| |
| public abstract void onReceivedSslError(ValueCallback<Boolean> callback, SslError error); |
| |
| public abstract void onReceivedLoginRequest(String realm, String account, String args); |
| |
| public abstract void onFormResubmission(Message dontResend, Message resend); |
| |
| public abstract void onDownloadStart(String url, String userAgent, String contentDisposition, |
| String mimeType, long contentLength); |
| |
| // TODO(joth): Make abstract once this has rolled in downstream. |
| public /*abstract*/ void showFileChooser(ValueCallback<String[]> uploadFilePathsCallback, |
| FileChooserParams fileChooserParams) { } |
| |
| public abstract void onGeolocationPermissionsShowPrompt(String origin, |
| GeolocationPermissions.Callback callback); |
| |
| public abstract void onGeolocationPermissionsHidePrompt(); |
| |
| public abstract void onScaleChangedScaled(float oldScale, float newScale); |
| |
| protected abstract void handleJsAlert(String url, String message, JsResultReceiver receiver); |
| |
| protected abstract void handleJsBeforeUnload(String url, String message, |
| JsResultReceiver receiver); |
| |
| protected abstract void handleJsConfirm(String url, String message, JsResultReceiver receiver); |
| |
| protected abstract void handleJsPrompt(String url, String message, String defaultValue, |
| JsPromptResultReceiver receiver); |
| |
| protected abstract boolean onCreateWindow(boolean isDialog, boolean isUserGesture); |
| |
| protected abstract void onCloseWindow(); |
| |
| public abstract void onReceivedTouchIconUrl(String url, boolean precomposed); |
| |
| public abstract void onReceivedIcon(Bitmap bitmap); |
| |
| public abstract void onReceivedTitle(String title); |
| |
| protected abstract void onRequestFocus(); |
| |
| protected abstract View getVideoLoadingProgressView(); |
| |
| public abstract void onPageStarted(String url); |
| |
| public abstract void onPageFinished(String url); |
| |
| public abstract void onReceivedError(int errorCode, String description, String failingUrl); |
| |
| // TODO (michaelbai): Remove this method once the same method remove from |
| // WebViewContentsClientAdapter. |
| public void onShowCustomView(View view, |
| int requestedOrientation, WebChromeClient.CustomViewCallback callback) { |
| } |
| |
| // TODO (michaelbai): This method should be abstract, having empty body here |
| // makes the merge to the Android easy. |
| public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) { |
| onShowCustomView(view, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, callback); |
| } |
| |
| public abstract void onHideCustomView(); |
| |
| public abstract Bitmap getDefaultVideoPoster(); |
| |
| //-------------------------------------------------------------------------------------------- |
| // Other WebView-specific methods |
| //-------------------------------------------------------------------------------------------- |
| // |
| public abstract void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, |
| boolean isDoneCounting); |
| |
| /** |
| * Called whenever there is a new content picture available. |
| * @param picture New picture. |
| */ |
| public abstract void onNewPicture(Picture picture); |
| |
| } |