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