blob: ec5c1cc14770b091c37786aad4308f7b1b92ecf2 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.webview.chromium;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.http.SslCertificate;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.util.Base64;
import android.util.Log;
import android.view.HardwareCanvas;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.webkit.DownloadListener;
import android.webkit.FindActionModeCallback;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebViewProvider;
import android.widget.TextView;
import org.chromium.android_webview.AwBrowserContext;
import org.chromium.android_webview.AwContents;
import org.chromium.base.ThreadUtils;
import org.chromium.content.browser.LoadUrlParams;
import org.chromium.net.NetworkChangeNotifier;
import java.io.BufferedWriter;
import java.io.File;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
/**
* This class is the delegate to which WebViewProxy forwards all API calls.
*
* Most of the actual functionality is implemented by AwContents (or ContentViewCore within
* it). This class also contains WebView-specific APIs that require the creation of other
* adapters (otherwise org.chromium.content would depend on the webview.chromium package)
* and a small set of no-op deprecated APIs.
*/
class WebViewChromium implements WebViewProvider,
WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate {
private static final String TAG = WebViewChromium.class.getSimpleName();
// The WebView that this WebViewChromium is the provider for.
WebView mWebView;
// Lets us access protected View-derived methods on the WebView instance we're backing.
WebView.PrivateAccess mWebViewPrivate;
// The client adapter class.
private WebViewContentsClientAdapter mContentsClientAdapter;
// Variables for functionality provided by this adapter ---------------------------------------
// WebSettings adapter, lazily initialized in the getter
private WebSettings mWebSettings;
// The WebView wrapper for ContentViewCore and required browser compontents.
private AwContents mAwContents;
// Non-null if this webview is using the GL accelerated draw path.
private DrawGLFunctor mGLfunctor;
private AwBrowserContext mBrowserContext;
private final WebView.HitTestResult mHitTestResult;
private final int mAppTargetSdkVersion;
public WebViewChromium(WebView webView, WebView.PrivateAccess webViewPrivate,
AwBrowserContext browserContext) {
mWebView = webView;
mWebViewPrivate = webViewPrivate;
mHitTestResult = new WebView.HitTestResult();
mBrowserContext = browserContext;
mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion;
}
static void completeWindowCreation(WebView parent, WebView child) {
AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents;
AwContents childContents =
child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents;
parentContents.supplyContentsForPopup(childContents);
}
// WebViewProvider methods --------------------------------------------------------------------
@Override
public void init(Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
// BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree
// so is ignored. TODO: remove it from WebViewProvider.
final boolean isAccessFromFileURLsGrantedByDefault =
mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
mContentsClientAdapter = new WebViewContentsClientAdapter(mWebView);
mAwContents = new AwContents(mBrowserContext, mWebView, new InternalAccessAdapter(),
mContentsClientAdapter, isAccessFromFileURLsGrantedByDefault);
if (privateBrowsing) {
final String msg = "Private browsing is not supported in WebView.";
if (mAppTargetSdkVersion >= Build.VERSION_CODES.KEY_LIME_PIE) {
throw new IllegalArgumentException(msg);
} else {
Log.w(TAG, msg);
// Intentionally irreversibly disable the webview instance, so that private
// user data cannot leak through misuse of a non-privateBrowing WebView instance.
// Can't just null out mAwContents as we never null-check it before use.
mAwContents.destroy();
TextView warningLabel = new TextView(mWebView.getContext());
warningLabel.setText(mWebView.getContext().getString(
com.android.internal.R.string.webviewchromium_private_browsing_warning));
mWebView.addView(warningLabel);
}
}
}
private RuntimeException createThreadException() {
return new IllegalStateException("Calling View methods on another thread than the UI " +
"thread. PLEASE FILE A BUG! go/klp-webview-bug");
}
// Intentionally not static, as no need to check thread on static methods
private void checkThread() {
if (!ThreadUtils.runningOnUiThread()) {
final RuntimeException threadViolation = createThreadException();
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
throw threadViolation;
}
});
}
}
@Override
public void setHorizontalScrollbarOverlay(boolean overlay) {
checkThread();
mAwContents.setHorizontalScrollbarOverlay(overlay);
}
@Override
public void setVerticalScrollbarOverlay(boolean overlay) {
checkThread();
mAwContents.setVerticalScrollbarOverlay(overlay);
}
@Override
public boolean overlayHorizontalScrollbar() {
checkThread();
return mAwContents.overlayHorizontalScrollbar();
}
@Override
public boolean overlayVerticalScrollbar() {
checkThread();
return mAwContents.overlayVerticalScrollbar();
}
@Override
public int getVisibleTitleHeight() {
// This is deprecated in WebView and should always return 0.
return 0;
}
@Override
public SslCertificate getCertificate() {
checkThread();
return mAwContents.getCertificate();
}
@Override
public void setCertificate(SslCertificate certificate) {
checkThread();
UnimplementedWebViewApi.invoke();
}
@Override
public void savePassword(String host, String username, String password) {
// This is a deprecated API: intentional no-op.
}
@Override
public void setHttpAuthUsernamePassword(String host, String realm, String username,
String password) {
checkThread();
mAwContents.setHttpAuthUsernamePassword(host, realm, username, password);
}
@Override
public String[] getHttpAuthUsernamePassword(String host, String realm) {
checkThread();
return mAwContents.getHttpAuthUsernamePassword(host, realm);
}
@Override
public void destroy() {
checkThread();
mAwContents.destroy();
if (mGLfunctor != null) {
mGLfunctor.destroy();
mGLfunctor = null;
}
}
@Override
public void setNetworkAvailable(boolean networkUp) {
checkThread();
NetworkChangeNotifier.forceConnectivityState(networkUp);
}
@Override
public WebBackForwardList saveState(Bundle outState) {
checkThread();
if (outState == null) return null;
if (!mAwContents.saveState(outState)) return null;
return copyBackForwardList();
}
@Override
public boolean savePicture(Bundle b, File dest) {
// Intentional no-op: hidden method on WebView.
return false;
}
@Override
public boolean restorePicture(Bundle b, File src) {
// Intentional no-op: hidden method on WebView.
return false;
}
@Override
public WebBackForwardList restoreState(Bundle inState) {
checkThread();
if (inState == null) return null;
if (!mAwContents.restoreState(inState)) return null;
return copyBackForwardList();
}
@Override
public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
// TODO: We may actually want to do some sanity checks here (like filter about://chrome).
// For backwards compatibility, apps targeting less than K will have JS URLs evaluated
// directly and any result of the evaluation will not replace the current page content.
// Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will
// have the result of that URL replace the content of the current page.
final String JAVASCRIPT_SCHEME = "javascript:";
if (mAppTargetSdkVersion < Build.VERSION_CODES.KEY_LIME_PIE &&
url.startsWith(JAVASCRIPT_SCHEME)) {
mAwContents.evaluateJavaScriptEvenIfNotYetNavigated(
url.substring(JAVASCRIPT_SCHEME.length()));
return;
}
LoadUrlParams params = new LoadUrlParams(url);
if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttpHeaders);
loadUrlOnUiThread(params);
}
@Override
public void loadUrl(String url) {
loadUrl(url, null);
}
@Override
public void postUrl(String url, byte[] postData) {
LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData);
Map<String,String> headers = new HashMap<String,String>();
headers.put("Content-Type", "application/x-www-form-urlencoded");
params.setExtraHeaders(headers);
loadUrlOnUiThread(params);
}
private static boolean isBase64Encoded(String encoding) {
return "base64".equals(encoding);
}
@Override
public void loadData(String data, String mimeType, String encoding) {
loadUrlOnUiThread(LoadUrlParams.createLoadDataParams(
data, mimeType, isBase64Encoded(encoding)));
}
@Override
public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding,
String historyUrl) {
LoadUrlParams loadUrlParams;
if (baseUrl != null && baseUrl.startsWith("data:")) {
// For backwards compatibility with WebViewClassic, we use the value of |encoding|
// as the charset, as long as it's not "base64".
boolean isBase64 = isBase64Encoded(encoding);
loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(
data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? null : encoding);
} else {
if (baseUrl == null || baseUrl.length() == 0) baseUrl = "about:blank";
// When loading data with a non-data: base URL, the classic WebView would effectively
// "dump" that string of data into the WebView without going through regular URL
// loading steps such as decoding URL-encoded entities. We achieve this same behavior by
// base64 encoding the data that is passed here and then loading that as a data: URL.
try {
loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl(
Base64.encodeToString(data.getBytes("utf-8"), Base64.DEFAULT), mimeType,
true, baseUrl, historyUrl, "utf-8");
} catch (java.io.UnsupportedEncodingException e) {
Log.wtf(TAG, "Unable to load data string " + data, e);
return;
}
}
loadUrlOnUiThread(loadUrlParams);
}
private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) {
if (ThreadUtils.runningOnUiThread()) {
mAwContents.loadUrl(loadUrlParams);
} else {
// Disallowed in WebView API for apps targetting a new SDK
assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
mAwContents.loadUrl(loadUrlParams);
}
});
}
}
public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) {
checkThread();
mAwContents.evaluateJavaScript(script, resultCallback);
}
@Override
public void saveWebArchive(String filename) {
checkThread();
saveWebArchive(filename, false, null);
}
@Override
public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
checkThread();
mAwContents.saveWebArchive(basename, autoname, callback);
}
@Override
public void stopLoading() {
checkThread();
mAwContents.stopLoading();
}
@Override
public void reload() {
checkThread();
mAwContents.reload();
}
@Override
public boolean canGoBack() {
checkThread();
return mAwContents.canGoBack();
}
@Override
public void goBack() {
checkThread();
mAwContents.goBack();
}
@Override
public boolean canGoForward() {
checkThread();
return mAwContents.canGoForward();
}
@Override
public void goForward() {
checkThread();
mAwContents.goForward();
}
@Override
public boolean canGoBackOrForward(int steps) {
checkThread();
return mAwContents.canGoBackOrForward(steps);
}
@Override
public void goBackOrForward(int steps) {
checkThread();
mAwContents.goBackOrForward(steps);
}
@Override
public boolean isPrivateBrowsingEnabled() {
// Not supported in this WebView implementation.
return false;
}
@Override
public boolean pageUp(boolean top) {
checkThread();
return mAwContents.pageUp(top);
}
@Override
public boolean pageDown(boolean bottom) {
checkThread();
return mAwContents.pageDown(bottom);
}
@Override
public void clearView() {
checkThread();
UnimplementedWebViewApi.invoke();
}
@Override
public Picture capturePicture() {
checkThread();
return mAwContents.capturePicture();
}
@Override
public void exportToPdf(OutputStream stream, int width, int height,
ValueCallback<Boolean> resultCallback) {
checkThread();
// TODO(sgurun) enable this only after upstream part lands
//mAwContents.exportToPdf(stream, width, height, resultCallback);
}
@Override
public float getScale() {
checkThread();
return mAwContents.getScale();
}
@Override
public void setInitialScale(int scaleInPercent) {
checkThread();
mAwContents.getSettings().setInitialPageScale(scaleInPercent);
}
@Override
public void invokeZoomPicker() {
checkThread();
mAwContents.invokeZoomPicker();
}
@Override
public WebView.HitTestResult getHitTestResult() {
checkThread();
AwContents.HitTestData data = mAwContents.getLastHitTestResult();
mHitTestResult.setType(data.hitTestResultType);
mHitTestResult.setExtra(data.hitTestResultExtraData);
return mHitTestResult;
}
@Override
public void requestFocusNodeHref(Message hrefMsg) {
checkThread();
mAwContents.requestFocusNodeHref(hrefMsg);
}
@Override
public void requestImageRef(Message msg) {
checkThread();
mAwContents.requestImageRef(msg);
}
@Override
public String getUrl() {
checkThread();
String url = mAwContents.getUrl();
if (url == null || url.trim().isEmpty()) return null;
return url;
}
@Override
public String getOriginalUrl() {
checkThread();
String url = mAwContents.getOriginalUrl();
if (url == null || url.trim().isEmpty()) return null;
return url;
}
@Override
public String getTitle() {
checkThread();
return mAwContents.getTitle();
}
@Override
public Bitmap getFavicon() {
checkThread();
return mAwContents.getFavicon();
}
@Override
public String getTouchIconUrl() {
// Intentional no-op: hidden method on WebView.
return null;
}
@Override
public int getProgress() {
checkThread();
return mAwContents.getMostRecentProgress();
}
@Override
public int getContentHeight() {
checkThread();
return mAwContents.getContentHeightCss();
}
@Override
public int getContentWidth() {
checkThread();
return mAwContents.getContentWidthCss();
}
@Override
public void pauseTimers() {
checkThread();
mAwContents.pauseTimers();
}
@Override
public void resumeTimers() {
checkThread();
mAwContents.resumeTimers();
}
@Override
public void onPause() {
checkThread();
mAwContents.onPause();
}
@Override
public void onResume() {
checkThread();
mAwContents.onResume();
}
@Override
public boolean isPaused() {
checkThread();
return mAwContents.isPaused();
}
@Override
public void freeMemory() {
checkThread();
UnimplementedWebViewApi.invoke();
}
@Override
public void clearCache(boolean includeDiskFiles) {
checkThread();
mAwContents.clearCache(includeDiskFiles);
}
/**
* This is a poorly named method, but we keep it for historical reasons.
*/
@Override
public void clearFormData() {
checkThread();
mAwContents.hideAutofillPopup();
}
@Override
public void clearHistory() {
checkThread();
mAwContents.clearHistory();
}
@Override
public void clearSslPreferences() {
checkThread();
mAwContents.clearSslPreferences();
}
@Override
public WebBackForwardList copyBackForwardList() {
checkThread();
return new WebBackForwardListChromium(
mAwContents.getNavigationHistory());
}
@Override
public void setFindListener(WebView.FindListener listener) {
checkThread();
mContentsClientAdapter.setFindListener(listener);
}
@Override
public void findNext(boolean forwards) {
checkThread();
mAwContents.findNext(forwards);
}
@Override
public int findAll(String searchString) {
checkThread();
mAwContents.findAllAsync(searchString);
return 0;
}
@Override
public void findAllAsync(String searchString) {
checkThread();
mAwContents.findAllAsync(searchString);
}
@Override
public boolean showFindDialog(String text, boolean showIme) {
checkThread();
if (mWebView.getParent() == null) {
return false;
}
FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext());
if (findAction == null) {
return false;
}
mWebView.startActionMode(findAction);
findAction.setWebView(mWebView);
if (showIme) {
findAction.showSoftInput();
}
if (text != null) {
findAction.setText(text);
findAction.findAll();
}
return true;
}
@Override
public void notifyFindDialogDismissed() {
checkThread();
clearMatches();
}
@Override
public void clearMatches() {
checkThread();
mAwContents.clearMatches();
}
@Override
public void documentHasImages(Message response) {
checkThread();
mAwContents.documentHasImages(response);
}
@Override
public void setWebViewClient(WebViewClient client) {
checkThread();
mContentsClientAdapter.setWebViewClient(client);
}
@Override
public void setDownloadListener(DownloadListener listener) {
checkThread();
mContentsClientAdapter.setDownloadListener(listener);
}
@Override
public void setWebChromeClient(WebChromeClient client) {
checkThread();
mContentsClientAdapter.setWebChromeClient(client);
}
@Override
public void setPictureListener(WebView.PictureListener listener) {
checkThread();
mContentsClientAdapter.setPictureListener(listener);
mAwContents.enableOnNewPicture(listener != null,
mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2);
}
@Override
public void addJavascriptInterface(Object obj, String interfaceName) {
checkThread();
Class<? extends Annotation> requiredAnnotation = null;
if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
requiredAnnotation = JavascriptInterface.class;
}
mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation);
}
@Override
public void removeJavascriptInterface(String interfaceName) {
checkThread();
mAwContents.removeJavascriptInterface(interfaceName);
}
@Override
public WebSettings getSettings() {
checkThread();
if (mWebSettings == null) {
mWebSettings = new ContentSettingsAdapter(mAwContents.getSettings());
}
return mWebSettings;
}
@Override
public void setMapTrackballToArrowKeys(boolean setMap) {
checkThread();
// This is a deprecated API: intentional no-op.
}
@Override
public void flingScroll(int vx, int vy) {
checkThread();
mAwContents.flingScroll(vx, vy);
}
@Override
public View getZoomControls() {
checkThread();
// This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed
// to stop very out-dated applications from crashing.
Log.w(TAG, "WebView doesn't support getZoomControls");
return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null;
}
@Override
public boolean canZoomIn() {
checkThread();
return mAwContents.canZoomIn();
}
@Override
public boolean canZoomOut() {
checkThread();
return mAwContents.canZoomOut();
}
@Override
public boolean zoomIn() {
checkThread();
return mAwContents.zoomIn();
}
@Override
public boolean zoomOut() {
checkThread();
return mAwContents.zoomOut();
}
@Override
public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) {
checkThread();
UnimplementedWebViewApi.invoke();
}
@Override
public View findHierarchyView(String className, int hashCode) {
checkThread();
UnimplementedWebViewApi.invoke();
return null;
}
// WebViewProvider glue methods ---------------------------------------------------------------
@Override
// This needs to be kept thread safe!
public WebViewProvider.ViewDelegate getViewDelegate() {
return this;
}
@Override
public WebViewProvider.ScrollDelegate getScrollDelegate() {
checkThread();
return this;
}
// WebViewProvider.ViewDelegate implementation ------------------------------------------------
// TODO: remove from WebViewProvider and use default implementation from
// ViewGroup.
// @Override
public boolean shouldDelayChildPressedState() {
checkThread();
return true;
}
// @Override
public AccessibilityNodeProvider getAccessibilityNodeProvider() {
checkThread();
return mAwContents.getAccessibilityNodeProvider();
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
checkThread();
mAwContents.onInitializeAccessibilityNodeInfo(info);
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
checkThread();
mAwContents.onInitializeAccessibilityEvent(event);
}
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
checkThread();
if (mAwContents.supportsAccessibilityAction(action)) {
return mAwContents.performAccessibilityAction(action, arguments);
}
return mWebViewPrivate.super_performAccessibilityAction(action, arguments);
}
@Override
public void setOverScrollMode(int mode) {
checkThread();
// This gets called from the android.view.View c'tor that WebView inherits from. This
// causes the method to be called when mAwContents == null.
// It's safe to ignore these calls however since AwContents will read the current value of
// this setting when it's created.
if (mAwContents != null) {
mAwContents.setOverScrollMode(mode);
}
}
@Override
public void setScrollBarStyle(int style) {
checkThread();
mAwContents.setScrollBarStyle(style);
}
@Override
public void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar,
int l, int t, int r, int b) {
checkThread();
// WebViewClassic was overriding this method to handle rubberband over-scroll. Since
// WebViewChromium doesn't support that the vanilla implementation of this method can be
// used.
mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b);
}
@Override
public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
checkThread();
mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
@Override
public void onWindowVisibilityChanged(int visibility) {
checkThread();
mAwContents.onWindowVisibilityChanged(visibility);
}
@Override
public void onDraw(Canvas canvas) {
checkThread();
mAwContents.onDraw(canvas);
}
@Override
public void setLayoutParams(ViewGroup.LayoutParams layoutParams) {
checkThread();
// TODO: This is the minimum implementation for HTMLViewer
// bringup. Likely will need to go up to ContentViewCore for
// a complete implementation.
mWebViewPrivate.super_setLayoutParams(layoutParams);
}
@Override
public boolean performLongClick() {
checkThread();
return mWebViewPrivate.super_performLongClick();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
checkThread();
mAwContents.onConfigurationChanged(newConfig);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
checkThread();
return mAwContents.onCreateInputConnection(outAttrs);
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
checkThread();
UnimplementedWebViewApi.invoke();
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
checkThread();
UnimplementedWebViewApi.invoke();
return false;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
checkThread();
return mAwContents.onKeyUp(keyCode, event);
}
@Override
public void onAttachedToWindow() {
checkThread();
mAwContents.onAttachedToWindow();
}
@Override
public void onDetachedFromWindow() {
checkThread();
mAwContents.onDetachedFromWindow();
if (mGLfunctor != null) {
mGLfunctor.detach();
}
}
@Override
public void onVisibilityChanged(View changedView, int visibility) {
checkThread();
// The AwContents will find out the container view visibility before the first draw so we
// can safely ignore onVisibilityChanged callbacks that happen before init().
if (mAwContents != null) {
mAwContents.onVisibilityChanged(changedView, visibility);
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
checkThread();
mAwContents.onWindowFocusChanged(hasWindowFocus);
}
@Override
public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
checkThread();
mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect);
}
@Override
public boolean setFrame(int left, int top, int right, int bottom) {
// TODO(joth): This is the minimum implementation for initial
// bringup. Likely will need to go up to AwContents for a complete
// implementation, e.g. setting the compositor visible region (to
// avoid painting tiles that are offscreen due to the view's position).
checkThread();
return mWebViewPrivate.super_setFrame(left, top, right, bottom);
}
@Override
public void onSizeChanged(int w, int h, int ow, int oh) {
checkThread();
mAwContents.onSizeChanged(w, h, ow, oh);
}
@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {
checkThread();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
checkThread();
return mAwContents.dispatchKeyEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
checkThread();
return mAwContents.onTouchEvent(ev);
}
@Override
public boolean onHoverEvent(MotionEvent event) {
checkThread();
return mAwContents.onHoverEvent(event);
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
checkThread();
return mAwContents.onGenericMotionEvent(event);
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
checkThread();
// Trackball event not handled, which eventually gets converted to DPAD keyevents
return false;
}
@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
checkThread();
mAwContents.requestFocus();
return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
checkThread();
mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
checkThread();
return mAwContents.requestChildRectangleOnScreen(child, rect, immediate);
}
@Override
public void setBackgroundColor(final int color) {
if (ThreadUtils.runningOnUiThread()) {
mAwContents.setBackgroundColor(color);
} else {
// Disallowed in WebView API for apps targetting a new SDK
assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2;
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
mAwContents.setBackgroundColor(color);
}
});
}
}
@Override
public void setLayerType(int layerType, Paint paint) {
checkThread();
UnimplementedWebViewApi.invoke();
}
@Override
public void preDispatchDraw(Canvas canvas) {
checkThread();
// TODO(leandrogracia): remove this method from WebViewProvider if we think
// we won't need it again.
}
// WebViewProvider.ScrollDelegate implementation ----------------------------------------------
@Override
public int computeHorizontalScrollRange() {
checkThread();
return mAwContents.computeHorizontalScrollRange();
}
@Override
public int computeHorizontalScrollOffset() {
checkThread();
return mAwContents.computeHorizontalScrollOffset();
}
@Override
public int computeVerticalScrollRange() {
checkThread();
return mAwContents.computeVerticalScrollRange();
}
@Override
public int computeVerticalScrollOffset() {
checkThread();
return mAwContents.computeVerticalScrollOffset();
}
@Override
public int computeVerticalScrollExtent() {
checkThread();
return mAwContents.computeVerticalScrollExtent();
}
@Override
public void computeScroll() {
checkThread();
mAwContents.computeScroll();
}
// AwContents.InternalAccessDelegate implementation --------------------------------------
private class InternalAccessAdapter implements AwContents.InternalAccessDelegate {
@Override
public boolean drawChild(Canvas arg0, View arg1, long arg2) {
UnimplementedWebViewApi.invoke();
return false;
}
@Override
public boolean super_onKeyUp(int arg0, KeyEvent arg1) {
UnimplementedWebViewApi.invoke();
return false;
}
@Override
public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) {
UnimplementedWebViewApi.invoke();
return false;
}
@Override
public boolean super_dispatchKeyEvent(KeyEvent event) {
return mWebViewPrivate.super_dispatchKeyEvent(event);
}
@Override
public boolean super_onGenericMotionEvent(MotionEvent arg0) {
UnimplementedWebViewApi.invoke();
return false;
}
@Override
public void super_onConfigurationChanged(Configuration arg0) {
UnimplementedWebViewApi.invoke();
}
@Override
public int super_getScrollBarStyle() {
return mWebViewPrivate.super_getScrollBarStyle();
}
@Override
public boolean awakenScrollBars() {
mWebViewPrivate.awakenScrollBars(0);
// TODO: modify the WebView.PrivateAccess to provide a return value.
return true;
}
@Override
public boolean super_awakenScrollBars(int arg0, boolean arg1) {
// TODO: need method on WebView.PrivateAccess?
UnimplementedWebViewApi.invoke();
return false;
}
@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {
mWebViewPrivate.setScrollXRaw(l);
mWebViewPrivate.setScrollYRaw(t);
mWebViewPrivate.onScrollChanged(l, t, oldl, oldt);
}
@Override
public void overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
@Override
public void super_scrollTo(int scrollX, int scrollY) {
mWebViewPrivate.super_scrollTo(scrollX, scrollY);
}
@Override
public void setMeasuredDimension(int measuredWidth, int measuredHeight) {
mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
public boolean requestDrawGL(Canvas canvas) {
if (mGLfunctor == null) {
mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext());
}
return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl());
}
}
}