• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AwContentsClient()49     public AwContentsClient() {
50         this(Looper.myLooper());
51     }
52 
53     // Alllow injection of the callback thread, for testing.
AwContentsClient(Looper looper)54     public AwContentsClient(Looper looper) {
55         mCallbackHelper = new AwContentsClientCallbackHelper(looper, this);
56     }
57 
58     class AwWebContentsObserver extends WebContentsObserverAndroid {
AwWebContentsObserver(ContentViewCore contentViewCore)59         public AwWebContentsObserver(ContentViewCore contentViewCore) {
60             super(contentViewCore);
61         }
62 
63         @Override
didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame)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
didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode, String description, String failingUrl)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
didNavigateMainFrame(String url, String baseUrl, boolean isNavigationToDifferentPage, boolean isFragmentNavigation)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
didNavigateAnyFrame(String url, String baseUrl, boolean isReload)105         public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) {
106             AwContentsClient.this.doUpdateVisitedHistory(url, isReload);
107         }
108 
109     }
110 
installWebContentsObserver(ContentViewCore contentViewCore)111     final void installWebContentsObserver(ContentViewCore contentViewCore) {
112         if (mWebContentsObserver != null) {
113             mWebContentsObserver.detachFromWebContents();
114         }
115         mWebContentsObserver = new AwWebContentsObserver(contentViewCore);
116     }
117 
getCallbackHelper()118     final AwContentsClientCallbackHelper getCallbackHelper() {
119         return mCallbackHelper;
120     }
121 
getCachedRendererBackgroundColor()122     final int getCachedRendererBackgroundColor() {
123         assert isCachedRendererBackgroundColorValid();
124         return mCachedRendererBackgroundColor;
125     }
126 
isCachedRendererBackgroundColorValid()127     final boolean isCachedRendererBackgroundColorValid() {
128         return mCachedRendererBackgroundColor != INVALID_COLOR;
129     }
130 
onBackgroundColorChanged(int color)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 
getVisitedHistory(ValueCallback<String[]> callback)168     public abstract void getVisitedHistory(ValueCallback<String[]> callback);
169 
doUpdateVisitedHistory(String url, boolean isReload)170     public abstract void doUpdateVisitedHistory(String url, boolean isReload);
171 
onProgressChanged(int progress)172     public abstract void onProgressChanged(int progress);
173 
shouldInterceptRequest( ShouldInterceptRequestParams params)174     public abstract AwWebResourceResponse shouldInterceptRequest(
175             ShouldInterceptRequestParams params);
176 
shouldOverrideKeyEvent(KeyEvent event)177     public abstract boolean shouldOverrideKeyEvent(KeyEvent event);
178 
shouldOverrideUrlLoading(String url)179     public abstract boolean shouldOverrideUrlLoading(String url);
180 
onLoadResource(String url)181     public abstract void onLoadResource(String url);
182 
onUnhandledKeyEvent(KeyEvent event)183     public abstract void onUnhandledKeyEvent(KeyEvent event);
184 
onConsoleMessage(ConsoleMessage consoleMessage)185     public abstract boolean onConsoleMessage(ConsoleMessage consoleMessage);
186 
onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm)187     public abstract void onReceivedHttpAuthRequest(AwHttpAuthHandler handler,
188             String host, String realm);
189 
onReceivedSslError(ValueCallback<Boolean> callback, SslError error)190     public abstract void onReceivedSslError(ValueCallback<Boolean> callback, SslError error);
191 
192     // TODO(sgurun): Make abstract once this has rolled in downstream.
onReceivedClientCertRequest( final AwContentsClientBridge.ClientCertificateRequestCallback callback, final String[] keyTypes, final Principal[] principals, final String host, final int port)193     public void onReceivedClientCertRequest(
194             final AwContentsClientBridge.ClientCertificateRequestCallback callback,
195             final String[] keyTypes, final Principal[] principals, final String host,
196             final int port) { }
197 
onReceivedLoginRequest(String realm, String account, String args)198     public abstract void onReceivedLoginRequest(String realm, String account, String args);
199 
onFormResubmission(Message dontResend, Message resend)200     public abstract void onFormResubmission(Message dontResend, Message resend);
201 
onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength)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.
showFileChooser(ValueCallback<String[]> uploadFilePathsCallback, FileChooserParams fileChooserParams)206     public /*abstract*/ void showFileChooser(ValueCallback<String[]> uploadFilePathsCallback,
207             FileChooserParams fileChooserParams) { }
208 
onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback)209     public abstract void onGeolocationPermissionsShowPrompt(String origin,
210             GeolocationPermissions.Callback callback);
211 
onGeolocationPermissionsHidePrompt()212     public abstract void onGeolocationPermissionsHidePrompt();
213 
214     // TODO(michaelbai): Change the abstract once merged
onPermissionRequest(AwPermissionRequest awPermissionRequest)215     public /*abstract*/ void onPermissionRequest(AwPermissionRequest awPermissionRequest) {}
216 
217     // TODO(michaelbai): Change the abstract once merged
onPermissionRequestCanceled( AwPermissionRequest awPermissionRequest)218     public /*abstract*/ void onPermissionRequestCanceled(
219             AwPermissionRequest awPermissionRequest) {}
220 
onScaleChangedScaled(float oldScale, float newScale)221     public abstract void onScaleChangedScaled(float oldScale, float newScale);
222 
handleJsAlert(String url, String message, JsResultReceiver receiver)223     protected abstract void handleJsAlert(String url, String message, JsResultReceiver receiver);
224 
handleJsBeforeUnload(String url, String message, JsResultReceiver receiver)225     protected abstract void handleJsBeforeUnload(String url, String message,
226             JsResultReceiver receiver);
227 
handleJsConfirm(String url, String message, JsResultReceiver receiver)228     protected abstract void handleJsConfirm(String url, String message, JsResultReceiver receiver);
229 
handleJsPrompt(String url, String message, String defaultValue, JsPromptResultReceiver receiver)230     protected abstract void handleJsPrompt(String url, String message, String defaultValue,
231             JsPromptResultReceiver receiver);
232 
onCreateWindow(boolean isDialog, boolean isUserGesture)233     protected abstract boolean onCreateWindow(boolean isDialog, boolean isUserGesture);
234 
onCloseWindow()235     protected abstract void onCloseWindow();
236 
onReceivedTouchIconUrl(String url, boolean precomposed)237     public abstract void onReceivedTouchIconUrl(String url, boolean precomposed);
238 
onReceivedIcon(Bitmap bitmap)239     public abstract void onReceivedIcon(Bitmap bitmap);
240 
onReceivedTitle(String title)241     public abstract void onReceivedTitle(String title);
242 
onRequestFocus()243     protected abstract void onRequestFocus();
244 
getVideoLoadingProgressView()245     protected abstract View getVideoLoadingProgressView();
246 
onPageStarted(String url)247     public abstract void onPageStarted(String url);
248 
onPageFinished(String url)249     public abstract void onPageFinished(String url);
250 
onReceivedError(int errorCode, String description, String failingUrl)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.
onShowCustomView(View view, int requestedOrientation, WebChromeClient.CustomViewCallback callback)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.
onShowCustomView(View view, WebChromeClient.CustomViewCallback callback)261     public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
262         onShowCustomView(view, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, callback);
263     }
264 
onHideCustomView()265     public abstract void onHideCustomView();
266 
getDefaultVideoPoster()267     public abstract Bitmap getDefaultVideoPoster();
268 
269     //--------------------------------------------------------------------------------------------
270     //                              Other WebView-specific methods
271     //--------------------------------------------------------------------------------------------
272     //
onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting)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      */
onNewPicture(Picture picture)280     public abstract void onNewPicture(Picture picture);
281 
282 }
283