| // Copyright (c) 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.ActivityInfo; |
| import android.graphics.Bitmap; |
| import android.graphics.Picture; |
| import android.graphics.Rect; |
| import android.graphics.RectF; |
| import android.net.http.SslError; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.util.Log; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.webkit.ConsoleMessage; |
| import android.webkit.GeolocationPermissions; |
| import android.webkit.SslErrorHandler; |
| import android.webkit.ValueCallback; |
| import android.webkit.WebChromeClient; |
| |
| import org.chromium.content.browser.ContentVideoView; |
| import org.chromium.content.browser.ContentVideoViewClient; |
| import org.chromium.content.browser.ContentVideoViewControls; |
| import org.chromium.content.browser.ContentViewClient; |
| 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 static final String TAG = "AwContentsClient"; |
| private final AwContentsClientCallbackHelper mCallbackHelper = |
| new AwContentsClientCallbackHelper(this); |
| |
| private AwWebContentsObserver mWebContentsObserver; |
| |
| private AwContentViewClient mContentViewClient = new AwContentViewClient(); |
| |
| // 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; |
| |
| class AwWebContentsObserver extends WebContentsObserverAndroid { |
| public AwWebContentsObserver(ContentViewCore contentViewCore) { |
| super(contentViewCore); |
| } |
| |
| @Override |
| public void didStopLoading(String url) { |
| AwContentsClient.this.onPageFinished(url); |
| } |
| |
| @Override |
| public void didFailLoad(boolean isProvisionalLoad, |
| boolean isMainFrame, int errorCode, String description, String failingUrl) { |
| 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. |
| return; |
| } |
| if (!isMainFrame) { |
| // The Android WebView does not notify the embedder of sub-frame failures. |
| return; |
| } |
| AwContentsClient.this.onReceivedError( |
| ErrorCodeConversionHelper.convertErrorCode(errorCode), description, failingUrl); |
| } |
| |
| @Override |
| public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) { |
| AwContentsClient.this.doUpdateVisitedHistory(url, isReload); |
| } |
| |
| } |
| |
| private class AwContentViewClient extends ContentViewClient { |
| @Override |
| public 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; |
| } |
| |
| @Override |
| public void onStartContentIntent(Context context, String contentUrl) { |
| // Callback when detecting a click on a content link. |
| AwContentsClient.this.shouldOverrideUrlLoading(contentUrl); |
| } |
| |
| @Override |
| public void onRendererCrash(boolean crashedWhileOomProtected) { |
| // This is not possible so long as the webview is run single process! |
| throw new RuntimeException("Renderer crash reported."); |
| } |
| |
| @Override |
| public void onUpdateTitle(String title) { |
| AwContentsClient.this.onReceivedTitle(title); |
| } |
| |
| @Override |
| public boolean shouldOverrideKeyEvent(KeyEvent event) { |
| return AwContentsClient.this.shouldOverrideKeyEvent(event); |
| } |
| |
| @Override |
| final public ContentVideoViewClient getContentVideoViewClient() { |
| return new AwContentVideoViewClient(); |
| } |
| } |
| |
| final void installWebContentsObserver(ContentViewCore contentViewCore) { |
| if (mWebContentsObserver != null) { |
| mWebContentsObserver.detachFromWebContents(); |
| } |
| mWebContentsObserver = new AwWebContentsObserver(contentViewCore); |
| } |
| |
| private class AwContentVideoViewClient implements ContentVideoViewClient { |
| @Override |
| public void onShowCustomView(View view) { |
| WebChromeClient.CustomViewCallback cb = new WebChromeClient.CustomViewCallback() { |
| @Override |
| public void onCustomViewHidden() { |
| ContentVideoView contentVideoView = ContentVideoView.getContentVideoView(); |
| if (contentVideoView != null) |
| contentVideoView.exitFullscreen(false); |
| } |
| }; |
| AwContentsClient.this.onShowCustomView(view, cb); |
| } |
| |
| @Override |
| public void onDestroyContentVideoView() { |
| AwContentsClient.this.onHideCustomView(); |
| } |
| |
| @Override |
| public View getVideoLoadingProgressView() { |
| return AwContentsClient.this.getVideoLoadingProgressView(); |
| } |
| |
| @Override |
| public ContentVideoViewControls createControls() { |
| return null; |
| } |
| } |
| |
| final AwContentsClientCallbackHelper getCallbackHelper() { |
| return mCallbackHelper; |
| } |
| |
| final ContentViewClient getContentViewClient() { |
| return mContentViewClient; |
| } |
| |
| final int getCachedRendererBackgroundColor() { |
| assert isCachedRendererBackgroundColorValid(); |
| return mCachedRendererBackgroundColor; |
| } |
| |
| final boolean isCachedRendererBackgroundColorValid() { |
| return mCachedRendererBackgroundColor != INVALID_COLOR; |
| } |
| |
| //-------------------------------------------------------------------------------------------- |
| // WebView specific methods that map directly to WebViewClient / WebChromeClient |
| //-------------------------------------------------------------------------------------------- |
| |
| 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); |
| |
| } |