WebViewChromium.java revision b28309c3f6d4527ccf98142468f99d056f137cbf
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.webview.chromium;
18
19import android.content.res.Configuration;
20import android.graphics.Bitmap;
21import android.graphics.Canvas;
22import android.graphics.Paint;
23import android.graphics.Picture;
24import android.graphics.Rect;
25import android.graphics.drawable.Drawable;
26import android.net.http.SslCertificate;
27import android.os.Build;
28import android.os.Bundle;
29import android.os.Message;
30import android.util.Base64;
31import android.util.Log;
32import android.view.HardwareCanvas;
33import android.view.KeyEvent;
34import android.view.MotionEvent;
35import android.view.View;
36import android.view.View.MeasureSpec;
37import android.view.ViewGroup;
38import android.view.accessibility.AccessibilityEvent;
39import android.view.accessibility.AccessibilityNodeInfo;
40import android.view.accessibility.AccessibilityNodeProvider;
41import android.view.inputmethod.EditorInfo;
42import android.view.inputmethod.InputConnection;
43import android.webkit.DownloadListener;
44import android.webkit.FindActionModeCallback;
45import android.webkit.JavascriptInterface;
46import android.webkit.ValueCallback;
47import android.webkit.WebBackForwardList;
48import android.webkit.WebChromeClient;
49import android.webkit.WebSettings;
50import android.webkit.WebView;
51import android.webkit.WebViewClient;
52import android.webkit.WebViewProvider;
53import android.widget.TextView;
54
55import org.chromium.android_webview.AwBrowserContext;
56import org.chromium.android_webview.AwContents;
57import org.chromium.base.ThreadUtils;
58import org.chromium.content.browser.LoadUrlParams;
59import org.chromium.net.NetworkChangeNotifier;
60
61import java.io.BufferedWriter;
62import java.io.File;
63import java.io.OutputStream;
64import java.lang.annotation.Annotation;
65import java.util.HashMap;
66import java.util.Map;
67
68/**
69 * This class is the delegate to which WebViewProxy forwards all API calls.
70 *
71 * Most of the actual functionality is implemented by AwContents (or ContentViewCore within
72 * it). This class also contains WebView-specific APIs that require the creation of other
73 * adapters (otherwise org.chromium.content would depend on the webview.chromium package)
74 * and a small set of no-op deprecated APIs.
75 */
76class WebViewChromium implements WebViewProvider,
77          WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate {
78
79    private static final String TAG = WebViewChromium.class.getSimpleName();
80
81    // The WebView that this WebViewChromium is the provider for.
82    WebView mWebView;
83    // Lets us access protected View-derived methods on the WebView instance we're backing.
84    WebView.PrivateAccess mWebViewPrivate;
85    // The client adapter class.
86    private WebViewContentsClientAdapter mContentsClientAdapter;
87
88    // Variables for functionality provided by this adapter ---------------------------------------
89    // WebSettings adapter, lazily initialized in the getter
90    private WebSettings mWebSettings;
91    // The WebView wrapper for ContentViewCore and required browser compontents.
92    private AwContents mAwContents;
93    // Non-null if this webview is using the GL accelerated draw path.
94    private DrawGLFunctor mGLfunctor;
95
96    private AwBrowserContext mBrowserContext;
97
98    private final WebView.HitTestResult mHitTestResult;
99
100    private final int mAppTargetSdkVersion;
101
102    public WebViewChromium(WebView webView, WebView.PrivateAccess webViewPrivate,
103            AwBrowserContext browserContext) {
104        checkThread();
105        mWebView = webView;
106        mWebViewPrivate = webViewPrivate;
107        mHitTestResult = new WebView.HitTestResult();
108        mBrowserContext = browserContext;
109        mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion;
110    }
111
112    static void completeWindowCreation(WebView parent, WebView child) {
113        AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents;
114        AwContents childContents =
115                child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents;
116        parentContents.supplyContentsForPopup(childContents);
117    }
118
119    // WebViewProvider methods --------------------------------------------------------------------
120
121    @Override
122    public void init(Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
123        // BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree
124        // so is ignored. TODO: remove it from WebViewProvider.
125        final boolean isAccessFromFileURLsGrantedByDefault =
126                 mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
127        mContentsClientAdapter = new WebViewContentsClientAdapter(mWebView);
128        mAwContents = new AwContents(mBrowserContext, mWebView, new InternalAccessAdapter(),
129                mContentsClientAdapter, isAccessFromFileURLsGrantedByDefault);
130
131        if (privateBrowsing) {
132            final String msg = "Private browsing is not supported in WebView.";
133            if (mAppTargetSdkVersion >= Build.VERSION_CODES.KEY_LIME_PIE) {
134                throw new IllegalArgumentException(msg);
135            } else {
136                Log.w(TAG, msg);
137                // Intentionally irreversibly disable the webview instance, so that private
138                // user data cannot leak through misuse of a non-privateBrowing WebView instance.
139                // Can't just null out mAwContents as we never null-check it before use.
140                mAwContents.destroy();
141                TextView warningLabel = new TextView(mWebView.getContext());
142                warningLabel.setText(mWebView.getContext().getString(
143                        com.android.internal.R.string.webviewchromium_private_browsing_warning));
144                mWebView.addView(warningLabel);
145            }
146        }
147
148    }
149
150    private RuntimeException createThreadException() {
151        return new IllegalStateException("Calling View methods on another thread than the UI " +
152                "thread. PLEASE FILE A BUG! go/klp-webview-bug");
153    }
154
155    //  Intentionally not static, as no need to check thread on static methods
156    private void checkThread() {
157        if (!ThreadUtils.runningOnUiThread()) {
158            final RuntimeException threadViolation = createThreadException();
159            ThreadUtils.postOnUiThread(new Runnable() {
160                @Override
161                public void run() {
162                    throw threadViolation;
163                }
164            });
165            throw createThreadException();
166        }
167    }
168
169    @Override
170    public void setHorizontalScrollbarOverlay(boolean overlay) {
171        checkThread();
172        mAwContents.setHorizontalScrollbarOverlay(overlay);
173    }
174
175    @Override
176    public void setVerticalScrollbarOverlay(boolean overlay) {
177        checkThread();
178        mAwContents.setVerticalScrollbarOverlay(overlay);
179    }
180
181    @Override
182    public boolean overlayHorizontalScrollbar() {
183        checkThread();
184        return mAwContents.overlayHorizontalScrollbar();
185    }
186
187    @Override
188    public boolean overlayVerticalScrollbar() {
189        checkThread();
190        return mAwContents.overlayVerticalScrollbar();
191    }
192
193    @Override
194    public int getVisibleTitleHeight() {
195        // This is deprecated in WebView and should always return 0.
196        return 0;
197    }
198
199    @Override
200    public SslCertificate getCertificate() {
201        checkThread();
202        return mAwContents.getCertificate();
203    }
204
205    @Override
206    public void setCertificate(SslCertificate certificate) {
207        checkThread();
208        UnimplementedWebViewApi.invoke();
209    }
210
211    @Override
212    public void savePassword(String host, String username, String password) {
213        // This is a deprecated API: intentional no-op.
214    }
215
216    @Override
217    public void setHttpAuthUsernamePassword(String host, String realm, String username,
218                                            String password) {
219        checkThread();
220        mAwContents.setHttpAuthUsernamePassword(host, realm, username, password);
221    }
222
223    @Override
224    public String[] getHttpAuthUsernamePassword(String host, String realm) {
225        checkThread();
226        return mAwContents.getHttpAuthUsernamePassword(host, realm);
227    }
228
229    @Override
230    public void destroy() {
231        checkThread();
232        mAwContents.destroy();
233        if (mGLfunctor != null) {
234            mGLfunctor.destroy();
235            mGLfunctor = null;
236        }
237    }
238
239    @Override
240    public void setNetworkAvailable(boolean networkUp) {
241        checkThread();
242        // Note that this purely toggles the JS navigator.online property.
243        // It does not in affect chromium or network stack state in any way.
244        mAwContents.setNetworkAvailable(networkUp);
245    }
246
247    @Override
248    public WebBackForwardList saveState(Bundle outState) {
249        checkThread();
250        if (outState == null) return null;
251        if (!mAwContents.saveState(outState)) return null;
252        return copyBackForwardList();
253    }
254
255    @Override
256    public boolean savePicture(Bundle b, File dest) {
257        // Intentional no-op: hidden method on WebView.
258        return false;
259    }
260
261    @Override
262    public boolean restorePicture(Bundle b, File src) {
263        // Intentional no-op: hidden method on WebView.
264        return false;
265    }
266
267    @Override
268    public WebBackForwardList restoreState(Bundle inState) {
269        checkThread();
270        if (inState == null) return null;
271        if (!mAwContents.restoreState(inState)) return null;
272        return copyBackForwardList();
273    }
274
275    @Override
276    public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
277        // TODO: We may actually want to do some sanity checks here (like filter about://chrome).
278
279        // For backwards compatibility, apps targeting less than K will have JS URLs evaluated
280        // directly and any result of the evaluation will not replace the current page content.
281        // Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will
282        // have the result of that URL replace the content of the current page.
283        final String JAVASCRIPT_SCHEME = "javascript:";
284        if (mAppTargetSdkVersion < Build.VERSION_CODES.KEY_LIME_PIE &&
285                url.startsWith(JAVASCRIPT_SCHEME)) {
286            mAwContents.evaluateJavaScriptEvenIfNotYetNavigated(
287                    url.substring(JAVASCRIPT_SCHEME.length()));
288            return;
289        }
290
291        LoadUrlParams params = new LoadUrlParams(url);
292        if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttpHeaders);
293        loadUrlOnUiThread(params);
294    }
295
296    @Override
297    public void loadUrl(String url) {
298        loadUrl(url, null);
299    }
300
301    @Override
302    public void postUrl(String url, byte[] postData) {
303        LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData);
304        Map<String,String> headers = new HashMap<String,String>();
305        headers.put("Content-Type", "application/x-www-form-urlencoded");
306        params.setExtraHeaders(headers);
307        loadUrlOnUiThread(params);
308    }
309
310    private static boolean isBase64Encoded(String encoding) {
311        return "base64".equals(encoding);
312    }
313
314    @Override
315    public void loadData(String data, String mimeType, String encoding) {
316        loadUrlOnUiThread(LoadUrlParams.createLoadDataParams(
317                data, mimeType, isBase64Encoded(encoding)));
318    }
319
320    @Override
321    public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding,
322            String historyUrl) {
323        LoadUrlParams loadUrlParams;
324
325        if (baseUrl != null && baseUrl.startsWith("data:")) {
326            // For backwards compatibility with WebViewClassic, we use the value of |encoding|
327            // as the charset, as long as it's not "base64".
328            boolean isBase64 = isBase64Encoded(encoding);
329            loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(
330                    data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? null : encoding);
331        } else {
332            if (baseUrl == null || baseUrl.length() == 0) baseUrl = "about:blank";
333            // When loading data with a non-data: base URL, the classic WebView would effectively
334            // "dump" that string of data into the WebView without going through regular URL
335            // loading steps such as decoding URL-encoded entities. We achieve this same behavior by
336            // base64 encoding the data that is passed here and then loading that as a data: URL.
337            try {
338                loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(
339                        Base64.encodeToString(data.getBytes("utf-8"), Base64.DEFAULT), mimeType,
340                        true, baseUrl, historyUrl, "utf-8");
341            } catch (java.io.UnsupportedEncodingException e) {
342                Log.wtf(TAG, "Unable to load data string " + data, e);
343                return;
344            }
345        }
346        loadUrlOnUiThread(loadUrlParams);
347    }
348
349    private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) {
350        if (ThreadUtils.runningOnUiThread()) {
351            mAwContents.loadUrl(loadUrlParams);
352        } else {
353            // Disallowed in WebView API for apps targetting a new SDK
354            assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
355            ThreadUtils.postOnUiThread(new Runnable() {
356                @Override
357                public void run() {
358                    mAwContents.loadUrl(loadUrlParams);
359                }
360            });
361        }
362    }
363
364    public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) {
365        checkThread();
366        mAwContents.evaluateJavaScript(script, resultCallback);
367    }
368
369    @Override
370    public void saveWebArchive(String filename) {
371        checkThread();
372        saveWebArchive(filename, false, null);
373    }
374
375    @Override
376    public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
377        checkThread();
378        mAwContents.saveWebArchive(basename, autoname, callback);
379    }
380
381    @Override
382    public void stopLoading() {
383        checkThread();
384        mAwContents.stopLoading();
385    }
386
387    @Override
388    public void reload() {
389        checkThread();
390        mAwContents.reload();
391    }
392
393    @Override
394    public boolean canGoBack() {
395        checkThread();
396        return mAwContents.canGoBack();
397    }
398
399    @Override
400    public void goBack() {
401        checkThread();
402        mAwContents.goBack();
403    }
404
405    @Override
406    public boolean canGoForward() {
407        checkThread();
408        return mAwContents.canGoForward();
409    }
410
411    @Override
412    public void goForward() {
413        checkThread();
414        mAwContents.goForward();
415    }
416
417    @Override
418    public boolean canGoBackOrForward(int steps) {
419        checkThread();
420        return mAwContents.canGoBackOrForward(steps);
421    }
422
423    @Override
424    public void goBackOrForward(int steps) {
425        checkThread();
426        mAwContents.goBackOrForward(steps);
427    }
428
429    @Override
430    public boolean isPrivateBrowsingEnabled() {
431        // Not supported in this WebView implementation.
432        return false;
433    }
434
435    @Override
436    public boolean pageUp(boolean top) {
437        checkThread();
438        return mAwContents.pageUp(top);
439    }
440
441    @Override
442    public boolean pageDown(boolean bottom) {
443        checkThread();
444        return mAwContents.pageDown(bottom);
445    }
446
447    @Override
448    public void clearView() {
449        checkThread();
450        UnimplementedWebViewApi.invoke();
451    }
452
453    @Override
454    public Picture capturePicture() {
455        checkThread();
456        return mAwContents.capturePicture();
457    }
458
459    @Override
460    public void exportToPdf(OutputStream stream, int width, int height,
461            ValueCallback<Boolean> resultCallback) {
462        checkThread();
463        // TODO(sgurun) enable this only after upstream part lands
464        //mAwContents.exportToPdf(stream, width, height, resultCallback);
465    }
466
467    @Override
468    public float getScale() {
469        checkThread();
470        return mAwContents.getScale();
471    }
472
473    @Override
474    public void setInitialScale(int scaleInPercent) {
475        checkThread();
476        mAwContents.getSettings().setInitialPageScale(scaleInPercent);
477    }
478
479    @Override
480    public void invokeZoomPicker() {
481        checkThread();
482        mAwContents.invokeZoomPicker();
483    }
484
485    @Override
486    public WebView.HitTestResult getHitTestResult() {
487        checkThread();
488        AwContents.HitTestData data = mAwContents.getLastHitTestResult();
489        mHitTestResult.setType(data.hitTestResultType);
490        mHitTestResult.setExtra(data.hitTestResultExtraData);
491        return mHitTestResult;
492    }
493
494    @Override
495    public void requestFocusNodeHref(Message hrefMsg) {
496        checkThread();
497        mAwContents.requestFocusNodeHref(hrefMsg);
498    }
499
500    @Override
501    public void requestImageRef(Message msg) {
502        checkThread();
503        mAwContents.requestImageRef(msg);
504    }
505
506    @Override
507    public String getUrl() {
508        checkThread();
509        String url =  mAwContents.getUrl();
510        if (url == null || url.trim().isEmpty()) return null;
511        return url;
512    }
513
514    @Override
515    public String getOriginalUrl() {
516        checkThread();
517        String url =  mAwContents.getOriginalUrl();
518        if (url == null || url.trim().isEmpty()) return null;
519        return url;
520    }
521
522    @Override
523    public String getTitle() {
524        checkThread();
525        return mAwContents.getTitle();
526    }
527
528    @Override
529    public Bitmap getFavicon() {
530        checkThread();
531        return mAwContents.getFavicon();
532    }
533
534    @Override
535    public String getTouchIconUrl() {
536        // Intentional no-op: hidden method on WebView.
537        return null;
538    }
539
540    @Override
541    public int getProgress() {
542        // No checkThread() because the value is cached java side (workaround for b/10533304).
543        return mAwContents.getMostRecentProgress();
544    }
545
546    @Override
547    public int getContentHeight() {
548        checkThread();
549        return mAwContents.getContentHeightCss();
550    }
551
552    @Override
553    public int getContentWidth() {
554        checkThread();
555        return mAwContents.getContentWidthCss();
556    }
557
558    @Override
559    public void pauseTimers() {
560        checkThread();
561        mAwContents.pauseTimers();
562    }
563
564    @Override
565    public void resumeTimers() {
566        checkThread();
567        mAwContents.resumeTimers();
568    }
569
570    @Override
571    public void onPause() {
572        checkThread();
573        mAwContents.onPause();
574    }
575
576    @Override
577    public void onResume() {
578        checkThread();
579        mAwContents.onResume();
580    }
581
582    @Override
583    public boolean isPaused() {
584        checkThread();
585        return mAwContents.isPaused();
586    }
587
588    @Override
589    public void freeMemory() {
590        checkThread();
591        UnimplementedWebViewApi.invoke();
592    }
593
594    @Override
595    public void clearCache(boolean includeDiskFiles) {
596        checkThread();
597        mAwContents.clearCache(includeDiskFiles);
598    }
599
600    /**
601     * This is a poorly named method, but we keep it for historical reasons.
602     */
603    @Override
604    public void clearFormData() {
605        checkThread();
606        mAwContents.hideAutofillPopup();
607    }
608
609    @Override
610    public void clearHistory() {
611        checkThread();
612        mAwContents.clearHistory();
613    }
614
615    @Override
616    public void clearSslPreferences() {
617        checkThread();
618        mAwContents.clearSslPreferences();
619    }
620
621    @Override
622    public WebBackForwardList copyBackForwardList() {
623        checkThread();
624        return new WebBackForwardListChromium(
625                mAwContents.getNavigationHistory());
626    }
627
628    @Override
629    public void setFindListener(WebView.FindListener listener) {
630        checkThread();
631        mContentsClientAdapter.setFindListener(listener);
632    }
633
634    @Override
635    public void findNext(boolean forwards) {
636        checkThread();
637        mAwContents.findNext(forwards);
638    }
639
640    @Override
641    public int findAll(String searchString) {
642        checkThread();
643        mAwContents.findAllAsync(searchString);
644        return 0;
645    }
646
647    @Override
648    public void findAllAsync(String searchString) {
649        checkThread();
650        mAwContents.findAllAsync(searchString);
651    }
652
653    @Override
654    public boolean showFindDialog(String text, boolean showIme) {
655        checkThread();
656        if (mWebView.getParent() == null) {
657            return false;
658        }
659
660        FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext());
661        if (findAction == null) {
662            return false;
663        }
664
665        mWebView.startActionMode(findAction);
666        findAction.setWebView(mWebView);
667        if (showIme) {
668            findAction.showSoftInput();
669        }
670
671        if (text != null) {
672            findAction.setText(text);
673            findAction.findAll();
674        }
675
676        return true;
677    }
678
679    @Override
680    public void notifyFindDialogDismissed() {
681        checkThread();
682        clearMatches();
683    }
684
685    @Override
686    public void clearMatches() {
687        checkThread();
688        mAwContents.clearMatches();
689    }
690
691    @Override
692    public void documentHasImages(Message response) {
693        checkThread();
694        mAwContents.documentHasImages(response);
695    }
696
697    @Override
698    public void setWebViewClient(WebViewClient client) {
699        checkThread();
700        mContentsClientAdapter.setWebViewClient(client);
701    }
702
703    @Override
704    public void setDownloadListener(DownloadListener listener) {
705        checkThread();
706        mContentsClientAdapter.setDownloadListener(listener);
707    }
708
709    @Override
710    public void setWebChromeClient(WebChromeClient client) {
711        checkThread();
712        mContentsClientAdapter.setWebChromeClient(client);
713    }
714
715    @Override
716    public void setPictureListener(WebView.PictureListener listener) {
717        checkThread();
718        mContentsClientAdapter.setPictureListener(listener);
719        mAwContents.enableOnNewPicture(listener != null,
720                mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2);
721    }
722
723    @Override
724    public void addJavascriptInterface(Object obj, String interfaceName) {
725        checkThread();
726        Class<? extends Annotation> requiredAnnotation = null;
727        if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
728           requiredAnnotation = JavascriptInterface.class;
729        }
730        mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation);
731    }
732
733    @Override
734    public void removeJavascriptInterface(String interfaceName) {
735        checkThread();
736        mAwContents.removeJavascriptInterface(interfaceName);
737    }
738
739    @Override
740    public WebSettings getSettings() {
741        checkThread();
742        if (mWebSettings == null) {
743            mWebSettings = new ContentSettingsAdapter(mAwContents.getSettings());
744        }
745        return mWebSettings;
746    }
747
748    @Override
749    public void setMapTrackballToArrowKeys(boolean setMap) {
750        checkThread();
751        // This is a deprecated API: intentional no-op.
752    }
753
754    @Override
755    public void flingScroll(int vx, int vy) {
756        checkThread();
757        mAwContents.flingScroll(vx, vy);
758    }
759
760    @Override
761    public View getZoomControls() {
762        checkThread();
763        // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed
764        // to stop very out-dated applications from crashing.
765        Log.w(TAG, "WebView doesn't support getZoomControls");
766        return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null;
767    }
768
769    @Override
770    public boolean canZoomIn() {
771        checkThread();
772        return mAwContents.canZoomIn();
773    }
774
775    @Override
776    public boolean canZoomOut() {
777        checkThread();
778        return mAwContents.canZoomOut();
779    }
780
781    @Override
782    public boolean zoomIn() {
783        checkThread();
784        return mAwContents.zoomIn();
785    }
786
787    @Override
788    public boolean zoomOut() {
789        checkThread();
790        return mAwContents.zoomOut();
791    }
792
793    @Override
794    public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) {
795        checkThread();
796        UnimplementedWebViewApi.invoke();
797    }
798
799    @Override
800    public View findHierarchyView(String className, int hashCode) {
801        checkThread();
802        UnimplementedWebViewApi.invoke();
803        return null;
804    }
805
806    // WebViewProvider glue methods ---------------------------------------------------------------
807
808    @Override
809    // This needs to be kept thread safe!
810    public WebViewProvider.ViewDelegate getViewDelegate() {
811        return this;
812    }
813
814    @Override
815    public WebViewProvider.ScrollDelegate getScrollDelegate() {
816        checkThread();
817        return this;
818    }
819
820
821    // WebViewProvider.ViewDelegate implementation ------------------------------------------------
822
823    // TODO: remove from WebViewProvider and use default implementation from
824    // ViewGroup.
825    // @Override
826    public boolean shouldDelayChildPressedState() {
827        checkThread();
828        return true;
829    }
830
831//    @Override
832    public AccessibilityNodeProvider getAccessibilityNodeProvider() {
833        checkThread();
834        return mAwContents.getAccessibilityNodeProvider();
835    }
836
837    @Override
838    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
839        checkThread();
840        mAwContents.onInitializeAccessibilityNodeInfo(info);
841    }
842
843    @Override
844    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
845        checkThread();
846        mAwContents.onInitializeAccessibilityEvent(event);
847    }
848
849    @Override
850    public boolean performAccessibilityAction(int action, Bundle arguments) {
851        checkThread();
852        if (mAwContents.supportsAccessibilityAction(action)) {
853            return mAwContents.performAccessibilityAction(action, arguments);
854        }
855        return mWebViewPrivate.super_performAccessibilityAction(action, arguments);
856    }
857
858    @Override
859    public void setOverScrollMode(int mode) {
860        checkThread();
861        // This gets called from the android.view.View c'tor that WebView inherits from. This
862        // causes the method to be called when mAwContents == null.
863        // It's safe to ignore these calls however since AwContents will read the current value of
864        // this setting when it's created.
865        if (mAwContents != null) {
866            mAwContents.setOverScrollMode(mode);
867        }
868    }
869
870    @Override
871    public void setScrollBarStyle(int style) {
872        checkThread();
873        mAwContents.setScrollBarStyle(style);
874    }
875
876    @Override
877    public void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar,
878                                        int l, int t, int r, int b) {
879        checkThread();
880        // WebViewClassic was overriding this method to handle rubberband over-scroll. Since
881        // WebViewChromium doesn't support that the vanilla implementation of this method can be
882        // used.
883        mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b);
884    }
885
886    @Override
887    public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
888        checkThread();
889        mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
890    }
891
892    @Override
893    public void onWindowVisibilityChanged(int visibility) {
894        checkThread();
895        mAwContents.onWindowVisibilityChanged(visibility);
896    }
897
898    @Override
899    public void onDraw(Canvas canvas) {
900        checkThread();
901        mAwContents.onDraw(canvas);
902    }
903
904    @Override
905    public void setLayoutParams(ViewGroup.LayoutParams layoutParams) {
906        checkThread();
907        // TODO: This is the minimum implementation for HTMLViewer
908        // bringup. Likely will need to go up to ContentViewCore for
909        // a complete implementation.
910        mWebViewPrivate.super_setLayoutParams(layoutParams);
911    }
912
913    @Override
914    public boolean performLongClick() {
915        checkThread();
916        return mWebViewPrivate.super_performLongClick();
917    }
918
919    @Override
920    public void onConfigurationChanged(Configuration newConfig) {
921        checkThread();
922        mAwContents.onConfigurationChanged(newConfig);
923    }
924
925    @Override
926    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
927        checkThread();
928        return mAwContents.onCreateInputConnection(outAttrs);
929    }
930
931    @Override
932    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
933        checkThread();
934        UnimplementedWebViewApi.invoke();
935        return false;
936    }
937
938    @Override
939    public boolean onKeyDown(int keyCode, KeyEvent event) {
940        checkThread();
941        UnimplementedWebViewApi.invoke();
942        return false;
943    }
944
945    @Override
946    public boolean onKeyUp(int keyCode, KeyEvent event) {
947        checkThread();
948        return mAwContents.onKeyUp(keyCode, event);
949    }
950
951    @Override
952    public void onAttachedToWindow() {
953        checkThread();
954        mAwContents.onAttachedToWindow();
955    }
956
957    @Override
958    public void onDetachedFromWindow() {
959        checkThread();
960        mAwContents.onDetachedFromWindow();
961        if (mGLfunctor != null) {
962            mGLfunctor.detach();
963        }
964    }
965
966    @Override
967    public void onVisibilityChanged(View changedView, int visibility) {
968        checkThread();
969        // The AwContents will find out the container view visibility before the first draw so we
970        // can safely ignore onVisibilityChanged callbacks that happen before init().
971        if (mAwContents != null) {
972            mAwContents.onVisibilityChanged(changedView, visibility);
973        }
974    }
975
976    @Override
977    public void onWindowFocusChanged(boolean hasWindowFocus) {
978        checkThread();
979        mAwContents.onWindowFocusChanged(hasWindowFocus);
980    }
981
982    @Override
983    public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
984        checkThread();
985        mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect);
986    }
987
988    @Override
989    public boolean setFrame(int left, int top, int right, int bottom) {
990        // TODO(joth): This is the minimum implementation for initial
991        // bringup. Likely will need to go up to AwContents for a complete
992        // implementation, e.g. setting the compositor visible region (to
993        // avoid painting tiles that are offscreen due to the view's position).
994        checkThread();
995        return mWebViewPrivate.super_setFrame(left, top, right, bottom);
996    }
997
998    @Override
999    public void onSizeChanged(int w, int h, int ow, int oh) {
1000        checkThread();
1001        mAwContents.onSizeChanged(w, h, ow, oh);
1002    }
1003
1004    @Override
1005    public void onScrollChanged(int l, int t, int oldl, int oldt) {
1006        checkThread();
1007    }
1008
1009    @Override
1010    public boolean dispatchKeyEvent(KeyEvent event) {
1011        checkThread();
1012        return mAwContents.dispatchKeyEvent(event);
1013    }
1014
1015    @Override
1016    public boolean onTouchEvent(MotionEvent ev) {
1017        checkThread();
1018        return mAwContents.onTouchEvent(ev);
1019    }
1020
1021    @Override
1022    public boolean onHoverEvent(MotionEvent event) {
1023        checkThread();
1024        return mAwContents.onHoverEvent(event);
1025    }
1026
1027    @Override
1028    public boolean onGenericMotionEvent(MotionEvent event) {
1029        checkThread();
1030        return mAwContents.onGenericMotionEvent(event);
1031    }
1032
1033    @Override
1034    public boolean onTrackballEvent(MotionEvent ev) {
1035        checkThread();
1036        // Trackball event not handled, which eventually gets converted to DPAD keyevents
1037        return false;
1038    }
1039
1040    @Override
1041    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
1042        checkThread();
1043        mAwContents.requestFocus();
1044        return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect);
1045    }
1046
1047    @Override
1048    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1049        checkThread();
1050        mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec);
1051    }
1052
1053    @Override
1054    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
1055        checkThread();
1056        return mAwContents.requestChildRectangleOnScreen(child, rect, immediate);
1057    }
1058
1059    @Override
1060    public void setBackgroundColor(final int color) {
1061        if (ThreadUtils.runningOnUiThread()) {
1062            mAwContents.setBackgroundColor(color);
1063        } else {
1064            // Disallowed in WebView API for apps targetting a new SDK
1065            assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
1066            ThreadUtils.postOnUiThread(new Runnable() {
1067                @Override
1068                public void run() {
1069                    mAwContents.setBackgroundColor(color);
1070                }
1071            });
1072        }
1073    }
1074
1075    @Override
1076    public void setLayerType(int layerType, Paint paint) {
1077        checkThread();
1078        UnimplementedWebViewApi.invoke();
1079    }
1080
1081    @Override
1082    public void preDispatchDraw(Canvas canvas) {
1083        checkThread();
1084        // TODO(leandrogracia): remove this method from WebViewProvider if we think
1085        // we won't need it again.
1086    }
1087
1088    // WebViewProvider.ScrollDelegate implementation ----------------------------------------------
1089
1090    @Override
1091    public int computeHorizontalScrollRange() {
1092        checkThread();
1093        return mAwContents.computeHorizontalScrollRange();
1094    }
1095
1096    @Override
1097    public int computeHorizontalScrollOffset() {
1098        checkThread();
1099        return mAwContents.computeHorizontalScrollOffset();
1100    }
1101
1102    @Override
1103    public int computeVerticalScrollRange() {
1104        checkThread();
1105        return mAwContents.computeVerticalScrollRange();
1106    }
1107
1108    @Override
1109    public int computeVerticalScrollOffset() {
1110        checkThread();
1111        return mAwContents.computeVerticalScrollOffset();
1112    }
1113
1114    @Override
1115    public int computeVerticalScrollExtent() {
1116        checkThread();
1117        return mAwContents.computeVerticalScrollExtent();
1118    }
1119
1120    @Override
1121    public void computeScroll() {
1122        checkThread();
1123        mAwContents.computeScroll();
1124    }
1125
1126    // AwContents.InternalAccessDelegate implementation --------------------------------------
1127    private class InternalAccessAdapter implements AwContents.InternalAccessDelegate {
1128        @Override
1129        public boolean drawChild(Canvas arg0, View arg1, long arg2) {
1130            UnimplementedWebViewApi.invoke();
1131            return false;
1132        }
1133
1134        @Override
1135        public boolean super_onKeyUp(int arg0, KeyEvent arg1) {
1136            UnimplementedWebViewApi.invoke();
1137            return false;
1138        }
1139
1140        @Override
1141        public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) {
1142            UnimplementedWebViewApi.invoke();
1143            return false;
1144        }
1145
1146        @Override
1147        public boolean super_dispatchKeyEvent(KeyEvent event) {
1148            return mWebViewPrivate.super_dispatchKeyEvent(event);
1149        }
1150
1151        @Override
1152        public boolean super_onGenericMotionEvent(MotionEvent arg0) {
1153            UnimplementedWebViewApi.invoke();
1154            return false;
1155        }
1156
1157        @Override
1158        public void super_onConfigurationChanged(Configuration arg0) {
1159            UnimplementedWebViewApi.invoke();
1160        }
1161
1162        @Override
1163        public int super_getScrollBarStyle() {
1164            return mWebViewPrivate.super_getScrollBarStyle();
1165        }
1166
1167        @Override
1168        public boolean awakenScrollBars() {
1169            mWebViewPrivate.awakenScrollBars(0);
1170            // TODO: modify the WebView.PrivateAccess to provide a return value.
1171            return true;
1172        }
1173
1174        @Override
1175        public boolean super_awakenScrollBars(int arg0, boolean arg1) {
1176            // TODO: need method on WebView.PrivateAccess?
1177            UnimplementedWebViewApi.invoke();
1178            return false;
1179        }
1180
1181        @Override
1182        public void onScrollChanged(int l, int t, int oldl, int oldt) {
1183            mWebViewPrivate.setScrollXRaw(l);
1184            mWebViewPrivate.setScrollYRaw(t);
1185            mWebViewPrivate.onScrollChanged(l, t, oldl, oldt);
1186        }
1187
1188        @Override
1189        public void overScrollBy(int deltaX, int deltaY,
1190            int scrollX, int scrollY,
1191            int scrollRangeX, int scrollRangeY,
1192            int maxOverScrollX, int maxOverScrollY,
1193            boolean isTouchEvent) {
1194            mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY,
1195                    scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
1196        }
1197
1198        @Override
1199        public void super_scrollTo(int scrollX, int scrollY) {
1200            mWebViewPrivate.super_scrollTo(scrollX, scrollY);
1201        }
1202
1203        @Override
1204        public void setMeasuredDimension(int measuredWidth, int measuredHeight) {
1205            mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight);
1206        }
1207
1208        @Override
1209        public boolean requestDrawGL(Canvas canvas) {
1210            if (mGLfunctor == null) {
1211                mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext());
1212            }
1213            return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl());
1214        }
1215    }
1216}
1217