Home | History | Annotate | Download | only in android_webview
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 package org.chromium.android_webview;
      6 
      7 import android.content.pm.ActivityInfo;
      8 import android.graphics.Bitmap;
      9 import android.graphics.Picture;
     10 import android.net.http.SslError;
     11 import android.os.Looper;
     12 import android.os.Message;
     13 import android.util.ArrayMap;
     14 import android.view.KeyEvent;
     15 import android.view.View;
     16 import android.webkit.ConsoleMessage;
     17 import android.webkit.GeolocationPermissions;
     18 import android.webkit.ValueCallback;
     19 import android.webkit.WebChromeClient;
     20 
     21 import org.chromium.android_webview.permission.AwPermissionRequest;
     22 import org.chromium.content.browser.ContentViewCore;
     23 import org.chromium.content.browser.WebContentsObserverAndroid;
     24 import org.chromium.net.NetError;
     25 
     26 import java.security.Principal;
     27 
     28 /**
     29  * Base-class that an AwContents embedder derives from to receive callbacks.
     30  * This extends ContentViewClient, as in many cases we want to pass-thru ContentViewCore
     31  * callbacks right to our embedder, and this setup facilities that.
     32  * For any other callbacks we need to make transformations of (e.g. adapt parameters
     33  * or perform filtering) we can provide final overrides for methods here, and then introduce
     34  * new abstract methods that the our own client must implement.
     35  * i.e.: all methods in this class should either be final, or abstract.
     36  */
     37 public abstract class AwContentsClient {
     38 
     39     private final AwContentsClientCallbackHelper mCallbackHelper;
     40 
     41     private AwWebContentsObserver mWebContentsObserver;
     42 
     43     // Last background color reported from the renderer. Holds the sentinal value INVALID_COLOR
     44     // if not valid.
     45     private int mCachedRendererBackgroundColor = INVALID_COLOR;
     46 
     47     private static final int INVALID_COLOR = 0;
     48 
     49     public AwContentsClient() {
     50         this(Looper.myLooper());
     51     }
     52 
     53     // Alllow injection of the callback thread, for testing.
     54     public AwContentsClient(Looper looper) {
     55         mCallbackHelper = new AwContentsClientCallbackHelper(looper, this);
     56     }
     57 
     58     class AwWebContentsObserver extends WebContentsObserverAndroid {
     59         public AwWebContentsObserver(ContentViewCore contentViewCore) {
     60             super(contentViewCore);
     61         }
     62 
     63         @Override
     64         public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
     65             String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
     66             boolean isErrorUrl =
     67                     unreachableWebDataUrl != null && unreachableWebDataUrl.equals(validatedUrl);
     68             if (isMainFrame && !isErrorUrl) {
     69                 AwContentsClient.this.onPageFinished(validatedUrl);
     70             }
     71         }
     72 
     73         @Override
     74         public void didFailLoad(boolean isProvisionalLoad,
     75                 boolean isMainFrame, int errorCode, String description, String failingUrl) {
     76             if (isMainFrame) {
     77                 if (errorCode != NetError.ERR_ABORTED) {
     78                     // This error code is generated for the following reasons:
     79                     // - WebView.stopLoading is called,
     80                     // - the navigation is intercepted by the embedder via shouldOverrideNavigation.
     81                     //
     82                     // The Android WebView does not notify the embedder of these situations using
     83                     // this error code with the WebViewClient.onReceivedError callback.
     84                     AwContentsClient.this.onReceivedError(
     85                             ErrorCodeConversionHelper.convertErrorCode(errorCode), description,
     86                                     failingUrl);
     87                 }
     88                 // Need to call onPageFinished after onReceivedError (if there is an error) for
     89                 // backwards compatibility with the classic webview.
     90                 AwContentsClient.this.onPageFinished(failingUrl);
     91             }
     92         }
     93 
     94         @Override
     95         public void didNavigateMainFrame(String url, String baseUrl,
     96                 boolean isNavigationToDifferentPage, boolean isFragmentNavigation) {
     97             // This is here to emulate the Classic WebView firing onPageFinished for main frame
     98             // navigations where only the hash fragment changes.
     99             if (isFragmentNavigation) {
    100                 AwContentsClient.this.onPageFinished(url);
    101             }
    102         }
    103 
    104         @Override
    105         public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) {
    106             AwContentsClient.this.doUpdateVisitedHistory(url, isReload);
    107         }
    108 
    109     }
    110 
    111     final void installWebContentsObserver(ContentViewCore contentViewCore) {
    112         if (mWebContentsObserver != null) {
    113             mWebContentsObserver.detachFromWebContents();
    114         }
    115         mWebContentsObserver = new AwWebContentsObserver(contentViewCore);
    116     }
    117 
    118     final AwContentsClientCallbackHelper getCallbackHelper() {
    119         return mCallbackHelper;
    120     }
    121 
    122     final int getCachedRendererBackgroundColor() {
    123         assert isCachedRendererBackgroundColorValid();
    124         return mCachedRendererBackgroundColor;
    125     }
    126 
    127     final boolean isCachedRendererBackgroundColorValid() {
    128         return mCachedRendererBackgroundColor != INVALID_COLOR;
    129     }
    130 
    131     final void onBackgroundColorChanged(int color) {
    132         // Avoid storing the sentinal INVALID_COLOR (note that both 0 and 1 are both
    133         // fully transparent so this transpose makes no visible difference).
    134         mCachedRendererBackgroundColor = color == INVALID_COLOR ? 1 : color;
    135     }
    136 
    137     //--------------------------------------------------------------------------------------------
    138     //             WebView specific methods that map directly to WebViewClient / WebChromeClient
    139     //--------------------------------------------------------------------------------------------
    140 
    141     /**
    142      * Parameters for the {@link AwContentsClient#showFileChooser} method.
    143      */
    144     public static class FileChooserParams {
    145         public int mode;
    146         public String acceptTypes;
    147         public String title;
    148         public String defaultFilename;
    149         public boolean capture;
    150     }
    151 
    152     /**
    153      * Parameters for the {@link AwContentsClient#shouldInterceptRequest} method.
    154      */
    155     public static class ShouldInterceptRequestParams {
    156         // Url of the request.
    157         public String url;
    158         // Is this for the main frame or a child iframe?
    159         public boolean isMainFrame;
    160         // Was a gesture associated with the request? Don't trust can easily be spoofed.
    161         public boolean hasUserGesture;
    162         // Method used (GET/POST/OPTIONS)
    163         public String method;
    164         // Headers that would have been sent to server.
    165         public ArrayMap<String, String> requestHeaders;
    166     }
    167 
    168     public abstract void getVisitedHistory(ValueCallback<String[]> callback);
    169 
    170     public abstract void doUpdateVisitedHistory(String url, boolean isReload);
    171 
    172     public abstract void onProgressChanged(int progress);
    173 
    174     public abstract AwWebResourceResponse shouldInterceptRequest(
    175             ShouldInterceptRequestParams params);
    176 
    177     public abstract boolean shouldOverrideKeyEvent(KeyEvent event);
    178 
    179     public abstract boolean shouldOverrideUrlLoading(String url);
    180 
    181     public abstract void onLoadResource(String url);
    182 
    183     public abstract void onUnhandledKeyEvent(KeyEvent event);
    184 
    185     public abstract boolean onConsoleMessage(ConsoleMessage consoleMessage);
    186 
    187     public abstract void onReceivedHttpAuthRequest(AwHttpAuthHandler handler,
    188             String host, String realm);
    189 
    190     public abstract void onReceivedSslError(ValueCallback<Boolean> callback, SslError error);
    191 
    192     // TODO(sgurun): Make abstract once this has rolled in downstream.
    193     public void onReceivedClientCertRequest(
    194             final AwContentsClientBridge.ClientCertificateRequestCallback callback,
    195             final String[] keyTypes, final Principal[] principals, final String host,
    196             final int port) { }
    197 
    198     public abstract void onReceivedLoginRequest(String realm, String account, String args);
    199 
    200     public abstract void onFormResubmission(Message dontResend, Message resend);
    201 
    202     public abstract void onDownloadStart(String url, String userAgent, String contentDisposition,
    203             String mimeType, long contentLength);
    204 
    205     // TODO(joth): Make abstract once this has rolled in downstream.
    206     public /*abstract*/ void showFileChooser(ValueCallback<String[]> uploadFilePathsCallback,
    207             FileChooserParams fileChooserParams) { }
    208 
    209     public abstract void onGeolocationPermissionsShowPrompt(String origin,
    210             GeolocationPermissions.Callback callback);
    211 
    212     public abstract void onGeolocationPermissionsHidePrompt();
    213 
    214     // TODO(michaelbai): Change the abstract once merged
    215     public /*abstract*/ void onPermissionRequest(AwPermissionRequest awPermissionRequest) {}
    216 
    217     // TODO(michaelbai): Change the abstract once merged
    218     public /*abstract*/ void onPermissionRequestCanceled(
    219             AwPermissionRequest awPermissionRequest) {}
    220 
    221     public abstract void onScaleChangedScaled(float oldScale, float newScale);
    222 
    223     protected abstract void handleJsAlert(String url, String message, JsResultReceiver receiver);
    224 
    225     protected abstract void handleJsBeforeUnload(String url, String message,
    226             JsResultReceiver receiver);
    227 
    228     protected abstract void handleJsConfirm(String url, String message, JsResultReceiver receiver);
    229 
    230     protected abstract void handleJsPrompt(String url, String message, String defaultValue,
    231             JsPromptResultReceiver receiver);
    232 
    233     protected abstract boolean onCreateWindow(boolean isDialog, boolean isUserGesture);
    234 
    235     protected abstract void onCloseWindow();
    236 
    237     public abstract void onReceivedTouchIconUrl(String url, boolean precomposed);
    238 
    239     public abstract void onReceivedIcon(Bitmap bitmap);
    240 
    241     public abstract void onReceivedTitle(String title);
    242 
    243     protected abstract void onRequestFocus();
    244 
    245     protected abstract View getVideoLoadingProgressView();
    246 
    247     public abstract void onPageStarted(String url);
    248 
    249     public abstract void onPageFinished(String url);
    250 
    251     public abstract void onReceivedError(int errorCode, String description, String failingUrl);
    252 
    253     // TODO (michaelbai): Remove this method once the same method remove from
    254     // WebViewContentsClientAdapter.
    255     public void onShowCustomView(View view,
    256            int requestedOrientation, WebChromeClient.CustomViewCallback callback) {
    257     }
    258 
    259     // TODO (michaelbai): This method should be abstract, having empty body here
    260     // makes the merge to the Android easy.
    261     public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
    262         onShowCustomView(view, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, callback);
    263     }
    264 
    265     public abstract void onHideCustomView();
    266 
    267     public abstract Bitmap getDefaultVideoPoster();
    268 
    269     //--------------------------------------------------------------------------------------------
    270     //                              Other WebView-specific methods
    271     //--------------------------------------------------------------------------------------------
    272     //
    273     public abstract void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
    274             boolean isDoneCounting);
    275 
    276     /**
    277      * Called whenever there is a new content picture available.
    278      * @param picture New picture.
    279      */
    280     public abstract void onNewPicture(Picture picture);
    281 
    282 }
    283