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