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