diff options
author | Jonathan Dixon <joth@google.com> | 2012-02-28 18:45:06 +0000 |
---|---|---|
committer | Jonathan Dixon <joth@google.com> | 2012-03-02 11:17:47 +0000 |
commit | 3c90952036a5ff7ddb2946c643f1a0bf1c31d53a (patch) | |
tree | 974ef2a94c60a2c72b8fbd804613792480a9c3e5 | |
parent | 0dc0da67d9775b2364a38d015e0610492708a02e (diff) | |
download | frameworks_base-3c90952036a5ff7ddb2946c643f1a0bf1c31d53a.zip frameworks_base-3c90952036a5ff7ddb2946c643f1a0bf1c31d53a.tar.gz frameworks_base-3c90952036a5ff7ddb2946c643f1a0bf1c31d53a.tar.bz2 |
Refactor WebView to be a thin proxy class
Splits interface and implementation; all client calls are forwarded
to an abstract WebViewProvider interface, and the existing implementation
moved into the WebViewClassic implementor of this interface.
Originally taken from a snapshot from the development branch, by:
git diff HEAD 9a4c328a54cc05e5 | git apply
- but then rebased to keep up to date with master
Interdepends on webkit and Browser changes:
https://android-git.corp.google.com/g/158979
https://android-git.corp.google.com/g/167911
Change-Id: I91403f32654ff308934e95c832d17b292a7d9b2e
32 files changed, 1714 insertions, 11034 deletions
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java index db66305..11bd815 100644 --- a/core/java/android/webkit/AccessibilityInjector.java +++ b/core/java/android/webkit/AccessibilityInjector.java @@ -79,8 +79,8 @@ class AccessibilityInjector { private static ArrayList<AccessibilityWebContentKeyBinding> sBindings = new ArrayList<AccessibilityWebContentKeyBinding>(); - // handle to the WebView this injector is associated with. - private final WebView mWebView; + // handle to the WebViewClassic this injector is associated with. + private final WebViewClassic mWebView; // events scheduled for sending as soon as we receive the selected text private final Stack<AccessibilityEvent> mScheduledEventStack = new Stack<AccessibilityEvent>(); @@ -98,11 +98,11 @@ class AccessibilityInjector { private int mLastDirection; /** - * Creates a new injector associated with a given {@link WebView}. + * Creates a new injector associated with a given {@link WebViewClassic}. * - * @param webView The associated WebView. + * @param webView The associated WebViewClassic. */ - public AccessibilityInjector(WebView webView) { + public AccessibilityInjector(WebViewClassic webView) { mWebView = webView; ensureWebContentKeyBindings(); } @@ -327,7 +327,7 @@ class AccessibilityInjector { AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SELECTED); event.setClassName(mWebView.getClass().getName()); event.setPackageName(mWebView.getContext().getPackageName()); - event.setEnabled(mWebView.isEnabled()); + event.setEnabled(mWebView.getWebView().isEnabled()); return event; } diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index 8ccc59c7..f09e29d 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -70,7 +70,7 @@ class BrowserFrame extends Handler { private final static int MAX_OUTSTANDING_REQUESTS = 300; private final CallbackProxy mCallbackProxy; - private final WebSettings mSettings; + private final WebSettingsClassic mSettings; private final Context mContext; private final WebViewDatabase mDatabase; private final WebViewCore mWebViewCore; @@ -200,7 +200,7 @@ class BrowserFrame extends Handler { * XXX: Called by WebCore thread. */ public BrowserFrame(Context context, WebViewCore w, CallbackProxy proxy, - WebSettings settings, Map<String, Object> javascriptInterfaces) { + WebSettingsClassic settings, Map<String, Object> javascriptInterfaces) { Context appContext = context.getApplicationContext(); diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 3a05bca..484c449 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -61,8 +61,8 @@ class CallbackProxy extends Handler { private volatile WebViewClient mWebViewClient; // Instance of WebChromeClient for handling all chrome functions. private volatile WebChromeClient mWebChromeClient; - // Instance of WebView for handling UI requests. - private final WebView mWebView; + // Instance of WebViewClassic for handling UI requests. + private final WebViewClassic mWebView; // Client registered callback listener for download events private volatile DownloadListener mDownloadListener; // Keep track of multiple progress updates. @@ -148,7 +148,7 @@ class CallbackProxy extends Handler { /** * Construct a new CallbackProxy. */ - public CallbackProxy(Context context, WebView w) { + public CallbackProxy(Context context, WebViewClassic w) { // Used to start a default activity. mContext = context; mWebView = w; @@ -221,7 +221,7 @@ class CallbackProxy extends Handler { } boolean override = false; if (mWebViewClient != null) { - override = mWebViewClient.shouldOverrideUrlLoading(mWebView, + override = mWebViewClient.shouldOverrideUrlLoading(mWebView.getWebView(), overrideUrl); } else { Intent intent = new Intent(Intent.ACTION_VIEW, @@ -248,7 +248,7 @@ class CallbackProxy extends Handler { */ public boolean uiOverrideKeyEvent(KeyEvent event) { if (mWebViewClient != null) { - return mWebViewClient.shouldOverrideKeyEvent(mWebView, event); + return mWebViewClient.shouldOverrideKeyEvent(mWebView.getWebView(), event); } return false; } @@ -264,7 +264,8 @@ class CallbackProxy extends Handler { String startedUrl = msg.getData().getString("url"); mWebView.onPageStarted(startedUrl); if (mWebViewClient != null) { - mWebViewClient.onPageStarted(mWebView, startedUrl, (Bitmap) msg.obj); + mWebViewClient.onPageStarted(mWebView.getWebView(), startedUrl, + (Bitmap) msg.obj); } break; @@ -272,26 +273,26 @@ class CallbackProxy extends Handler { String finishedUrl = (String) msg.obj; mWebView.onPageFinished(finishedUrl); if (mWebViewClient != null) { - mWebViewClient.onPageFinished(mWebView, finishedUrl); + mWebViewClient.onPageFinished(mWebView.getWebView(), finishedUrl); } break; case RECEIVED_ICON: if (mWebChromeClient != null) { - mWebChromeClient.onReceivedIcon(mWebView, (Bitmap) msg.obj); + mWebChromeClient.onReceivedIcon(mWebView.getWebView(), (Bitmap) msg.obj); } break; case RECEIVED_TOUCH_ICON_URL: if (mWebChromeClient != null) { - mWebChromeClient.onReceivedTouchIconUrl(mWebView, + mWebChromeClient.onReceivedTouchIconUrl(mWebView.getWebView(), (String) msg.obj, msg.arg1 == 1); } break; case RECEIVED_TITLE: if (mWebChromeClient != null) { - mWebChromeClient.onReceivedTitle(mWebView, + mWebChromeClient.onReceivedTitle(mWebView.getWebView(), (String) msg.obj); } break; @@ -301,7 +302,7 @@ class CallbackProxy extends Handler { int reasonCode = msg.arg1; final String description = msg.getData().getString("description"); final String failUrl = msg.getData().getString("failingUrl"); - mWebViewClient.onReceivedError(mWebView, reasonCode, + mWebViewClient.onReceivedError(mWebView.getWebView(), reasonCode, description, failUrl); } break; @@ -312,7 +313,7 @@ class CallbackProxy extends Handler { Message dontResend = (Message) msg.getData().getParcelable("dontResend"); if (mWebViewClient != null) { - mWebViewClient.onFormResubmission(mWebView, dontResend, + mWebViewClient.onFormResubmission(mWebView.getWebView(), dontResend, resend); } else { dontResend.sendToTarget(); @@ -335,7 +336,7 @@ class CallbackProxy extends Handler { HttpAuthHandler handler = (HttpAuthHandler) msg.obj; String host = msg.getData().getString("host"); String realm = msg.getData().getString("realm"); - mWebViewClient.onReceivedHttpAuthRequest(mWebView, handler, + mWebViewClient.onReceivedHttpAuthRequest(mWebView.getWebView(), handler, host, realm); } break; @@ -344,7 +345,7 @@ class CallbackProxy extends Handler { if (mWebViewClient != null) { HashMap<String, Object> map = (HashMap<String, Object>) msg.obj; - mWebViewClient.onReceivedSslError(mWebView, + mWebViewClient.onReceivedSslError(mWebView.getWebView(), (SslErrorHandler) map.get("handler"), (SslError) map.get("error")); } @@ -352,7 +353,7 @@ class CallbackProxy extends Handler { case PROCEEDED_AFTER_SSL_ERROR: if (mWebViewClient != null) { - mWebViewClient.onProceededAfterSslError(mWebView, + mWebViewClient.onProceededAfterSslError(mWebView.getWebView(), (SslError) msg.obj); } break; @@ -361,7 +362,7 @@ class CallbackProxy extends Handler { if (mWebViewClient != null) { HashMap<String, Object> map = (HashMap<String, Object>) msg.obj; - mWebViewClient.onReceivedClientCertRequest(mWebView, + mWebViewClient.onReceivedClientCertRequest(mWebView.getWebView(), (ClientCertRequestHandler) map.get("handler"), (String) map.get("host_and_port")); } @@ -373,7 +374,7 @@ class CallbackProxy extends Handler { // changed. synchronized (this) { if (mWebChromeClient != null) { - mWebChromeClient.onProgressChanged(mWebView, + mWebChromeClient.onProgressChanged(mWebView.getWebView(), mLatestProgress); } mProgressUpdatePending = false; @@ -382,14 +383,14 @@ class CallbackProxy extends Handler { case UPDATE_VISITED: if (mWebViewClient != null) { - mWebViewClient.doUpdateVisitedHistory(mWebView, + mWebViewClient.doUpdateVisitedHistory(mWebView.getWebView(), (String) msg.obj, msg.arg1 != 0); } break; case LOAD_RESOURCE: if (mWebViewClient != null) { - mWebViewClient.onLoadResource(mWebView, (String) msg.obj); + mWebViewClient.onLoadResource(mWebView.getWebView(), (String) msg.obj); } break; @@ -409,7 +410,7 @@ class CallbackProxy extends Handler { case CREATE_WINDOW: if (mWebChromeClient != null) { - if (!mWebChromeClient.onCreateWindow(mWebView, + if (!mWebChromeClient.onCreateWindow(mWebView.getWebView(), msg.arg1 == 1, msg.arg2 == 1, (Message) msg.obj)) { synchronized (this) { @@ -422,13 +423,13 @@ class CallbackProxy extends Handler { case REQUEST_FOCUS: if (mWebChromeClient != null) { - mWebChromeClient.onRequestFocus(mWebView); + mWebChromeClient.onRequestFocus(mWebView.getWebView()); } break; case CLOSE_WINDOW: if (mWebChromeClient != null) { - mWebChromeClient.onCloseWindow((WebView) msg.obj); + mWebChromeClient.onCloseWindow(((WebViewClassic) msg.obj).getWebView()); } break; @@ -449,7 +450,7 @@ class CallbackProxy extends Handler { case ASYNC_KEYEVENTS: if (mWebViewClient != null) { - mWebViewClient.onUnhandledKeyEvent(mWebView, + mWebViewClient.onUnhandledKeyEvent(mWebView.getWebView(), (KeyEvent) msg.obj); } break; @@ -516,7 +517,7 @@ class CallbackProxy extends Handler { final JsResult res = (JsResult) msg.obj; String message = msg.getData().getString("message"); String url = msg.getData().getString("url"); - if (!mWebChromeClient.onJsAlert(mWebView, url, message, + if (!mWebChromeClient.onJsAlert(mWebView.getWebView(), url, message, res)) { if (!canShowAlertDialog()) { res.cancel(); @@ -552,7 +553,7 @@ class CallbackProxy extends Handler { final JsResult res = (JsResult) msg.obj; String message = msg.getData().getString("message"); String url = msg.getData().getString("url"); - if (!mWebChromeClient.onJsConfirm(mWebView, url, message, + if (!mWebChromeClient.onJsConfirm(mWebView.getWebView(), url, message, res)) { if (!canShowAlertDialog()) { res.cancel(); @@ -597,7 +598,7 @@ class CallbackProxy extends Handler { String message = msg.getData().getString("message"); String defaultVal = msg.getData().getString("default"); String url = msg.getData().getString("url"); - if (!mWebChromeClient.onJsPrompt(mWebView, url, message, + if (!mWebChromeClient.onJsPrompt(mWebView.getWebView(), url, message, defaultVal, res)) { if (!canShowAlertDialog()) { res.cancel(); @@ -653,7 +654,7 @@ class CallbackProxy extends Handler { final JsResult res = (JsResult) msg.obj; String message = msg.getData().getString("message"); String url = msg.getData().getString("url"); - if (!mWebChromeClient.onJsBeforeUnload(mWebView, url, + if (!mWebChromeClient.onJsBeforeUnload(mWebView.getWebView(), url, message, res)) { if (!canShowAlertDialog()) { res.cancel(); @@ -710,7 +711,7 @@ class CallbackProxy extends Handler { case SCALE_CHANGED: if (mWebViewClient != null) { - mWebViewClient.onScaleChanged(mWebView, msg.getData() + mWebViewClient.onScaleChanged(mWebView.getWebView(), msg.getData() .getFloat("old"), msg.getData().getFloat("new")); } break; @@ -817,7 +818,7 @@ class CallbackProxy extends Handler { String realm = msg.getData().getString("realm"); String account = msg.getData().getString("account"); String args = msg.getData().getString("args"); - mWebViewClient.onReceivedLoginRequest(mWebView, realm, + mWebViewClient.onReceivedLoginRequest(mWebView.getWebView(), realm, account, args); } break; @@ -1074,7 +1075,7 @@ class CallbackProxy extends Handler { } // Note: This method does _not_ send a message. WebResourceResponse r = - mWebViewClient.shouldInterceptRequest(mWebView, url); + mWebViewClient.shouldInterceptRequest(mWebView.getWebView(), url); if (r == null) { sendMessage(obtainMessage(LOAD_RESOURCE, url)); } @@ -1219,7 +1220,8 @@ class CallbackProxy extends Handler { return null; } - WebView.WebViewTransport transport = mWebView.new WebViewTransport(); + WebView.WebViewTransport transport = + mWebView.getWebView().new WebViewTransport(); final Message msg = obtainMessage(NOTIFY); msg.obj = transport; synchronized (this) { @@ -1234,7 +1236,7 @@ class CallbackProxy extends Handler { } } - WebView w = transport.getWebView(); + WebViewClassic w = WebViewClassic.fromWebView(transport.getWebView()); if (w != null) { WebViewCore core = w.getWebViewCore(); // If WebView.destroy() has been called, core may be null. Skip @@ -1257,7 +1259,7 @@ class CallbackProxy extends Handler { sendEmptyMessage(REQUEST_FOCUS); } - public void onCloseWindow(WebView window) { + public void onCloseWindow(WebViewClassic window) { // Do an unsynchronized quick check to avoid posting if no callback has // been set. if (mWebChromeClient == null) { diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java index 10b0885..964cf3e 100644 --- a/core/java/android/webkit/FindActionModeCallback.java +++ b/core/java/android/webkit/FindActionModeCallback.java @@ -38,7 +38,7 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher, private View mCustomView; private EditText mEditText; private TextView mMatches; - private WebView mWebView; + private WebViewClassic mWebView; private InputMethodManager mInput; private Resources mResources; private boolean mMatchesFound; @@ -90,7 +90,7 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher, * Set the WebView to search. Must be non null, and set before calling * startActionMode. */ - void setWebView(WebView webView) { + void setWebView(WebViewClassic webView) { if (null == webView) { throw new AssertionError("WebView supplied to " + "FindActionModeCallback cannot be null"); @@ -218,7 +218,7 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher, public void onDestroyActionMode(ActionMode mode) { mActionMode = null; mWebView.notifyFindDialogDismissed(); - mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0); + mInput.hideSoftInputFromWindow(mWebView.getWebView().getWindowToken(), 0); } @Override @@ -232,7 +232,7 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher, throw new AssertionError( "No WebView for FindActionModeCallback::onActionItemClicked"); } - mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0); + mInput.hideSoftInputFromWindow(mWebView.getWebView().getWindowToken(), 0); switch(item.getItemId()) { case com.android.internal.R.id.find_prev: findNext(false); diff --git a/core/java/android/webkit/GeolocationService.java b/core/java/android/webkit/GeolocationService.java index 91de1d8..225053b 100755 --- a/core/java/android/webkit/GeolocationService.java +++ b/core/java/android/webkit/GeolocationService.java @@ -24,7 +24,6 @@ import android.location.LocationManager; import android.location.LocationProvider; import android.os.Bundle; import android.util.Log; -import android.webkit.WebView; import android.webkit.WebViewCore; diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java index aedecf0..8e1f573 100644 --- a/core/java/android/webkit/HTML5Audio.java +++ b/core/java/android/webkit/HTML5Audio.java @@ -92,7 +92,7 @@ class HTML5Audio extends Handler private class IsPrivateBrowsingEnabledGetter { private boolean mIsReady; private boolean mIsPrivateBrowsingEnabled; - IsPrivateBrowsingEnabledGetter(Looper uiThreadLooper, final WebView webView) { + IsPrivateBrowsingEnabledGetter(Looper uiThreadLooper, final WebViewClassic webView) { new Handler(uiThreadLooper).post(new Runnable() { @Override public void run() { diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java index bc0557e..fac549d 100644 --- a/core/java/android/webkit/HTML5VideoFullScreen.java +++ b/core/java/android/webkit/HTML5VideoFullScreen.java @@ -236,7 +236,7 @@ public class HTML5VideoFullScreen extends HTML5VideoView @Override public void enterFullScreenVideoState(int layerId, - HTML5VideoViewProxy proxy, WebView webView) { + HTML5VideoViewProxy proxy, WebViewClassic webView) { mFullScreenMode = FULLSCREEN_SURFACECREATING; mCurrentBufferPercentage = 0; mPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); diff --git a/core/java/android/webkit/HTML5VideoView.java b/core/java/android/webkit/HTML5VideoView.java index 73166cb..0d3b755 100644 --- a/core/java/android/webkit/HTML5VideoView.java +++ b/core/java/android/webkit/HTML5VideoView.java @@ -280,7 +280,7 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener { // screen mode. Some are specific to one type, but currently are called // directly from the proxy. public void enterFullScreenVideoState(int layerId, - HTML5VideoViewProxy proxy, WebView webView) { + HTML5VideoViewProxy proxy, WebViewClassic webView) { } public boolean isFullScreenMode() { diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java index d306c86..1644b06 100644 --- a/core/java/android/webkit/HTML5VideoViewProxy.java +++ b/core/java/android/webkit/HTML5VideoViewProxy.java @@ -75,8 +75,8 @@ class HTML5VideoViewProxy extends Handler int mNativePointer; // The handler for WebCore thread messages; private Handler mWebCoreHandler; - // The WebView instance that created this view. - private WebView mWebView; + // The WebViewClassic instance that created this view. + private WebViewClassic mWebView; // The poster image to be shown when the video is not playing. // This ref prevents the bitmap from being GC'ed. private Bitmap mPoster; @@ -142,7 +142,7 @@ class HTML5VideoViewProxy extends Handler } public static void enterFullScreenVideo(int layerId, String url, - HTML5VideoViewProxy proxy, WebView webView) { + HTML5VideoViewProxy proxy, WebViewClassic webView) { // Save the inline video info and inherit it in the full screen int savePosition = 0; if (mHTML5VideoView != null) { @@ -163,7 +163,7 @@ class HTML5VideoViewProxy extends Handler } public static void exitFullScreenVideo(HTML5VideoViewProxy proxy, - WebView webView) { + WebViewClassic webView) { if (!mHTML5VideoView.fullScreenExited() && mHTML5VideoView.isFullScreenMode()) { WebChromeClient client = webView.getWebChromeClient(); if (client != null) { @@ -551,7 +551,7 @@ class HTML5VideoViewProxy extends Handler * @param webView is the WebView that hosts the video. * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object. */ - private HTML5VideoViewProxy(WebView webView, int nativePtr) { + private HTML5VideoViewProxy(WebViewClassic webView, int nativePtr) { // This handler is for the main (UI) thread. super(Looper.getMainLooper()); // Save the WebView object. @@ -721,7 +721,7 @@ class HTML5VideoViewProxy extends Handler return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr); } - /* package */ WebView getWebView() { + /* package */ WebViewClassic getWebView() { return mWebView; } diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java index b498435..e6eaa14 100644 --- a/core/java/android/webkit/JWebCoreJavaBridge.java +++ b/core/java/android/webkit/JWebCoreJavaBridge.java @@ -43,10 +43,10 @@ final class JWebCoreJavaBridge extends Handler { private boolean mTimerPaused; private boolean mHasDeferredTimers; - // keep track of the main WebView attached to the current window so that we + // keep track of the main WebViewClassic attached to the current window so that we // can get the proper Context. - private static WeakReference<WebView> sCurrentMainWebView = - new WeakReference<WebView>(null); + private static WeakReference<WebViewClassic> sCurrentMainWebView = + new WeakReference<WebViewClassic>(null); /* package */ static final int REFRESH_PLUGINS = 100; @@ -67,15 +67,15 @@ final class JWebCoreJavaBridge extends Handler { nativeFinalize(); } - static synchronized void setActiveWebView(WebView webview) { + static synchronized void setActiveWebView(WebViewClassic webview) { if (sCurrentMainWebView.get() != null) { // it is possible if there is a sub-WebView. Do nothing. return; } - sCurrentMainWebView = new WeakReference<WebView>(webview); + sCurrentMainWebView = new WeakReference<WebViewClassic>(webview); } - static synchronized void removeActiveWebView(WebView webview) { + static synchronized void removeActiveWebView(WebViewClassic webview) { if (sCurrentMainWebView.get() != webview) { // it is possible if there is a sub-WebView. Do nothing. return; @@ -259,7 +259,7 @@ final class JWebCoreJavaBridge extends Handler { synchronized private String getSignedPublicKey(int index, String challenge, String url) { - WebView current = sCurrentMainWebView.get(); + WebViewClassic current = sCurrentMainWebView.get(); if (current != null) { // generateKeyPair expects organizations which we don't have. Ignore // url. diff --git a/core/java/android/webkit/OverScrollGlow.java b/core/java/android/webkit/OverScrollGlow.java index e906f7f..d91f860 100644 --- a/core/java/android/webkit/OverScrollGlow.java +++ b/core/java/android/webkit/OverScrollGlow.java @@ -29,7 +29,7 @@ import android.widget.EdgeEffect; * @hide */ public class OverScrollGlow { - private WebView mHostView; + private WebViewClassic mHostView; private EdgeEffect mEdgeGlowTop; private EdgeEffect mEdgeGlowBottom; @@ -39,7 +39,7 @@ public class OverScrollGlow { private int mOverScrollDeltaX; private int mOverScrollDeltaY; - public OverScrollGlow(WebView host) { + public OverScrollGlow(WebViewClassic host) { mHostView = host; Context context = host.getContext(); mEdgeGlowTop = new EdgeEffect(context); @@ -80,7 +80,7 @@ public class OverScrollGlow { mOverScrollDeltaX = 0; } - if (maxY > 0 || mHostView.getOverScrollMode() == View.OVER_SCROLL_ALWAYS) { + if (maxY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) { final int pulledToY = oldY + mOverScrollDeltaY; if (pulledToY < 0) { mEdgeGlowTop.onPull((float) mOverScrollDeltaY / mHostView.getHeight()); @@ -120,7 +120,7 @@ public class OverScrollGlow { * @param rangeY Maximum range for vertical scrolling */ public void absorbGlow(int x, int y, int oldX, int oldY, int rangeX, int rangeY) { - if (rangeY > 0 || mHostView.getOverScrollMode() == View.OVER_SCROLL_ALWAYS) { + if (rangeY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) { if (y < 0 && oldY >= 0) { mEdgeGlowTop.onAbsorb((int) mHostView.mScroller.getCurrVelocity()); if (!mEdgeGlowBottom.isFinished()) { diff --git a/core/java/android/webkit/PluginFullScreenHolder.java b/core/java/android/webkit/PluginFullScreenHolder.java index 42ba7c9..665cd9d 100644 --- a/core/java/android/webkit/PluginFullScreenHolder.java +++ b/core/java/android/webkit/PluginFullScreenHolder.java @@ -35,7 +35,7 @@ import android.widget.FrameLayout; class PluginFullScreenHolder { - private final WebView mWebView; + private final WebViewClassic mWebView; private final int mNpp; private final int mOrientation; @@ -44,7 +44,7 @@ class PluginFullScreenHolder { private View mContentView; - PluginFullScreenHolder(WebView webView, int orientation, int npp) { + PluginFullScreenHolder(WebViewClassic webView, int orientation, int npp) { mWebView = webView; mNpp = npp; mOrientation = orientation; @@ -134,7 +134,7 @@ class PluginFullScreenHolder { new WebChromeClient.CustomViewCallback() { public void onCustomViewHidden() { - mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN) + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.HIDE_FULLSCREEN) .sendToTarget(); mWebView.getWebViewCore().sendMessage( diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java index ab3b6d5..fe40156 100644 --- a/core/java/android/webkit/PluginManager.java +++ b/core/java/android/webkit/PluginManager.java @@ -34,7 +34,7 @@ import android.os.SystemProperties; import android.util.Log; /** - * Class for managing the relationship between the {@link WebView} and installed + * Class for managing the relationship between the {@link WebViewClassic} and installed * plugins in the system. You can find this class through * {@link PluginManager#getInstance}. * diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java index 2a770f5..57628d3 100644 --- a/core/java/android/webkit/SelectActionModeCallback.java +++ b/core/java/android/webkit/SelectActionModeCallback.java @@ -26,11 +26,11 @@ import android.view.Menu; import android.view.MenuItem; class SelectActionModeCallback implements ActionMode.Callback { - private WebView mWebView; + private WebViewClassic mWebView; private ActionMode mActionMode; private boolean mIsTextSelected = true; - void setWebView(WebView webView) { + void setWebView(WebViewClassic webView) { mWebView = webView; } diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java index 153c1c2..34065a1 100644 --- a/core/java/android/webkit/ViewManager.java +++ b/core/java/android/webkit/ViewManager.java @@ -16,6 +16,7 @@ package android.webkit; +import android.util.DisplayMetrics; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; @@ -24,7 +25,7 @@ import android.widget.AbsoluteLayout; import java.util.ArrayList; class ViewManager { - private final WebView mWebView; + private final WebViewClassic mWebView; private final ArrayList<ChildView> mChildren = new ArrayList<ChildView>(); private boolean mHidden; private boolean mReadyToDraw; @@ -74,7 +75,7 @@ class ViewManager { } private void attachViewOnUIThread() { - mWebView.addView(mView); + mWebView.getWebView().addView(mView); mChildren.add(this); if (!mReadyToDraw) { mView.setVisibility(View.GONE); @@ -93,16 +94,15 @@ class ViewManager { } private void removeViewOnUIThread() { - mWebView.removeView(mView); + mWebView.getWebView().removeView(mView); mChildren.remove(this); } } - ViewManager(WebView w) { + ViewManager(WebViewClassic w) { mWebView = w; - - int pixelArea = w.getResources().getDisplayMetrics().widthPixels * - w.getResources().getDisplayMetrics().heightPixels; + DisplayMetrics metrics = w.getWebView().getResources().getDisplayMetrics(); + int pixelArea = metrics.widthPixels * metrics.heightPixels; /* set the threshold to be 275% larger than the screen size. The percentage is simply an estimation and is not based on anything but basic trial-and-error tests run on multiple devices. diff --git a/core/java/android/webkit/ViewStateSerializer.java b/core/java/android/webkit/ViewStateSerializer.java index 5f91ed3..a22fc26 100644 --- a/core/java/android/webkit/ViewStateSerializer.java +++ b/core/java/android/webkit/ViewStateSerializer.java @@ -34,7 +34,7 @@ class ViewStateSerializer { static final int VERSION = 1; - static boolean serializeViewState(OutputStream stream, WebView web) + static boolean serializeViewState(OutputStream stream, WebViewClassic web) throws IOException { int baseLayer = web.getBaseLayer(); if (baseLayer == 0) { @@ -48,7 +48,7 @@ class ViewStateSerializer { new byte[WORKING_STREAM_STORAGE]); } - static DrawData deserializeViewState(InputStream stream, WebView web) + static DrawData deserializeViewState(InputStream stream, WebViewClassic web) throws IOException { DataInputStream dis = new DataInputStream(stream); int version = dis.readInt(); diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index c463b40..cddd7ab 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -16,16 +16,7 @@ package android.webkit; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Handler; import android.os.Message; -import android.util.DisplayMetrics; -import android.util.EventLog; - -import java.util.Locale; /** * Manages settings state for a WebView. When a WebView is first created, it @@ -35,7 +26,18 @@ import java.util.Locale; * been destroyed, any method call on WebSettings will throw an * IllegalStateException. */ +// This is (effectively) an abstract base class; concrete WebViewProviders must +// create a class derived from this, and return an instance of it in the +// WebViewProvider.getWebSettingsProvider() method implementation. public class WebSettings { + // TODO: Remove MustOverrideException and make all methods throwing it abstract instead; + // needs API file update. + private static class MustOverrideException extends RuntimeException { + MustOverrideException() { + super("abstract function called: must be overriden!"); + } + } + /** * Enum for controlling the layout of html. * NORMAL means no rendering changes. @@ -141,379 +143,12 @@ public class WebSettings { OFF } - // TODO: Keep this up to date - private static final String PREVIOUS_VERSION = "4.0.3"; - - // WebView associated with this WebSettings. - private WebView mWebView; - // BrowserFrame used to access the native frame pointer. - private BrowserFrame mBrowserFrame; - // Flag to prevent multiple SYNC messages at one time. - private boolean mSyncPending = false; - // Custom handler that queues messages until the WebCore thread is active. - private final EventHandler mEventHandler; - - // Private settings so we don't have to go into native code to - // retrieve the values. After setXXX, postSync() needs to be called. - // - // The default values need to match those in WebSettings.cpp - // If the defaults change, please also update the JavaDocs so developers - // know what they are. - private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS; - private Context mContext; - private int mTextSize = 100; - private String mStandardFontFamily = "sans-serif"; - private String mFixedFontFamily = "monospace"; - private String mSansSerifFontFamily = "sans-serif"; - private String mSerifFontFamily = "serif"; - private String mCursiveFontFamily = "cursive"; - private String mFantasyFontFamily = "fantasy"; - private String mDefaultTextEncoding; - private String mUserAgent; - private boolean mUseDefaultUserAgent; - private String mAcceptLanguage; - private int mMinimumFontSize = 8; - private int mMinimumLogicalFontSize = 8; - private int mDefaultFontSize = 16; - private int mDefaultFixedFontSize = 13; - private int mPageCacheCapacity = 0; - private boolean mLoadsImagesAutomatically = true; - private boolean mBlockNetworkImage = false; - private boolean mBlockNetworkLoads; - private boolean mJavaScriptEnabled = false; - private boolean mHardwareAccelSkia = false; - private boolean mShowVisualIndicator = false; - private PluginState mPluginState = PluginState.OFF; - private boolean mJavaScriptCanOpenWindowsAutomatically = false; - private boolean mUseDoubleTree = false; - private boolean mUseWideViewport = false; - private boolean mSupportMultipleWindows = false; - private boolean mShrinksStandaloneImagesToFit = false; - private long mMaximumDecodedImageSize = 0; // 0 means default - private boolean mPrivateBrowsingEnabled = false; - private boolean mSyntheticLinksEnabled = true; - // HTML5 API flags - private boolean mAppCacheEnabled = false; - private boolean mDatabaseEnabled = false; - private boolean mDomStorageEnabled = false; - private boolean mWorkersEnabled = false; // only affects V8. - private boolean mGeolocationEnabled = true; - private boolean mXSSAuditorEnabled = false; - // HTML5 configuration parameters - private long mAppCacheMaxSize = Long.MAX_VALUE; - private String mAppCachePath = null; - private String mDatabasePath = ""; - // The WebCore DatabaseTracker only allows the database path to be set - // once. Keep track of when the path has been set. - private boolean mDatabasePathHasBeenSet = false; - private String mGeolocationDatabasePath = ""; - // Don't need to synchronize the get/set methods as they - // are basic types, also none of these values are used in - // native WebCore code. - private ZoomDensity mDefaultZoom = ZoomDensity.MEDIUM; - private RenderPriority mRenderPriority = RenderPriority.NORMAL; - private int mOverrideCacheMode = LOAD_DEFAULT; - private int mDoubleTapZoom = 100; - private boolean mSaveFormData = true; - private boolean mAutoFillEnabled = false; - private boolean mSavePassword = true; - private boolean mLightTouchEnabled = false; - private boolean mNeedInitialFocus = true; - private boolean mNavDump = false; - private boolean mSupportZoom = true; - private boolean mBuiltInZoomControls = false; - private boolean mDisplayZoomControls = true; - private boolean mAllowFileAccess = true; - private boolean mAllowContentAccess = true; - private boolean mLoadWithOverviewMode = false; - private boolean mEnableSmoothTransition = false; - private boolean mForceUserScalable = false; - - // AutoFill Profile data - /** - * @hide for now, pending API council approval. - */ - public static class AutoFillProfile { - private int mUniqueId; - private String mFullName; - private String mEmailAddress; - private String mCompanyName; - private String mAddressLine1; - private String mAddressLine2; - private String mCity; - private String mState; - private String mZipCode; - private String mCountry; - private String mPhoneNumber; - - public AutoFillProfile(int uniqueId, String fullName, String email, - String companyName, String addressLine1, String addressLine2, - String city, String state, String zipCode, String country, - String phoneNumber) { - mUniqueId = uniqueId; - mFullName = fullName; - mEmailAddress = email; - mCompanyName = companyName; - mAddressLine1 = addressLine1; - mAddressLine2 = addressLine2; - mCity = city; - mState = state; - mZipCode = zipCode; - mCountry = country; - mPhoneNumber = phoneNumber; - } - - public int getUniqueId() { return mUniqueId; } - public String getFullName() { return mFullName; } - public String getEmailAddress() { return mEmailAddress; } - public String getCompanyName() { return mCompanyName; } - public String getAddressLine1() { return mAddressLine1; } - public String getAddressLine2() { return mAddressLine2; } - public String getCity() { return mCity; } - public String getState() { return mState; } - public String getZipCode() { return mZipCode; } - public String getCountry() { return mCountry; } - public String getPhoneNumber() { return mPhoneNumber; } - } - - - private AutoFillProfile mAutoFillProfile; - - private boolean mUseWebViewBackgroundForOverscroll = true; - - // private WebSettings, not accessible by the host activity - static private int mDoubleTapToastCount = 3; - - private static final String PREF_FILE = "WebViewSettings"; - private static final String DOUBLE_TAP_TOAST_COUNT = "double_tap_toast_count"; - - // Class to handle messages before WebCore is ready. - private class EventHandler { - // Message id for syncing - static final int SYNC = 0; - // Message id for setting priority - static final int PRIORITY = 1; - // Message id for writing double-tap toast count - static final int SET_DOUBLE_TAP_TOAST_COUNT = 2; - // Actual WebCore thread handler - private Handler mHandler; - - private synchronized void createHandler() { - // as mRenderPriority can be set before thread is running, sync up - setRenderPriority(); - - // create a new handler - mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case SYNC: - synchronized (WebSettings.this) { - if (mBrowserFrame.mNativeFrame != 0) { - nativeSync(mBrowserFrame.mNativeFrame); - } - mSyncPending = false; - } - break; - - case PRIORITY: { - setRenderPriority(); - break; - } - - case SET_DOUBLE_TAP_TOAST_COUNT: { - SharedPreferences.Editor editor = mContext - .getSharedPreferences(PREF_FILE, - Context.MODE_PRIVATE).edit(); - editor.putInt(DOUBLE_TAP_TOAST_COUNT, - mDoubleTapToastCount); - editor.commit(); - break; - } - } - } - }; - } - - private void setRenderPriority() { - synchronized (WebSettings.this) { - if (mRenderPriority == RenderPriority.NORMAL) { - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_DEFAULT); - } else if (mRenderPriority == RenderPriority.HIGH) { - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_FOREGROUND + - android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE); - } else if (mRenderPriority == RenderPriority.LOW) { - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_BACKGROUND); - } - } - } - - /** - * Send a message to the private queue or handler. - */ - private synchronized boolean sendMessage(Message msg) { - if (mHandler != null) { - mHandler.sendMessage(msg); - return true; - } else { - return false; - } - } - } - - // User agent strings. - private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (X11; " + - "Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) " + - "Chrome/11.0.696.34 Safari/534.24"; - private static final String IPHONE_USERAGENT = - "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)" - + " AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0" - + " Mobile/7A341 Safari/528.16"; - private static Locale sLocale; - private static Object sLockForLocaleSettings; - - /** - * Package constructor to prevent clients from creating a new settings - * instance. - */ - WebSettings(Context context, WebView webview) { - mEventHandler = new EventHandler(); - mContext = context; - mWebView = webview; - mDefaultTextEncoding = context.getString(com.android.internal. - R.string.default_text_encoding); - - if (sLockForLocaleSettings == null) { - sLockForLocaleSettings = new Object(); - sLocale = Locale.getDefault(); - } - mAcceptLanguage = getCurrentAcceptLanguage(); - mUserAgent = getCurrentUserAgent(); - mUseDefaultUserAgent = true; - - mBlockNetworkLoads = mContext.checkPermission( - "android.permission.INTERNET", android.os.Process.myPid(), - android.os.Process.myUid()) != PackageManager.PERMISSION_GRANTED; - } - - private static final String ACCEPT_LANG_FOR_US_LOCALE = "en-US"; - - /** - * Looks at sLocale and returns current AcceptLanguage String. - * @return Current AcceptLanguage String. - */ - private String getCurrentAcceptLanguage() { - Locale locale; - synchronized(sLockForLocaleSettings) { - locale = sLocale; - } - StringBuilder buffer = new StringBuilder(); - addLocaleToHttpAcceptLanguage(buffer, locale); - - if (!Locale.US.equals(locale)) { - if (buffer.length() > 0) { - buffer.append(", "); - } - buffer.append(ACCEPT_LANG_FOR_US_LOCALE); - } - - return buffer.toString(); - } - /** - * Convert obsolete language codes, including Hebrew/Indonesian/Yiddish, - * to new standard. + * Hidden constructor to prevent clients from creating a new settings + * instance or deriving the class. + * @hide */ - private static String convertObsoleteLanguageCodeToNew(String langCode) { - if (langCode == null) { - return null; - } - if ("iw".equals(langCode)) { - // Hebrew - return "he"; - } else if ("in".equals(langCode)) { - // Indonesian - return "id"; - } else if ("ji".equals(langCode)) { - // Yiddish - return "yi"; - } - return langCode; - } - - private static void addLocaleToHttpAcceptLanguage(StringBuilder builder, - Locale locale) { - String language = convertObsoleteLanguageCodeToNew(locale.getLanguage()); - if (language != null) { - builder.append(language); - String country = locale.getCountry(); - if (country != null) { - builder.append("-"); - builder.append(country); - } - } - } - - /** - * Looks at sLocale and mContext and returns current UserAgent String. - * @return Current UserAgent String. - */ - private synchronized String getCurrentUserAgent() { - Locale locale; - synchronized(sLockForLocaleSettings) { - locale = sLocale; - } - StringBuffer buffer = new StringBuffer(); - // Add version - final String version = Build.VERSION.RELEASE; - if (version.length() > 0) { - if (Character.isDigit(version.charAt(0))) { - // Release is a version, eg "3.1" - buffer.append(version); - } else { - // Release is a codename, eg "Honeycomb" - // In this case, use the previous release's version - buffer.append(PREVIOUS_VERSION); - } - } else { - // default to "1.0" - buffer.append("1.0"); - } - buffer.append("; "); - final String language = locale.getLanguage(); - if (language != null) { - buffer.append(convertObsoleteLanguageCodeToNew(language)); - final String country = locale.getCountry(); - if (country != null) { - buffer.append("-"); - buffer.append(country.toLowerCase()); - } - } else { - // default to "en" - buffer.append("en"); - } - buffer.append(";"); - // add the model for the release build - if ("REL".equals(Build.VERSION.CODENAME)) { - final String model = Build.MODEL; - if (model.length() > 0) { - buffer.append(" "); - buffer.append(model); - } - } - final String id = Build.ID; - if (id.length() > 0) { - buffer.append(" Build/"); - buffer.append(id); - } - String mobile = mContext.getResources().getText( - com.android.internal.R.string.web_user_agent_target_content).toString(); - final String base = mContext.getResources().getText( - com.android.internal.R.string.web_user_agent).toString(); - return String.format(base, buffer, mobile); + protected WebSettings() { } /** @@ -522,7 +157,7 @@ public class WebSettings { */ @Deprecated public void setNavDump(boolean enabled) { - mNavDump = enabled; + throw new MustOverrideException(); } /** @@ -531,37 +166,35 @@ public class WebSettings { */ @Deprecated public boolean getNavDump() { - return mNavDump; + throw new MustOverrideException(); } /** * Set whether the WebView supports zoom */ public void setSupportZoom(boolean support) { - mSupportZoom = support; - mWebView.updateMultiTouchSupport(mContext); + throw new MustOverrideException(); } /** * Returns whether the WebView supports zoom */ public boolean supportZoom() { - return mSupportZoom; + throw new MustOverrideException(); } /** * Sets whether the zoom mechanism built into WebView is used. */ public void setBuiltInZoomControls(boolean enabled) { - mBuiltInZoomControls = enabled; - mWebView.updateMultiTouchSupport(mContext); + throw new MustOverrideException(); } /** * Returns true if the zoom mechanism built into WebView is being used. */ public boolean getBuiltInZoomControls() { - return mBuiltInZoomControls; + throw new MustOverrideException(); } /** @@ -571,15 +204,14 @@ public class WebSettings { * to work without the on screen controls */ public void setDisplayZoomControls(boolean enabled) { - mDisplayZoomControls = enabled; - mWebView.updateMultiTouchSupport(mContext); + throw new MustOverrideException(); } /** * Returns true if the on screen zoom buttons are being used. */ public boolean getDisplayZoomControls() { - return mDisplayZoomControls; + throw new MustOverrideException(); } /** @@ -589,14 +221,14 @@ public class WebSettings { * file:///android_res. */ public void setAllowFileAccess(boolean allow) { - mAllowFileAccess = allow; + throw new MustOverrideException(); } /** * Returns true if this WebView supports file access. */ public boolean getAllowFileAccess() { - return mAllowFileAccess; + throw new MustOverrideException(); } /** @@ -605,28 +237,28 @@ public class WebSettings { * system. The default is enabled. */ public void setAllowContentAccess(boolean allow) { - mAllowContentAccess = allow; + throw new MustOverrideException(); } /** * Returns true if this WebView supports content url access. */ public boolean getAllowContentAccess() { - return mAllowContentAccess; + throw new MustOverrideException(); } /** * Set whether the WebView loads a page with overview mode. */ public void setLoadWithOverviewMode(boolean overview) { - mLoadWithOverviewMode = overview; + throw new MustOverrideException(); } /** * Returns true if this WebView loads page with overview mode */ public boolean getLoadWithOverviewMode() { - return mLoadWithOverviewMode; + throw new MustOverrideException(); } /** @@ -637,15 +269,14 @@ public class WebSettings { * If it is false, WebView will keep its fidelity. The default value is false. */ public void setEnableSmoothTransition(boolean enable) { - mEnableSmoothTransition = enable; + throw new MustOverrideException(); } - /** * Returns true if the WebView enables smooth transition while panning or * zooming. */ public boolean enableSmoothTransition() { - return mEnableSmoothTransition; + throw new MustOverrideException(); } /** @@ -656,7 +287,7 @@ public class WebSettings { */ @Deprecated public void setUseWebViewBackgroundForOverscrollBackground(boolean view) { - mUseWebViewBackgroundForOverscroll = view; + throw new MustOverrideException(); } /** @@ -666,14 +297,14 @@ public class WebSettings { */ @Deprecated public boolean getUseWebViewBackgroundForOverscrollBackground() { - return mUseWebViewBackgroundForOverscroll; + throw new MustOverrideException(); } /** * Store whether the WebView is saving form data. */ public void setSaveFormData(boolean save) { - mSaveFormData = save; + throw new MustOverrideException(); } /** @@ -681,21 +312,21 @@ public class WebSettings { * entries/autofill++. Always false in private browsing mode. */ public boolean getSaveFormData() { - return mSaveFormData && !mPrivateBrowsingEnabled; + throw new MustOverrideException(); } /** * Store whether the WebView is saving password. */ public void setSavePassword(boolean save) { - mSavePassword = save; + throw new MustOverrideException(); } /** * Return whether the WebView is saving password. */ public boolean getSavePassword() { - return mSavePassword; + throw new MustOverrideException(); } /** @@ -703,14 +334,7 @@ public class WebSettings { * @param textZoom A percent value for increasing or decreasing the text. */ public synchronized void setTextZoom(int textZoom) { - if (mTextSize != textZoom) { - if (WebView.mLogEvent) { - EventLog.writeEvent(EventLogTags.BROWSER_TEXT_SIZE_CHANGE, - mTextSize, textZoom); - } - mTextSize = textZoom; - postSync(); - } + throw new MustOverrideException(); } /** @@ -719,7 +343,7 @@ public class WebSettings { * @see setTextSizeZoom */ public synchronized int getTextZoom() { - return mTextSize; + throw new MustOverrideException(); } /** @@ -729,7 +353,7 @@ public class WebSettings { * @deprecated Use {@link #setTextZoom(int)} instead */ public synchronized void setTextSize(TextSize t) { - setTextZoom(t.value); + throw new MustOverrideException(); } /** @@ -741,40 +365,7 @@ public class WebSettings { * @deprecated Use {@link #getTextZoom()} instead */ public synchronized TextSize getTextSize() { - TextSize closestSize = null; - int smallestDelta = Integer.MAX_VALUE; - for (TextSize size : TextSize.values()) { - int delta = Math.abs(mTextSize - size.value); - if (delta == 0) { - return size; - } - if (delta < smallestDelta) { - smallestDelta = delta; - closestSize = size; - } - } - return closestSize != null ? closestSize : TextSize.NORMAL; - } - - /** - * Set the double-tap zoom of the page in percent. Default is 100. - * @param doubleTapZoom A percent value for increasing or decreasing the double-tap zoom. - * @hide - */ - public void setDoubleTapZoom(int doubleTapZoom) { - if (mDoubleTapZoom != doubleTapZoom) { - mDoubleTapZoom = doubleTapZoom; - mWebView.updateDoubleTapZoom(doubleTapZoom); - } - } - - /** - * Get the double-tap zoom of the page in percent. - * @return A percent value describing the double-tap zoom. - * @hide - */ - public int getDoubleTapZoom() { - return mDoubleTapZoom; + throw new MustOverrideException(); } /** @@ -784,10 +375,7 @@ public class WebSettings { * @see WebSettings.ZoomDensity */ public void setDefaultZoom(ZoomDensity zoom) { - if (mDefaultZoom != zoom) { - mDefaultZoom = zoom; - mWebView.adjustDefaultZoomDensity(zoom.value); - } + throw new MustOverrideException(); } /** @@ -797,21 +385,21 @@ public class WebSettings { * @see WebSettings.ZoomDensity */ public ZoomDensity getDefaultZoom() { - return mDefaultZoom; + throw new MustOverrideException(); } /** * Enables using light touches to make a selection and activate mouseovers. */ public void setLightTouchEnabled(boolean enabled) { - mLightTouchEnabled = enabled; + throw new MustOverrideException(); } /** * Returns true if light touches are enabled. */ public boolean getLightTouchEnabled() { - return mLightTouchEnabled; + throw new MustOverrideException(); } /** @@ -820,7 +408,7 @@ public class WebSettings { */ @Deprecated public synchronized void setUseDoubleTree(boolean use) { - return; + // Specified to do nothing, so no need for derived classes to override. } /** @@ -829,6 +417,7 @@ public class WebSettings { */ @Deprecated public synchronized boolean getUseDoubleTree() { + // Returns false unconditionally, so no need for derived classes to override. return false; } @@ -841,23 +430,7 @@ public class WebSettings { */ @Deprecated public synchronized void setUserAgent(int ua) { - String uaString = null; - if (ua == 1) { - if (DESKTOP_USERAGENT.equals(mUserAgent)) { - return; // do nothing - } else { - uaString = DESKTOP_USERAGENT; - } - } else if (ua == 2) { - if (IPHONE_USERAGENT.equals(mUserAgent)) { - return; // do nothing - } else { - uaString = IPHONE_USERAGENT; - } - } else if (ua != 0) { - return; // do nothing - } - setUserAgentString(uaString); + throw new MustOverrideException(); } /** @@ -870,31 +443,21 @@ public class WebSettings { */ @Deprecated public synchronized int getUserAgent() { - if (DESKTOP_USERAGENT.equals(mUserAgent)) { - return 1; - } else if (IPHONE_USERAGENT.equals(mUserAgent)) { - return 2; - } else if (mUseDefaultUserAgent) { - return 0; - } - return -1; + throw new MustOverrideException(); } /** * Tell the WebView to use the wide viewport */ public synchronized void setUseWideViewPort(boolean use) { - if (mUseWideViewport != use) { - mUseWideViewport = use; - postSync(); - } + throw new MustOverrideException(); } /** * @return True if the WebView is using a wide viewport */ public synchronized boolean getUseWideViewPort() { - return mUseWideViewport; + throw new MustOverrideException(); } /** @@ -903,10 +466,7 @@ public class WebSettings { * boolean, Message)} is implemented by the host application. */ public synchronized void setSupportMultipleWindows(boolean support) { - if (mSupportMultipleWindows != support) { - mSupportMultipleWindows = support; - postSync(); - } + throw new MustOverrideException(); } /** @@ -915,7 +475,7 @@ public class WebSettings { * boolean, Message)} is implemented by the host application. */ public synchronized boolean supportMultipleWindows() { - return mSupportMultipleWindows; + throw new MustOverrideException(); } /** @@ -925,12 +485,7 @@ public class WebSettings { * @see WebSettings.LayoutAlgorithm */ public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) { - // XXX: This will only be affective if libwebcore was built with - // ANDROID_LAYOUT defined. - if (mLayoutAlgorithm != l) { - mLayoutAlgorithm = l; - postSync(); - } + throw new MustOverrideException(); } /** @@ -940,7 +495,7 @@ public class WebSettings { * @see WebSettings.LayoutAlgorithm */ public synchronized LayoutAlgorithm getLayoutAlgorithm() { - return mLayoutAlgorithm; + throw new MustOverrideException(); } /** @@ -948,10 +503,7 @@ public class WebSettings { * @param font A font family name. */ public synchronized void setStandardFontFamily(String font) { - if (font != null && !font.equals(mStandardFontFamily)) { - mStandardFontFamily = font; - postSync(); - } + throw new MustOverrideException(); } /** @@ -959,7 +511,7 @@ public class WebSettings { * @return The standard font family name as a string. */ public synchronized String getStandardFontFamily() { - return mStandardFontFamily; + throw new MustOverrideException(); } /** @@ -967,10 +519,7 @@ public class WebSettings { * @param font A font family name. */ public synchronized void setFixedFontFamily(String font) { - if (font != null && !font.equals(mFixedFontFamily)) { - mFixedFontFamily = font; - postSync(); - } + throw new MustOverrideException(); } /** @@ -978,7 +527,7 @@ public class WebSettings { * @return The fixed font family name as a string. */ public synchronized String getFixedFontFamily() { - return mFixedFontFamily; + throw new MustOverrideException(); } /** @@ -986,10 +535,7 @@ public class WebSettings { * @param font A font family name. */ public synchronized void setSansSerifFontFamily(String font) { - if (font != null && !font.equals(mSansSerifFontFamily)) { - mSansSerifFontFamily = font; - postSync(); - } + throw new MustOverrideException(); } /** @@ -997,7 +543,7 @@ public class WebSettings { * @return The sans-serif font family name as a string. */ public synchronized String getSansSerifFontFamily() { - return mSansSerifFontFamily; + throw new MustOverrideException(); } /** @@ -1005,10 +551,7 @@ public class WebSettings { * @param font A font family name. */ public synchronized void setSerifFontFamily(String font) { - if (font != null && !font.equals(mSerifFontFamily)) { - mSerifFontFamily = font; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1016,7 +559,7 @@ public class WebSettings { * @return The serif font family name as a string. */ public synchronized String getSerifFontFamily() { - return mSerifFontFamily; + throw new MustOverrideException(); } /** @@ -1024,10 +567,7 @@ public class WebSettings { * @param font A font family name. */ public synchronized void setCursiveFontFamily(String font) { - if (font != null && !font.equals(mCursiveFontFamily)) { - mCursiveFontFamily = font; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1035,7 +575,7 @@ public class WebSettings { * @return The cursive font family name as a string. */ public synchronized String getCursiveFontFamily() { - return mCursiveFontFamily; + throw new MustOverrideException(); } /** @@ -1043,10 +583,7 @@ public class WebSettings { * @param font A font family name. */ public synchronized void setFantasyFontFamily(String font) { - if (font != null && !font.equals(mFantasyFontFamily)) { - mFantasyFontFamily = font; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1054,7 +591,7 @@ public class WebSettings { * @return The fantasy font family name as a string. */ public synchronized String getFantasyFontFamily() { - return mFantasyFontFamily; + throw new MustOverrideException(); } /** @@ -1063,11 +600,7 @@ public class WebSettings { * Any number outside the specified range will be pinned. */ public synchronized void setMinimumFontSize(int size) { - size = pin(size); - if (mMinimumFontSize != size) { - mMinimumFontSize = size; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1075,7 +608,7 @@ public class WebSettings { * @return A non-negative integer between 1 and 72. */ public synchronized int getMinimumFontSize() { - return mMinimumFontSize; + throw new MustOverrideException(); } /** @@ -1084,11 +617,7 @@ public class WebSettings { * Any number outside the specified range will be pinned. */ public synchronized void setMinimumLogicalFontSize(int size) { - size = pin(size); - if (mMinimumLogicalFontSize != size) { - mMinimumLogicalFontSize = size; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1096,7 +625,7 @@ public class WebSettings { * @return A non-negative integer between 1 and 72. */ public synchronized int getMinimumLogicalFontSize() { - return mMinimumLogicalFontSize; + throw new MustOverrideException(); } /** @@ -1105,11 +634,7 @@ public class WebSettings { * Any number outside the specified range will be pinned. */ public synchronized void setDefaultFontSize(int size) { - size = pin(size); - if (mDefaultFontSize != size) { - mDefaultFontSize = size; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1117,7 +642,7 @@ public class WebSettings { * @return A non-negative integer between 1 and 72. */ public synchronized int getDefaultFontSize() { - return mDefaultFontSize; + throw new MustOverrideException(); } /** @@ -1126,11 +651,7 @@ public class WebSettings { * Any number outside the specified range will be pinned. */ public synchronized void setDefaultFixedFontSize(int size) { - size = pin(size); - if (mDefaultFixedFontSize != size) { - mDefaultFixedFontSize = size; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1138,21 +659,7 @@ public class WebSettings { * @return A non-negative integer between 1 and 72. */ public synchronized int getDefaultFixedFontSize() { - return mDefaultFixedFontSize; - } - - /** - * Set the number of pages cached by the WebKit for the history navigation. - * @param size A non-negative integer between 0 (no cache) and 20 (max). - * @hide - */ - public synchronized void setPageCacheCapacity(int size) { - if (size < 0) size = 0; - if (size > 20) size = 20; - if (mPageCacheCapacity != size) { - mPageCacheCapacity = size; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1165,10 +672,7 @@ public class WebSettings { * @param flag Whether the WebView should load image resources. */ public synchronized void setLoadsImagesAutomatically(boolean flag) { - if (mLoadsImagesAutomatically != flag) { - mLoadsImagesAutomatically = flag; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1177,7 +681,7 @@ public class WebSettings { * @return True if the WebView loads image resources. */ public synchronized boolean getLoadsImagesAutomatically() { - return mLoadsImagesAutomatically; + throw new MustOverrideException(); } /** @@ -1195,10 +699,7 @@ public class WebSettings { * @see #setBlockNetworkLoads */ public synchronized void setBlockNetworkImage(boolean flag) { - if (mBlockNetworkImage != flag) { - mBlockNetworkImage = flag; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1207,7 +708,7 @@ public class WebSettings { * @return True if the WebView does not load image resources from the network. */ public synchronized boolean getBlockNetworkImage() { - return mBlockNetworkImage; + throw new MustOverrideException(); } /** @@ -1226,11 +727,7 @@ public class WebSettings { * @see android.webkit.WebView#reload */ public synchronized void setBlockNetworkLoads(boolean flag) { - if (mBlockNetworkLoads != flag) { - mBlockNetworkLoads = flag; - verifyNetworkAccess(); - postSync(); - } + throw new MustOverrideException(); } /** @@ -1241,20 +738,7 @@ public class WebSettings { * @return True if the WebView does not load any resources from the network. */ public synchronized boolean getBlockNetworkLoads() { - return mBlockNetworkLoads; - } - - - private void verifyNetworkAccess() { - if (!mBlockNetworkLoads) { - if (mContext.checkPermission("android.permission.INTERNET", - android.os.Process.myPid(), android.os.Process.myUid()) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException - ("Permission denied - " + - "application missing INTERNET permission"); - } - } + throw new MustOverrideException(); } /** @@ -1262,50 +746,7 @@ public class WebSettings { * @param flag True if the WebView should execute javascript. */ public synchronized void setJavaScriptEnabled(boolean flag) { - if (mJavaScriptEnabled != flag) { - mJavaScriptEnabled = flag; - postSync(); - } - } - - /** - * Tell the WebView to use Skia's hardware accelerated rendering path - * @param flag True if the WebView should use Skia's hw-accel path - * @hide - */ - public synchronized void setHardwareAccelSkiaEnabled(boolean flag) { - if (mHardwareAccelSkia != flag) { - mHardwareAccelSkia = flag; - postSync(); - } - } - - /** - * @return True if the WebView is using hardware accelerated skia - * @hide - */ - public synchronized boolean getHardwareAccelSkiaEnabled() { - return mHardwareAccelSkia; - } - - /** - * Tell the WebView to show the visual indicator - * @param flag True if the WebView should show the visual indicator - * @hide - */ - public synchronized void setShowVisualIndicator(boolean flag) { - if (mShowVisualIndicator != flag) { - mShowVisualIndicator = flag; - postSync(); - } - } - - /** - * @return True if the WebView is showing the visual indicator - * @hide - */ - public synchronized boolean getShowVisualIndicator() { - return mShowVisualIndicator; + throw new MustOverrideException(); } /** @@ -1316,7 +757,7 @@ public class WebSettings { */ @Deprecated public synchronized void setPluginsEnabled(boolean flag) { - setPluginState(flag ? PluginState.ON : PluginState.OFF); + throw new MustOverrideException(); } /** @@ -1327,10 +768,7 @@ public class WebSettings { * @param state One of the PluginState values. */ public synchronized void setPluginState(PluginState state) { - if (mPluginState != state) { - mPluginState = state; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1342,6 +780,7 @@ public class WebSettings { */ @Deprecated public synchronized void setPluginsPath(String pluginsPath) { + // Specified to do nothing, so no need for derived classes to override. } /** @@ -1352,11 +791,7 @@ public class WebSettings { * be saved. May be the empty string but should never be null. */ public synchronized void setDatabasePath(String databasePath) { - if (databasePath != null && !mDatabasePathHasBeenSet) { - mDatabasePath = databasePath; - mDatabasePathHasBeenSet = true; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1367,40 +802,26 @@ public class WebSettings { * should never be null. */ public synchronized void setGeolocationDatabasePath(String databasePath) { - if (databasePath != null - && !databasePath.equals(mGeolocationDatabasePath)) { - mGeolocationDatabasePath = databasePath; - postSync(); - } + throw new MustOverrideException(); } /** - * Enable or disable the Application Cache API. - * @param flag Whether to enable the Application Cache API. + * Tell the WebView to enable Application Caches API. + * @param flag True if the WebView should enable Application Caches. */ public synchronized void setAppCacheEnabled(boolean flag) { - if (mAppCacheEnabled != flag) { - mAppCacheEnabled = flag; - postSync(); - } + throw new MustOverrideException(); } /** - * Set the path used by the Application Cache API to store files. This - * setting is applied to all WebViews in the application. In order for the - * Application Cache API to function, this method must be called with a - * path which exists and is writable by the application. This method may - * only be called once: repeated calls are ignored. - * @param path Path to the directory that should be used to store Application - * Cache files. + * Set a custom path to the Application Caches files. The client + * must ensure it exists before this call. + * @param appCachePath String path to the directory containing Application + * Caches files. The appCache path can be the empty string but should not + * be null. Passing null for this parameter will result in a no-op. */ - public synchronized void setAppCachePath(String path) { - // We test for a valid path and for repeated setting on the native - // side, but we can avoid syncing in some simple cases. - if (mAppCachePath == null && path != null && !path.isEmpty()) { - mAppCachePath = path; - postSync(); - } + public synchronized void setAppCachePath(String appCachePath) { + throw new MustOverrideException(); } /** @@ -1408,10 +829,7 @@ public class WebSettings { * @param appCacheMaxSize the maximum size in bytes. */ public synchronized void setAppCacheMaxSize(long appCacheMaxSize) { - if (appCacheMaxSize != mAppCacheMaxSize) { - mAppCacheMaxSize = appCacheMaxSize; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1420,10 +838,7 @@ public class WebSettings { * API. */ public synchronized void setDatabaseEnabled(boolean flag) { - if (mDatabaseEnabled != flag) { - mDatabaseEnabled = flag; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1432,10 +847,7 @@ public class WebSettings { * API. */ public synchronized void setDomStorageEnabled(boolean flag) { - if (mDomStorageEnabled != flag) { - mDomStorageEnabled = flag; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1443,16 +855,15 @@ public class WebSettings { * @return True if the DOM Storage API's are enabled. */ public synchronized boolean getDomStorageEnabled() { - return mDomStorageEnabled; + throw new MustOverrideException(); } - /** * Return the path to where database storage API databases are saved for * the current WebView. * @return the String path to the database storage API databases. */ public synchronized String getDatabasePath() { - return mDatabasePath; + throw new MustOverrideException(); } /** @@ -1460,21 +871,7 @@ public class WebSettings { * @return True if the database storage API is enabled. */ public synchronized boolean getDatabaseEnabled() { - return mDatabaseEnabled; - } - - /** - * Tell the WebView to enable WebWorkers API. - * @param flag True if the WebView should enable WebWorkers. - * Note that this flag only affects V8. JSC does not have - * an equivalent setting. - * @hide - */ - public synchronized void setWorkersEnabled(boolean flag) { - if (mWorkersEnabled != flag) { - mWorkersEnabled = flag; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1482,22 +879,7 @@ public class WebSettings { * @param flag Whether Geolocation should be enabled. */ public synchronized void setGeolocationEnabled(boolean flag) { - if (mGeolocationEnabled != flag) { - mGeolocationEnabled = flag; - postSync(); - } - } - - /** - * Sets whether XSS Auditor is enabled. - * @param flag Whether XSS Auditor should be enabled. - * @hide Only used by LayoutTestController. - */ - public synchronized void setXSSAuditorEnabled(boolean flag) { - if (mXSSAuditorEnabled != flag) { - mXSSAuditorEnabled = flag; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1505,7 +887,7 @@ public class WebSettings { * @return True if javascript is enabled. */ public synchronized boolean getJavaScriptEnabled() { - return mJavaScriptEnabled; + throw new MustOverrideException(); } /** @@ -1515,7 +897,7 @@ public class WebSettings { */ @Deprecated public synchronized boolean getPluginsEnabled() { - return mPluginState == PluginState.ON; + throw new MustOverrideException(); } /** @@ -1523,7 +905,7 @@ public class WebSettings { * @return A value corresponding to the enum PluginState. */ public synchronized PluginState getPluginState() { - return mPluginState; + throw new MustOverrideException(); } /** @@ -1535,6 +917,7 @@ public class WebSettings { */ @Deprecated public synchronized String getPluginsPath() { + // Unconditionally returns empty string, so no need for derived classes to override. return ""; } @@ -1543,12 +926,8 @@ public class WebSettings { * javascript function window.open(). * @param flag True if javascript can open windows automatically. */ - public synchronized void setJavaScriptCanOpenWindowsAutomatically( - boolean flag) { - if (mJavaScriptCanOpenWindowsAutomatically != flag) { - mJavaScriptCanOpenWindowsAutomatically = flag; - postSync(); - } + public synchronized void setJavaScriptCanOpenWindowsAutomatically(boolean flag) { + throw new MustOverrideException(); } /** @@ -1558,18 +937,14 @@ public class WebSettings { * window.open(). */ public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() { - return mJavaScriptCanOpenWindowsAutomatically; + throw new MustOverrideException(); } - /** * Set the default text encoding name to use when decoding html pages. * @param encoding The text encoding name. */ public synchronized void setDefaultTextEncodingName(String encoding) { - if (encoding != null && !encoding.equals(mDefaultTextEncoding)) { - mDefaultTextEncoding = encoding; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1577,7 +952,7 @@ public class WebSettings { * @return The default text encoding name as a string. */ public synchronized String getDefaultTextEncodingName() { - return mDefaultTextEncoding; + throw new MustOverrideException(); } /** @@ -1585,66 +960,14 @@ public class WebSettings { * it will use the system default user-agent string. */ public synchronized void setUserAgentString(String ua) { - if (ua == null || ua.length() == 0) { - synchronized(sLockForLocaleSettings) { - Locale currentLocale = Locale.getDefault(); - if (!sLocale.equals(currentLocale)) { - sLocale = currentLocale; - mAcceptLanguage = getCurrentAcceptLanguage(); - } - } - ua = getCurrentUserAgent(); - mUseDefaultUserAgent = true; - } else { - mUseDefaultUserAgent = false; - } - - if (!ua.equals(mUserAgent)) { - mUserAgent = ua; - postSync(); - } + throw new MustOverrideException(); } /** * Return the WebView's user-agent string. */ public synchronized String getUserAgentString() { - if (DESKTOP_USERAGENT.equals(mUserAgent) || - IPHONE_USERAGENT.equals(mUserAgent) || - !mUseDefaultUserAgent) { - return mUserAgent; - } - - boolean doPostSync = false; - synchronized(sLockForLocaleSettings) { - Locale currentLocale = Locale.getDefault(); - if (!sLocale.equals(currentLocale)) { - sLocale = currentLocale; - mUserAgent = getCurrentUserAgent(); - mAcceptLanguage = getCurrentAcceptLanguage(); - doPostSync = true; - } - } - if (doPostSync) { - postSync(); - } - return mUserAgent; - } - - /* package api to grab the Accept Language string. */ - /*package*/ synchronized String getAcceptLanguage() { - synchronized(sLockForLocaleSettings) { - Locale currentLocale = Locale.getDefault(); - if (!sLocale.equals(currentLocale)) { - sLocale = currentLocale; - mAcceptLanguage = getCurrentAcceptLanguage(); - } - } - return mAcceptLanguage; - } - - /* package */ boolean isNarrowColumnLayout() { - return getLayoutAlgorithm() == LayoutAlgorithm.NARROW_COLUMNS; + throw new MustOverrideException(); } /** @@ -1654,14 +977,7 @@ public class WebSettings { * @param flag */ public void setNeedInitialFocus(boolean flag) { - if (mNeedInitialFocus != flag) { - mNeedInitialFocus = flag; - } - } - - /* Package api to get the choice whether it needs to set initial focus. */ - /* package */ boolean getNeedInitialFocus() { - return mNeedInitialFocus; + throw new MustOverrideException(); } /** @@ -1671,11 +987,7 @@ public class WebSettings { * @param priority RenderPriority, can be normal, high or low. */ public synchronized void setRenderPriority(RenderPriority priority) { - if (mRenderPriority != priority) { - mRenderPriority = priority; - mEventHandler.sendMessage(Message.obtain(null, - EventHandler.PRIORITY)); - } + throw new MustOverrideException(); } /** @@ -1687,10 +999,7 @@ public class WebSettings { * @param mode One of the LOAD_ values. */ public void setCacheMode(int mode) { - if (mode != mOverrideCacheMode) { - mOverrideCacheMode = mode; - postSync(); - } + throw new MustOverrideException(); } /** @@ -1698,204 +1007,6 @@ public class WebSettings { * description, see the {@link #setCacheMode(int)} function. */ public int getCacheMode() { - return mOverrideCacheMode; + throw new MustOverrideException(); } - - /** - * If set, webkit alternately shrinks and expands images viewed outside - * of an HTML page to fit the screen. This conflicts with attempts by - * the UI to zoom in and out of an image, so it is set false by default. - * @param shrink Set true to let webkit shrink the standalone image to fit. - * {@hide} - */ - public void setShrinksStandaloneImagesToFit(boolean shrink) { - if (mShrinksStandaloneImagesToFit != shrink) { - mShrinksStandaloneImagesToFit = shrink; - postSync(); - } - } - - /** - * Specify the maximum decoded image size. The default is - * 2 megs for small memory devices and 8 megs for large memory devices. - * @param size The maximum decoded size, or zero to set to the default. - * @hide - */ - public void setMaximumDecodedImageSize(long size) { - if (mMaximumDecodedImageSize != size) { - mMaximumDecodedImageSize = size; - postSync(); - } - } - - /** - * Returns whether to use fixed viewport. Use fixed viewport - * whenever wide viewport is on. - */ - /* package */ boolean getUseFixedViewport() { - return getUseWideViewPort(); - } - - /** - * Returns whether private browsing is enabled. - */ - /* package */ boolean isPrivateBrowsingEnabled() { - return mPrivateBrowsingEnabled; - } - - /** - * Sets whether private browsing is enabled. - * @param flag Whether private browsing should be enabled. - */ - /* package */ synchronized void setPrivateBrowsingEnabled(boolean flag) { - if (mPrivateBrowsingEnabled != flag) { - mPrivateBrowsingEnabled = flag; - - // AutoFill is dependant on private browsing being enabled so - // reset it to take account of the new value of mPrivateBrowsingEnabled. - setAutoFillEnabled(mAutoFillEnabled); - - postSync(); - } - } - - /** - * Returns whether the viewport metatag can disable zooming - * @hide - */ - public boolean forceUserScalable() { - return mForceUserScalable; - } - - /** - * Sets whether viewport metatag can disable zooming. - * @param flag Whether or not to forceably enable user scalable. - * @hide - */ - public synchronized void setForceUserScalable(boolean flag) { - mForceUserScalable = flag; - } - - synchronized void setSyntheticLinksEnabled(boolean flag) { - if (mSyntheticLinksEnabled != flag) { - mSyntheticLinksEnabled = flag; - postSync(); - } - } - - /** - * @hide - */ - public synchronized void setAutoFillEnabled(boolean enabled) { - // AutoFill is always disabled in private browsing mode. - boolean autoFillEnabled = enabled && !mPrivateBrowsingEnabled; - if (mAutoFillEnabled != autoFillEnabled) { - mAutoFillEnabled = autoFillEnabled; - postSync(); - } - } - - /** - * @hide - */ - public synchronized boolean getAutoFillEnabled() { - return mAutoFillEnabled; - } - - /** - * @hide - */ - public synchronized void setAutoFillProfile(AutoFillProfile profile) { - if (mAutoFillProfile != profile) { - mAutoFillProfile = profile; - postSync(); - } - } - - /** - * @hide - */ - public synchronized AutoFillProfile getAutoFillProfile() { - return mAutoFillProfile; - } - - int getDoubleTapToastCount() { - return mDoubleTapToastCount; - } - - void setDoubleTapToastCount(int count) { - if (mDoubleTapToastCount != count) { - mDoubleTapToastCount = count; - // write the settings in the non-UI thread - mEventHandler.sendMessage(Message.obtain(null, - EventHandler.SET_DOUBLE_TAP_TOAST_COUNT)); - } - } - - /** - * @hide - */ - public void setProperty(String key, String value) { - if (mWebView.nativeSetProperty(key, value)) { - mWebView.contentInvalidateAll(); - } - } - - /** - * @hide - */ - public String getProperty(String key) { - return mWebView.nativeGetProperty(key); - } - - /** - * Transfer messages from the queue to the new WebCoreThread. Called from - * WebCore thread. - */ - /*package*/ - synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) { - mBrowserFrame = frame; - if (DebugFlags.WEB_SETTINGS) { - junit.framework.Assert.assertTrue(frame.mNativeFrame != 0); - } - - SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE, - Context.MODE_PRIVATE); - if (mDoubleTapToastCount > 0) { - mDoubleTapToastCount = sp.getInt(DOUBLE_TAP_TOAST_COUNT, - mDoubleTapToastCount); - } - nativeSync(frame.mNativeFrame); - mSyncPending = false; - mEventHandler.createHandler(); - } - - /** - * Let the Settings object know that our owner is being destroyed. - */ - /*package*/ - synchronized void onDestroyed() { - } - - private int pin(int size) { - // FIXME: 72 is just an arbitrary max text size value. - if (size < 1) { - return 1; - } else if (size > 72) { - return 72; - } - return size; - } - - /* Post a SYNC message to handle syncing the native settings. */ - private synchronized void postSync() { - // Only post if a sync is not pending - if (!mSyncPending) { - mSyncPending = mEventHandler.sendMessage( - Message.obtain(null, EventHandler.SYNC)); - } - } - - // Synchronize the native and java settings. - private native void nativeSync(int nativeFrame); } diff --git a/core/java/android/webkit/WebSettingsClassic.java b/core/java/android/webkit/WebSettingsClassic.java index c463b40..6850eea 100644 --- a/core/java/android/webkit/WebSettingsClassic.java +++ b/core/java/android/webkit/WebSettingsClassic.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * 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. @@ -28,124 +28,15 @@ import android.util.EventLog; import java.util.Locale; /** - * Manages settings state for a WebView. When a WebView is first created, it - * obtains a set of default settings. These default settings will be returned - * from any getter call. A WebSettings object obtained from - * WebView.getSettings() is tied to the life of the WebView. If a WebView has - * been destroyed, any method call on WebSettings will throw an - * IllegalStateException. + * WebSettings implementation for the WebViewClassic implementation of WebView. + * @hide */ -public class WebSettings { - /** - * Enum for controlling the layout of html. - * NORMAL means no rendering changes. - * SINGLE_COLUMN moves all content into one column that is the width of the - * view. - * NARROW_COLUMNS makes all columns no wider than the screen if possible. - */ - // XXX: These must match LayoutAlgorithm in Settings.h in WebCore. - public enum LayoutAlgorithm { - NORMAL, - /** - * @deprecated This algorithm is now obsolete. - */ - @Deprecated - SINGLE_COLUMN, - NARROW_COLUMNS - } - - /** - * Enum for specifying the text size. - * SMALLEST is 50% - * SMALLER is 75% - * NORMAL is 100% - * LARGER is 150% - * LARGEST is 200% - * @deprecated Use {@link WebSettings#setTextZoom(int)} and {@link WebSettings#getTextZoom()} instead. - */ - public enum TextSize { - SMALLEST(50), - SMALLER(75), - NORMAL(100), - LARGER(150), - LARGEST(200); - TextSize(int size) { - value = size; - } - int value; - } - - /** - * Enum for specifying the WebView's desired density. - * FAR makes 100% looking like in 240dpi - * MEDIUM makes 100% looking like in 160dpi - * CLOSE makes 100% looking like in 120dpi - */ - public enum ZoomDensity { - FAR(150), // 240dpi - MEDIUM(100), // 160dpi - CLOSE(75); // 120dpi - ZoomDensity(int size) { - value = size; - } - int value; - } - - /** - * Default cache usage pattern Use with {@link #setCacheMode}. - */ - public static final int LOAD_DEFAULT = -1; - - /** - * Normal cache usage pattern Use with {@link #setCacheMode}. - */ - public static final int LOAD_NORMAL = 0; - - /** - * Use cache if content is there, even if expired (eg, history nav) - * If it is not in the cache, load from network. - * Use with {@link #setCacheMode}. - */ - public static final int LOAD_CACHE_ELSE_NETWORK = 1; - - /** - * Don't use the cache, load from network - * Use with {@link #setCacheMode}. - */ - public static final int LOAD_NO_CACHE = 2; - - /** - * Don't use the network, load from cache only. - * Use with {@link #setCacheMode}. - */ - public static final int LOAD_CACHE_ONLY = 3; - - public enum RenderPriority { - NORMAL, - HIGH, - LOW - } - - /** - * The plugin state effects how plugins are treated on a page. ON means - * that any object will be loaded even if a plugin does not exist to handle - * the content. ON_DEMAND means that if there is a plugin installed that - * can handle the content, a placeholder is shown until the user clicks on - * the placeholder. Once clicked, the plugin will be enabled on the page. - * OFF means that all plugins will be turned off and any fallback content - * will be used. - */ - public enum PluginState { - ON, - ON_DEMAND, - OFF - } - +public class WebSettingsClassic extends WebSettings { // TODO: Keep this up to date private static final String PREVIOUS_VERSION = "4.0.3"; // WebView associated with this WebSettings. - private WebView mWebView; + private WebViewClassic mWebView; // BrowserFrame used to access the native frame pointer. private BrowserFrame mBrowserFrame; // Flag to prevent multiple SYNC messages at one time. @@ -308,7 +199,7 @@ public class WebSettings { public void handleMessage(Message msg) { switch (msg.what) { case SYNC: - synchronized (WebSettings.this) { + synchronized (WebSettingsClassic.this) { if (mBrowserFrame.mNativeFrame != 0) { nativeSync(mBrowserFrame.mNativeFrame); } @@ -336,7 +227,7 @@ public class WebSettings { } private void setRenderPriority() { - synchronized (WebSettings.this) { + synchronized (WebSettingsClassic.this) { if (mRenderPriority == RenderPriority.NORMAL) { android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DEFAULT); @@ -379,7 +270,7 @@ public class WebSettings { * Package constructor to prevent clients from creating a new settings * instance. */ - WebSettings(Context context, WebView webview) { + WebSettingsClassic(Context context, WebViewClassic webview) { mEventHandler = new EventHandler(); mContext = context; mWebView = webview; @@ -517,194 +408,195 @@ public class WebSettings { } /** - * Enables dumping the pages navigation cache to a text file. - * @deprecated This method is now obsolete. + * @see android.webkit.WebSettings#setNavDump(boolean) */ + @Override @Deprecated public void setNavDump(boolean enabled) { mNavDump = enabled; } /** - * Returns true if dumping the navigation cache is enabled. - * @deprecated This method is now obsolete. + * @see android.webkit.WebSettings#getNavDump() */ + @Override @Deprecated public boolean getNavDump() { return mNavDump; } /** - * Set whether the WebView supports zoom + * @see android.webkit.WebSettings#setSupportZoom(boolean) */ + @Override public void setSupportZoom(boolean support) { mSupportZoom = support; mWebView.updateMultiTouchSupport(mContext); } /** - * Returns whether the WebView supports zoom + * @see android.webkit.WebSettings#supportZoom() */ + @Override public boolean supportZoom() { return mSupportZoom; } /** - * Sets whether the zoom mechanism built into WebView is used. + * @see android.webkit.WebSettings#setBuiltInZoomControls(boolean) */ + @Override public void setBuiltInZoomControls(boolean enabled) { mBuiltInZoomControls = enabled; mWebView.updateMultiTouchSupport(mContext); } /** - * Returns true if the zoom mechanism built into WebView is being used. + * @see android.webkit.WebSettings#getBuiltInZoomControls() */ + @Override public boolean getBuiltInZoomControls() { return mBuiltInZoomControls; } /** - * Sets whether the on screen zoom buttons are used. - * A combination of built in zoom controls enabled - * and on screen zoom controls disabled allows for pinch to zoom - * to work without the on screen controls + * @see android.webkit.WebSettings#setDisplayZoomControls(boolean) */ + @Override public void setDisplayZoomControls(boolean enabled) { mDisplayZoomControls = enabled; mWebView.updateMultiTouchSupport(mContext); } /** - * Returns true if the on screen zoom buttons are being used. + * @see android.webkit.WebSettings#getDisplayZoomControls() */ + @Override public boolean getDisplayZoomControls() { return mDisplayZoomControls; } /** - * Enable or disable file access within WebView. File access is enabled by - * default. Note that this enables or disables file system access only. - * Assets and resources are still accessible using file:///android_asset and - * file:///android_res. + * @see android.webkit.WebSettings#setAllowFileAccess(boolean) */ + @Override public void setAllowFileAccess(boolean allow) { mAllowFileAccess = allow; } /** - * Returns true if this WebView supports file access. + * @see android.webkit.WebSettings#getAllowFileAccess() */ + @Override public boolean getAllowFileAccess() { return mAllowFileAccess; } /** - * Enable or disable content url access within WebView. Content url access - * allows WebView to load content from a content provider installed in the - * system. The default is enabled. + * @see android.webkit.WebSettings#setAllowContentAccess(boolean) */ + @Override public void setAllowContentAccess(boolean allow) { mAllowContentAccess = allow; } /** - * Returns true if this WebView supports content url access. + * @see android.webkit.WebSettings#getAllowContentAccess() */ + @Override public boolean getAllowContentAccess() { return mAllowContentAccess; } /** - * Set whether the WebView loads a page with overview mode. + * @see android.webkit.WebSettings#setLoadWithOverviewMode(boolean) */ + @Override public void setLoadWithOverviewMode(boolean overview) { mLoadWithOverviewMode = overview; } /** - * Returns true if this WebView loads page with overview mode + * @see android.webkit.WebSettings#getLoadWithOverviewMode() */ + @Override public boolean getLoadWithOverviewMode() { return mLoadWithOverviewMode; } /** - * Set whether the WebView will enable smooth transition while panning or - * zooming or while the window hosting the WebView does not have focus. - * If it is true, WebView will choose a solution to maximize the performance. - * e.g. the WebView's content may not be updated during the transition. - * If it is false, WebView will keep its fidelity. The default value is false. + * @see android.webkit.WebSettings#setEnableSmoothTransition(boolean) */ + @Override public void setEnableSmoothTransition(boolean enable) { mEnableSmoothTransition = enable; } /** - * Returns true if the WebView enables smooth transition while panning or - * zooming. + * @see android.webkit.WebSettings#enableSmoothTransition() */ + @Override public boolean enableSmoothTransition() { return mEnableSmoothTransition; } /** - * Set whether the WebView uses its background for over scroll background. - * If true, it will use the WebView's background. If false, it will use an - * internal pattern. Default is true. - * @deprecated This method is now obsolete. + * @see android.webkit.WebSettings#setUseWebViewBackgroundForOverscrollBackground(boolean) */ + @Override @Deprecated public void setUseWebViewBackgroundForOverscrollBackground(boolean view) { mUseWebViewBackgroundForOverscroll = view; } /** - * Returns true if this WebView uses WebView's background instead of - * internal pattern for over scroll background. - * @deprecated This method is now obsolete. + * @see android.webkit.WebSettings#getUseWebViewBackgroundForOverscrollBackground() */ + @Override @Deprecated public boolean getUseWebViewBackgroundForOverscrollBackground() { return mUseWebViewBackgroundForOverscroll; } /** - * Store whether the WebView is saving form data. + * @see android.webkit.WebSettings#setSaveFormData(boolean) */ + @Override public void setSaveFormData(boolean save) { mSaveFormData = save; } /** - * Return whether the WebView is saving form data and displaying prior - * entries/autofill++. Always false in private browsing mode. + * @see android.webkit.WebSettings#getSaveFormData() */ + @Override public boolean getSaveFormData() { return mSaveFormData && !mPrivateBrowsingEnabled; } /** - * Store whether the WebView is saving password. + * @see android.webkit.WebSettings#setSavePassword(boolean) */ + @Override public void setSavePassword(boolean save) { mSavePassword = save; } /** - * Return whether the WebView is saving password. + * @see android.webkit.WebSettings#getSavePassword() */ + @Override public boolean getSavePassword() { return mSavePassword; } /** - * Set the text zoom of the page in percent. Default is 100. - * @param textZoom A percent value for increasing or decreasing the text. + * @see android.webkit.WebSettings#setTextZoom(int) */ + @Override public synchronized void setTextZoom(int textZoom) { if (mTextSize != textZoom) { - if (WebView.mLogEvent) { + if (WebViewClassic.mLogEvent) { EventLog.writeEvent(EventLogTags.BROWSER_TEXT_SIZE_CHANGE, mTextSize, textZoom); } @@ -714,32 +606,25 @@ public class WebSettings { } /** - * Get the text zoom of the page in percent. - * @return A percent value describing the text zoom. - * @see setTextSizeZoom + * @see android.webkit.WebSettings#getTextZoom() */ + @Override public synchronized int getTextZoom() { return mTextSize; } /** - * Set the text size of the page. - * @param t A TextSize value for increasing or decreasing the text. - * @see WebSettings.TextSize - * @deprecated Use {@link #setTextZoom(int)} instead + * @see android.webkit.WebSettings#setTextSize(android.webkit.WebSettingsClassic.TextSize) */ + @Override public synchronized void setTextSize(TextSize t) { setTextZoom(t.value); } /** - * Get the text size of the page. If the text size was previously specified - * in percent using {@link #setTextZoom(int)}, this will return - * the closest matching {@link TextSize}. - * @return A TextSize enum value describing the text size. - * @see WebSettings.TextSize - * @deprecated Use {@link #getTextZoom()} instead + * @see android.webkit.WebSettings#getTextSize() */ + @Override public synchronized TextSize getTextSize() { TextSize closestSize = null; int smallestDelta = Integer.MAX_VALUE; @@ -778,11 +663,9 @@ public class WebSettings { } /** - * Set the default zoom density of the page. This should be called from UI - * thread. - * @param zoom A ZoomDensity value - * @see WebSettings.ZoomDensity + * @see android.webkit.WebSettings#setDefaultZoom(android.webkit.WebSettingsClassic.ZoomDensity) */ + @Override public void setDefaultZoom(ZoomDensity zoom) { if (mDefaultZoom != zoom) { mDefaultZoom = zoom; @@ -791,54 +674,51 @@ public class WebSettings { } /** - * Get the default zoom density of the page. This should be called from UI - * thread. - * @return A ZoomDensity value - * @see WebSettings.ZoomDensity + * @see android.webkit.WebSettings#getDefaultZoom() */ + @Override public ZoomDensity getDefaultZoom() { return mDefaultZoom; } /** - * Enables using light touches to make a selection and activate mouseovers. + * @see android.webkit.WebSettings#setLightTouchEnabled(boolean) */ + @Override public void setLightTouchEnabled(boolean enabled) { mLightTouchEnabled = enabled; } /** - * Returns true if light touches are enabled. + * @see android.webkit.WebSettings#getLightTouchEnabled() */ + @Override public boolean getLightTouchEnabled() { return mLightTouchEnabled; } /** - * @deprecated This setting controlled a rendering optimization - * that is no longer present. Setting it now has no effect. + * @see android.webkit.WebSettings#setUseDoubleTree(boolean) */ + @Override @Deprecated public synchronized void setUseDoubleTree(boolean use) { return; } /** - * @deprecated This setting controlled a rendering optimization - * that is no longer present. Setting it now has no effect. + * @see android.webkit.WebSettings#getUseDoubleTree() */ + @Override @Deprecated public synchronized boolean getUseDoubleTree() { return false; } /** - * Tell the WebView about user-agent string. - * @param ua 0 if the WebView should use an Android user-agent string, - * 1 if the WebView should use a desktop user-agent string. - * - * @deprecated Please use setUserAgentString instead. + * @see android.webkit.WebSettings#setUserAgent(int) */ + @Override @Deprecated public synchronized void setUserAgent(int ua) { String uaString = null; @@ -861,13 +741,9 @@ public class WebSettings { } /** - * Return user-agent as int - * @return int 0 if the WebView is using an Android user-agent string. - * 1 if the WebView is using a desktop user-agent string. - * -1 if the WebView is using user defined user-agent string. - * - * @deprecated Please use getUserAgentString instead. + * @see android.webkit.WebSettings#getUserAgent() */ + @Override @Deprecated public synchronized int getUserAgent() { if (DESKTOP_USERAGENT.equals(mUserAgent)) { @@ -881,8 +757,9 @@ public class WebSettings { } /** - * Tell the WebView to use the wide viewport + * @see android.webkit.WebSettings#setUseWideViewPort(boolean) */ + @Override public synchronized void setUseWideViewPort(boolean use) { if (mUseWideViewport != use) { mUseWideViewport = use; @@ -891,17 +768,17 @@ public class WebSettings { } /** - * @return True if the WebView is using a wide viewport + * @see android.webkit.WebSettings#getUseWideViewPort() */ + @Override public synchronized boolean getUseWideViewPort() { return mUseWideViewport; } /** - * Tell the WebView whether it supports multiple windows. TRUE means - * that {@link WebChromeClient#onCreateWindow(WebView, boolean, - * boolean, Message)} is implemented by the host application. + * @see android.webkit.WebSettings#setSupportMultipleWindows(boolean) */ + @Override public synchronized void setSupportMultipleWindows(boolean support) { if (mSupportMultipleWindows != support) { mSupportMultipleWindows = support; @@ -910,20 +787,17 @@ public class WebSettings { } /** - * @return True if the WebView is supporting multiple windows. This means - * that {@link WebChromeClient#onCreateWindow(WebView, boolean, - * boolean, Message)} is implemented by the host application. + * @see android.webkit.WebSettings#supportMultipleWindows() */ + @Override public synchronized boolean supportMultipleWindows() { return mSupportMultipleWindows; } /** - * Set the underlying layout algorithm. This will cause a relayout of the - * WebView. - * @param l A LayoutAlgorithm enum specifying the algorithm to use. - * @see WebSettings.LayoutAlgorithm + * @see android.webkit.WebSettings#setLayoutAlgorithm(android.webkit.WebSettingsClassic.LayoutAlgorithm) */ + @Override public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) { // XXX: This will only be affective if libwebcore was built with // ANDROID_LAYOUT defined. @@ -934,19 +808,17 @@ public class WebSettings { } /** - * Return the current layout algorithm. The default is NARROW_COLUMNS. - * @return LayoutAlgorithm enum value describing the layout algorithm - * being used. - * @see WebSettings.LayoutAlgorithm + * @see android.webkit.WebSettings#getLayoutAlgorithm() */ + @Override public synchronized LayoutAlgorithm getLayoutAlgorithm() { return mLayoutAlgorithm; } /** - * Set the standard font family name. - * @param font A font family name. + * @see android.webkit.WebSettings#setStandardFontFamily(java.lang.String) */ + @Override public synchronized void setStandardFontFamily(String font) { if (font != null && !font.equals(mStandardFontFamily)) { mStandardFontFamily = font; @@ -955,17 +827,17 @@ public class WebSettings { } /** - * Get the standard font family name. The default is "sans-serif". - * @return The standard font family name as a string. + * @see android.webkit.WebSettings#getStandardFontFamily() */ + @Override public synchronized String getStandardFontFamily() { return mStandardFontFamily; } /** - * Set the fixed font family name. - * @param font A font family name. + * @see android.webkit.WebSettings#setFixedFontFamily(java.lang.String) */ + @Override public synchronized void setFixedFontFamily(String font) { if (font != null && !font.equals(mFixedFontFamily)) { mFixedFontFamily = font; @@ -974,17 +846,17 @@ public class WebSettings { } /** - * Get the fixed font family name. The default is "monospace". - * @return The fixed font family name as a string. + * @see android.webkit.WebSettings#getFixedFontFamily() */ + @Override public synchronized String getFixedFontFamily() { return mFixedFontFamily; } /** - * Set the sans-serif font family name. - * @param font A font family name. + * @see android.webkit.WebSettings#setSansSerifFontFamily(java.lang.String) */ + @Override public synchronized void setSansSerifFontFamily(String font) { if (font != null && !font.equals(mSansSerifFontFamily)) { mSansSerifFontFamily = font; @@ -993,17 +865,17 @@ public class WebSettings { } /** - * Get the sans-serif font family name. - * @return The sans-serif font family name as a string. + * @see android.webkit.WebSettings#getSansSerifFontFamily() */ + @Override public synchronized String getSansSerifFontFamily() { return mSansSerifFontFamily; } /** - * Set the serif font family name. The default is "sans-serif". - * @param font A font family name. + * @see android.webkit.WebSettings#setSerifFontFamily(java.lang.String) */ + @Override public synchronized void setSerifFontFamily(String font) { if (font != null && !font.equals(mSerifFontFamily)) { mSerifFontFamily = font; @@ -1012,17 +884,17 @@ public class WebSettings { } /** - * Get the serif font family name. The default is "serif". - * @return The serif font family name as a string. + * @see android.webkit.WebSettings#getSerifFontFamily() */ + @Override public synchronized String getSerifFontFamily() { return mSerifFontFamily; } /** - * Set the cursive font family name. - * @param font A font family name. + * @see android.webkit.WebSettings#setCursiveFontFamily(java.lang.String) */ + @Override public synchronized void setCursiveFontFamily(String font) { if (font != null && !font.equals(mCursiveFontFamily)) { mCursiveFontFamily = font; @@ -1031,17 +903,17 @@ public class WebSettings { } /** - * Get the cursive font family name. The default is "cursive". - * @return The cursive font family name as a string. + * @see android.webkit.WebSettings#getCursiveFontFamily() */ + @Override public synchronized String getCursiveFontFamily() { return mCursiveFontFamily; } /** - * Set the fantasy font family name. - * @param font A font family name. + * @see android.webkit.WebSettings#setFantasyFontFamily(java.lang.String) */ + @Override public synchronized void setFantasyFontFamily(String font) { if (font != null && !font.equals(mFantasyFontFamily)) { mFantasyFontFamily = font; @@ -1050,18 +922,17 @@ public class WebSettings { } /** - * Get the fantasy font family name. The default is "fantasy". - * @return The fantasy font family name as a string. + * @see android.webkit.WebSettings#getFantasyFontFamily() */ + @Override public synchronized String getFantasyFontFamily() { return mFantasyFontFamily; } /** - * Set the minimum font size. - * @param size A non-negative integer between 1 and 72. - * Any number outside the specified range will be pinned. + * @see android.webkit.WebSettings#setMinimumFontSize(int) */ + @Override public synchronized void setMinimumFontSize(int size) { size = pin(size); if (mMinimumFontSize != size) { @@ -1071,18 +942,17 @@ public class WebSettings { } /** - * Get the minimum font size. The default is 8. - * @return A non-negative integer between 1 and 72. + * @see android.webkit.WebSettings#getMinimumFontSize() */ + @Override public synchronized int getMinimumFontSize() { return mMinimumFontSize; } /** - * Set the minimum logical font size. - * @param size A non-negative integer between 1 and 72. - * Any number outside the specified range will be pinned. + * @see android.webkit.WebSettings#setMinimumLogicalFontSize(int) */ + @Override public synchronized void setMinimumLogicalFontSize(int size) { size = pin(size); if (mMinimumLogicalFontSize != size) { @@ -1092,18 +962,17 @@ public class WebSettings { } /** - * Get the minimum logical font size. The default is 8. - * @return A non-negative integer between 1 and 72. + * @see android.webkit.WebSettings#getMinimumLogicalFontSize() */ + @Override public synchronized int getMinimumLogicalFontSize() { return mMinimumLogicalFontSize; } /** - * Set the default font size. - * @param size A non-negative integer between 1 and 72. - * Any number outside the specified range will be pinned. + * @see android.webkit.WebSettings#setDefaultFontSize(int) */ + @Override public synchronized void setDefaultFontSize(int size) { size = pin(size); if (mDefaultFontSize != size) { @@ -1113,18 +982,17 @@ public class WebSettings { } /** - * Get the default font size. The default is 16. - * @return A non-negative integer between 1 and 72. + * @see android.webkit.WebSettings#getDefaultFontSize() */ + @Override public synchronized int getDefaultFontSize() { return mDefaultFontSize; } /** - * Set the default fixed font size. - * @param size A non-negative integer between 1 and 72. - * Any number outside the specified range will be pinned. + * @see android.webkit.WebSettings#setDefaultFixedFontSize(int) */ + @Override public synchronized void setDefaultFixedFontSize(int size) { size = pin(size); if (mDefaultFixedFontSize != size) { @@ -1134,9 +1002,9 @@ public class WebSettings { } /** - * Get the default fixed font size. The default is 16. - * @return A non-negative integer between 1 and 72. + * @see android.webkit.WebSettings#getDefaultFixedFontSize() */ + @Override public synchronized int getDefaultFixedFontSize() { return mDefaultFixedFontSize; } @@ -1156,14 +1024,9 @@ public class WebSettings { } /** - * Sets whether the WebView should load image resources. Note that this method - * controls loading of all images, including those embedded using the data - * URI scheme. Use {@link #setBlockNetworkImage} to control loading only - * of images specified using network URI schemes. Note that if the value of this - * setting is changed from false to true, all images resources referenced - * by content currently displayed by the WebView are loaded automatically. - * @param flag Whether the WebView should load image resources. + * @see android.webkit.WebSettings#setLoadsImagesAutomatically(boolean) */ + @Override public synchronized void setLoadsImagesAutomatically(boolean flag) { if (mLoadsImagesAutomatically != flag) { mLoadsImagesAutomatically = flag; @@ -1172,28 +1035,17 @@ public class WebSettings { } /** - * Returns true if the WebView loads image resources. This includes - * images embedded using the data URI scheme. The default is true. - * @return True if the WebView loads image resources. + * @see android.webkit.WebSettings#getLoadsImagesAutomatically() */ + @Override public synchronized boolean getLoadsImagesAutomatically() { return mLoadsImagesAutomatically; } /** - * Sets whether the WebView should not load image resources from the - * network (resources accessed via http and https URI schemes). Note - * that this method has no effect unless - * {@link #getLoadsImagesAutomatically} returns true. Also note that - * disabling all network loads using {@link #setBlockNetworkLoads} - * will also prevent network images from loading, even if this flag is set - * to false. When the value of this setting is changed from true to false, - * network images resources referenced by content currently displayed by - * the WebView are fetched automatically. - * @param flag Whether the WebView should not load image resources from - * the network. - * @see #setBlockNetworkLoads + * @see android.webkit.WebSettings#setBlockNetworkImage(boolean) */ + @Override public synchronized void setBlockNetworkImage(boolean flag) { if (mBlockNetworkImage != flag) { mBlockNetworkImage = flag; @@ -1202,29 +1054,17 @@ public class WebSettings { } /** - * Returns true if the WebView does not load image resources from the network. - * The default is false. - * @return True if the WebView does not load image resources from the network. + * @see android.webkit.WebSettings#getBlockNetworkImage() */ + @Override public synchronized boolean getBlockNetworkImage() { return mBlockNetworkImage; } /** - * Sets whether the WebView should not load resources from the network. - * Use {@link #setBlockNetworkImage} to only avoid loading - * image resources. Note that if the value of this setting is - * changed from true to false, network resources referenced by content - * currently displayed by the WebView are not fetched until - * {@link android.webkit.WebView#reload} is called. - * If the application does not have the - * {@link android.Manifest.permission#INTERNET} permission, attempts to set - * a value of false will cause a {@link java.lang.SecurityException} - * to be thrown. - * @param flag Whether the WebView should not load any resources - * from the network. - * @see android.webkit.WebView#reload + * @see android.webkit.WebSettings#setBlockNetworkLoads(boolean) */ + @Override public synchronized void setBlockNetworkLoads(boolean flag) { if (mBlockNetworkLoads != flag) { mBlockNetworkLoads = flag; @@ -1234,12 +1074,9 @@ public class WebSettings { } /** - * Returns true if the WebView does not load any resources from the network. - * The default value is false if the application has the - * {@link android.Manifest.permission#INTERNET} permission, otherwise it is - * true. - * @return True if the WebView does not load any resources from the network. + * @see android.webkit.WebSettings#getBlockNetworkLoads() */ + @Override public synchronized boolean getBlockNetworkLoads() { return mBlockNetworkLoads; } @@ -1258,9 +1095,9 @@ public class WebSettings { } /** - * Tell the WebView to enable javascript execution. - * @param flag True if the WebView should execute javascript. + * @see android.webkit.WebSettings#setJavaScriptEnabled(boolean) */ + @Override public synchronized void setJavaScriptEnabled(boolean flag) { if (mJavaScriptEnabled != flag) { mJavaScriptEnabled = flag; @@ -1309,23 +1146,18 @@ public class WebSettings { } /** - * Tell the WebView to enable plugins. - * @param flag True if the WebView should load plugins. - * @deprecated This method has been deprecated in favor of - * {@link #setPluginState} + * @see android.webkit.WebSettings#setPluginsEnabled(boolean) */ + @Override @Deprecated public synchronized void setPluginsEnabled(boolean flag) { setPluginState(flag ? PluginState.ON : PluginState.OFF); } /** - * Tell the WebView to enable, disable, or have plugins on demand. On - * demand mode means that if a plugin exists that can handle the embedded - * content, a placeholder icon will be shown instead of the plugin. When - * the placeholder is clicked, the plugin will be enabled. - * @param state One of the PluginState values. + * @see android.webkit.WebSettings#setPluginState(android.webkit.WebSettingsClassic.PluginState) */ + @Override public synchronized void setPluginState(PluginState state) { if (mPluginState != state) { mPluginState = state; @@ -1334,23 +1166,17 @@ public class WebSettings { } /** - * Set a custom path to plugins used by the WebView. This method is - * obsolete since each plugin is now loaded from its own package. - * @param pluginsPath String path to the directory containing plugins. - * @deprecated This method is no longer used as plugins are loaded from - * their own APK via the system's package manager. + * @see android.webkit.WebSettings#setPluginsPath(java.lang.String) */ + @Override @Deprecated public synchronized void setPluginsPath(String pluginsPath) { } /** - * Set the path to where database storage API databases should be saved. - * Nota that the WebCore Database Tracker only allows the path to be set once. - * This will update WebCore when the Sync runs in the C++ side. - * @param databasePath String path to the directory where databases should - * be saved. May be the empty string but should never be null. + * @see android.webkit.WebSettings#setDatabasePath(java.lang.String) */ + @Override public synchronized void setDatabasePath(String databasePath) { if (databasePath != null && !mDatabasePathHasBeenSet) { mDatabasePath = databasePath; @@ -1360,12 +1186,9 @@ public class WebSettings { } /** - * Set the path where the Geolocation permissions database should be saved. - * This will update WebCore when the Sync runs in the C++ side. - * @param databasePath String path to the directory where the Geolocation - * permissions database should be saved. May be the empty string but - * should never be null. + * @see android.webkit.WebSettings#setGeolocationDatabasePath(java.lang.String) */ + @Override public synchronized void setGeolocationDatabasePath(String databasePath) { if (databasePath != null && !databasePath.equals(mGeolocationDatabasePath)) { @@ -1375,9 +1198,9 @@ public class WebSettings { } /** - * Enable or disable the Application Cache API. - * @param flag Whether to enable the Application Cache API. + * @see android.webkit.WebSettings#setAppCacheEnabled(boolean) */ + @Override public synchronized void setAppCacheEnabled(boolean flag) { if (mAppCacheEnabled != flag) { mAppCacheEnabled = flag; @@ -1386,14 +1209,9 @@ public class WebSettings { } /** - * Set the path used by the Application Cache API to store files. This - * setting is applied to all WebViews in the application. In order for the - * Application Cache API to function, this method must be called with a - * path which exists and is writable by the application. This method may - * only be called once: repeated calls are ignored. - * @param path Path to the directory that should be used to store Application - * Cache files. + * @see android.webkit.WebSettings#setAppCachePath(java.lang.String) */ + @Override public synchronized void setAppCachePath(String path) { // We test for a valid path and for repeated setting on the native // side, but we can avoid syncing in some simple cases. @@ -1404,9 +1222,9 @@ public class WebSettings { } /** - * Set the maximum size for the Application Caches content. - * @param appCacheMaxSize the maximum size in bytes. + * @see android.webkit.WebSettings#setAppCacheMaxSize(long) */ + @Override public synchronized void setAppCacheMaxSize(long appCacheMaxSize) { if (appCacheMaxSize != mAppCacheMaxSize) { mAppCacheMaxSize = appCacheMaxSize; @@ -1415,10 +1233,9 @@ public class WebSettings { } /** - * Set whether the database storage API is enabled. - * @param flag boolean True if the WebView should use the database storage - * API. + * @see android.webkit.WebSettings#setDatabaseEnabled(boolean) */ + @Override public synchronized void setDatabaseEnabled(boolean flag) { if (mDatabaseEnabled != flag) { mDatabaseEnabled = flag; @@ -1427,10 +1244,9 @@ public class WebSettings { } /** - * Set whether the DOM storage API is enabled. - * @param flag boolean True if the WebView should use the DOM storage - * API. + * @see android.webkit.WebSettings#setDomStorageEnabled(boolean) */ + @Override public synchronized void setDomStorageEnabled(boolean flag) { if (mDomStorageEnabled != flag) { mDomStorageEnabled = flag; @@ -1439,26 +1255,25 @@ public class WebSettings { } /** - * Returns true if the DOM Storage API's are enabled. - * @return True if the DOM Storage API's are enabled. + * @see android.webkit.WebSettings#getDomStorageEnabled() */ + @Override public synchronized boolean getDomStorageEnabled() { return mDomStorageEnabled; } /** - * Return the path to where database storage API databases are saved for - * the current WebView. - * @return the String path to the database storage API databases. + * @see android.webkit.WebSettings#getDatabasePath() */ + @Override public synchronized String getDatabasePath() { return mDatabasePath; } /** - * Returns true if database storage API is enabled. - * @return True if the database storage API is enabled. + * @see android.webkit.WebSettings#getDatabaseEnabled() */ + @Override public synchronized boolean getDatabaseEnabled() { return mDatabaseEnabled; } @@ -1478,9 +1293,9 @@ public class WebSettings { } /** - * Sets whether Geolocation is enabled. - * @param flag Whether Geolocation should be enabled. + * @see android.webkit.WebSettings#setGeolocationEnabled(boolean) */ + @Override public synchronized void setGeolocationEnabled(boolean flag) { if (mGeolocationEnabled != flag) { mGeolocationEnabled = flag; @@ -1501,48 +1316,43 @@ public class WebSettings { } /** - * Return true if javascript is enabled. <b>Note: The default is false.</b> - * @return True if javascript is enabled. + * @see android.webkit.WebSettings#getJavaScriptEnabled() */ + @Override public synchronized boolean getJavaScriptEnabled() { return mJavaScriptEnabled; } /** - * Return true if plugins are enabled. - * @return True if plugins are enabled. - * @deprecated This method has been replaced by {@link #getPluginState} + * @see android.webkit.WebSettings#getPluginsEnabled() */ + @Override @Deprecated public synchronized boolean getPluginsEnabled() { return mPluginState == PluginState.ON; } /** - * Return the current plugin state. - * @return A value corresponding to the enum PluginState. + * @see android.webkit.WebSettings#getPluginState() */ + @Override public synchronized PluginState getPluginState() { return mPluginState; } /** - * Returns the directory that contains the plugin libraries. This method is - * obsolete since each plugin is now loaded from its own package. - * @return An empty string. - * @deprecated This method is no longer used as plugins are loaded from - * their own APK via the system's package manager. + * @see android.webkit.WebSettings#getPluginsPath() */ + @Override @Deprecated public synchronized String getPluginsPath() { return ""; } /** - * Tell javascript to open windows automatically. This applies to the - * javascript function window.open(). - * @param flag True if javascript can open windows automatically. + * @see android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically(boolean) */ + @Override public synchronized void setJavaScriptCanOpenWindowsAutomatically( boolean flag) { if (mJavaScriptCanOpenWindowsAutomatically != flag) { @@ -1552,19 +1362,17 @@ public class WebSettings { } /** - * Return true if javascript can open windows automatically. The default - * is false. - * @return True if javascript can open windows automatically during - * window.open(). + * @see android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically() */ + @Override public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() { return mJavaScriptCanOpenWindowsAutomatically; } /** - * Set the default text encoding name to use when decoding html pages. - * @param encoding The text encoding name. + * @see android.webkit.WebSettings#setDefaultTextEncodingName(java.lang.String) */ + @Override public synchronized void setDefaultTextEncodingName(String encoding) { if (encoding != null && !encoding.equals(mDefaultTextEncoding)) { mDefaultTextEncoding = encoding; @@ -1573,17 +1381,17 @@ public class WebSettings { } /** - * Get the default text encoding name. The default is "Latin-1". - * @return The default text encoding name as a string. + * @see android.webkit.WebSettings#getDefaultTextEncodingName() */ + @Override public synchronized String getDefaultTextEncodingName() { return mDefaultTextEncoding; } /** - * Set the WebView's user-agent string. If the string "ua" is null or empty, - * it will use the system default user-agent string. + * @see android.webkit.WebSettings#setUserAgentString(java.lang.String) */ + @Override public synchronized void setUserAgentString(String ua) { if (ua == null || ua.length() == 0) { synchronized(sLockForLocaleSettings) { @@ -1606,8 +1414,9 @@ public class WebSettings { } /** - * Return the WebView's user-agent string. + * @see android.webkit.WebSettings#getUserAgentString() */ + @Override public synchronized String getUserAgentString() { if (DESKTOP_USERAGENT.equals(mUserAgent) || IPHONE_USERAGENT.equals(mUserAgent) || @@ -1648,11 +1457,9 @@ public class WebSettings { } /** - * Tell the WebView whether it needs to set a node to have focus when - * {@link WebView#requestFocus(int, android.graphics.Rect)} is called. - * - * @param flag + * @see android.webkit.WebSettings#setNeedInitialFocus(boolean) */ + @Override public void setNeedInitialFocus(boolean flag) { if (mNeedInitialFocus != flag) { mNeedInitialFocus = flag; @@ -1665,11 +1472,9 @@ public class WebSettings { } /** - * Set the priority of the Render thread. Unlike the other settings, this - * one only needs to be called once per process. The default is NORMAL. - * - * @param priority RenderPriority, can be normal, high or low. + * @see android.webkit.WebSettings#setRenderPriority(android.webkit.WebSettingsClassic.RenderPriority) */ + @Override public synchronized void setRenderPriority(RenderPriority priority) { if (mRenderPriority != priority) { mRenderPriority = priority; @@ -1679,13 +1484,9 @@ public class WebSettings { } /** - * Override the way the cache is used. The way the cache is used is based - * on the navigation option. For a normal page load, the cache is checked - * and content is re-validated as needed. When navigating back, content is - * not revalidated, instead the content is just pulled from the cache. - * This function allows the client to override this behavior. - * @param mode One of the LOAD_ values. + * @see android.webkit.WebSettings#setCacheMode(int) */ + @Override public void setCacheMode(int mode) { if (mode != mOverrideCacheMode) { mOverrideCacheMode = mode; @@ -1694,9 +1495,9 @@ public class WebSettings { } /** - * Return the current setting for overriding the cache mode. For a full - * description, see the {@link #setCacheMode(int)} function. + * @see android.webkit.WebSettings#getCacheMode() */ + @Override public int getCacheMode() { return mOverrideCacheMode; } diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index 510c168..a01c42d 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -78,7 +78,7 @@ import java.util.ArrayList; private int mRingInset; - private WebView mWebView; + private WebViewClassic mWebView; private boolean mSingle; private int mWidthSpec; private int mHeightSpec; @@ -177,7 +177,7 @@ import java.util.ArrayList; * @param context The Context for this WebTextView. * @param webView The WebView that created this. */ - /* package */ WebTextView(Context context, WebView webView, int autoFillQueryId) { + /* package */ WebTextView(Context context, WebViewClassic webView, int autoFillQueryId) { super(context, null, com.android.internal.R.attr.webTextViewStyle); mWebView = webView; mMaxLength = -1; @@ -833,9 +833,9 @@ import java.util.ArrayList; } mInsideRemove = true; boolean isFocused = hasFocus(); - mWebView.removeView(this); + mWebView.getWebView().removeView(this); if (isFocused) { - mWebView.requestFocus(); + mWebView.getWebView().requestFocus(); } mInsideRemove = false; mHandler.removeCallbacksAndMessages(null); @@ -997,7 +997,7 @@ import java.util.ArrayList; } if (getParent() == null) { // Insert the view so that it's drawn first (at index 0) - mWebView.addView(this, 0, lp); + mWebView.getWebView().addView(this, 0, lp); } else if (needsUpdate) { setLayoutParams(lp); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index a850379..a561577 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -16,126 +16,35 @@ package android.webkit; -import android.animation.ObjectAnimator; import android.annotation.Widget; -import android.app.ActivityManager; -import android.app.AlertDialog; -import android.content.BroadcastReceiver; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.ComponentCallbacks2; import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.database.DataSetObserver; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.BitmapShader; import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.DrawFilter; -import android.graphics.Paint; -import android.graphics.PaintFlagsDrawFilter; import android.graphics.Picture; -import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.RegionIterator; -import android.graphics.Shader; import android.graphics.drawable.Drawable; -import android.net.Proxy; -import android.net.ProxyProperties; -import android.net.Uri; import android.net.http.SslCertificate; -import android.os.AsyncTask; import android.os.Bundle; -import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.StrictMode; -import android.os.SystemClock; -import android.provider.Settings; -import android.security.KeyChain; -import android.speech.tts.TextToSpeech; -import android.text.Editable; -import android.text.InputType; -import android.text.Selection; -import android.text.TextUtils; import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.EventLog; import android.util.Log; -import android.view.Display; -import android.view.Gravity; -import android.view.HapticFeedbackConstants; -import android.view.HardwareCanvas; -import android.view.InputDevice; -import android.view.KeyCharacterMap; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.ScaleGestureDetector; -import android.view.SoundEffectConstants; -import android.view.VelocityTracker; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.ViewParent; +import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; -import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; -import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodManager; -import android.webkit.HTML5VideoInline; -import android.webkit.WebTextView.AutoCompleteAdapter; -import android.webkit.WebViewCore.DrawData; -import android.webkit.WebViewCore.EventHub; -import android.webkit.WebViewCore.TextFieldInitData; -import android.webkit.WebViewCore.TouchEventData; -import android.webkit.WebViewCore.TouchHighlightData; -import android.webkit.WebViewCore.WebKitHitTest; import android.widget.AbsoluteLayout; -import android.widget.Adapter; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.CheckedTextView; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.OverScroller; -import android.widget.PopupWindow; -import android.widget.TextView; -import android.widget.Toast; - -import junit.framework.Assert; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.Vector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * <p>A View that displays web pages. This class is the basis upon which you @@ -345,452 +254,25 @@ import java.util.regex.Pattern; * * */ +/* + * Implementation notes. + * The WebView is a thin API class that delegates its public API to a backend WebViewProvider + * class instance. WebView extends {@link AbsoluteLayout} for backward compatibility reasons. + * Methods are delegated to the provider implementation: all public API methods introduced in this + * file are fully delegated, whereas public and protected methods from the View base classes are + * only delegated where a specific need exists for them to do so. + */ @Widget public class WebView extends AbsoluteLayout implements ViewTreeObserver.OnGlobalFocusChangeListener, ViewGroup.OnHierarchyChangeListener { - private class InnerGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { - @Override - public void onGlobalLayout() { - if (isShown()) { - setGLRectViewport(); - } - } - } - - private class InnerScrollChangedListener implements ViewTreeObserver.OnScrollChangedListener { - @Override - public void onScrollChanged() { - if (isShown()) { - setGLRectViewport(); - } - } - } - - /** - * InputConnection used for ContentEditable. This captures changes - * to the text and sends them either as key strokes or text changes. - */ - private class WebViewInputConnection extends BaseInputConnection { - // Used for mapping characters to keys typed. - private KeyCharacterMap mKeyCharacterMap; - private boolean mIsKeySentByMe; - private int mInputType; - private int mImeOptions; - private String mHint; - private int mMaxLength; - - public WebViewInputConnection() { - super(WebView.this, true); - } - - @Override - public boolean sendKeyEvent(KeyEvent event) { - // Some IMEs send key events directly using sendKeyEvents. - // WebViewInputConnection should treat these as text changes. - if (!mIsKeySentByMe) { - if (event.getAction() == KeyEvent.ACTION_UP) { - if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) { - return deleteSurroundingText(1, 0); - } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) { - return deleteSurroundingText(0, 1); - } else if (event.getUnicodeChar() != 0){ - String newComposingText = - Character.toString((char)event.getUnicodeChar()); - return commitText(newComposingText, 1); - } - } else if (event.getAction() == KeyEvent.ACTION_DOWN && - (event.getKeyCode() == KeyEvent.KEYCODE_DEL - || event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL - || event.getUnicodeChar() != 0)) { - return true; // only act on action_down - } - } - return super.sendKeyEvent(event); - } - - public void setTextAndKeepSelection(CharSequence text) { - Editable editable = getEditable(); - int selectionStart = Selection.getSelectionStart(editable); - int selectionEnd = Selection.getSelectionEnd(editable); - text = limitReplaceTextByMaxLength(text, editable.length()); - editable.replace(0, editable.length(), text); - restartInput(); - // Keep the previous selection. - selectionStart = Math.min(selectionStart, editable.length()); - selectionEnd = Math.min(selectionEnd, editable.length()); - setSelection(selectionStart, selectionEnd); - } - - public void replaceSelection(CharSequence text) { - Editable editable = getEditable(); - int selectionStart = Selection.getSelectionStart(editable); - int selectionEnd = Selection.getSelectionEnd(editable); - text = limitReplaceTextByMaxLength(text, selectionEnd - selectionStart); - setNewText(selectionStart, selectionEnd, text); - editable.replace(selectionStart, selectionEnd, text); - restartInput(); - // Move caret to the end of the new text - int newCaret = selectionStart + text.length(); - setSelection(newCaret, newCaret); - } - - @Override - public boolean setComposingText(CharSequence text, int newCursorPosition) { - Editable editable = getEditable(); - int start = getComposingSpanStart(editable); - int end = getComposingSpanEnd(editable); - if (start < 0 || end < 0) { - start = Selection.getSelectionStart(editable); - end = Selection.getSelectionEnd(editable); - } - if (end < start) { - int temp = end; - end = start; - start = temp; - } - CharSequence limitedText = limitReplaceTextByMaxLength(text, end - start); - setNewText(start, end, limitedText); - if (limitedText != text) { - newCursorPosition -= text.length() - limitedText.length(); - } - super.setComposingText(limitedText, newCursorPosition); - if (limitedText != text) { - restartInput(); - int lastCaret = start + limitedText.length(); - finishComposingText(); - setSelection(lastCaret, lastCaret); - } - return true; - } - - @Override - public boolean commitText(CharSequence text, int newCursorPosition) { - setComposingText(text, newCursorPosition); - int cursorPosition = Selection.getSelectionEnd(getEditable()); - setComposingRegion(cursorPosition, cursorPosition); - return true; - } - - @Override - public boolean deleteSurroundingText(int leftLength, int rightLength) { - Editable editable = getEditable(); - int cursorPosition = Selection.getSelectionEnd(editable); - int startDelete = Math.max(0, cursorPosition - leftLength); - int endDelete = Math.min(editable.length(), - cursorPosition + rightLength); - setNewText(startDelete, endDelete, ""); - return super.deleteSurroundingText(leftLength, rightLength); - } - - @Override - public boolean performEditorAction(int editorAction) { - - boolean handled = true; - switch (editorAction) { - case EditorInfo.IME_ACTION_NEXT: - WebView.this.requestFocus(FOCUS_FORWARD); - break; - case EditorInfo.IME_ACTION_PREVIOUS: - WebView.this.requestFocus(FOCUS_BACKWARD); - break; - case EditorInfo.IME_ACTION_DONE: - WebView.this.hideSoftKeyboard(); - break; - case EditorInfo.IME_ACTION_GO: - case EditorInfo.IME_ACTION_SEARCH: - WebView.this.hideSoftKeyboard(); - String text = getEditable().toString(); - passToJavaScript(text, new KeyEvent(KeyEvent.ACTION_DOWN, - KeyEvent.KEYCODE_ENTER)); - passToJavaScript(text, new KeyEvent(KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_ENTER)); - break; - - default: - handled = super.performEditorAction(editorAction); - break; - } - - return handled; - } - - public void initEditorInfo(WebViewCore.TextFieldInitData initData) { - int type = initData.mType; - int inputType = InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT; - int imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI - | EditorInfo.IME_FLAG_NO_FULLSCREEN; - if (!initData.mIsSpellCheckEnabled) { - inputType |= InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; - } - if (WebTextView.TEXT_AREA != type - && initData.mIsTextFieldNext) { - imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT; - } - switch (type) { - case WebTextView.NORMAL_TEXT_FIELD: - imeOptions |= EditorInfo.IME_ACTION_GO; - break; - case WebTextView.TEXT_AREA: - inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE - | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES - | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; - imeOptions |= EditorInfo.IME_ACTION_NONE; - break; - case WebTextView.PASSWORD: - inputType |= EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD; - imeOptions |= EditorInfo.IME_ACTION_GO; - break; - case WebTextView.SEARCH: - imeOptions |= EditorInfo.IME_ACTION_SEARCH; - break; - case WebTextView.EMAIL: - // inputType needs to be overwritten because of the different text variation. - inputType = InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS; - imeOptions |= EditorInfo.IME_ACTION_GO; - break; - case WebTextView.NUMBER: - // inputType needs to be overwritten because of the different class. - inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL - | InputType.TYPE_NUMBER_FLAG_SIGNED | InputType.TYPE_NUMBER_FLAG_DECIMAL; - // Number and telephone do not have both a Tab key and an - // action, so set the action to NEXT - imeOptions |= EditorInfo.IME_ACTION_NEXT; - break; - case WebTextView.TELEPHONE: - // inputType needs to be overwritten because of the different class. - inputType = InputType.TYPE_CLASS_PHONE; - imeOptions |= EditorInfo.IME_ACTION_NEXT; - break; - case WebTextView.URL: - // TYPE_TEXT_VARIATION_URI prevents Tab key from showing, so - // exclude it for now. - imeOptions |= EditorInfo.IME_ACTION_GO; - inputType |= InputType.TYPE_TEXT_VARIATION_URI; - break; - default: - imeOptions |= EditorInfo.IME_ACTION_GO; - break; - } - mHint = initData.mLabel; - mInputType = inputType; - mImeOptions = imeOptions; - mMaxLength = initData.mMaxLength; - } - - public void setupEditorInfo(EditorInfo outAttrs) { - outAttrs.inputType = mInputType; - outAttrs.imeOptions = mImeOptions; - outAttrs.hintText = mHint; - outAttrs.initialCapsMode = getCursorCapsMode(InputType.TYPE_CLASS_TEXT); - } - - /** - * Sends a text change to webkit indirectly. If it is a single- - * character add or delete, it sends it as a key stroke. If it cannot - * be represented as a key stroke, it sends it as a field change. - * @param start The start offset (inclusive) of the text being changed. - * @param end The end offset (exclusive) of the text being changed. - * @param text The new text to replace the changed text. - */ - private void setNewText(int start, int end, CharSequence text) { - mIsKeySentByMe = true; - Editable editable = getEditable(); - CharSequence original = editable.subSequence(start, end); - boolean isCharacterAdd = false; - boolean isCharacterDelete = false; - int textLength = text.length(); - int originalLength = original.length(); - if (textLength > originalLength) { - isCharacterAdd = (textLength == originalLength + 1) - && TextUtils.regionMatches(text, 0, original, 0, - originalLength); - } else if (originalLength > textLength) { - isCharacterDelete = (textLength == originalLength - 1) - && TextUtils.regionMatches(text, 0, original, 0, - textLength); - } - if (isCharacterAdd) { - sendCharacter(text.charAt(textLength - 1)); - } else if (isCharacterDelete) { - sendKey(KeyEvent.KEYCODE_DEL); - } else if ((textLength != originalLength) || - !TextUtils.regionMatches(text, 0, original, 0, - textLength)) { - // Send a message so that key strokes and text replacement - // do not come out of order. - Message replaceMessage = mPrivateHandler.obtainMessage( - REPLACE_TEXT, start, end, text.toString()); - mPrivateHandler.sendMessage(replaceMessage); - } - mIsKeySentByMe = false; - } - - /** - * Send a single character to the WebView as a key down and up event. - * @param c The character to be sent. - */ - private void sendCharacter(char c) { - if (mKeyCharacterMap == null) { - mKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); - } - char[] chars = new char[1]; - chars[0] = c; - KeyEvent[] events = mKeyCharacterMap.getEvents(chars); - if (events != null) { - for (KeyEvent event : events) { - sendKeyEvent(event); - } - } else { - Message msg = mPrivateHandler.obtainMessage(KEY_PRESS, (int) c, 0); - mPrivateHandler.sendMessage(msg); - } - } - - /** - * Send a key event for a specific key code, not a standard - * unicode character. - * @param keyCode The key code to send. - */ - private void sendKey(int keyCode) { - long eventTime = SystemClock.uptimeMillis(); - sendKeyEvent(new KeyEvent(eventTime, eventTime, - KeyEvent.ACTION_DOWN, keyCode, 0, 0, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, - KeyEvent.FLAG_SOFT_KEYBOARD)); - sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, - KeyEvent.ACTION_UP, keyCode, 0, 0, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, - KeyEvent.FLAG_SOFT_KEYBOARD)); - } - - private CharSequence limitReplaceTextByMaxLength(CharSequence text, - int numReplaced) { - if (mMaxLength > 0) { - Editable editable = getEditable(); - int maxReplace = mMaxLength - editable.length() + numReplaced; - if (maxReplace < text.length()) { - maxReplace = Math.max(maxReplace, 0); - // New length is greater than the maximum. trim it down. - text = text.subSequence(0, maxReplace); - } - } - return text; - } - - private void restartInput() { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - // Since the text has changed, do not allow the IME to replace the - // existing text as though it were a completion. - imm.restartInput(WebView.this); - } - } - } - - private class PastePopupWindow extends PopupWindow implements OnClickListener { - private ViewGroup mContentView; - private TextView mPasteTextView; - - public PastePopupWindow() { - super(WebView.this.mContext, null, - com.android.internal.R.attr.textSelectHandleWindowStyle); - setClippingEnabled(true); - LinearLayout linearLayout = new LinearLayout(WebView.this.getContext()); - linearLayout.setOrientation(LinearLayout.HORIZONTAL); - mContentView = linearLayout; - mContentView.setBackgroundResource( - com.android.internal.R.drawable.text_edit_paste_window); - - LayoutInflater inflater = (LayoutInflater)WebView.this.mContext. - getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - ViewGroup.LayoutParams wrapContent = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - - mPasteTextView = (TextView) inflater.inflate( - com.android.internal.R.layout.text_edit_action_popup_text, null); - mPasteTextView.setLayoutParams(wrapContent); - mContentView.addView(mPasteTextView); - mPasteTextView.setText(com.android.internal.R.string.paste); - mPasteTextView.setOnClickListener(this); - this.setContentView(mContentView); - } - - public void show(Rect cursorRect, int windowLeft, int windowTop) { - measureContent(); - - int width = mContentView.getMeasuredWidth(); - int height = mContentView.getMeasuredHeight(); - int y = cursorRect.top - height; - if (y < windowTop) { - // There's not enough room vertically, move it below the - // handle. - // The selection handle is vertically offset by 1/4 of the - // line height. - y = cursorRect.bottom - (cursorRect.height() / 4) + - mSelectHandleCenter.getIntrinsicHeight(); - } - int x = cursorRect.centerX() - (width / 2); - if (x < windowLeft) { - x = windowLeft; - } - if (!isShowing()) { - showAtLocation(WebView.this, Gravity.NO_GRAVITY, x, y); - } - update(x, y, width, height); - } - - public void hide() { - dismiss(); - } - - @Override - public void onClick(View view) { - pasteFromClipboard(); - selectionDone(); - } - - protected void measureContent() { - final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); - mContentView.measure( - View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, - View.MeasureSpec.AT_MOST), - View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, - View.MeasureSpec.AT_MOST)); - } - } - - // The listener to capture global layout change event. - private InnerGlobalLayoutListener mGlobalLayoutListener = null; - - // The listener to capture scroll event. - private InnerScrollChangedListener mScrollChangedListener = null; + // Default Provider factory class name. + private static final String DEFAULT_WEB_VIEW_FACTORY = "android.webkit.WebViewClassic$Factory"; - // if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing - // the screen all-the-time. Good for profiling our drawing code - static private final boolean AUTO_REDRAW_HACK = false; - // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK - private boolean mAutoRedraw; - - // Reference to the AlertDialog displayed by InvokeListBox. - // It's used to dismiss the dialog in destroy if not done before. - private AlertDialog mListBoxDialog = null; - - static final String LOGTAG = "webview"; - - private ZoomManager mZoomManager; - - private final Rect mGLRectViewport = new Rect(); - private final Rect mViewRectViewport = new Rect(); - private final RectF mVisibleContentRect = new RectF(); - private boolean mGLViewportEmpty = false; - WebViewInputConnection mInputConnection = null; - private int mFieldPointer; - private PastePopupWindow mPasteWindow; + private static final String LOGTAG = "webview_proxy"; + // TODO: flip DEBUG to always be disabled. + private static final boolean DEBUG = true; /** * Transportation object for returning WebView across thread boundaries. @@ -815,531 +297,6 @@ public class WebView extends AbsoluteLayout } } - private static class OnTrimMemoryListener implements ComponentCallbacks2 { - private static OnTrimMemoryListener sInstance = null; - - static void init(Context c) { - if (sInstance == null) { - sInstance = new OnTrimMemoryListener(c.getApplicationContext()); - } - } - - private OnTrimMemoryListener(Context c) { - c.registerComponentCallbacks(this); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - // Ignore - } - - @Override - public void onLowMemory() { - // Ignore - } - - @Override - public void onTrimMemory(int level) { - if (DebugFlags.WEB_VIEW) { - Log.d("WebView", "onTrimMemory: " + level); - } - // When framework reset EGL context during high memory pressure, all - // the existing GL resources for the html5 video will be destroyed - // at native side. - // Here we just need to clean up the Surface Texture which is static. - HTML5VideoInline.cleanupSurfaceTexture(); - WebView.nativeOnTrimMemory(level); - } - - } - - // A final CallbackProxy shared by WebViewCore and BrowserFrame. - private final CallbackProxy mCallbackProxy; - - private final WebViewDatabase mDatabase; - - // SSL certificate for the main top-level page (if secure) - private SslCertificate mCertificate; - - // Native WebView pointer that is 0 until the native object has been - // created. - private int mNativeClass; - // This would be final but it needs to be set to null when the WebView is - // destroyed. - private WebViewCore mWebViewCore; - // Handler for dispatching UI messages. - /* package */ final Handler mPrivateHandler = new PrivateHandler(); - private WebTextView mWebTextView; - // Used to ignore changes to webkit text that arrives to the UI side after - // more key events. - private int mTextGeneration; - - /* package */ void incrementTextGeneration() { mTextGeneration++; } - - // Used by WebViewCore to create child views. - /* package */ final ViewManager mViewManager; - - // Used to display in full screen mode - PluginFullScreenHolder mFullScreenHolder; - - /** - * Position of the last touch event in pixels. - * Use integer to prevent loss of dragging delta calculation accuracy; - * which was done in float and converted to integer, and resulted in gradual - * and compounding touch position and view dragging mismatch. - */ - private int mLastTouchX; - private int mLastTouchY; - private int mStartTouchX; - private int mStartTouchY; - private float mAverageAngle; - - /** - * Time of the last touch event. - */ - private long mLastTouchTime; - - /** - * Time of the last time sending touch event to WebViewCore - */ - private long mLastSentTouchTime; - - /** - * The minimum elapsed time before sending another ACTION_MOVE event to - * WebViewCore. This really should be tuned for each type of the devices. - * For example in Google Map api test case, it takes Dream device at least - * 150ms to do a full cycle in the WebViewCore by processing a touch event, - * triggering the layout and drawing the picture. While the same process - * takes 60+ms on the current high speed device. If we make - * TOUCH_SENT_INTERVAL too small, there will be multiple touch events sent - * to WebViewCore queue and the real layout and draw events will be pushed - * to further, which slows down the refresh rate. Choose 50 to favor the - * current high speed devices. For Dream like devices, 100 is a better - * choice. Maybe make this in the buildspec later. - * (Update 12/14/2010: changed to 0 since current device should be able to - * handle the raw events and Map team voted to have the raw events too. - */ - private static final int TOUCH_SENT_INTERVAL = 0; - private int mCurrentTouchInterval = TOUCH_SENT_INTERVAL; - - /** - * Helper class to get velocity for fling - */ - VelocityTracker mVelocityTracker; - private int mMaximumFling; - private float mLastVelocity; - private float mLastVelX; - private float mLastVelY; - - // The id of the native layer being scrolled. - private int mCurrentScrollingLayerId; - private Rect mScrollingLayerRect = new Rect(); - - // only trigger accelerated fling if the new velocity is at least - // MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION times of the previous velocity - private static final float MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION = 0.2f; - - /** - * Touch mode - */ - private int mTouchMode = TOUCH_DONE_MODE; - private static final int TOUCH_INIT_MODE = 1; - private static final int TOUCH_DRAG_START_MODE = 2; - private static final int TOUCH_DRAG_MODE = 3; - private static final int TOUCH_SHORTPRESS_START_MODE = 4; - private static final int TOUCH_SHORTPRESS_MODE = 5; - private static final int TOUCH_DOUBLE_TAP_MODE = 6; - private static final int TOUCH_DONE_MODE = 7; - private static final int TOUCH_PINCH_DRAG = 8; - private static final int TOUCH_DRAG_LAYER_MODE = 9; - - // Whether to forward the touch events to WebCore - // Can only be set by WebKit via JNI. - private boolean mForwardTouchEvents = false; - - // Whether to prevent default during touch. The initial value depends on - // mForwardTouchEvents. If WebCore wants all the touch events, it says yes - // for touch down. Otherwise UI will wait for the answer of the first - // confirmed move before taking over the control. - private static final int PREVENT_DEFAULT_NO = 0; - private static final int PREVENT_DEFAULT_MAYBE_YES = 1; - private static final int PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN = 2; - private static final int PREVENT_DEFAULT_YES = 3; - private static final int PREVENT_DEFAULT_IGNORE = 4; - private int mPreventDefault = PREVENT_DEFAULT_IGNORE; - - // true when the touch movement exceeds the slop - private boolean mConfirmMove; - - // if true, touch events will be first processed by WebCore, if prevent - // default is not set, the UI will continue handle them. - private boolean mDeferTouchProcess; - - // to avoid interfering with the current touch events, track them - // separately. Currently no snapping or fling in the deferred process mode - private int mDeferTouchMode = TOUCH_DONE_MODE; - private float mLastDeferTouchX; - private float mLastDeferTouchY; - - // To keep track of whether the current drag was initiated by a WebTextView, - // so that we know not to hide the cursor - boolean mDragFromTextInput; - - // Whether or not to draw the cursor ring. - private boolean mDrawCursorRing = true; - - // true if onPause has been called (and not onResume) - private boolean mIsPaused; - - private HitTestResult mInitialHitTestResult; - private WebKitHitTest mFocusedNode; - - /** - * Customizable constant - */ - // pre-computed square of ViewConfiguration.getScaledTouchSlop() - private int mTouchSlopSquare; - // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop() - private int mDoubleTapSlopSquare; - // pre-computed density adjusted navigation slop - private int mNavSlop; - // This should be ViewConfiguration.getTapTimeout() - // But system time out is 100ms, which is too short for the browser. - // In the browser, if it switches out of tap too soon, jump tap won't work. - // In addition, a double tap on a trackpad will always have a duration of - // 300ms, so this value must be at least that (otherwise we will timeout the - // first tap and convert it to a long press). - private static final int TAP_TIMEOUT = 300; - // This should be ViewConfiguration.getLongPressTimeout() - // But system time out is 500ms, which is too short for the browser. - // With a short timeout, it's difficult to treat trigger a short press. - private static final int LONG_PRESS_TIMEOUT = 1000; - // needed to avoid flinging after a pause of no movement - private static final int MIN_FLING_TIME = 250; - // draw unfiltered after drag is held without movement - private static final int MOTIONLESS_TIME = 100; - // The amount of content to overlap between two screens when going through - // pages with the space bar, in pixels. - private static final int PAGE_SCROLL_OVERLAP = 24; - - /** - * These prevent calling requestLayout if either dimension is fixed. This - * depends on the layout parameters and the measure specs. - */ - boolean mWidthCanMeasure; - boolean mHeightCanMeasure; - - // Remember the last dimensions we sent to the native side so we can avoid - // sending the same dimensions more than once. - int mLastWidthSent; - int mLastHeightSent; - // Since view height sent to webkit could be fixed to avoid relayout, this - // value records the last sent actual view height. - int mLastActualHeightSent; - - private int mContentWidth; // cache of value from WebViewCore - private int mContentHeight; // cache of value from WebViewCore - - // Need to have the separate control for horizontal and vertical scrollbar - // style than the View's single scrollbar style - private boolean mOverlayHorizontalScrollbar = true; - private boolean mOverlayVerticalScrollbar = false; - - // our standard speed. this way small distances will be traversed in less - // time than large distances, but we cap the duration, so that very large - // distances won't take too long to get there. - private static final int STD_SPEED = 480; // pixels per second - // time for the longest scroll animation - private static final int MAX_DURATION = 750; // milliseconds - private static final int SLIDE_TITLE_DURATION = 500; // milliseconds - - // Used by OverScrollGlow - OverScroller mScroller; - - private boolean mInOverScrollMode = false; - private static Paint mOverScrollBackground; - private static Paint mOverScrollBorder; - - private boolean mWrapContent; - private static final int MOTIONLESS_FALSE = 0; - private static final int MOTIONLESS_PENDING = 1; - private static final int MOTIONLESS_TRUE = 2; - private static final int MOTIONLESS_IGNORE = 3; - private int mHeldMotionless; - - // An instance for injecting accessibility in WebViews with disabled - // JavaScript or ones for which no accessibility script exists - private AccessibilityInjector mAccessibilityInjector; - - // flag indicating if accessibility script is injected so we - // know to handle Shift and arrows natively first - private boolean mAccessibilityScriptInjected; - - - /** - * How long the caret handle will last without being touched. - */ - private static final long CARET_HANDLE_STAMINA_MS = 3000; - - private Drawable mSelectHandleLeft; - private Drawable mSelectHandleRight; - private Drawable mSelectHandleCenter; - private Rect mSelectCursorBase = new Rect(); - private int mSelectCursorBaseLayerId; - private Rect mSelectCursorExtent = new Rect(); - private int mSelectCursorExtentLayerId; - private Rect mSelectDraggingCursor; - private Point mSelectDraggingOffset = new Point(); - private boolean mIsCaretSelection; - static final int HANDLE_ID_START = 0; - static final int HANDLE_ID_END = 1; - static final int HANDLE_ID_BASE = 2; - static final int HANDLE_ID_EXTENT = 3; - - static boolean sDisableNavcache = false; - static boolean sEnableWebTextView = false; - // the color used to highlight the touch rectangles - static final int HIGHLIGHT_COLOR = 0x6633b5e5; - // the region indicating where the user touched on the screen - private Region mTouchHighlightRegion = new Region(); - // the paint for the touch highlight - private Paint mTouchHightlightPaint = new Paint(); - // debug only - private static final boolean DEBUG_TOUCH_HIGHLIGHT = true; - private static final int TOUCH_HIGHLIGHT_ELAPSE_TIME = 2000; - private Paint mTouchCrossHairColor; - private int mTouchHighlightX; - private int mTouchHighlightY; - private long mTouchHighlightRequested; - - // Basically this proxy is used to tell the Video to update layer tree at - // SetBaseLayer time and to pause when WebView paused. - private HTML5VideoViewProxy mHTML5VideoViewProxy; - - // If we are using a set picture, don't send view updates to webkit - private boolean mBlockWebkitViewMessages = false; - - // cached value used to determine if we need to switch drawing models - private boolean mHardwareAccelSkia = false; - - /* - * Private message ids - */ - private static final int REMEMBER_PASSWORD = 1; - private static final int NEVER_REMEMBER_PASSWORD = 2; - private static final int SWITCH_TO_SHORTPRESS = 3; - private static final int SWITCH_TO_LONGPRESS = 4; - private static final int RELEASE_SINGLE_TAP = 5; - private static final int REQUEST_FORM_DATA = 6; - private static final int DRAG_HELD_MOTIONLESS = 8; - private static final int AWAKEN_SCROLL_BARS = 9; - private static final int PREVENT_DEFAULT_TIMEOUT = 10; - private static final int SCROLL_SELECT_TEXT = 11; - - - private static final int FIRST_PRIVATE_MSG_ID = REMEMBER_PASSWORD; - private static final int LAST_PRIVATE_MSG_ID = SCROLL_SELECT_TEXT; - - /* - * Package message ids - */ - static final int SCROLL_TO_MSG_ID = 101; - static final int NEW_PICTURE_MSG_ID = 105; - static final int UPDATE_TEXT_ENTRY_MSG_ID = 106; - static final int WEBCORE_INITIALIZED_MSG_ID = 107; - static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 108; - static final int UPDATE_ZOOM_RANGE = 109; - static final int UNHANDLED_NAV_KEY = 110; - static final int CLEAR_TEXT_ENTRY = 111; - static final int UPDATE_TEXT_SELECTION_MSG_ID = 112; - static final int SHOW_RECT_MSG_ID = 113; - static final int LONG_PRESS_CENTER = 114; - static final int PREVENT_TOUCH_ID = 115; - static final int WEBCORE_NEED_TOUCH_EVENTS = 116; - // obj=Rect in doc coordinates - static final int INVAL_RECT_MSG_ID = 117; - static final int REQUEST_KEYBOARD = 118; - static final int DO_MOTION_UP = 119; - static final int SHOW_FULLSCREEN = 120; - static final int HIDE_FULLSCREEN = 121; - static final int DOM_FOCUS_CHANGED = 122; - static final int REPLACE_BASE_CONTENT = 123; - static final int FORM_DID_BLUR = 124; - static final int RETURN_LABEL = 125; - static final int UPDATE_MATCH_COUNT = 126; - static final int CENTER_FIT_RECT = 127; - static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128; - static final int SET_SCROLLBAR_MODES = 129; - static final int SELECTION_STRING_CHANGED = 130; - static final int HIT_TEST_RESULT = 131; - static final int SAVE_WEBARCHIVE_FINISHED = 132; - - static final int SET_AUTOFILLABLE = 133; - static final int AUTOFILL_COMPLETE = 134; - - static final int SELECT_AT = 135; - static final int SCREEN_ON = 136; - static final int ENTER_FULLSCREEN_VIDEO = 137; - static final int UPDATE_SELECTION = 138; - static final int UPDATE_ZOOM_DENSITY = 139; - static final int EXIT_FULLSCREEN_VIDEO = 140; - - static final int COPY_TO_CLIPBOARD = 141; - static final int INIT_EDIT_FIELD = 142; - static final int REPLACE_TEXT = 143; - static final int CLEAR_CARET_HANDLE = 144; - static final int KEY_PRESS = 145; - - private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID; - private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT; - - static final String[] HandlerPrivateDebugString = { - "REMEMBER_PASSWORD", // = 1; - "NEVER_REMEMBER_PASSWORD", // = 2; - "SWITCH_TO_SHORTPRESS", // = 3; - "SWITCH_TO_LONGPRESS", // = 4; - "RELEASE_SINGLE_TAP", // = 5; - "REQUEST_FORM_DATA", // = 6; - "RESUME_WEBCORE_PRIORITY", // = 7; - "DRAG_HELD_MOTIONLESS", // = 8; - "AWAKEN_SCROLL_BARS", // = 9; - "PREVENT_DEFAULT_TIMEOUT", // = 10; - "SCROLL_SELECT_TEXT" // = 11; - }; - - static final String[] HandlerPackageDebugString = { - "SCROLL_TO_MSG_ID", // = 101; - "102", // = 102; - "103", // = 103; - "104", // = 104; - "NEW_PICTURE_MSG_ID", // = 105; - "UPDATE_TEXT_ENTRY_MSG_ID", // = 106; - "WEBCORE_INITIALIZED_MSG_ID", // = 107; - "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 108; - "UPDATE_ZOOM_RANGE", // = 109; - "UNHANDLED_NAV_KEY", // = 110; - "CLEAR_TEXT_ENTRY", // = 111; - "UPDATE_TEXT_SELECTION_MSG_ID", // = 112; - "SHOW_RECT_MSG_ID", // = 113; - "LONG_PRESS_CENTER", // = 114; - "PREVENT_TOUCH_ID", // = 115; - "WEBCORE_NEED_TOUCH_EVENTS", // = 116; - "INVAL_RECT_MSG_ID", // = 117; - "REQUEST_KEYBOARD", // = 118; - "DO_MOTION_UP", // = 119; - "SHOW_FULLSCREEN", // = 120; - "HIDE_FULLSCREEN", // = 121; - "DOM_FOCUS_CHANGED", // = 122; - "REPLACE_BASE_CONTENT", // = 123; - "FORM_DID_BLUR", // = 124; - "RETURN_LABEL", // = 125; - "UPDATE_MATCH_COUNT", // = 126; - "CENTER_FIT_RECT", // = 127; - "REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128; - "SET_SCROLLBAR_MODES", // = 129; - "SELECTION_STRING_CHANGED", // = 130; - "SET_TOUCH_HIGHLIGHT_RECTS", // = 131; - "SAVE_WEBARCHIVE_FINISHED", // = 132; - "SET_AUTOFILLABLE", // = 133; - "AUTOFILL_COMPLETE", // = 134; - "SELECT_AT", // = 135; - "SCREEN_ON", // = 136; - "ENTER_FULLSCREEN_VIDEO", // = 137; - "UPDATE_SELECTION", // = 138; - "UPDATE_ZOOM_DENSITY" // = 139; - }; - - // If the site doesn't use the viewport meta tag to specify the viewport, - // use DEFAULT_VIEWPORT_WIDTH as the default viewport width - static final int DEFAULT_VIEWPORT_WIDTH = 980; - - // normally we try to fit the content to the minimum preferred width - // calculated by the Webkit. To avoid the bad behavior when some site's - // minimum preferred width keeps growing when changing the viewport width or - // the minimum preferred width is huge, an upper limit is needed. - static int sMaxViewportWidth = DEFAULT_VIEWPORT_WIDTH; - - // initial scale in percent. 0 means using default. - private int mInitialScaleInPercent = 0; - - // Whether or not a scroll event should be sent to webkit. This is only set - // to false when restoring the scroll position. - private boolean mSendScrollEvent = true; - - private int mSnapScrollMode = SNAP_NONE; - private static final int SNAP_NONE = 0; - private static final int SNAP_LOCK = 1; // not a separate state - private static final int SNAP_X = 2; // may be combined with SNAP_LOCK - private static final int SNAP_Y = 4; // may be combined with SNAP_LOCK - private boolean mSnapPositive; - - // keep these in sync with their counterparts in WebView.cpp - private static final int DRAW_EXTRAS_NONE = 0; - private static final int DRAW_EXTRAS_SELECTION = 1; - private static final int DRAW_EXTRAS_CURSOR_RING = 2; - - // keep this in sync with WebCore:ScrollbarMode in WebKit - private static final int SCROLLBAR_AUTO = 0; - private static final int SCROLLBAR_ALWAYSOFF = 1; - // as we auto fade scrollbar, this is ignored. - private static final int SCROLLBAR_ALWAYSON = 2; - private int mHorizontalScrollBarMode = SCROLLBAR_AUTO; - private int mVerticalScrollBarMode = SCROLLBAR_AUTO; - - // constants for determining script injection strategy - private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1; - private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0; - private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1; - - // the alias via which accessibility JavaScript interface is exposed - private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility"; - - // Template for JavaScript that injects a screen-reader. - private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE = - "javascript:(function() {" + - " var chooser = document.createElement('script');" + - " chooser.type = 'text/javascript';" + - " chooser.src = '%1s';" + - " document.getElementsByTagName('head')[0].appendChild(chooser);" + - " })();"; - - // Regular expression that matches the "axs" URL parameter. - // The value of 0 means the accessibility script is opted out - // The value of 1 means the accessibility script is already injected - private static final String PATTERN_MATCH_AXS_URL_PARAMETER = "(\\?axs=(0|1))|(&axs=(0|1))"; - - // TextToSpeech instance exposed to JavaScript to the injected screenreader. - private TextToSpeech mTextToSpeech; - - // variable to cache the above pattern in case accessibility is enabled. - private Pattern mMatchAxsUrlParameterPattern; - - /** - * Max distance to overscroll by in pixels. - * This how far content can be pulled beyond its normal bounds by the user. - */ - private int mOverscrollDistance; - - /** - * Max distance to overfling by in pixels. - * This is how far flinged content can move beyond the end of its normal bounds. - */ - private int mOverflingDistance; - - private OverScrollGlow mOverScrollGlow; - - // Used to match key downs and key ups - private Vector<Integer> mKeysPressed; - - /* package */ static boolean mLogEvent = true; - - // for event log - private long mLastTouchUpTime = 0; - - private WebViewCore.AutoFillData mAutoFillData; - - private static boolean sNotificationsEnabled = true; - /** * URI scheme for telephone number */ @@ -1353,26 +310,6 @@ public class WebView extends AbsoluteLayout */ public static final String SCHEME_GEO = "geo:0,0?q="; - private int mBackgroundColor = Color.WHITE; - - private static final long SELECT_SCROLL_INTERVAL = 1000 / 60; // 60 / second - private int mAutoScrollX = 0; - private int mAutoScrollY = 0; - private int mMinAutoScrollX = 0; - private int mMaxAutoScrollX = 0; - private int mMinAutoScrollY = 0; - private int mMaxAutoScrollY = 0; - private Rect mScrollingLayerBounds = new Rect(); - private boolean mSentAutoScrollMessage = false; - - // used for serializing asynchronously handled touch events. - private final TouchEventQueue mTouchEventQueue = new TouchEventQueue(); - - // Used to track whether picture updating was paused due to a window focus change. - private boolean mPictureUpdatePausedForFocusChange = false; - - // Used to notify listeners of a new picture. - private PictureListener mPictureListener; /** * Interface to listen for new pictures as they change. * @deprecated This interface is now obsolete. @@ -1440,15 +377,24 @@ public class WebView extends AbsoluteLayout private int mType; private String mExtra; - HitTestResult() { + /** + * @hide Only for use by WebViewProvider implementations + */ + public HitTestResult() { mType = UNKNOWN_TYPE; } - private void setType(int type) { + /** + * @hide Only for use by WebViewProvider implementations + */ + public void setType(int type) { mType = type; } - private void setExtra(String extra) { + /** + * @hide Only for use by WebViewProvider implementations + */ + public void setExtra(String extra) { mExtra = extra; } @@ -1471,15 +417,6 @@ public class WebView extends AbsoluteLayout } /** - * Refer to {@link WebView#requestFocusNodeHref(Message)} for more information - */ - static class FocusNodeHref { - static final String TITLE = "title"; - static final String URL = "url"; - static final String SRC = "src"; - } - - /** * Construct a new WebView with a Context object. * @param context A Context object used to access application assets. */ @@ -1529,418 +466,20 @@ public class WebView extends AbsoluteLayout * @param javaScriptInterfaces is a Map of interface names, as keys, and * object implementing those interfaces, as values. * @param privateBrowsing If true the web view will be initialized in private mode. - * @hide This is an implementation detail. + * @hide This is used internally by dumprendertree, as it requires the javaScript interfaces to + * be added synchronously, before a subsequent loadUrl call takes effect. */ + @SuppressWarnings("deprecation") // for super() call into deprecated base class constructor. protected WebView(Context context, AttributeSet attrs, int defStyle, Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) { super(context, attrs, defStyle); - checkThread(); - if (context == null) { throw new IllegalArgumentException("Invalid context argument"); } + checkThread(); - // Used by the chrome stack to find application paths - JniUtil.setContext(context); - - mCallbackProxy = new CallbackProxy(context, this); - mViewManager = new ViewManager(this); - L10nUtils.setApplicationContext(context.getApplicationContext()); - mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces); - mDatabase = WebViewDatabase.getInstance(context); - mScroller = new OverScroller(context, null, 0, 0, false); //TODO Use OverScroller's flywheel - mZoomManager = new ZoomManager(this, mCallbackProxy); - - /* The init method must follow the creation of certain member variables, - * such as the mZoomManager. - */ - init(); - setupPackageListener(context); - setupProxyListener(context); - setupTrustStorageListener(context); - updateMultiTouchSupport(context); - - if (privateBrowsing) { - startPrivateBrowsing(); - } - - mAutoFillData = new WebViewCore.AutoFillData(); - } - - private static class TrustStorageListener extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) { - handleCertTrustChanged(); - } - } - } - private static TrustStorageListener sTrustStorageListener; - - /** - * Handles update to the trust storage. - */ - private static void handleCertTrustChanged() { - // send a message for indicating trust storage change - WebViewCore.sendStaticMessage(EventHub.TRUST_STORAGE_UPDATED, null); - } - - /* - * @param context This method expects this to be a valid context. - */ - private static void setupTrustStorageListener(Context context) { - if (sTrustStorageListener != null ) { - return; - } - IntentFilter filter = new IntentFilter(); - filter.addAction(KeyChain.ACTION_STORAGE_CHANGED); - sTrustStorageListener = new TrustStorageListener(); - Intent current = - context.getApplicationContext().registerReceiver(sTrustStorageListener, filter); - if (current != null) { - handleCertTrustChanged(); - } - } - - private static class ProxyReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) { - handleProxyBroadcast(intent); - } - } - } - - /* - * Receiver for PROXY_CHANGE_ACTION, will be null when it is not added handling broadcasts. - */ - private static ProxyReceiver sProxyReceiver; - - /* - * @param context This method expects this to be a valid context - */ - private static synchronized void setupProxyListener(Context context) { - if (sProxyReceiver != null || sNotificationsEnabled == false) { - return; - } - IntentFilter filter = new IntentFilter(); - filter.addAction(Proxy.PROXY_CHANGE_ACTION); - sProxyReceiver = new ProxyReceiver(); - Intent currentProxy = context.getApplicationContext().registerReceiver( - sProxyReceiver, filter); - if (currentProxy != null) { - handleProxyBroadcast(currentProxy); - } - } - - /* - * @param context This method expects this to be a valid context - */ - private static synchronized void disableProxyListener(Context context) { - if (sProxyReceiver == null) - return; - - context.getApplicationContext().unregisterReceiver(sProxyReceiver); - sProxyReceiver = null; - } - - private static void handleProxyBroadcast(Intent intent) { - ProxyProperties proxyProperties = (ProxyProperties)intent.getExtra(Proxy.EXTRA_PROXY_INFO); - if (proxyProperties == null || proxyProperties.getHost() == null) { - WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, null); - return; - } - WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, proxyProperties); - } - - /* - * A variable to track if there is a receiver added for ACTION_PACKAGE_ADDED - * or ACTION_PACKAGE_REMOVED. - */ - private static boolean sPackageInstallationReceiverAdded = false; - - /* - * A set of Google packages we monitor for the - * navigator.isApplicationInstalled() API. Add additional packages as - * needed. - */ - private static Set<String> sGoogleApps; - static { - sGoogleApps = new HashSet<String>(); - sGoogleApps.add("com.google.android.youtube"); - } - - private static class PackageListener extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - final String packageName = intent.getData().getSchemeSpecificPart(); - final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); - if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) { - // if it is replacing, refreshPlugins() when adding - return; - } - - if (sGoogleApps.contains(packageName)) { - if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { - WebViewCore.sendStaticMessage(EventHub.ADD_PACKAGE_NAME, packageName); - } else { - WebViewCore.sendStaticMessage(EventHub.REMOVE_PACKAGE_NAME, packageName); - } - } - - PluginManager pm = PluginManager.getInstance(context); - if (pm.containsPluginPermissionAndSignatures(packageName)) { - pm.refreshPlugins(Intent.ACTION_PACKAGE_ADDED.equals(action)); - } - } - } - - private void setupPackageListener(Context context) { - - /* - * we must synchronize the instance check and the creation of the - * receiver to ensure that only ONE receiver exists for all WebView - * instances. - */ - synchronized (WebView.class) { - - // if the receiver already exists then we do not need to register it - // again - if (sPackageInstallationReceiverAdded) { - return; - } - - IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addDataScheme("package"); - BroadcastReceiver packageListener = new PackageListener(); - context.getApplicationContext().registerReceiver(packageListener, filter); - sPackageInstallationReceiverAdded = true; - } - - // check if any of the monitored apps are already installed - AsyncTask<Void, Void, Set<String>> task = new AsyncTask<Void, Void, Set<String>>() { - - @Override - protected Set<String> doInBackground(Void... unused) { - Set<String> installedPackages = new HashSet<String>(); - PackageManager pm = mContext.getPackageManager(); - for (String name : sGoogleApps) { - try { - pm.getPackageInfo(name, - PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES); - installedPackages.add(name); - } catch (PackageManager.NameNotFoundException e) { - // package not found - } - } - return installedPackages; - } - - // Executes on the UI thread - @Override - protected void onPostExecute(Set<String> installedPackages) { - if (mWebViewCore != null) { - mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, installedPackages); - } - } - }; - task.execute(); - } - - void updateMultiTouchSupport(Context context) { - mZoomManager.updateMultiTouchSupport(context); - } - - private void init() { - OnTrimMemoryListener.init(getContext()); - sDisableNavcache = nativeDisableNavcache(); - setWillNotDraw(false); - setFocusable(true); - setFocusableInTouchMode(true); - setClickable(true); - setLongClickable(true); - - final ViewConfiguration configuration = ViewConfiguration.get(getContext()); - int slop = configuration.getScaledTouchSlop(); - mTouchSlopSquare = slop * slop; - slop = configuration.getScaledDoubleTapSlop(); - mDoubleTapSlopSquare = slop * slop; - final float density = getContext().getResources().getDisplayMetrics().density; - // use one line height, 16 based on our current default font, for how - // far we allow a touch be away from the edge of a link - mNavSlop = (int) (16 * density); - mZoomManager.init(density); - mMaximumFling = configuration.getScaledMaximumFlingVelocity(); - - // Compute the inverse of the density squared. - DRAG_LAYER_INVERSE_DENSITY_SQUARED = 1 / (density * density); - - mOverscrollDistance = configuration.getScaledOverscrollDistance(); - mOverflingDistance = configuration.getScaledOverflingDistance(); - - setScrollBarStyle(super.getScrollBarStyle()); - // Initially use a size of two, since the user is likely to only hold - // down two keys at a time (shift + another key) - mKeysPressed = new Vector<Integer>(2); - mHTML5VideoViewProxy = null ; - } - - @Override - public boolean shouldDelayChildPressedState() { - return true; - } - - /** - * Adds accessibility APIs to JavaScript. - * - * Note: This method is responsible to performing the necessary - * check if the accessibility APIs should be exposed. - */ - private void addAccessibilityApisToJavaScript() { - if (AccessibilityManager.getInstance(mContext).isEnabled() - && getSettings().getJavaScriptEnabled()) { - // exposing the TTS for now ... - final Context ctx = getContext(); - if (ctx != null) { - final String packageName = ctx.getPackageName(); - if (packageName != null) { - mTextToSpeech = new TextToSpeech(getContext(), null, null, - packageName + ".**webview**", true); - addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE); - } - } - } - } - - /** - * Removes accessibility APIs from JavaScript. - */ - private void removeAccessibilityApisFromJavaScript() { - // exposing the TTS for now ... - if (mTextToSpeech != null) { - removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE); - mTextToSpeech.shutdown(); - mTextToSpeech = null; - } - } - - @Override - public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - info.setScrollable(isScrollableForAccessibility()); - } - - @Override - public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - event.setScrollable(isScrollableForAccessibility()); - event.setScrollX(mScrollX); - event.setScrollY(mScrollY); - final int convertedContentWidth = contentToViewX(getContentWidth()); - final int adjustedViewWidth = getWidth() - mPaddingLeft - mPaddingRight; - event.setMaxScrollX(Math.max(convertedContentWidth - adjustedViewWidth, 0)); - final int convertedContentHeight = contentToViewY(getContentHeight()); - final int adjustedViewHeight = getHeight() - mPaddingTop - mPaddingBottom; - event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0)); - } - - private boolean isScrollableForAccessibility() { - return (contentToViewX(getContentWidth()) > getWidth() - mPaddingLeft - mPaddingRight - || contentToViewY(getContentHeight()) > getHeight() - mPaddingTop - mPaddingBottom); - } - - @Override - public void setOverScrollMode(int mode) { - super.setOverScrollMode(mode); - if (mode != OVER_SCROLL_NEVER) { - if (mOverScrollGlow == null) { - mOverScrollGlow = new OverScrollGlow(this); - } - } else { - mOverScrollGlow = null; - } - } - - /* package */ void adjustDefaultZoomDensity(int zoomDensity) { - final float density = mContext.getResources().getDisplayMetrics().density - * 100 / zoomDensity; - updateDefaultZoomDensity(density); - } - - /* package */ void updateDefaultZoomDensity(float density) { - mNavSlop = (int) (16 * density); - mZoomManager.updateDefaultZoomDensity(density); - } - - /* package */ boolean onSavePassword(String schemePlusHost, String username, - String password, final Message resumeMsg) { - boolean rVal = false; - if (resumeMsg == null) { - // null resumeMsg implies saving password silently - mDatabase.setUsernamePassword(schemePlusHost, username, password); - } else { - final Message remember = mPrivateHandler.obtainMessage( - REMEMBER_PASSWORD); - remember.getData().putString("host", schemePlusHost); - remember.getData().putString("username", username); - remember.getData().putString("password", password); - remember.obj = resumeMsg; - - final Message neverRemember = mPrivateHandler.obtainMessage( - NEVER_REMEMBER_PASSWORD); - neverRemember.getData().putString("host", schemePlusHost); - neverRemember.getData().putString("username", username); - neverRemember.getData().putString("password", password); - neverRemember.obj = resumeMsg; - - new AlertDialog.Builder(getContext()) - .setTitle(com.android.internal.R.string.save_password_label) - .setMessage(com.android.internal.R.string.save_password_message) - .setPositiveButton(com.android.internal.R.string.save_password_notnow, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - resumeMsg.sendToTarget(); - } - }) - .setNeutralButton(com.android.internal.R.string.save_password_remember, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - remember.sendToTarget(); - } - }) - .setNegativeButton(com.android.internal.R.string.save_password_never, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - neverRemember.sendToTarget(); - } - }) - .setOnCancelListener(new OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - resumeMsg.sendToTarget(); - } - }).show(); - // Return true so that WebViewCore will pause while the dialog is - // up. - rVal = true; - } - return rVal; - } - - @Override - public void setScrollBarStyle(int style) { - if (style == View.SCROLLBARS_INSIDE_INSET - || style == View.SCROLLBARS_OUTSIDE_INSET) { - mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false; - } else { - mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true; - } - super.setScrollBarStyle(style); + ensureProviderCreated(); + mProvider.init(javaScriptInterfaces, privateBrowsing); } /** @@ -1949,7 +488,7 @@ public class WebView extends AbsoluteLayout */ public void setHorizontalScrollbarOverlay(boolean overlay) { checkThread(); - mOverlayHorizontalScrollbar = overlay; + mProvider.setHorizontalScrollbarOverlay(overlay); } /** @@ -1958,7 +497,7 @@ public class WebView extends AbsoluteLayout */ public void setVerticalScrollbarOverlay(boolean overlay) { checkThread(); - mOverlayVerticalScrollbar = overlay; + mProvider.setVerticalScrollbarOverlay(overlay); } /** @@ -1967,7 +506,7 @@ public class WebView extends AbsoluteLayout */ public boolean overlayHorizontalScrollbar() { checkThread(); - return mOverlayHorizontalScrollbar; + return mProvider.overlayHorizontalScrollbar(); } /** @@ -1976,80 +515,17 @@ public class WebView extends AbsoluteLayout */ public boolean overlayVerticalScrollbar() { checkThread(); - return mOverlayVerticalScrollbar; - } - - /* - * Return the width of the view where the content of WebView should render - * to. - * Note: this can be called from WebCoreThread. - */ - /* package */ int getViewWidth() { - if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) { - return getWidth(); - } else { - return Math.max(0, getWidth() - getVerticalScrollbarWidth()); - } - } - - /** - * Returns the height (in pixels) of the embedded title bar (if any). Does not care about - * scrolling - * @hide - */ - protected int getTitleHeight() { - return mTitleBar != null ? mTitleBar.getHeight() : 0; + return mProvider.overlayVerticalScrollbar(); } /** * Return the visible height (in pixels) of the embedded title bar (if any). * - * @return This method is obsolete and always returns 0. * @deprecated This method is now obsolete. */ - @Deprecated public int getVisibleTitleHeight() { - // Actually, this method returns the height of the embedded title bar if one is set via the - // hidden setEmbeddedTitleBar method. checkThread(); - return getVisibleTitleHeightImpl(); - } - - private int getVisibleTitleHeightImpl() { - // need to restrict mScrollY due to over scroll - return Math.max(getTitleHeight() - Math.max(0, mScrollY), - getOverlappingActionModeHeight()); - } - - private int mCachedOverlappingActionModeHeight = -1; - - private int getOverlappingActionModeHeight() { - if (mFindCallback == null) { - return 0; - } - if (mCachedOverlappingActionModeHeight < 0) { - getGlobalVisibleRect(mGlobalVisibleRect, mGlobalVisibleOffset); - mCachedOverlappingActionModeHeight = Math.max(0, - mFindCallback.getActionModeGlobalBottom() - mGlobalVisibleRect.top); - } - return mCachedOverlappingActionModeHeight; - } - - /* - * Return the height of the view where the content of WebView should render - * to. Note that this excludes mTitleBar, if there is one. - * Note: this can be called from WebCoreThread. - */ - /* package */ int getViewHeight() { - return getViewHeightWithTitle() - getVisibleTitleHeightImpl(); - } - - int getViewHeightWithTitle() { - int height = getHeight(); - if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) { - height -= getHorizontalScrollbarHeight(); - } - return height; + return mProvider.getVisibleTitleHeight(); } /** @@ -2058,7 +534,7 @@ public class WebView extends AbsoluteLayout */ public SslCertificate getCertificate() { checkThread(); - return mCertificate; + return mProvider.getCertificate(); } /** @@ -2066,11 +542,7 @@ public class WebView extends AbsoluteLayout */ public void setCertificate(SslCertificate certificate) { checkThread(); - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "setCertificate=" + certificate); - } - // here, the certificate can be null (if the site is not secure) - mCertificate = certificate; + mProvider.setCertificate(certificate); } //------------------------------------------------------------------------- @@ -2086,7 +558,7 @@ public class WebView extends AbsoluteLayout */ public void savePassword(String host, String username, String password) { checkThread(); - mDatabase.setUsernamePassword(host, username, password); + mProvider.savePassword(host, username, password); } /** @@ -2101,7 +573,7 @@ public class WebView extends AbsoluteLayout public void setHttpAuthUsernamePassword(String host, String realm, String username, String password) { checkThread(); - mDatabase.setHttpAuthUsernamePassword(host, realm, username, password); + mProvider.setHttpAuthUsernamePassword(host, realm, username, password); } /** @@ -2115,38 +587,7 @@ public class WebView extends AbsoluteLayout */ public String[] getHttpAuthUsernamePassword(String host, String realm) { checkThread(); - return mDatabase.getHttpAuthUsernamePassword(host, realm); - } - - /** - * Remove Find or Select ActionModes, if active. - */ - private void clearActionModes() { - if (mSelectCallback != null) { - mSelectCallback.finish(); - } - if (mFindCallback != null) { - mFindCallback.finish(); - } - } - - /** - * Called to clear state when moving from one page to another, or changing - * in some other way that makes elements associated with the current page - * (such as WebTextView or ActionModes) no longer relevant. - */ - private void clearHelpers() { - clearTextEntry(); - clearActionModes(); - dismissFullScreenMode(); - cancelSelectDialog(); - } - - private void cancelSelectDialog() { - if (mListBoxDialog != null) { - mListBoxDialog.cancel(); - mListBoxDialog = null; - } + return mProvider.getHttpAuthUsernamePassword(host, realm); } /** @@ -2156,45 +597,7 @@ public class WebView extends AbsoluteLayout */ public void destroy() { checkThread(); - destroyImpl(); - } - - private void destroyImpl() { - clearHelpers(); - if (mListBoxDialog != null) { - mListBoxDialog.dismiss(); - mListBoxDialog = null; - } - // remove so that it doesn't cause events - if (mWebTextView != null) { - mWebTextView.remove(); - mWebTextView = null; - } - if (mNativeClass != 0) nativeStopGL(); - if (mWebViewCore != null) { - // Set the handlers to null before destroying WebViewCore so no - // more messages will be posted. - mCallbackProxy.setWebViewClient(null); - mCallbackProxy.setWebChromeClient(null); - // Tell WebViewCore to destroy itself - synchronized (this) { - WebViewCore webViewCore = mWebViewCore; - mWebViewCore = null; // prevent using partial webViewCore - webViewCore.destroy(); - } - // Remove any pending messages that might not be serviced yet. - mPrivateHandler.removeCallbacksAndMessages(null); - mCallbackProxy.removeCallbacksAndMessages(null); - // Wake up the WebCore thread just in case it is waiting for a - // JavaScript dialog. - synchronized (mCallbackProxy) { - mCallbackProxy.notify(); - } - } - if (mNativeClass != 0) { - nativeDestroy(); - mNativeClass = 0; - } + mProvider.destroy(); } /** @@ -2206,12 +609,7 @@ public class WebView extends AbsoluteLayout @Deprecated public static void enablePlatformNotifications() { checkThread(); - synchronized (WebView.class) { - sNotificationsEnabled = true; - Context context = JniUtil.getContext(); - if (context != null) - setupProxyListener(context); - } + getFactory().getStatics().setPlatformNotificationsEnabled(true); } /** @@ -2223,24 +621,7 @@ public class WebView extends AbsoluteLayout @Deprecated public static void disablePlatformNotifications() { checkThread(); - synchronized (WebView.class) { - sNotificationsEnabled = false; - Context context = JniUtil.getContext(); - if (context != null) - disableProxyListener(context); - } - } - - /** - * Sets JavaScript engine flags. - * - * @param flags JS engine flags in a String - * - * @hide This is an implementation detail. - */ - public void setJsFlags(String flags) { - checkThread(); - mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags); + getFactory().getStatics().setPlatformNotificationsEnabled(false); } /** @@ -2251,22 +632,10 @@ public class WebView extends AbsoluteLayout */ public void setNetworkAvailable(boolean networkUp) { checkThread(); - mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE, - networkUp ? 1 : 0, 0); + mProvider.setNetworkAvailable(networkUp); } /** - * Inform WebView about the current network type. - * {@hide} - */ - public void setNetworkType(String type, String subtype) { - checkThread(); - Map<String, String> map = new HashMap<String, String>(); - map.put("type", type); - map.put("subtype", subtype); - mWebViewCore.sendMessage(EventHub.SET_NETWORK_TYPE, map); - } - /** * Save the state of this WebView used in * {@link android.app.Activity#onSaveInstanceState}. Please note that this * method no longer stores the display data for this WebView. The previous @@ -2281,49 +650,7 @@ public class WebView extends AbsoluteLayout */ public WebBackForwardList saveState(Bundle outState) { checkThread(); - if (outState == null) { - return null; - } - // We grab a copy of the back/forward list because a client of WebView - // may have invalidated the history list by calling clearHistory. - WebBackForwardList list = copyBackForwardList(); - final int currentIndex = list.getCurrentIndex(); - final int size = list.getSize(); - // We should fail saving the state if the list is empty or the index is - // not in a valid range. - if (currentIndex < 0 || currentIndex >= size || size == 0) { - return null; - } - outState.putInt("index", currentIndex); - // FIXME: This should just be a byte[][] instead of ArrayList but - // Parcel.java does not have the code to handle multi-dimensional - // arrays. - ArrayList<byte[]> history = new ArrayList<byte[]>(size); - for (int i = 0; i < size; i++) { - WebHistoryItem item = list.getItemAtIndex(i); - if (null == item) { - // FIXME: this shouldn't happen - // need to determine how item got set to null - Log.w(LOGTAG, "saveState: Unexpected null history item."); - return null; - } - byte[] data = item.getFlattenedData(); - if (data == null) { - // It would be very odd to not have any data for a given history - // item. And we will fail to rebuild the history list without - // flattened data. - return null; - } - history.add(data); - } - outState.putSerializable("history", history); - if (mCertificate != null) { - outState.putBundle("certificate", - SslCertificate.saveState(mCertificate)); - } - outState.putBoolean("privateBrowsingEnabled", isPrivateBrowsingEnabled()); - mZoomManager.saveZoomState(outState); - return list; + return mProvider.saveState(outState); } /** @@ -2338,59 +665,7 @@ public class WebView extends AbsoluteLayout @Deprecated public boolean savePicture(Bundle b, final File dest) { checkThread(); - if (dest == null || b == null) { - return false; - } - final Picture p = capturePicture(); - // Use a temporary file while writing to ensure the destination file - // contains valid data. - final File temp = new File(dest.getPath() + ".writing"); - new Thread(new Runnable() { - @Override - public void run() { - FileOutputStream out = null; - try { - out = new FileOutputStream(temp); - p.writeToStream(out); - // Writing the picture succeeded, rename the temporary file - // to the destination. - temp.renameTo(dest); - } catch (Exception e) { - // too late to do anything about it. - } finally { - if (out != null) { - try { - out.close(); - } catch (Exception e) { - // Can't do anything about that - } - } - temp.delete(); - } - } - }).start(); - // now update the bundle - b.putInt("scrollX", mScrollX); - b.putInt("scrollY", mScrollY); - mZoomManager.saveZoomState(b); - return true; - } - - private void restoreHistoryPictureFields(Picture p, Bundle b) { - int sx = b.getInt("scrollX", 0); - int sy = b.getInt("scrollY", 0); - - mDrawHistory = true; - mHistoryPicture = p; - - mScrollX = sx; - mScrollY = sy; - mZoomManager.restoreZoomState(b); - final float scale = mZoomManager.getScale(); - mHistoryWidth = Math.round(p.getWidth() * scale); - mHistoryHeight = Math.round(p.getHeight() * scale); - - invalidate(); + return mProvider.savePicture(b, dest); } /** @@ -2406,91 +681,7 @@ public class WebView extends AbsoluteLayout @Deprecated public boolean restorePicture(Bundle b, File src) { checkThread(); - if (src == null || b == null) { - return false; - } - if (!src.exists()) { - return false; - } - try { - final FileInputStream in = new FileInputStream(src); - final Bundle copy = new Bundle(b); - new Thread(new Runnable() { - @Override - public void run() { - try { - final Picture p = Picture.createFromStream(in); - if (p != null) { - // Post a runnable on the main thread to update the - // history picture fields. - mPrivateHandler.post(new Runnable() { - @Override - public void run() { - restoreHistoryPictureFields(p, copy); - } - }); - } - } finally { - try { - in.close(); - } catch (Exception e) { - // Nothing we can do now. - } - } - } - }).start(); - } catch (FileNotFoundException e){ - e.printStackTrace(); - } - return true; - } - - /** - * Saves the view data to the output stream. The output is highly - * version specific, and may not be able to be loaded by newer versions - * of WebView. - * @param stream The {@link OutputStream} to save to - * @return True if saved successfully - * @hide - */ - public boolean saveViewState(OutputStream stream) { - try { - return ViewStateSerializer.serializeViewState(stream, this); - } catch (IOException e) { - Log.w(LOGTAG, "Failed to saveViewState", e); - } - return false; - } - - /** - * Loads the view data from the input stream. See - * {@link #saveViewState(OutputStream)} for more information. - * @param stream The {@link InputStream} to load from - * @return True if loaded successfully - * @hide - */ - public boolean loadViewState(InputStream stream) { - try { - mLoadedPicture = ViewStateSerializer.deserializeViewState(stream, this); - mBlockWebkitViewMessages = true; - setNewPicture(mLoadedPicture, true); - mLoadedPicture.mViewState = null; - return true; - } catch (IOException e) { - Log.w(LOGTAG, "Failed to loadViewState", e); - } - return false; - } - - /** - * Clears the view state set with {@link #loadViewState(InputStream)}. - * This WebView will then switch to showing the content from webkit - * @hide - */ - public void clearViewState() { - mBlockWebkitViewMessages = false; - mLoadedPicture = null; - invalidate(); + return mProvider.restorePicture(b, src); } /** @@ -2509,55 +700,7 @@ public class WebView extends AbsoluteLayout */ public WebBackForwardList restoreState(Bundle inState) { checkThread(); - WebBackForwardList returnList = null; - if (inState == null) { - return returnList; - } - if (inState.containsKey("index") && inState.containsKey("history")) { - mCertificate = SslCertificate.restoreState( - inState.getBundle("certificate")); - - final WebBackForwardList list = mCallbackProxy.getBackForwardList(); - final int index = inState.getInt("index"); - // We can't use a clone of the list because we need to modify the - // shared copy, so synchronize instead to prevent concurrent - // modifications. - synchronized (list) { - final List<byte[]> history = - (List<byte[]>) inState.getSerializable("history"); - final int size = history.size(); - // Check the index bounds so we don't crash in native code while - // restoring the history index. - if (index < 0 || index >= size) { - return null; - } - for (int i = 0; i < size; i++) { - byte[] data = history.remove(0); - if (data == null) { - // If we somehow have null data, we cannot reconstruct - // the item and thus our history list cannot be rebuilt. - return null; - } - WebHistoryItem item = new WebHistoryItem(data); - list.addHistoryItem(item); - } - // Grab the most recent copy to return to the caller. - returnList = copyBackForwardList(); - // Update the copy to have the correct index. - returnList.setCurrentIndex(index); - } - // Restore private browsing setting. - if (inState.getBoolean("privateBrowsingEnabled")) { - getSettings().setPrivateBrowsingEnabled(true); - } - mZoomManager.restoreZoomState(inState); - // Remove all pending messages because we are restoring previous - // state. - mWebViewCore.removeMessages(); - // Send a restore state message. - mWebViewCore.sendMessage(EventHub.RESTORE_STATE, index); - } - return returnList; + return mProvider.restoreState(inState); } /** @@ -2572,16 +715,7 @@ public class WebView extends AbsoluteLayout */ public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { checkThread(); - loadUrlImpl(url, additionalHttpHeaders); - } - - private void loadUrlImpl(String url, Map<String, String> extraHeaders) { - switchOutDrawHistory(); - WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData(); - arg.mUrl = url; - arg.mExtraHeaders = extraHeaders; - mWebViewCore.sendMessage(EventHub.LOAD_URL, arg); - clearHelpers(); + mProvider.loadUrl(url, additionalHttpHeaders); } /** @@ -2590,14 +724,7 @@ public class WebView extends AbsoluteLayout */ public void loadUrl(String url) { checkThread(); - loadUrlImpl(url); - } - - private void loadUrlImpl(String url) { - if (url == null) { - return; - } - loadUrlImpl(url, null); + mProvider.loadUrl(url); } /** @@ -2610,16 +737,7 @@ public class WebView extends AbsoluteLayout */ public void postUrl(String url, byte[] postData) { checkThread(); - if (URLUtil.isNetworkUrl(url)) { - switchOutDrawHistory(); - WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData(); - arg.mUrl = url; - arg.mPostData = postData; - mWebViewCore.sendMessage(EventHub.POST_URL, arg); - clearHelpers(); - } else { - loadUrlImpl(url); - } + mProvider.postUrl(url, postData); } /** @@ -2650,18 +768,7 @@ public class WebView extends AbsoluteLayout */ public void loadData(String data, String mimeType, String encoding) { checkThread(); - loadDataImpl(data, mimeType, encoding); - } - - private void loadDataImpl(String data, String mimeType, String encoding) { - StringBuilder dataUrl = new StringBuilder("data:"); - dataUrl.append(mimeType); - if ("base64".equals(encoding)) { - dataUrl.append(";base64"); - } - dataUrl.append(","); - dataUrl.append(data); - loadUrlImpl(dataUrl.toString()); + mProvider.loadData(data, mimeType, encoding); } /** @@ -2689,20 +796,7 @@ public class WebView extends AbsoluteLayout public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) { checkThread(); - - if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) { - loadDataImpl(data, mimeType, encoding); - return; - } - switchOutDrawHistory(); - WebViewCore.BaseUrlData arg = new WebViewCore.BaseUrlData(); - arg.mBaseUrl = baseUrl; - arg.mData = data; - arg.mMimeType = mimeType; - arg.mEncoding = encoding; - arg.mHistoryUrl = historyUrl; - mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg); - clearHelpers(); + mProvider.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl); } /** @@ -2712,20 +806,7 @@ public class WebView extends AbsoluteLayout */ public void saveWebArchive(String filename) { checkThread(); - saveWebArchiveImpl(filename, false, null); - } - - /* package */ static class SaveWebArchiveMessage { - SaveWebArchiveMessage (String basename, boolean autoname, ValueCallback<String> callback) { - mBasename = basename; - mAutoname = autoname; - mCallback = callback; - } - - /* package */ final String mBasename; - /* package */ final boolean mAutoname; - /* package */ final ValueCallback<String> mCallback; - /* package */ String mResultFile; + mProvider.saveWebArchive(filename); } /** @@ -2742,13 +823,7 @@ public class WebView extends AbsoluteLayout */ public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) { checkThread(); - saveWebArchiveImpl(basename, autoname, callback); - } - - private void saveWebArchiveImpl(String basename, boolean autoname, - ValueCallback<String> callback) { - mWebViewCore.sendMessage(EventHub.SAVE_WEBARCHIVE, - new SaveWebArchiveMessage(basename, autoname, callback)); + mProvider.saveWebArchive(basename, autoname, callback); } /** @@ -2756,10 +831,7 @@ public class WebView extends AbsoluteLayout */ public void stopLoading() { checkThread(); - // TODO: should we clear all the messages in the queue before sending - // STOP_LOADING? - switchOutDrawHistory(); - mWebViewCore.sendMessage(EventHub.STOP_LOADING); + mProvider.stopLoading(); } /** @@ -2767,9 +839,7 @@ public class WebView extends AbsoluteLayout */ public void reload() { checkThread(); - clearHelpers(); - switchOutDrawHistory(); - mWebViewCore.sendMessage(EventHub.RELOAD); + mProvider.reload(); } /** @@ -2778,14 +848,7 @@ public class WebView extends AbsoluteLayout */ public boolean canGoBack() { checkThread(); - WebBackForwardList l = mCallbackProxy.getBackForwardList(); - synchronized (l) { - if (l.getClearPending()) { - return false; - } else { - return l.getCurrentIndex() > 0; - } - } + return mProvider.canGoBack(); } /** @@ -2793,7 +856,7 @@ public class WebView extends AbsoluteLayout */ public void goBack() { checkThread(); - goBackOrForwardImpl(-1); + mProvider.goBack(); } /** @@ -2802,14 +865,7 @@ public class WebView extends AbsoluteLayout */ public boolean canGoForward() { checkThread(); - WebBackForwardList l = mCallbackProxy.getBackForwardList(); - synchronized (l) { - if (l.getClearPending()) { - return false; - } else { - return l.getCurrentIndex() < l.getSize() - 1; - } - } + return mProvider.canGoForward(); } /** @@ -2817,7 +873,7 @@ public class WebView extends AbsoluteLayout */ public void goForward() { checkThread(); - goBackOrForwardImpl(1); + mProvider.goForward(); } /** @@ -2828,15 +884,7 @@ public class WebView extends AbsoluteLayout */ public boolean canGoBackOrForward(int steps) { checkThread(); - WebBackForwardList l = mCallbackProxy.getBackForwardList(); - synchronized (l) { - if (l.getClearPending()) { - return false; - } else { - int newIndex = l.getCurrentIndex() + steps; - return newIndex >= 0 && newIndex < l.getSize(); - } - } + return mProvider.canGoBackOrForward(steps); } /** @@ -2848,19 +896,7 @@ public class WebView extends AbsoluteLayout */ public void goBackOrForward(int steps) { checkThread(); - goBackOrForwardImpl(steps); - } - - private void goBackOrForwardImpl(int steps) { - goBackOrForward(steps, false); - } - - private void goBackOrForward(int steps, boolean ignoreSnapshot) { - if (steps != 0) { - clearHelpers(); - mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps, - ignoreSnapshot ? 1 : 0); - } + mProvider.goBackOrForward(steps); } /** @@ -2868,20 +904,7 @@ public class WebView extends AbsoluteLayout */ public boolean isPrivateBrowsingEnabled() { checkThread(); - return getSettings().isPrivateBrowsingEnabled(); - } - - private void startPrivateBrowsing() { - getSettings().setPrivateBrowsingEnabled(true); - } - - private boolean extendScroll(int y) { - int finalY = mScroller.getFinalY(); - int newY = pinLocY(finalY + y); - if (newY == finalY) return false; - mScroller.setFinalY(newY); - mScroller.extendDuration(computeDuration(0, y)); - return true; + return mProvider.isPrivateBrowsingEnabled(); } /** @@ -2891,24 +914,7 @@ public class WebView extends AbsoluteLayout */ public boolean pageUp(boolean top) { checkThread(); - if (mNativeClass == 0) { - return false; - } - nativeClearCursor(); // start next trackball movement from page edge - if (top) { - // go to the top of the document - return pinScrollTo(mScrollX, 0, true, 0); - } - // Page up - int h = getHeight(); - int y; - if (h > 2 * PAGE_SCROLL_OVERLAP) { - y = -h + PAGE_SCROLL_OVERLAP; - } else { - y = -h / 2; - } - return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) - : extendScroll(y); + return mProvider.pageUp(top); } /** @@ -2918,23 +924,7 @@ public class WebView extends AbsoluteLayout */ public boolean pageDown(boolean bottom) { checkThread(); - if (mNativeClass == 0) { - return false; - } - nativeClearCursor(); // start next trackball movement from page edge - if (bottom) { - return pinScrollTo(mScrollX, computeRealVerticalScrollRange(), true, 0); - } - // Page down. - int h = getHeight(); - int y; - if (h > 2 * PAGE_SCROLL_OVERLAP) { - y = h - PAGE_SCROLL_OVERLAP; - } else { - y = h / 2; - } - return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) - : extendScroll(y); + return mProvider.pageDown(bottom); } /** @@ -2943,10 +933,7 @@ public class WebView extends AbsoluteLayout */ public void clearView() { checkThread(); - mContentWidth = 0; - mContentHeight = 0; - setBaseLayer(0, null, false, false); - mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT); + mProvider.clearView(); } /** @@ -2960,29 +947,7 @@ public class WebView extends AbsoluteLayout */ public Picture capturePicture() { checkThread(); - if (mNativeClass == 0) return null; - Picture result = new Picture(); - nativeCopyBaseContentToPicture(result); - return result; - } - - /** - * Return true if the browser is displaying a TextView for text input. - */ - private boolean inEditingMode() { - return mWebTextView != null && mWebTextView.getParent() != null; - } - - /** - * Remove the WebTextView. - */ - private void clearTextEntry() { - if (inEditingMode()) { - mWebTextView.remove(); - } else { - // The keyboard may be open with the WebView as the served view - hideSoftKeyboard(); - } + return mProvider.capturePicture(); } /** @@ -2991,16 +956,7 @@ public class WebView extends AbsoluteLayout */ public float getScale() { checkThread(); - return mZoomManager.getScale(); - } - - /** - * Compute the reading level scale of the WebView - * @param scale The current scale. - * @return The reading level scale. - */ - /*package*/ float computeReadingLevelScale(float scale) { - return mZoomManager.computeReadingLevelScale(scale); + return mProvider.getScale(); } /** @@ -3015,7 +971,7 @@ public class WebView extends AbsoluteLayout */ public void setInitialScale(int scaleInPercent) { checkThread(); - mZoomManager.setInitialScaleInPercent(scaleInPercent); + mProvider.setInitialScale(scaleInPercent); } /** @@ -3025,12 +981,7 @@ public class WebView extends AbsoluteLayout */ public void invokeZoomPicker() { checkThread(); - if (!getSettings().supportZoom()) { - Log.w(LOGTAG, "This WebView doesn't support zoom."); - return; - } - clearHelpers(); - mZoomManager.invokeZoomPicker(); + mProvider.invokeZoomPicker(); } /** @@ -3053,101 +1004,9 @@ public class WebView extends AbsoluteLayout */ public HitTestResult getHitTestResult() { checkThread(); - return hitTestResult(mInitialHitTestResult); - } - - private HitTestResult hitTestResult(HitTestResult fallback) { - if (mNativeClass == 0 || sDisableNavcache) { - return fallback; - } - - HitTestResult result = new HitTestResult(); - if (nativeHasCursorNode()) { - if (nativeCursorIsTextInput()) { - result.setType(HitTestResult.EDIT_TEXT_TYPE); - } else { - String text = nativeCursorText(); - if (text != null) { - if (text.startsWith(SCHEME_TEL)) { - result.setType(HitTestResult.PHONE_TYPE); - result.setExtra(URLDecoder.decode(text - .substring(SCHEME_TEL.length()))); - } else if (text.startsWith(SCHEME_MAILTO)) { - result.setType(HitTestResult.EMAIL_TYPE); - result.setExtra(text.substring(SCHEME_MAILTO.length())); - } else if (text.startsWith(SCHEME_GEO)) { - result.setType(HitTestResult.GEO_TYPE); - result.setExtra(URLDecoder.decode(text - .substring(SCHEME_GEO.length()))); - } else if (nativeCursorIsAnchor()) { - result.setType(HitTestResult.SRC_ANCHOR_TYPE); - result.setExtra(text); - } - } - } - } else if (fallback != null) { - /* If webkit causes a rebuild while the long press is in progress, - * the cursor node may be reset, even if it is still around. This - * uses the cursor node saved when the touch began. Since the - * nativeImageURI below only changes the result if it is successful, - * this uses the data beneath the touch if available or the original - * tap data otherwise. - */ - Log.v(LOGTAG, "hitTestResult use fallback"); - result = fallback; - } - int type = result.getType(); - if (type == HitTestResult.UNKNOWN_TYPE - || type == HitTestResult.SRC_ANCHOR_TYPE) { - // Now check to see if it is an image. - int contentX = viewToContentX(mLastTouchX + mScrollX); - int contentY = viewToContentY(mLastTouchY + mScrollY); - String text = nativeImageURI(contentX, contentY); - if (text != null) { - result.setType(type == HitTestResult.UNKNOWN_TYPE ? - HitTestResult.IMAGE_TYPE : - HitTestResult.SRC_IMAGE_ANCHOR_TYPE); - result.setExtra(text); - } - } - return result; - } - - int getBlockLeftEdge(int x, int y, float readingScale) { - if (!sDisableNavcache) { - return nativeGetBlockLeftEdge(x, y, readingScale); - } - - float invReadingScale = 1.0f / readingScale; - int readingWidth = (int) (getViewWidth() * invReadingScale); - int left = NO_LEFTEDGE; - if (mFocusedNode != null) { - final int length = mFocusedNode.mEnclosingParentRects.length; - for (int i = 0; i < length; i++) { - Rect rect = mFocusedNode.mEnclosingParentRects[i]; - if (rect.width() < mFocusedNode.mHitTestSlop) { - // ignore bounding boxes that are too small - continue; - } else if (left != NO_LEFTEDGE && rect.width() > readingWidth) { - // stop when bounding box doesn't fit the screen width - // at reading scale - break; - } - - left = rect.left; - } - } - - return left; + return mProvider.getHitTestResult(); } - // Called by JNI when the DOM has changed the focus. Clear the focus so - // that new keys will go to the newly focused field - private void domChangedFocus() { - if (inEditingMode()) { - mPrivateHandler.obtainMessage(DOM_FOCUS_CHANGED).sendToTarget(); - } - } /** * Request the anchor or image element URL at the last tapped point. * If hrefMsg is null, this method returns immediately and does not @@ -3164,32 +1023,7 @@ public class WebView extends AbsoluteLayout */ public void requestFocusNodeHref(Message hrefMsg) { checkThread(); - if (hrefMsg == null) { - return; - } - int contentX = viewToContentX(mLastTouchX + mScrollX); - int contentY = viewToContentY(mLastTouchY + mScrollY); - if (mFocusedNode != null && mFocusedNode.mHitTestX == contentX - && mFocusedNode.mHitTestY == contentY) { - hrefMsg.getData().putString(FocusNodeHref.URL, mFocusedNode.mLinkUrl); - hrefMsg.getData().putString(FocusNodeHref.TITLE, mFocusedNode.mAnchorText); - hrefMsg.getData().putString(FocusNodeHref.SRC, mFocusedNode.mImageUrl); - hrefMsg.sendToTarget(); - return; - } - if (nativeHasCursorNode()) { - Rect cursorBounds = cursorRingBounds(); - if (!cursorBounds.contains(contentX, contentY)) { - int slop = viewToContentDimension(mNavSlop); - cursorBounds.inset(-slop, -slop); - if (cursorBounds.contains(contentX, contentY)) { - contentX = cursorBounds.centerX(); - contentY = cursorBounds.centerY(); - } - } - } - mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF, - contentX, contentY, hrefMsg); + mProvider.requestFocusNodeHref(hrefMsg); } /** @@ -3201,503 +1035,7 @@ public class WebView extends AbsoluteLayout */ public void requestImageRef(Message msg) { checkThread(); - if (0 == mNativeClass) return; // client isn't initialized - int contentX = viewToContentX(mLastTouchX + mScrollX); - int contentY = viewToContentY(mLastTouchY + mScrollY); - String ref = nativeImageURI(contentX, contentY); - Bundle data = msg.getData(); - data.putString("url", ref); - msg.setData(data); - msg.sendToTarget(); - } - - static int pinLoc(int x, int viewMax, int docMax) { -// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax); - if (docMax < viewMax) { // the doc has room on the sides for "blank" - // pin the short document to the top/left of the screen - x = 0; -// Log.d(LOGTAG, "--- center " + x); - } else if (x < 0) { - x = 0; -// Log.d(LOGTAG, "--- zero"); - } else if (x + viewMax > docMax) { - x = docMax - viewMax; -// Log.d(LOGTAG, "--- pin " + x); - } - return x; - } - - // Expects x in view coordinates - int pinLocX(int x) { - if (mInOverScrollMode) return x; - return pinLoc(x, getViewWidth(), computeRealHorizontalScrollRange()); - } - - // Expects y in view coordinates - int pinLocY(int y) { - if (mInOverScrollMode) return y; - return pinLoc(y, getViewHeightWithTitle(), - computeRealVerticalScrollRange() + getTitleHeight()); - } - - /** - * A title bar which is embedded in this WebView, and scrolls along with it - * vertically, but not horizontally. - */ - private View mTitleBar; - - /** - * the title bar rendering gravity - */ - private int mTitleGravity; - - /** - * Add or remove a title bar to be embedded into the WebView, and scroll - * along with it vertically, while remaining in view horizontally. Pass - * null to remove the title bar from the WebView, and return to drawing - * the WebView normally without translating to account for the title bar. - * @hide - */ - public void setEmbeddedTitleBar(View v) { - if (mTitleBar == v) return; - if (mTitleBar != null) { - removeView(mTitleBar); - } - if (null != v) { - addView(v, new AbsoluteLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0)); - } - mTitleBar = v; - } - - /** - * Set where to render the embedded title bar - * NO_GRAVITY at the top of the page - * TOP at the top of the screen - * @hide - */ - public void setTitleBarGravity(int gravity) { - mTitleGravity = gravity; - // force refresh - invalidate(); - } - - /** - * Given a distance in view space, convert it to content space. Note: this - * does not reflect translation, just scaling, so this should not be called - * with coordinates, but should be called for dimensions like width or - * height. - */ - private int viewToContentDimension(int d) { - return Math.round(d * mZoomManager.getInvScale()); - } - - /** - * Given an x coordinate in view space, convert it to content space. Also - * may be used for absolute heights (such as for the WebTextView's - * textSize, which is unaffected by the height of the title bar). - */ - /*package*/ int viewToContentX(int x) { - return viewToContentDimension(x); - } - - /** - * Given a y coordinate in view space, convert it to content space. - * Takes into account the height of the title bar if there is one - * embedded into the WebView. - */ - /*package*/ int viewToContentY(int y) { - return viewToContentDimension(y - getTitleHeight()); - } - - /** - * Given a x coordinate in view space, convert it to content space. - * Returns the result as a float. - */ - private float viewToContentXf(int x) { - return x * mZoomManager.getInvScale(); - } - - /** - * Given a y coordinate in view space, convert it to content space. - * Takes into account the height of the title bar if there is one - * embedded into the WebView. Returns the result as a float. - */ - private float viewToContentYf(int y) { - return (y - getTitleHeight()) * mZoomManager.getInvScale(); - } - - /** - * Given a distance in content space, convert it to view space. Note: this - * does not reflect translation, just scaling, so this should not be called - * with coordinates, but should be called for dimensions like width or - * height. - */ - /*package*/ int contentToViewDimension(int d) { - return Math.round(d * mZoomManager.getScale()); - } - - /** - * Given an x coordinate in content space, convert it to view - * space. - */ - /*package*/ int contentToViewX(int x) { - return contentToViewDimension(x); - } - - /** - * Given a y coordinate in content space, convert it to view - * space. Takes into account the height of the title bar. - */ - /*package*/ int contentToViewY(int y) { - return contentToViewDimension(y) + getTitleHeight(); - } - - private Rect contentToViewRect(Rect x) { - return new Rect(contentToViewX(x.left), contentToViewY(x.top), - contentToViewX(x.right), contentToViewY(x.bottom)); - } - - /* To invalidate a rectangle in content coordinates, we need to transform - the rect into view coordinates, so we can then call invalidate(...). - - Normally, we would just call contentToView[XY](...), which eventually - calls Math.round(coordinate * mActualScale). However, for invalidates, - we need to account for the slop that occurs with antialiasing. To - address that, we are a little more liberal in the size of the rect that - we invalidate. - - This liberal calculation calls floor() for the top/left, and ceil() for - the bottom/right coordinates. This catches the possible extra pixels of - antialiasing that we might have missed with just round(). - */ - - // Called by JNI to invalidate the View, given rectangle coordinates in - // content space - private void viewInvalidate(int l, int t, int r, int b) { - final float scale = mZoomManager.getScale(); - final int dy = getTitleHeight(); - invalidate((int)Math.floor(l * scale), - (int)Math.floor(t * scale) + dy, - (int)Math.ceil(r * scale), - (int)Math.ceil(b * scale) + dy); - } - - // Called by JNI to invalidate the View after a delay, given rectangle - // coordinates in content space - private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) { - final float scale = mZoomManager.getScale(); - final int dy = getTitleHeight(); - postInvalidateDelayed(delay, - (int)Math.floor(l * scale), - (int)Math.floor(t * scale) + dy, - (int)Math.ceil(r * scale), - (int)Math.ceil(b * scale) + dy); - } - - private void invalidateContentRect(Rect r) { - viewInvalidate(r.left, r.top, r.right, r.bottom); - } - - // stop the scroll animation, and don't let a subsequent fling add - // to the existing velocity - private void abortAnimation() { - mScroller.abortAnimation(); - mLastVelocity = 0; - } - - /* call from webcoreview.draw(), so we're still executing in the UI thread - */ - private void recordNewContentSize(int w, int h, boolean updateLayout) { - - // premature data from webkit, ignore - if ((w | h) == 0) { - return; - } - - // don't abort a scroll animation if we didn't change anything - if (mContentWidth != w || mContentHeight != h) { - // record new dimensions - mContentWidth = w; - mContentHeight = h; - // If history Picture is drawn, don't update scroll. They will be - // updated when we get out of that mode. - if (!mDrawHistory) { - // repin our scroll, taking into account the new content size - updateScrollCoordinates(pinLocX(mScrollX), pinLocY(mScrollY)); - if (!mScroller.isFinished()) { - // We are in the middle of a scroll. Repin the final scroll - // position. - mScroller.setFinalX(pinLocX(mScroller.getFinalX())); - mScroller.setFinalY(pinLocY(mScroller.getFinalY())); - } - } - } - contentSizeChanged(updateLayout); - } - - // Used to avoid sending many visible rect messages. - private Rect mLastVisibleRectSent = new Rect(); - private Rect mLastGlobalRect = new Rect(); - private Rect mVisibleRect = new Rect(); - private Rect mGlobalVisibleRect = new Rect(); - private Point mScrollOffset = new Point(); - - Rect sendOurVisibleRect() { - if (mZoomManager.isPreventingWebkitUpdates()) return mLastVisibleRectSent; - calcOurContentVisibleRect(mVisibleRect); - // Rect.equals() checks for null input. - if (!mVisibleRect.equals(mLastVisibleRectSent)) { - if (!mBlockWebkitViewMessages) { - mScrollOffset.set(mVisibleRect.left, mVisibleRect.top); - mWebViewCore.removeMessages(EventHub.SET_SCROLL_OFFSET); - mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET, - nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, mScrollOffset); - } - mLastVisibleRectSent.set(mVisibleRect); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - } - if (getGlobalVisibleRect(mGlobalVisibleRect) - && !mGlobalVisibleRect.equals(mLastGlobalRect)) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "sendOurVisibleRect=(" + mGlobalVisibleRect.left + "," - + mGlobalVisibleRect.top + ",r=" + mGlobalVisibleRect.right + ",b=" - + mGlobalVisibleRect.bottom); - } - // TODO: the global offset is only used by windowRect() - // in ChromeClientAndroid ; other clients such as touch - // and mouse events could return view + screen relative points. - if (!mBlockWebkitViewMessages) { - mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, mGlobalVisibleRect); - } - mLastGlobalRect.set(mGlobalVisibleRect); - } - return mVisibleRect; - } - - private Point mGlobalVisibleOffset = new Point(); - // Sets r to be the visible rectangle of our webview in view coordinates - private void calcOurVisibleRect(Rect r) { - getGlobalVisibleRect(r, mGlobalVisibleOffset); - r.offset(-mGlobalVisibleOffset.x, -mGlobalVisibleOffset.y); - } - - // Sets r to be our visible rectangle in content coordinates - private void calcOurContentVisibleRect(Rect r) { - calcOurVisibleRect(r); - r.left = viewToContentX(r.left); - // viewToContentY will remove the total height of the title bar. Add - // the visible height back in to account for the fact that if the title - // bar is partially visible, the part of the visible rect which is - // displaying our content is displaced by that amount. - r.top = viewToContentY(r.top + getVisibleTitleHeightImpl()); - r.right = viewToContentX(r.right); - r.bottom = viewToContentY(r.bottom); - } - - private Rect mContentVisibleRect = new Rect(); - // Sets r to be our visible rectangle in content coordinates. We use this - // method on the native side to compute the position of the fixed layers. - // Uses floating coordinates (necessary to correctly place elements when - // the scale factor is not 1) - private void calcOurContentVisibleRectF(RectF r) { - calcOurVisibleRect(mContentVisibleRect); - r.left = viewToContentXf(mContentVisibleRect.left); - // viewToContentY will remove the total height of the title bar. Add - // the visible height back in to account for the fact that if the title - // bar is partially visible, the part of the visible rect which is - // displaying our content is displaced by that amount. - r.top = viewToContentYf(mContentVisibleRect.top + getVisibleTitleHeightImpl()); - r.right = viewToContentXf(mContentVisibleRect.right); - r.bottom = viewToContentYf(mContentVisibleRect.bottom); - } - - static class ViewSizeData { - int mWidth; - int mHeight; - float mHeightWidthRatio; - int mActualViewHeight; - int mTextWrapWidth; - int mAnchorX; - int mAnchorY; - float mScale; - boolean mIgnoreHeight; - } - - /** - * Compute unzoomed width and height, and if they differ from the last - * values we sent, send them to webkit (to be used as new viewport) - * - * @param force ensures that the message is sent to webkit even if the width - * or height has not changed since the last message - * - * @return true if new values were sent - */ - boolean sendViewSizeZoom(boolean force) { - if (mBlockWebkitViewMessages) return false; - if (mZoomManager.isPreventingWebkitUpdates()) return false; - - int viewWidth = getViewWidth(); - int newWidth = Math.round(viewWidth * mZoomManager.getInvScale()); - // This height could be fixed and be different from actual visible height. - int viewHeight = getViewHeightWithTitle() - getTitleHeight(); - int newHeight = Math.round(viewHeight * mZoomManager.getInvScale()); - // Make the ratio more accurate than (newHeight / newWidth), since the - // latter both are calculated and rounded. - float heightWidthRatio = (float) viewHeight / viewWidth; - /* - * Because the native side may have already done a layout before the - * View system was able to measure us, we have to send a height of 0 to - * remove excess whitespace when we grow our width. This will trigger a - * layout and a change in content size. This content size change will - * mean that contentSizeChanged will either call this method directly or - * indirectly from onSizeChanged. - */ - if (newWidth > mLastWidthSent && mWrapContent) { - newHeight = 0; - heightWidthRatio = 0; - } - // Actual visible content height. - int actualViewHeight = Math.round(getViewHeight() * mZoomManager.getInvScale()); - // Avoid sending another message if the dimensions have not changed. - if (newWidth != mLastWidthSent || newHeight != mLastHeightSent || force || - actualViewHeight != mLastActualHeightSent) { - ViewSizeData data = new ViewSizeData(); - data.mWidth = newWidth; - data.mHeight = newHeight; - data.mHeightWidthRatio = heightWidthRatio; - data.mActualViewHeight = actualViewHeight; - data.mTextWrapWidth = Math.round(viewWidth / mZoomManager.getTextWrapScale()); - data.mScale = mZoomManager.getScale(); - data.mIgnoreHeight = mZoomManager.isFixedLengthAnimationInProgress() - && !mHeightCanMeasure; - data.mAnchorX = mZoomManager.getDocumentAnchorX(); - data.mAnchorY = mZoomManager.getDocumentAnchorY(); - mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data); - mLastWidthSent = newWidth; - mLastHeightSent = newHeight; - mLastActualHeightSent = actualViewHeight; - mZoomManager.clearDocumentAnchor(); - return true; - } - return false; - } - - /** - * Update the double-tap zoom. - */ - /* package */ void updateDoubleTapZoom(int doubleTapZoom) { - mZoomManager.updateDoubleTapZoom(doubleTapZoom); - } - - private int computeRealHorizontalScrollRange() { - if (mDrawHistory) { - return mHistoryWidth; - } else { - // to avoid rounding error caused unnecessary scrollbar, use floor - return (int) Math.floor(mContentWidth * mZoomManager.getScale()); - } - } - - @Override - protected int computeHorizontalScrollRange() { - int range = computeRealHorizontalScrollRange(); - - // Adjust reported range if overscrolled to compress the scroll bars - final int scrollX = mScrollX; - final int overscrollRight = computeMaxScrollX(); - if (scrollX < 0) { - range -= scrollX; - } else if (scrollX > overscrollRight) { - range += scrollX - overscrollRight; - } - - return range; - } - - @Override - protected int computeHorizontalScrollOffset() { - return Math.max(mScrollX, 0); - } - - private int computeRealVerticalScrollRange() { - if (mDrawHistory) { - return mHistoryHeight; - } else { - // to avoid rounding error caused unnecessary scrollbar, use floor - return (int) Math.floor(mContentHeight * mZoomManager.getScale()); - } - } - - @Override - protected int computeVerticalScrollRange() { - int range = computeRealVerticalScrollRange(); - - // Adjust reported range if overscrolled to compress the scroll bars - final int scrollY = mScrollY; - final int overscrollBottom = computeMaxScrollY(); - if (scrollY < 0) { - range -= scrollY; - } else if (scrollY > overscrollBottom) { - range += scrollY - overscrollBottom; - } - - return range; - } - - @Override - protected int computeVerticalScrollOffset() { - return Math.max(mScrollY - getTitleHeight(), 0); - } - - @Override - protected int computeVerticalScrollExtent() { - return getViewHeight(); - } - - /** @hide */ - @Override - protected void onDrawVerticalScrollBar(Canvas canvas, - Drawable scrollBar, - int l, int t, int r, int b) { - if (mScrollY < 0) { - t -= mScrollY; - } - scrollBar.setBounds(l, t + getVisibleTitleHeightImpl(), r, b); - scrollBar.draw(canvas); - } - - @Override - protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, - boolean clampedY) { - // Special-case layer scrolling so that we do not trigger normal scroll - // updating. - if (mTouchMode == TOUCH_DRAG_LAYER_MODE) { - scrollLayerTo(scrollX, scrollY); - return; - } - mInOverScrollMode = false; - int maxX = computeMaxScrollX(); - int maxY = computeMaxScrollY(); - if (maxX == 0) { - // do not over scroll x if the page just fits the screen - scrollX = pinLocX(scrollX); - } else if (scrollX < 0 || scrollX > maxX) { - mInOverScrollMode = true; - } - if (scrollY < 0 || scrollY > maxY) { - mInOverScrollMode = true; - } - - int oldX = mScrollX; - int oldY = mScrollY; - - super.scrollTo(scrollX, scrollY); - - if (mOverScrollGlow != null) { - mOverScrollGlow.pullGlow(mScrollX, mScrollY, oldX, oldY, maxX, maxY); - } + mProvider.requestImageRef(msg); } /** @@ -3708,8 +1046,7 @@ public class WebView extends AbsoluteLayout */ public String getUrl() { checkThread(); - WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); - return h != null ? h.getUrl() : null; + return mProvider.getUrl(); } /** @@ -3722,8 +1059,7 @@ public class WebView extends AbsoluteLayout */ public String getOriginalUrl() { checkThread(); - WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); - return h != null ? h.getOriginalUrl() : null; + return mProvider.getOriginalUrl(); } /** @@ -3733,8 +1069,7 @@ public class WebView extends AbsoluteLayout */ public String getTitle() { checkThread(); - WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); - return h != null ? h.getTitle() : null; + return mProvider.getTitle(); } /** @@ -3744,8 +1079,7 @@ public class WebView extends AbsoluteLayout */ public Bitmap getFavicon() { checkThread(); - WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); - return h != null ? h.getFavicon() : null; + return mProvider.getFavicon(); } /** @@ -3755,8 +1089,7 @@ public class WebView extends AbsoluteLayout * @hide */ public String getTouchIconUrl() { - WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); - return h != null ? h.getTouchIconUrl() : null; + return mProvider.getTouchIconUrl(); } /** @@ -3765,7 +1098,7 @@ public class WebView extends AbsoluteLayout */ public int getProgress() { checkThread(); - return mCallbackProxy.getProgress(); + return mProvider.getProgress(); } /** @@ -3773,7 +1106,7 @@ public class WebView extends AbsoluteLayout */ public int getContentHeight() { checkThread(); - return mContentHeight; + return mProvider.getContentHeight(); } /** @@ -3781,14 +1114,7 @@ public class WebView extends AbsoluteLayout * @hide */ public int getContentWidth() { - return mContentWidth; - } - - /** - * @hide - */ - public int getPageBackgroundColor() { - return nativeGetBackgroundColor(); + return mProvider.getContentWidth(); } /** @@ -3798,7 +1124,7 @@ public class WebView extends AbsoluteLayout */ public void pauseTimers() { checkThread(); - mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS); + mProvider.pauseTimers(); } /** @@ -3807,7 +1133,7 @@ public class WebView extends AbsoluteLayout */ public void resumeTimers() { checkThread(); - mWebViewCore.sendMessage(EventHub.RESUME_TIMERS); + mProvider.resumeTimers(); } /** @@ -3820,38 +1146,7 @@ public class WebView extends AbsoluteLayout */ public void onPause() { checkThread(); - if (!mIsPaused) { - mIsPaused = true; - mWebViewCore.sendMessage(EventHub.ON_PAUSE); - // We want to pause the current playing video when switching out - // from the current WebView/tab. - if (mHTML5VideoViewProxy != null) { - mHTML5VideoViewProxy.pauseAndDispatch(); - } - if (mNativeClass != 0) { - nativeSetPauseDrawing(mNativeClass, true); - } - - cancelSelectDialog(); - WebCoreThreadWatchdog.pause(); - } - } - - @Override - protected void onWindowVisibilityChanged(int visibility) { - super.onWindowVisibilityChanged(visibility); - updateDrawingState(); - } - - void updateDrawingState() { - if (mNativeClass == 0 || mIsPaused) return; - if (getWindowVisibility() != VISIBLE) { - nativeSetPauseDrawing(mNativeClass, true); - } else if (getVisibility() != VISIBLE) { - nativeSetPauseDrawing(mNativeClass, true); - } else { - nativeSetPauseDrawing(mNativeClass, false); - } + mProvider.onPause(); } /** @@ -3859,22 +1154,7 @@ public class WebView extends AbsoluteLayout */ public void onResume() { checkThread(); - if (mIsPaused) { - mIsPaused = false; - mWebViewCore.sendMessage(EventHub.ON_RESUME); - if (mNativeClass != 0) { - nativeSetPauseDrawing(mNativeClass, false); - } - } - // Ensure that the watchdog has a currently valid Context to be able to display - // a prompt dialog. For example, if the Activity was finished whilst the WebCore - // thread was blocked and the Activity is started again, we may reuse the blocked - // thread, but we'll have a new Activity. - WebCoreThreadWatchdog.updateContext(mContext); - // We get a call to onResume for new WebViews (i.e. mIsPaused will be false). We need - // to ensure that the Watchdog thread is running for the new WebView, so call - // it outside the if block above. - WebCoreThreadWatchdog.resume(); + mProvider.onResume(); } /** @@ -3883,7 +1163,7 @@ public class WebView extends AbsoluteLayout * @hide */ public boolean isPaused() { - return mIsPaused; + return mProvider.isPaused(); } /** @@ -3892,7 +1172,7 @@ public class WebView extends AbsoluteLayout */ public void freeMemory() { checkThread(); - mWebViewCore.sendMessage(EventHub.FREE_MEMORY); + mProvider.freeMemory(); } /** @@ -3903,11 +1183,7 @@ public class WebView extends AbsoluteLayout */ public void clearCache(boolean includeDiskFiles) { checkThread(); - // Note: this really needs to be a static method as it clears cache for all - // WebView. But we need mWebViewCore to send message to WebCore thread, so - // we can't make this static. - mWebViewCore.sendMessage(EventHub.CLEAR_CACHE, - includeDiskFiles ? 1 : 0, 0); + mProvider.clearCache(includeDiskFiles); } /** @@ -3916,9 +1192,7 @@ public class WebView extends AbsoluteLayout */ public void clearFormData() { checkThread(); - if (inEditingMode()) { - mWebTextView.setAdapterCustom(null); - } + mProvider.clearFormData(); } /** @@ -3926,8 +1200,7 @@ public class WebView extends AbsoluteLayout */ public void clearHistory() { checkThread(); - mCallbackProxy.getBackForwardList().setClearPending(); - mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY); + mProvider.clearHistory(); } /** @@ -3936,7 +1209,7 @@ public class WebView extends AbsoluteLayout */ public void clearSslPreferences() { checkThread(); - mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE); + mProvider.clearSslPreferences(); } /** @@ -3949,7 +1222,8 @@ public class WebView extends AbsoluteLayout */ public WebBackForwardList copyBackForwardList() { checkThread(); - return mCallbackProxy.getBackForwardList().clone(); + return mProvider.copyBackForwardList(); + } /* @@ -3961,8 +1235,7 @@ public class WebView extends AbsoluteLayout */ public void findNext(boolean forward) { checkThread(); - if (0 == mNativeClass) return; // client isn't initialized - mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0); + mProvider.findNext(forward); } /* @@ -3972,40 +1245,8 @@ public class WebView extends AbsoluteLayout * that were found. */ public int findAll(String find) { - return findAllBody(find, false); - } - - /** - * @hide - */ - public void findAllAsync(String find) { - findAllBody(find, true); - } - - private int findAllBody(String find, boolean isAsync) { checkThread(); - if (0 == mNativeClass) return 0; // client isn't initialized - mLastFind = find; - mWebViewCore.removeMessages(EventHub.FIND_ALL); - WebViewCore.FindAllRequest request = new - WebViewCore.FindAllRequest(find); - if (isAsync) { - mWebViewCore.sendMessage(EventHub.FIND_ALL, request); - return 0; // no need to wait for response - } - synchronized(request) { - try { - mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL, - request); - while (request.mMatchCount == -1) { - request.wait(); - } - } - catch (InterruptedException e) { - return 0; - } - } - return request.mMatchCount; + return mProvider.findAll(find); } /** @@ -4020,56 +1261,10 @@ public class WebView extends AbsoluteLayout */ public boolean showFindDialog(String text, boolean showIme) { checkThread(); - FindActionModeCallback callback = new FindActionModeCallback(mContext); - if (getParent() == null || startActionMode(callback) == null) { - // Could not start the action mode, so end Find on page - return false; - } - mCachedOverlappingActionModeHeight = -1; - mFindCallback = callback; - setFindIsUp(true); - mFindCallback.setWebView(this); - if (showIme) { - mFindCallback.showSoftInput(); - } else if (text != null) { - mFindCallback.setText(text); - mFindCallback.findAll(); - return true; - } - if (text == null) { - text = mLastFind; - } - if (text != null) { - mFindCallback.setText(text); - mFindCallback.findAll(); - } - return true; + return mProvider.showFindDialog(text, showIme); } /** - * Keep track of the find callback so that we can remove its titlebar if - * necessary. - */ - private FindActionModeCallback mFindCallback; - - /** - * Toggle whether the find dialog is showing, for both native and Java. - */ - private void setFindIsUp(boolean isUp) { - mFindIsUp = isUp; - if (0 == mNativeClass) return; // client isn't initialized - nativeSetFindIsUp(isUp); - } - - // Used to know whether the find dialog is open. Affects whether - // or not we draw the highlights for matches. - private boolean mFindIsUp; - - // Keep track of the last string sent, so we can search again when find is - // reopened. - private String mLastFind; - - /** * Return the first substring consisting of the address of a physical * location. Currently, only addresses in the United States are detected, * and consist of: @@ -4091,33 +1286,7 @@ public class WebView extends AbsoluteLayout */ public static String findAddress(String addr) { checkThread(); - return findAddress(addr, false); - } - - /** - * @hide - * Return the first substring consisting of the address of a physical - * location. Currently, only addresses in the United States are detected, - * and consist of: - * - a house number - * - a street name - * - a street type (Road, Circle, etc), either spelled out or abbreviated - * - a city name - * - a state or territory, either spelled out or two-letter abbr. - * - an optional 5 digit or 9 digit zip code. - * - * Names are optionally capitalized, and the zip code, if present, - * must be valid for the state. The street type must be a standard USPS - * spelling or abbreviation. The state or territory must also be spelled - * or abbreviated using USPS standards. The house number may not exceed - * five digits. - * @param addr The string to search for addresses. - * @param caseInsensitive addr Set to true to make search ignore case. - * - * @return the address, or if no address is found, return null. - */ - public static String findAddress(String addr, boolean caseInsensitive) { - return WebViewCore.nativeFindAddress(addr, caseInsensitive); + return getFactory().getStatics().findAddress(addr); } /* @@ -4125,28 +1294,7 @@ public class WebView extends AbsoluteLayout */ public void clearMatches() { checkThread(); - if (mNativeClass == 0) - return; - mWebViewCore.removeMessages(EventHub.FIND_ALL); - mWebViewCore.sendMessage(EventHub.FIND_ALL, null); - } - - - /** - * Called when the find ActionMode ends. - */ - void notifyFindDialogDismissed() { - mFindCallback = null; - mCachedOverlappingActionModeHeight = -1; - if (mWebViewCore == null) { - return; - } - clearMatches(); - setFindIsUp(false); - // Now that the dialog has been removed, ensure that we scroll to a - // location that is not beyond the end of the page. - pinScrollTo(mScrollX, mScrollY, false, 0); - invalidate(); + mProvider.clearMatches(); } /** @@ -4157,427 +1305,7 @@ public class WebView extends AbsoluteLayout */ public void documentHasImages(Message response) { checkThread(); - if (response == null) { - return; - } - mWebViewCore.sendMessage(EventHub.DOC_HAS_IMAGES, response); - } - - /** - * Request the scroller to abort any ongoing animation - * - * @hide - */ - public void stopScroll() { - mScroller.forceFinished(true); - mLastVelocity = 0; - } - - @Override - public void computeScroll() { - if (mScroller.computeScrollOffset()) { - int oldX = mScrollX; - int oldY = mScrollY; - int x = mScroller.getCurrX(); - int y = mScroller.getCurrY(); - invalidate(); // So we draw again - - if (!mScroller.isFinished()) { - int rangeX = computeMaxScrollX(); - int rangeY = computeMaxScrollY(); - int overflingDistance = mOverflingDistance; - - // Use the layer's scroll data if needed. - if (mTouchMode == TOUCH_DRAG_LAYER_MODE) { - oldX = mScrollingLayerRect.left; - oldY = mScrollingLayerRect.top; - rangeX = mScrollingLayerRect.right; - rangeY = mScrollingLayerRect.bottom; - // No overscrolling for layers. - overflingDistance = 0; - } - - overScrollBy(x - oldX, y - oldY, oldX, oldY, - rangeX, rangeY, - overflingDistance, overflingDistance, false); - - if (mOverScrollGlow != null) { - mOverScrollGlow.absorbGlow(x, y, oldX, oldY, rangeX, rangeY); - } - } else { - if (mTouchMode != TOUCH_DRAG_LAYER_MODE) { - mScrollX = x; - mScrollY = y; - } else { - // Update the layer position instead of WebView. - scrollLayerTo(x, y); - } - abortAnimation(); - nativeSetIsScrolling(false); - if (!mBlockWebkitViewMessages) { - WebViewCore.resumePriority(); - if (!mSelectingText) { - WebViewCore.resumeUpdatePicture(mWebViewCore); - } - } - if (oldX != mScrollX || oldY != mScrollY) { - sendOurVisibleRect(); - } - } - } else { - super.computeScroll(); - } - } - - private void scrollLayerTo(int x, int y) { - if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) { - return; - } - if (mSelectingText) { - int dx = mScrollingLayerRect.left - x; - int dy = mScrollingLayerRect.top - y; - if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) { - mSelectCursorBase.offset(dx, dy); - } - if (mSelectCursorExtentLayerId == mCurrentScrollingLayerId) { - mSelectCursorExtent.offset(dx, dy); - } - } - nativeScrollLayer(mCurrentScrollingLayerId, x, y); - mScrollingLayerRect.left = x; - mScrollingLayerRect.top = y; - mWebViewCore.sendMessage(WebViewCore.EventHub.SCROLL_LAYER, mCurrentScrollingLayerId, - mScrollingLayerRect); - onScrollChanged(mScrollX, mScrollY, mScrollX, mScrollY); - invalidate(); - } - - private static int computeDuration(int dx, int dy) { - int distance = Math.max(Math.abs(dx), Math.abs(dy)); - int duration = distance * 1000 / STD_SPEED; - return Math.min(duration, MAX_DURATION); - } - - // helper to pin the scrollBy parameters (already in view coordinates) - // returns true if the scroll was changed - private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) { - return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration); - } - // helper to pin the scrollTo parameters (already in view coordinates) - // returns true if the scroll was changed - private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) { - x = pinLocX(x); - y = pinLocY(y); - int dx = x - mScrollX; - int dy = y - mScrollY; - - if ((dx | dy) == 0) { - return false; - } - abortAnimation(); - if (animate) { - // Log.d(LOGTAG, "startScroll: " + dx + " " + dy); - mScroller.startScroll(mScrollX, mScrollY, dx, dy, - animationDuration > 0 ? animationDuration : computeDuration(dx, dy)); - awakenScrollBars(mScroller.getDuration()); - invalidate(); - } else { - scrollTo(x, y); - } - return true; - } - - // Scale from content to view coordinates, and pin. - // Also called by jni webview.cpp - private boolean setContentScrollBy(int cx, int cy, boolean animate) { - if (mDrawHistory) { - // disallow WebView to change the scroll position as History Picture - // is used in the view system. - // TODO: as we switchOutDrawHistory when trackball or navigation - // keys are hit, this should be safe. Right? - return false; - } - cx = contentToViewDimension(cx); - cy = contentToViewDimension(cy); - if (mHeightCanMeasure) { - // move our visible rect according to scroll request - if (cy != 0) { - Rect tempRect = new Rect(); - calcOurVisibleRect(tempRect); - tempRect.offset(cx, cy); - requestRectangleOnScreen(tempRect); - } - // FIXME: We scroll horizontally no matter what because currently - // ScrollView and ListView will not scroll horizontally. - // FIXME: Why do we only scroll horizontally if there is no - // vertical scroll? -// Log.d(LOGTAG, "setContentScrollBy cy=" + cy); - return cy == 0 && cx != 0 && pinScrollBy(cx, 0, animate, 0); - } else { - return pinScrollBy(cx, cy, animate, 0); - } - } - - /** - * Called by CallbackProxy when the page starts loading. - * @param url The URL of the page which has started loading. - */ - /* package */ void onPageStarted(String url) { - // every time we start a new page, we want to reset the - // WebView certificate: if the new site is secure, we - // will reload it and get a new certificate set; - // if the new site is not secure, the certificate must be - // null, and that will be the case - setCertificate(null); - - // reset the flag since we set to true in if need after - // loading is see onPageFinished(Url) - mAccessibilityScriptInjected = false; - } - - /** - * Called by CallbackProxy when the page finishes loading. - * @param url The URL of the page which has finished loading. - */ - /* package */ void onPageFinished(String url) { - if (mPageThatNeedsToSlideTitleBarOffScreen != null) { - // If the user is now on a different page, or has scrolled the page - // past the point where the title bar is offscreen, ignore the - // scroll request. - if (mPageThatNeedsToSlideTitleBarOffScreen.equals(url) - && mScrollX == 0 && mScrollY == 0) { - pinScrollTo(0, mYDistanceToSlideTitleOffScreen, true, - SLIDE_TITLE_DURATION); - } - mPageThatNeedsToSlideTitleBarOffScreen = null; - } - mZoomManager.onPageFinished(url); - injectAccessibilityForUrl(url); - } - - /** - * This method injects accessibility in the loaded document if accessibility - * is enabled. If JavaScript is enabled we try to inject a URL specific script. - * If no URL specific script is found or JavaScript is disabled we fallback to - * the default {@link AccessibilityInjector} implementation. - * </p> - * If the URL has the "axs" paramter set to 1 it has already done the - * script injection so we do nothing. If the parameter is set to 0 - * the URL opts out accessibility script injection so we fall back to - * the default {@link AccessibilityInjector}. - * </p> - * Note: If the user has not opted-in the accessibility script injection no scripts - * are injected rather the default {@link AccessibilityInjector} implementation - * is used. - * - * @param url The URL loaded by this {@link WebView}. - */ - private void injectAccessibilityForUrl(String url) { - if (mWebViewCore == null) { - return; - } - AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext); - - if (!accessibilityManager.isEnabled()) { - // it is possible that accessibility was turned off between reloads - ensureAccessibilityScriptInjectorInstance(false); - return; - } - - if (!getSettings().getJavaScriptEnabled()) { - // no JS so we fallback to the basic buil-in support - ensureAccessibilityScriptInjectorInstance(true); - return; - } - - // check the URL "axs" parameter to choose appropriate action - int axsParameterValue = getAxsUrlParameterValue(url); - if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED) { - boolean onDeviceScriptInjectionEnabled = (Settings.Secure.getInt(mContext - .getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1); - if (onDeviceScriptInjectionEnabled) { - ensureAccessibilityScriptInjectorInstance(false); - // neither script injected nor script injection opted out => we inject - loadUrl(getScreenReaderInjectingJs()); - // TODO: Set this flag after successfull script injection. Maybe upon injection - // the chooser should update the meta tag and we check it to declare success - mAccessibilityScriptInjected = true; - } else { - // injection disabled so we fallback to the basic built-in support - ensureAccessibilityScriptInjectorInstance(true); - } - } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) { - // injection opted out so we fallback to the basic buil-in support - ensureAccessibilityScriptInjectorInstance(true); - } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) { - ensureAccessibilityScriptInjectorInstance(false); - // the URL provides accessibility but we still need to add our generic script - loadUrl(getScreenReaderInjectingJs()); - } else { - Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue); - } - } - - /** - * Ensures the instance of the {@link AccessibilityInjector} to be present ot not. - * - * @param present True to ensure an insance, false to ensure no instance. - */ - private void ensureAccessibilityScriptInjectorInstance(boolean present) { - if (present) { - if (mAccessibilityInjector == null) { - mAccessibilityInjector = new AccessibilityInjector(this); - } - } else { - mAccessibilityInjector = null; - } - } - - /** - * Gets JavaScript that injects a screen-reader. - * - * @return The JavaScript snippet. - */ - private String getScreenReaderInjectingJs() { - String screenReaderUrl = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL); - return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl); - } - - /** - * Gets the "axs" URL parameter value. - * - * @param url A url to fetch the paramter from. - * @return The parameter value if such, -1 otherwise. - */ - private int getAxsUrlParameterValue(String url) { - if (mMatchAxsUrlParameterPattern == null) { - mMatchAxsUrlParameterPattern = Pattern.compile(PATTERN_MATCH_AXS_URL_PARAMETER); - } - Matcher matcher = mMatchAxsUrlParameterPattern.matcher(url); - if (matcher.find()) { - String keyValuePair = url.substring(matcher.start(), matcher.end()); - return Integer.parseInt(keyValuePair.split("=")[1]); - } - return -1; - } - - /** - * The URL of a page that sent a message to scroll the title bar off screen. - * - * Many mobile sites tell the page to scroll to (0,1) in order to scroll the - * title bar off the screen. Sometimes, the scroll position is set before - * the page finishes loading. Rather than scrolling while the page is still - * loading, keep track of the URL and new scroll position so we can perform - * the scroll once the page finishes loading. - */ - private String mPageThatNeedsToSlideTitleBarOffScreen; - - /** - * The destination Y scroll position to be used when the page finishes - * loading. See mPageThatNeedsToSlideTitleBarOffScreen. - */ - private int mYDistanceToSlideTitleOffScreen; - - // scale from content to view coordinates, and pin - // return true if pin caused the final x/y different than the request cx/cy, - // and a future scroll may reach the request cx/cy after our size has - // changed - // return false if the view scroll to the exact position as it is requested, - // where negative numbers are taken to mean 0 - private boolean setContentScrollTo(int cx, int cy) { - if (mDrawHistory) { - // disallow WebView to change the scroll position as History Picture - // is used in the view system. - // One known case where this is called is that WebCore tries to - // restore the scroll position. As history Picture already uses the - // saved scroll position, it is ok to skip this. - return false; - } - int vx; - int vy; - if ((cx | cy) == 0) { - // If the page is being scrolled to (0,0), do not add in the title - // bar's height, and simply scroll to (0,0). (The only other work - // in contentToView_ is to multiply, so this would not change 0.) - vx = 0; - vy = 0; - } else { - vx = contentToViewX(cx); - vy = contentToViewY(cy); - } -// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" + -// vx + " " + vy + "]"); - // Some mobile sites attempt to scroll the title bar off the page by - // scrolling to (0,1). If we are at the top left corner of the - // page, assume this is an attempt to scroll off the title bar, and - // animate the title bar off screen slowly enough that the user can see - // it. - if (cx == 0 && cy == 1 && mScrollX == 0 && mScrollY == 0 - && mTitleBar != null) { - // FIXME: 100 should be defined somewhere as our max progress. - if (getProgress() < 100) { - // Wait to scroll the title bar off screen until the page has - // finished loading. Keep track of the URL and the destination - // Y position - mPageThatNeedsToSlideTitleBarOffScreen = getUrl(); - mYDistanceToSlideTitleOffScreen = vy; - } else { - pinScrollTo(vx, vy, true, SLIDE_TITLE_DURATION); - } - // Since we are animating, we have not yet reached the desired - // scroll position. Do not return true to request another attempt - return false; - } - pinScrollTo(vx, vy, false, 0); - // If the request was to scroll to a negative coordinate, treat it as if - // it was a request to scroll to 0 - if ((mScrollX != vx && cx >= 0) || (mScrollY != vy && cy >= 0)) { - return true; - } else { - return false; - } - } - - // scale from content to view coordinates, and pin - private void spawnContentScrollTo(int cx, int cy) { - if (mDrawHistory) { - // disallow WebView to change the scroll position as History Picture - // is used in the view system. - return; - } - int vx = contentToViewX(cx); - int vy = contentToViewY(cy); - pinScrollTo(vx, vy, true, 0); - } - - /** - * These are from webkit, and are in content coordinate system (unzoomed) - */ - private void contentSizeChanged(boolean updateLayout) { - // suppress 0,0 since we usually see real dimensions soon after - // this avoids drawing the prev content in a funny place. If we find a - // way to consolidate these notifications, this check may become - // obsolete - if ((mContentWidth | mContentHeight) == 0) { - return; - } - - if (mHeightCanMeasure) { - if (getMeasuredHeight() != contentToViewDimension(mContentHeight) - || updateLayout) { - requestLayout(); - } - } else if (mWidthCanMeasure) { - if (getMeasuredWidth() != contentToViewDimension(mContentWidth) - || updateLayout) { - requestLayout(); - } - } else { - // If we don't request a layout, try to send our view size to the - // native side to ensure that WebCore has the correct dimensions. - sendViewSizeZoom(false); - } + mProvider.documentHasImages(response); } /** @@ -4587,17 +1315,7 @@ public class WebView extends AbsoluteLayout */ public void setWebViewClient(WebViewClient client) { checkThread(); - mCallbackProxy.setWebViewClient(client); - } - - /** - * Gets the WebViewClient - * @return the current WebViewClient instance. - * - * @hide This is an implementation detail. - */ - public WebViewClient getWebViewClient() { - return mCallbackProxy.getWebViewClient(); + mProvider.setWebViewClient(client); } /** @@ -4608,7 +1326,7 @@ public class WebView extends AbsoluteLayout */ public void setDownloadListener(DownloadListener listener) { checkThread(); - mCallbackProxy.setDownloadListener(listener); + mProvider.setDownloadListener(listener); } /** @@ -4619,36 +1337,7 @@ public class WebView extends AbsoluteLayout */ public void setWebChromeClient(WebChromeClient client) { checkThread(); - mCallbackProxy.setWebChromeClient(client); - } - - /** - * Gets the chrome handler. - * @return the current WebChromeClient instance. - * - * @hide This is an implementation detail. - */ - public WebChromeClient getWebChromeClient() { - return mCallbackProxy.getWebChromeClient(); - } - - /** - * Set the back/forward list client. This is an implementation of - * WebBackForwardListClient for handling new items and changes in the - * history index. - * @param client An implementation of WebBackForwardListClient. - * {@hide} - */ - public void setWebBackForwardListClient(WebBackForwardListClient client) { - mCallbackProxy.setWebBackForwardListClient(client); - } - - /** - * Gets the WebBackForwardListClient. - * {@hide} - */ - public WebBackForwardListClient getWebBackForwardListClient() { - return mCallbackProxy.getWebBackForwardListClient(); + mProvider.setWebChromeClient(client); } /** @@ -4660,23 +1349,7 @@ public class WebView extends AbsoluteLayout @Deprecated public void setPictureListener(PictureListener listener) { checkThread(); - mPictureListener = listener; - } - - /** - * {@hide} - */ - /* FIXME: Debug only! Remove for SDK! */ - public void externalRepresentation(Message callback) { - mWebViewCore.sendMessage(EventHub.REQUEST_EXT_REPRESENTATION, callback); - } - - /** - * {@hide} - */ - /* FIXME: Debug only! Remove for SDK! */ - public void documentAsText(Message callback) { - mWebViewCore.sendMessage(EventHub.REQUEST_DOC_AS_TEXT, callback); + mProvider.setPictureListener(listener); } /** @@ -4707,13 +1380,7 @@ public class WebView extends AbsoluteLayout */ public void addJavascriptInterface(Object object, String name) { checkThread(); - if (object == null) { - return; - } - WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData(); - arg.mObject = object; - arg.mInterfaceName = name; - mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg); + mProvider.addJavascriptInterface(object, name); } /** @@ -4722,11 +1389,7 @@ public class WebView extends AbsoluteLayout */ public void removeJavascriptInterface(String interfaceName) { checkThread(); - if (mWebViewCore != null) { - WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData(); - arg.mInterfaceName = interfaceName; - mWebViewCore.sendMessage(EventHub.REMOVE_JS_INTERFACE, arg); - } + mProvider.removeJavascriptInterface(interfaceName); } /** @@ -4737,1410 +1400,31 @@ public class WebView extends AbsoluteLayout */ public WebSettings getSettings() { checkThread(); - return (mWebViewCore != null) ? mWebViewCore.getSettings() : null; + return mProvider.getSettings(); } - /** - * Return the list of currently loaded plugins. - * @return The list of currently loaded plugins. - * - * @hide - * @deprecated This was used for Gears, which has been deprecated. - */ + /** + * Return the list of currently loaded plugins. + * @return The list of currently loaded plugins. + * + * @hide + * @deprecated This was used for Gears, which has been deprecated. + */ @Deprecated public static synchronized PluginList getPluginList() { checkThread(); return new PluginList(); } - /** - * @hide - * @deprecated This was used for Gears, which has been deprecated. - */ + /** + * @hide + * @deprecated This was used for Gears, which has been deprecated. + */ @Deprecated public void refreshPlugins(boolean reloadOpenPages) { checkThread(); } - //------------------------------------------------------------------------- - // Override View methods - //------------------------------------------------------------------------- - - @Override - protected void finalize() throws Throwable { - try { - if (mNativeClass != 0) { - mPrivateHandler.post(new Runnable() { - @Override - public void run() { - destroy(); - } - }); - } - } finally { - super.finalize(); - } - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (child == mTitleBar) { - // When drawing the title bar, move it horizontally to always show - // at the top of the WebView. - mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft()); - int newTop = 0; - if (mTitleGravity == Gravity.NO_GRAVITY) { - newTop = Math.min(0, mScrollY); - } else if (mTitleGravity == Gravity.TOP) { - newTop = mScrollY; - } - mTitleBar.setBottom(newTop + mTitleBar.getHeight()); - mTitleBar.setTop(newTop); - } - return super.drawChild(canvas, child, drawingTime); - } - - private void drawContent(Canvas canvas, boolean drawRings) { - drawCoreAndCursorRing(canvas, mBackgroundColor, - mDrawCursorRing && drawRings); - } - - /** - * Draw the background when beyond bounds - * @param canvas Canvas to draw into - */ - private void drawOverScrollBackground(Canvas canvas) { - if (mOverScrollBackground == null) { - mOverScrollBackground = new Paint(); - Bitmap bm = BitmapFactory.decodeResource( - mContext.getResources(), - com.android.internal.R.drawable.status_bar_background); - mOverScrollBackground.setShader(new BitmapShader(bm, - Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)); - mOverScrollBorder = new Paint(); - mOverScrollBorder.setStyle(Paint.Style.STROKE); - mOverScrollBorder.setStrokeWidth(0); - mOverScrollBorder.setColor(0xffbbbbbb); - } - - int top = 0; - int right = computeRealHorizontalScrollRange(); - int bottom = top + computeRealVerticalScrollRange(); - // first draw the background and anchor to the top of the view - canvas.save(); - canvas.translate(mScrollX, mScrollY); - canvas.clipRect(-mScrollX, top - mScrollY, right - mScrollX, bottom - - mScrollY, Region.Op.DIFFERENCE); - canvas.drawPaint(mOverScrollBackground); - canvas.restore(); - // then draw the border - canvas.drawRect(-1, top - 1, right, bottom, mOverScrollBorder); - // next clip the region for the content - canvas.clipRect(0, top, right, bottom); - } - - @Override - protected void onDraw(Canvas canvas) { - if (inFullScreenMode()) { - return; // no need to draw anything if we aren't visible. - } - // if mNativeClass is 0, the WebView is either destroyed or not - // initialized. In either case, just draw the background color and return - if (mNativeClass == 0) { - canvas.drawColor(mBackgroundColor); - return; - } - - // if both mContentWidth and mContentHeight are 0, it means there is no - // valid Picture passed to WebView yet. This can happen when WebView - // just starts. Draw the background and return. - if ((mContentWidth | mContentHeight) == 0 && mHistoryPicture == null) { - canvas.drawColor(mBackgroundColor); - return; - } - - if (canvas.isHardwareAccelerated()) { - mZoomManager.setHardwareAccelerated(); - } else { - mWebViewCore.resumeWebKitDraw(); - } - - int saveCount = canvas.save(); - if (mInOverScrollMode && !getSettings() - .getUseWebViewBackgroundForOverscrollBackground()) { - drawOverScrollBackground(canvas); - } - if (mTitleBar != null) { - canvas.translate(0, getTitleHeight()); - } - boolean drawNativeRings = !sDisableNavcache; - drawContent(canvas, drawNativeRings); - canvas.restoreToCount(saveCount); - - if (AUTO_REDRAW_HACK && mAutoRedraw) { - invalidate(); - } - mWebViewCore.signalRepaintDone(); - - if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas)) { - invalidate(); - } - - if (mFocusTransition != null) { - mFocusTransition.draw(canvas); - } else if (shouldDrawHighlightRect()) { - RegionIterator iter = new RegionIterator(mTouchHighlightRegion); - Rect r = new Rect(); - while (iter.next(r)) { - canvas.drawRect(r, mTouchHightlightPaint); - } - } - if (DEBUG_TOUCH_HIGHLIGHT) { - if (getSettings().getNavDump()) { - if ((mTouchHighlightX | mTouchHighlightY) != 0) { - if (mTouchCrossHairColor == null) { - mTouchCrossHairColor = new Paint(); - mTouchCrossHairColor.setColor(Color.RED); - } - canvas.drawLine(mTouchHighlightX - mNavSlop, - mTouchHighlightY - mNavSlop, mTouchHighlightX - + mNavSlop + 1, mTouchHighlightY + mNavSlop - + 1, mTouchCrossHairColor); - canvas.drawLine(mTouchHighlightX + mNavSlop + 1, - mTouchHighlightY - mNavSlop, mTouchHighlightX - - mNavSlop, - mTouchHighlightY + mNavSlop + 1, - mTouchCrossHairColor); - } - } - } - } - - private void removeTouchHighlight() { - mWebViewCore.removeMessages(EventHub.HIT_TEST); - mPrivateHandler.removeMessages(HIT_TEST_RESULT); - setTouchHighlightRects(null); - } - - @Override - public void setLayoutParams(ViewGroup.LayoutParams params) { - if (params.height == LayoutParams.WRAP_CONTENT) { - mWrapContent = true; - } - super.setLayoutParams(params); - } - - @Override - public boolean performLongClick() { - // performLongClick() is the result of a delayed message. If we switch - // to windows overview, the WebView will be temporarily removed from the - // view system. In that case, do nothing. - if (getParent() == null) return false; - - // A multi-finger gesture can look like a long press; make sure we don't take - // long press actions if we're scaling. - final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector(); - if (detector != null && detector.isInProgress()) { - return false; - } - - if (mNativeClass != 0 && nativeCursorIsTextInput()) { - // Send the click so that the textfield is in focus - centerKeyPressOnTextField(); - rebuildWebTextView(); - } else { - clearTextEntry(); - } - if (inEditingMode()) { - // Since we just called rebuildWebTextView, the layout is not set - // properly. Update it so it can correctly find the word to select. - mWebTextView.ensureLayout(); - // Provide a touch down event to WebTextView, which will allow it - // to store the location to use in performLongClick. - AbsoluteLayout.LayoutParams params - = (AbsoluteLayout.LayoutParams) mWebTextView.getLayoutParams(); - MotionEvent fake = MotionEvent.obtain(mLastTouchTime, - mLastTouchTime, MotionEvent.ACTION_DOWN, - mLastTouchX - params.x + mScrollX, - mLastTouchY - params.y + mScrollY, 0); - mWebTextView.dispatchTouchEvent(fake); - return mWebTextView.performLongClick(); - } - if (mSelectingText) return false; // long click does nothing on selection - /* if long click brings up a context menu, the super function - * returns true and we're done. Otherwise, nothing happened when - * the user clicked. */ - if (super.performLongClick()) { - return true; - } - /* In the case where the application hasn't already handled the long - * click action, look for a word under the click. If one is found, - * animate the text selection into view. - * FIXME: no animation code yet */ - final boolean isSelecting = selectText(); - if (isSelecting) { - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - } else if (focusCandidateIsEditableText()) { - mSelectCallback = new SelectActionModeCallback(); - mSelectCallback.setWebView(this); - mSelectCallback.setTextSelected(false); - startActionMode(mSelectCallback); - } - return isSelecting; - } - - /** - * Select the word at the last click point. - * - * @hide This is an implementation detail. - */ - public boolean selectText() { - int x = viewToContentX(mLastTouchX + mScrollX); - int y = viewToContentY(mLastTouchY + mScrollY); - return selectText(x, y); - } - - /** - * Select the word at the indicated content coordinates. - */ - boolean selectText(int x, int y) { - mWebViewCore.sendMessage(EventHub.SELECT_WORD_AT, x, y); - return true; - } - - private int mOrientation = Configuration.ORIENTATION_UNDEFINED; - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - mCachedOverlappingActionModeHeight = -1; - if (mSelectingText && mOrientation != newConfig.orientation) { - selectionDone(); - } - mOrientation = newConfig.orientation; - if (mWebViewCore != null && !mBlockWebkitViewMessages) { - mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT); - } - } - - /** - * Keep track of the Callback so we can end its ActionMode or remove its - * titlebar. - */ - private SelectActionModeCallback mSelectCallback; - - // These values are possible options for didUpdateWebTextViewDimensions. - private static final int FULLY_ON_SCREEN = 0; - private static final int INTERSECTS_SCREEN = 1; - private static final int ANYWHERE = 2; - - /** - * Check to see if the focused textfield/textarea is still on screen. If it - * is, update the the dimensions and location of WebTextView. Otherwise, - * remove the WebTextView. Should be called when the zoom level changes. - * @param intersection How to determine whether the textfield/textarea is - * still on screen. - * @return boolean True if the textfield/textarea is still on screen and the - * dimensions/location of WebTextView have been updated. - */ - private boolean didUpdateWebTextViewDimensions(int intersection) { - Rect contentBounds = nativeFocusCandidateNodeBounds(); - Rect vBox = contentToViewRect(contentBounds); - Rect visibleRect = new Rect(); - calcOurVisibleRect(visibleRect); - offsetByLayerScrollPosition(vBox); - // If the textfield is on screen, place the WebTextView in - // its new place, accounting for our new scroll/zoom values, - // and adjust its textsize. - boolean onScreen; - switch (intersection) { - case FULLY_ON_SCREEN: - onScreen = visibleRect.contains(vBox); - break; - case INTERSECTS_SCREEN: - onScreen = Rect.intersects(visibleRect, vBox); - break; - case ANYWHERE: - onScreen = true; - break; - default: - throw new AssertionError( - "invalid parameter passed to didUpdateWebTextViewDimensions"); - } - if (onScreen) { - mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), - vBox.height()); - mWebTextView.updateTextSize(); - updateWebTextViewPadding(); - return true; - } else { - // The textfield is now off screen. The user probably - // was not zooming to see the textfield better. Remove - // the WebTextView. If the user types a key, and the - // textfield is still in focus, we will reconstruct - // the WebTextView and scroll it back on screen. - mWebTextView.remove(); - return false; - } - } - - private void offsetByLayerScrollPosition(Rect box) { - if ((mCurrentScrollingLayerId != 0) - && (mCurrentScrollingLayerId == nativeFocusCandidateLayerId())) { - box.offsetTo(box.left - mScrollingLayerRect.left, - box.top - mScrollingLayerRect.top); - } - } - - void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator, - boolean isPictureAfterFirstLayout) { - if (mNativeClass == 0) - return; - boolean queueFull; - queueFull = nativeSetBaseLayer(mNativeClass, layer, invalRegion, - showVisualIndicator, isPictureAfterFirstLayout); - - if (layer == 0 || isPictureAfterFirstLayout) { - mWebViewCore.resumeWebKitDraw(); - } else if (queueFull) { - // temporarily disable webkit draw throttling - // TODO: re-enable - // mWebViewCore.pauseWebKitDraw(); - } - - if (mHTML5VideoViewProxy != null) { - mHTML5VideoViewProxy.setBaseLayer(layer); - } - } - - int getBaseLayer() { - if (mNativeClass == 0) { - return 0; - } - return nativeGetBaseLayer(); - } - - private void onZoomAnimationStart() { - // If it is in password mode, turn it off so it does not draw misplaced. - if (inEditingMode()) { - mWebTextView.setVisibility(INVISIBLE); - } - } - - private void onZoomAnimationEnd() { - // adjust the edit text view if needed - if (inEditingMode() - && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)) { - // If it is a password field, start drawing the WebTextView once - // again. - mWebTextView.setVisibility(VISIBLE); - } - } - - void onFixedLengthZoomAnimationStart() { - WebViewCore.pauseUpdatePicture(getWebViewCore()); - onZoomAnimationStart(); - } - - void onFixedLengthZoomAnimationEnd() { - if (!mBlockWebkitViewMessages && !mSelectingText) { - WebViewCore.resumeUpdatePicture(mWebViewCore); - } - onZoomAnimationEnd(); - } - - private static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG | - Paint.DITHER_FLAG | - Paint.SUBPIXEL_TEXT_FLAG; - private static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG | - Paint.DITHER_FLAG; - - private final DrawFilter mZoomFilter = - new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG); - // If we need to trade better quality for speed, set mScrollFilter to null - private final DrawFilter mScrollFilter = - new PaintFlagsDrawFilter(SCROLL_BITS, 0); - - private void drawCoreAndCursorRing(Canvas canvas, int color, - boolean drawCursorRing) { - if (mDrawHistory) { - canvas.scale(mZoomManager.getScale(), mZoomManager.getScale()); - canvas.drawPicture(mHistoryPicture); - return; - } - if (mNativeClass == 0) return; - - boolean animateZoom = mZoomManager.isFixedLengthAnimationInProgress(); - boolean animateScroll = ((!mScroller.isFinished() - || mVelocityTracker != null) - && (mTouchMode != TOUCH_DRAG_MODE || - mHeldMotionless != MOTIONLESS_TRUE)) - || mDeferTouchMode == TOUCH_DRAG_MODE; - if (mTouchMode == TOUCH_DRAG_MODE) { - if (mHeldMotionless == MOTIONLESS_PENDING) { - mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS); - mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS); - mHeldMotionless = MOTIONLESS_FALSE; - } - if (mHeldMotionless == MOTIONLESS_FALSE) { - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME); - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(AWAKEN_SCROLL_BARS), - ViewConfiguration.getScrollDefaultDelay()); - mHeldMotionless = MOTIONLESS_PENDING; - } - } - int saveCount = canvas.save(); - if (animateZoom) { - mZoomManager.animateZoom(canvas); - } else if (!canvas.isHardwareAccelerated()) { - canvas.scale(mZoomManager.getScale(), mZoomManager.getScale()); - } - - boolean UIAnimationsRunning = false; - // Currently for each draw we compute the animation values; - // We may in the future decide to do that independently. - if (mNativeClass != 0 && !canvas.isHardwareAccelerated() - && nativeEvaluateLayersAnimations(mNativeClass)) { - UIAnimationsRunning = true; - // If we have unfinished (or unstarted) animations, - // we ask for a repaint. We only need to do this in software - // rendering (with hardware rendering we already have a different - // method of requesting a repaint) - mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED); - invalidate(); - } - - // decide which adornments to draw - int extras = DRAW_EXTRAS_NONE; - if (!mFindIsUp) { - if (mSelectingText) { - extras = DRAW_EXTRAS_SELECTION; - } else if (drawCursorRing) { - extras = DRAW_EXTRAS_CURSOR_RING; - } - } - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp - + " mSelectingText=" + mSelectingText - + " nativePageShouldHandleShiftAndArrows()=" - + nativePageShouldHandleShiftAndArrows() - + " animateZoom=" + animateZoom - + " extras=" + extras); - } - - calcOurContentVisibleRectF(mVisibleContentRect); - if (canvas.isHardwareAccelerated()) { - Rect glRectViewport = mGLViewportEmpty ? null : mGLRectViewport; - Rect viewRectViewport = mGLViewportEmpty ? null : mViewRectViewport; - - int functor = nativeGetDrawGLFunction(mNativeClass, glRectViewport, - viewRectViewport, mVisibleContentRect, getScale(), extras); - ((HardwareCanvas) canvas).callDrawGLFunction(functor); - if (mHardwareAccelSkia != getSettings().getHardwareAccelSkiaEnabled()) { - mHardwareAccelSkia = getSettings().getHardwareAccelSkiaEnabled(); - nativeUseHardwareAccelSkia(mHardwareAccelSkia); - } - - } else { - DrawFilter df = null; - if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) { - df = mZoomFilter; - } else if (animateScroll) { - df = mScrollFilter; - } - canvas.setDrawFilter(df); - // XXX: Revisit splitting content. Right now it causes a - // synchronization problem with layers. - int content = nativeDraw(canvas, mVisibleContentRect, color, - extras, false); - canvas.setDrawFilter(null); - if (!mBlockWebkitViewMessages && content != 0) { - mWebViewCore.sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0); - } - } - - canvas.restoreToCount(saveCount); - if (mSelectingText) { - drawTextSelectionHandles(canvas); - } - - if (extras == DRAW_EXTRAS_CURSOR_RING) { - if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) { - mTouchMode = TOUCH_SHORTPRESS_MODE; - } - } - if (mFocusSizeChanged) { - mFocusSizeChanged = false; - // If we are zooming, this will get handled above, when the zoom - // finishes. We also do not need to do this unless the WebTextView - // is showing. With hardware acceleration, the pageSwapCallback() - // updates the WebTextView position in sync with page swapping - if (!canvas.isHardwareAccelerated() && !animateZoom && inEditingMode()) { - didUpdateWebTextViewDimensions(ANYWHERE); - } - } - } - - private void drawTextSelectionHandles(Canvas canvas) { - int[] handles = new int[4]; - getSelectionHandles(handles); - int start_x = contentToViewDimension(handles[0]); - int start_y = contentToViewDimension(handles[1]); - int end_x = contentToViewDimension(handles[2]); - int end_y = contentToViewDimension(handles[3]); - - if (mIsCaretSelection) { - if (mSelectHandleCenter == null) { - mSelectHandleCenter = mContext.getResources().getDrawable( - com.android.internal.R.drawable.text_select_handle_middle); - } - // Caret handle is centered - start_x -= (mSelectHandleCenter.getIntrinsicWidth() / 2); - mSelectHandleCenter.setBounds(start_x, start_y, - start_x + mSelectHandleCenter.getIntrinsicWidth(), - start_y + mSelectHandleCenter.getIntrinsicHeight()); - mSelectHandleCenter.draw(canvas); - } else { - if (mSelectHandleLeft == null) { - mSelectHandleLeft = mContext.getResources().getDrawable( - com.android.internal.R.drawable.text_select_handle_left); - } - // Magic formula copied from TextView - start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4; - mSelectHandleLeft.setBounds(start_x, start_y, - start_x + mSelectHandleLeft.getIntrinsicWidth(), - start_y + mSelectHandleLeft.getIntrinsicHeight()); - if (mSelectHandleRight == null) { - mSelectHandleRight = mContext.getResources().getDrawable( - com.android.internal.R.drawable.text_select_handle_right); - } - end_x -= mSelectHandleRight.getIntrinsicWidth() / 4; - mSelectHandleRight.setBounds(end_x, end_y, - end_x + mSelectHandleRight.getIntrinsicWidth(), - end_y + mSelectHandleRight.getIntrinsicHeight()); - mSelectHandleLeft.draw(canvas); - mSelectHandleRight.draw(canvas); - } - } - - /** - * Takes an int[4] array as an output param with the values being - * startX, startY, endX, endY - */ - private void getSelectionHandles(int[] handles) { - handles[0] = mSelectCursorBase.right; - handles[1] = mSelectCursorBase.bottom - - (mSelectCursorBase.height() / 4); - handles[2] = mSelectCursorExtent.left; - handles[3] = mSelectCursorExtent.bottom - - (mSelectCursorExtent.height() / 4); - if (!nativeIsBaseFirst(mNativeClass)) { - int swap = handles[0]; - handles[0] = handles[2]; - handles[2] = swap; - swap = handles[1]; - handles[1] = handles[3]; - handles[3] = swap; - } - } - - // draw history - private boolean mDrawHistory = false; - private Picture mHistoryPicture = null; - private int mHistoryWidth = 0; - private int mHistoryHeight = 0; - - // Only check the flag, can be called from WebCore thread - boolean drawHistory() { - return mDrawHistory; - } - - int getHistoryPictureWidth() { - return (mHistoryPicture != null) ? mHistoryPicture.getWidth() : 0; - } - - // Should only be called in UI thread - void switchOutDrawHistory() { - if (null == mWebViewCore) return; // CallbackProxy may trigger this - if (mDrawHistory && (getProgress() == 100 || nativeHasContent())) { - mDrawHistory = false; - mHistoryPicture = null; - invalidate(); - int oldScrollX = mScrollX; - int oldScrollY = mScrollY; - mScrollX = pinLocX(mScrollX); - mScrollY = pinLocY(mScrollY); - if (oldScrollX != mScrollX || oldScrollY != mScrollY) { - onScrollChanged(mScrollX, mScrollY, oldScrollX, oldScrollY); - } else { - sendOurVisibleRect(); - } - } - } - - // TODO: Remove this - WebViewCore.CursorData cursorData() { - if (sDisableNavcache) { - return new WebViewCore.CursorData(0, 0, 0, 0); - } - WebViewCore.CursorData result = cursorDataNoPosition(); - Point position = nativeCursorPosition(); - result.mX = position.x; - result.mY = position.y; - return result; - } - - WebViewCore.CursorData cursorDataNoPosition() { - WebViewCore.CursorData result = new WebViewCore.CursorData(); - result.mMoveGeneration = nativeMoveGeneration(); - result.mFrame = nativeCursorFramePointer(); - return result; - } - - /** - * Delete text from start to end in the focused textfield. If there is no - * focus, or if start == end, silently fail. If start and end are out of - * order, swap them. - * @param start Beginning of selection to delete. - * @param end End of selection to delete. - */ - /* package */ void deleteSelection(int start, int end) { - mTextGeneration++; - WebViewCore.TextSelectionData data - = new WebViewCore.TextSelectionData(start, end, 0); - mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0, - data); - } - - /** - * Set the selection to (start, end) in the focused textfield. If start and - * end are out of order, swap them. - * @param start Beginning of selection. - * @param end End of selection. - */ - /* package */ void setSelection(int start, int end) { - if (mWebViewCore != null) { - mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end); - } - } - - @Override - public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - if (mInputConnection == null) { - mInputConnection = new WebViewInputConnection(); - } - mInputConnection.setupEditorInfo(outAttrs); - return mInputConnection; - } - - /** - * Called in response to a message from webkit telling us that the soft - * keyboard should be launched. - */ - private void displaySoftKeyboard(boolean isTextView) { - InputMethodManager imm = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - - // bring it back to the default level scale so that user can enter text - boolean zoom = mZoomManager.getScale() < mZoomManager.getDefaultScale(); - if (zoom) { - mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY); - mZoomManager.setZoomScale(mZoomManager.getDefaultScale(), false); - } - if (isTextView) { - rebuildWebTextView(); - if (inEditingMode()) { - imm.showSoftInput(mWebTextView, 0, mWebTextView.getResultReceiver()); - if (zoom) { - didUpdateWebTextViewDimensions(INTERSECTS_SCREEN); - } - return; - } - } - // Used by plugins and contentEditable. - // Also used if the navigation cache is out of date, and - // does not recognize that a textfield is in focus. In that - // case, use WebView as the targeted view. - // see http://b/issue?id=2457459 - imm.showSoftInput(this, 0); - } - - // Called by WebKit to instruct the UI to hide the keyboard - private void hideSoftKeyboard() { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null && (imm.isActive(this) - || (inEditingMode() && imm.isActive(mWebTextView)))) { - imm.hideSoftInputFromWindow(this.getWindowToken(), 0); - } - } - - /* - * This method checks the current focus and cursor and potentially rebuilds - * mWebTextView to have the appropriate properties, such as password, - * multiline, and what text it contains. It also removes it if necessary. - */ - /* package */ void rebuildWebTextView() { - if (!sEnableWebTextView) { - return; // always use WebKit's text entry - } - // If the WebView does not have focus, do nothing until it gains focus. - if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) { - return; - } - boolean alreadyThere = inEditingMode(); - // inEditingMode can only return true if mWebTextView is non-null, - // so we can safely call remove() if (alreadyThere) - if (0 == mNativeClass || !nativeFocusCandidateIsTextInput()) { - if (alreadyThere) { - mWebTextView.remove(); - } - return; - } - // At this point, we know we have found an input field, so go ahead - // and create the WebTextView if necessary. - if (mWebTextView == null) { - mWebTextView = new WebTextView(mContext, WebView.this, mAutoFillData.getQueryId()); - // Initialize our generation number. - mTextGeneration = 0; - } - mWebTextView.updateTextSize(); - updateWebTextViewPosition(); - String text = nativeFocusCandidateText(); - int nodePointer = nativeFocusCandidatePointer(); - // This needs to be called before setType, which may call - // requestFormData, and it needs to have the correct nodePointer. - mWebTextView.setNodePointer(nodePointer); - mWebTextView.setType(nativeFocusCandidateType()); - // Gravity needs to be set after setType - mWebTextView.setGravityForRtl(nativeFocusCandidateIsRtlText()); - if (null == text) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "rebuildWebTextView null == text"); - } - text = ""; - } - mWebTextView.setTextAndKeepSelection(text); - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null && imm.isActive(mWebTextView)) { - imm.restartInput(mWebTextView); - mWebTextView.clearComposingText(); - } - if (isFocused()) { - mWebTextView.requestFocus(); - } - } - - private void updateWebTextViewPosition() { - Rect visibleRect = new Rect(); - calcOurContentVisibleRect(visibleRect); - // Note that sendOurVisibleRect calls viewToContent, so the coordinates - // should be in content coordinates. - Rect bounds = nativeFocusCandidateNodeBounds(); - Rect vBox = contentToViewRect(bounds); - offsetByLayerScrollPosition(vBox); - mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height()); - if (!Rect.intersects(bounds, visibleRect)) { - revealSelection(); - } - updateWebTextViewPadding(); - } - - /** - * Update the padding of mWebTextView based on the native textfield/textarea - */ - void updateWebTextViewPadding() { - Rect paddingRect = nativeFocusCandidatePaddingRect(); - if (paddingRect != null) { - // Use contentToViewDimension since these are the dimensions of - // the padding. - mWebTextView.setPadding( - contentToViewDimension(paddingRect.left), - contentToViewDimension(paddingRect.top), - contentToViewDimension(paddingRect.right), - contentToViewDimension(paddingRect.bottom)); - } - } - - /** - * Tell webkit to put the cursor on screen. - */ - /* package */ void revealSelection() { - if (mWebViewCore != null) { - mWebViewCore.sendMessage(EventHub.REVEAL_SELECTION); - } - } - - /** - * Called by WebTextView to find saved form data associated with the - * textfield - * @param name Name of the textfield. - * @param nodePointer Pointer to the node of the textfield, so it can be - * compared to the currently focused textfield when the data is - * retrieved. - * @param autoFillable true if WebKit has determined this field is part of - * a form that can be auto filled. - * @param autoComplete true if the attribute "autocomplete" is set to true - * on the textfield. - */ - /* package */ void requestFormData(String name, int nodePointer, - boolean autoFillable, boolean autoComplete) { - if (mWebViewCore.getSettings().getSaveFormData()) { - Message update = mPrivateHandler.obtainMessage(REQUEST_FORM_DATA); - update.arg1 = nodePointer; - RequestFormData updater = new RequestFormData(name, getUrl(), - update, autoFillable, autoComplete); - Thread t = new Thread(updater); - t.start(); - } - } - - /** - * Pass a message to find out the <label> associated with the <input> - * identified by nodePointer - * @param framePointer Pointer to the frame containing the <input> node - * @param nodePointer Pointer to the node for which a <label> is desired. - */ - /* package */ void requestLabel(int framePointer, int nodePointer) { - mWebViewCore.sendMessage(EventHub.REQUEST_LABEL, framePointer, - nodePointer); - } - - /* - * This class requests an Adapter for the WebTextView which shows past - * entries stored in the database. It is a Runnable so that it can be done - * in its own thread, without slowing down the UI. - */ - private class RequestFormData implements Runnable { - private String mName; - private String mUrl; - private Message mUpdateMessage; - private boolean mAutoFillable; - private boolean mAutoComplete; - private WebSettings mWebSettings; - - public RequestFormData(String name, String url, Message msg, - boolean autoFillable, boolean autoComplete) { - mName = name; - mUrl = WebTextView.urlForAutoCompleteData(url); - mUpdateMessage = msg; - mAutoFillable = autoFillable; - mAutoComplete = autoComplete; - mWebSettings = getSettings(); - } - - @Override - public void run() { - ArrayList<String> pastEntries = new ArrayList<String>(); - - if (mAutoFillable) { - // Note that code inside the adapter click handler in WebTextView depends - // on the AutoFill item being at the top of the drop down list. If you change - // the order, make sure to do it there too! - if (mWebSettings != null && mWebSettings.getAutoFillProfile() != null) { - pastEntries.add(getResources().getText( - com.android.internal.R.string.autofill_this_form).toString() + - " " + - mAutoFillData.getPreviewString()); - mWebTextView.setAutoFillProfileIsSet(true); - } else { - // There is no autofill profile set up yet, so add an option that - // will invite the user to set their profile up. - pastEntries.add(getResources().getText( - com.android.internal.R.string.setup_autofill).toString()); - mWebTextView.setAutoFillProfileIsSet(false); - } - } - - if (mAutoComplete) { - pastEntries.addAll(mDatabase.getFormData(mUrl, mName)); - } - - if (pastEntries.size() > 0) { - AutoCompleteAdapter adapter = new - AutoCompleteAdapter(mContext, pastEntries); - mUpdateMessage.obj = adapter; - mUpdateMessage.sendToTarget(); - } - } - } - - /** - * Dump the display tree to "/sdcard/displayTree.txt" - * - * @hide debug only - */ - public void dumpDisplayTree() { - nativeDumpDisplayTree(getUrl()); - } - - /** - * Dump the dom tree to adb shell if "toFile" is False, otherwise dump it to - * "/sdcard/domTree.txt" - * - * @hide debug only - */ - public void dumpDomTree(boolean toFile) { - mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE, toFile ? 1 : 0, 0); - } - - /** - * Dump the render tree to adb shell if "toFile" is False, otherwise dump it - * to "/sdcard/renderTree.txt" - * - * @hide debug only - */ - public void dumpRenderTree(boolean toFile) { - mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE, toFile ? 1 : 0, 0); - } - - /** - * Called by DRT on UI thread, need to proxy to WebCore thread. - * - * @hide debug only - */ - public void useMockDeviceOrientation() { - mWebViewCore.sendMessage(EventHub.USE_MOCK_DEVICE_ORIENTATION); - } - - /** - * Called by DRT on WebCore thread. - * - * @hide debug only - */ - public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha, - boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) { - mWebViewCore.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, - canProvideGamma, gamma); - } - - // This is used to determine long press with the center key. Does not - // affect long press with the trackball/touch. - private boolean mGotCenterDown = false; - - @Override - public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { - if (mBlockWebkitViewMessages) { - return false; - } - // send complex characters to webkit for use by JS and plugins - if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getCharacters() != null) { - // pass the key to DOM - mWebViewCore.sendMessage(EventHub.KEY_DOWN, event); - mWebViewCore.sendMessage(EventHub.KEY_UP, event); - // return true as DOM handles the key - return true; - } - return false; - } - - private boolean isEnterActionKey(int keyCode) { - return keyCode == KeyEvent.KEYCODE_DPAD_CENTER - || keyCode == KeyEvent.KEYCODE_ENTER - || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis() - + "keyCode=" + keyCode - + ", " + event + ", unicode=" + event.getUnicodeChar()); - } - if (mIsCaretSelection) { - selectionDone(); - } - if (mBlockWebkitViewMessages) { - return false; - } - - // don't implement accelerator keys here; defer to host application - if (event.isCtrlPressed()) { - return false; - } - - if (mNativeClass == 0) { - return false; - } - - // do this hack up front, so it always works, regardless of touch-mode - if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) { - mAutoRedraw = !mAutoRedraw; - if (mAutoRedraw) { - invalidate(); - } - return true; - } - - // Bubble up the key event if - // 1. it is a system key; or - // 2. the host application wants to handle it; - if (event.isSystem() - || mCallbackProxy.uiOverrideKeyEvent(event)) { - return false; - } - - // accessibility support - if (accessibilityScriptInjected()) { - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - // if an accessibility script is injected we delegate to it the key handling. - // this script is a screen reader which is a fully fledged solution for blind - // users to navigate in and interact with web pages. - mWebViewCore.sendMessage(EventHub.KEY_DOWN, event); - return true; - } else { - // Clean up if accessibility was disabled after loading the current URL. - mAccessibilityScriptInjected = false; - } - } else if (mAccessibilityInjector != null) { - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - if (mAccessibilityInjector.onKeyEvent(event)) { - // if an accessibility injector is present (no JavaScript enabled or the site - // opts out injecting our JavaScript screen reader) we let it decide whether - // to act on and consume the event. - return true; - } - } else { - // Clean up if accessibility was disabled after loading the current URL. - mAccessibilityInjector = null; - } - } - - if (keyCode == KeyEvent.KEYCODE_PAGE_UP) { - if (event.hasNoModifiers()) { - pageUp(false); - return true; - } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) { - pageUp(true); - return true; - } - } - - if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) { - if (event.hasNoModifiers()) { - pageDown(false); - return true; - } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) { - pageDown(true); - return true; - } - } - - if (keyCode == KeyEvent.KEYCODE_MOVE_HOME && event.hasNoModifiers()) { - pageUp(true); - return true; - } - - if (keyCode == KeyEvent.KEYCODE_MOVE_END && event.hasNoModifiers()) { - pageDown(true); - return true; - } - - if (keyCode >= KeyEvent.KEYCODE_DPAD_UP - && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) { - switchOutDrawHistory(); - if (nativePageShouldHandleShiftAndArrows()) { - letPageHandleNavKey(keyCode, event.getEventTime(), true, event.getMetaState()); - return true; - } - if (event.hasModifiers(KeyEvent.META_ALT_ON)) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - pageUp(true); - return true; - case KeyEvent.KEYCODE_DPAD_DOWN: - pageDown(true); - return true; - case KeyEvent.KEYCODE_DPAD_LEFT: - nativeClearCursor(); // start next trackball movement from page edge - return pinScrollTo(0, mScrollY, true, 0); - case KeyEvent.KEYCODE_DPAD_RIGHT: - nativeClearCursor(); // start next trackball movement from page edge - return pinScrollTo(mContentWidth, mScrollY, true, 0); - } - } - if (navHandledKey(keyCode, 1, false, event.getEventTime())) { - playSoundEffect(keyCodeToSoundsEffect(keyCode)); - return true; - } - // Bubble up the key event as WebView doesn't handle it - return false; - } - - if (isEnterActionKey(keyCode)) { - switchOutDrawHistory(); - boolean wantsKeyEvents = nativeCursorNodePointer() == 0 - || nativeCursorWantsKeyEvents(); - if (event.getRepeatCount() == 0) { - if (mSelectingText) { - return true; // discard press if copy in progress - } - mGotCenterDown = true; - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT); - if (!wantsKeyEvents) return true; - } - // Bubble up the key event as WebView doesn't handle it - if (!wantsKeyEvents) return false; - } - - if (getSettings().getNavDump()) { - switch (keyCode) { - case KeyEvent.KEYCODE_4: - dumpDisplayTree(); - break; - case KeyEvent.KEYCODE_5: - case KeyEvent.KEYCODE_6: - dumpDomTree(keyCode == KeyEvent.KEYCODE_5); - break; - case KeyEvent.KEYCODE_7: - case KeyEvent.KEYCODE_8: - dumpRenderTree(keyCode == KeyEvent.KEYCODE_7); - break; - } - } - - if (nativeCursorIsTextInput()) { - // This message will put the node in focus, for the DOM's notion - // of focus. - mWebViewCore.sendMessage(EventHub.FAKE_CLICK, nativeCursorFramePointer(), - nativeCursorNodePointer()); - // This will bring up the WebTextView and put it in focus, for - // our view system's notion of focus - rebuildWebTextView(); - // Now we need to pass the event to it - if (inEditingMode()) { - mWebTextView.setDefaultSelection(); - return mWebTextView.dispatchKeyEvent(event); - } - } else if (nativeHasFocusNode()) { - // In this case, the cursor is not on a text input, but the focus - // might be. Check it, and if so, hand over to the WebTextView. - rebuildWebTextView(); - if (inEditingMode()) { - mWebTextView.setDefaultSelection(); - return mWebTextView.dispatchKeyEvent(event); - } - } - - // TODO: should we pass all the keys to DOM or check the meta tag - if (nativeCursorWantsKeyEvents() || true) { - // pass the key to DOM - mWebViewCore.sendMessage(EventHub.KEY_DOWN, event); - // return true as DOM handles the key - return true; - } - - // Bubble up the key event as WebView doesn't handle it - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis() - + ", " + event + ", unicode=" + event.getUnicodeChar()); - } - if (mBlockWebkitViewMessages) { - return false; - } - - if (mNativeClass == 0) { - return false; - } - - // special CALL handling when cursor node's href is "tel:XXX" - if (keyCode == KeyEvent.KEYCODE_CALL && nativeHasCursorNode()) { - String text = nativeCursorText(); - if (!nativeCursorIsTextInput() && text != null - && text.startsWith(SCHEME_TEL)) { - Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text)); - getContext().startActivity(intent); - return true; - } - } - - // Bubble up the key event if - // 1. it is a system key; or - // 2. the host application wants to handle it; - if (event.isSystem() - || mCallbackProxy.uiOverrideKeyEvent(event)) { - return false; - } - - // accessibility support - if (accessibilityScriptInjected()) { - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - // if an accessibility script is injected we delegate to it the key handling. - // this script is a screen reader which is a fully fledged solution for blind - // users to navigate in and interact with web pages. - mWebViewCore.sendMessage(EventHub.KEY_UP, event); - return true; - } else { - // Clean up if accessibility was disabled after loading the current URL. - mAccessibilityScriptInjected = false; - } - } else if (mAccessibilityInjector != null) { - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - if (mAccessibilityInjector.onKeyEvent(event)) { - // if an accessibility injector is present (no JavaScript enabled or the site - // opts out injecting our JavaScript screen reader) we let it decide whether to - // act on and consume the event. - return true; - } - } else { - // Clean up if accessibility was disabled after loading the current URL. - mAccessibilityInjector = null; - } - } - - if (keyCode >= KeyEvent.KEYCODE_DPAD_UP - && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) { - if (nativePageShouldHandleShiftAndArrows()) { - letPageHandleNavKey(keyCode, event.getEventTime(), false, event.getMetaState()); - return true; - } - // always handle the navigation keys in the UI thread - // Bubble up the key event as WebView doesn't handle it - return false; - } - - if (isEnterActionKey(keyCode)) { - // remove the long press message first - mPrivateHandler.removeMessages(LONG_PRESS_CENTER); - mGotCenterDown = false; - - if (mSelectingText) { - copySelection(); - selectionDone(); - return true; // discard press if copy in progress - } - - if (!sDisableNavcache) { - // perform the single click - Rect visibleRect = sendOurVisibleRect(); - // Note that sendOurVisibleRect calls viewToContent, so the - // coordinates should be in content coordinates. - if (!nativeCursorIntersects(visibleRect)) { - return false; - } - WebViewCore.CursorData data = cursorData(); - mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data); - playSoundEffect(SoundEffectConstants.CLICK); - if (nativeCursorIsTextInput()) { - rebuildWebTextView(); - centerKeyPressOnTextField(); - if (inEditingMode()) { - mWebTextView.setDefaultSelection(); - } - return true; - } - clearTextEntry(); - nativeShowCursorTimed(); - if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) { - return true; - } - if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) { - mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame, - nativeCursorNodePointer()); - return true; - } - } - } - - // TODO: should we pass all the keys to DOM or check the meta tag - if (nativeCursorWantsKeyEvents() || true) { - // pass the key to DOM - mWebViewCore.sendMessage(EventHub.KEY_UP, event); - // return true as DOM handles the key - return true; - } - - // Bubble up the key event as WebView doesn't handle it - return false; - } - - private boolean startSelectActionMode() { - mSelectCallback = new SelectActionModeCallback(); - mSelectCallback.setTextSelected(!mIsCaretSelection); - mSelectCallback.setWebView(this); - if (startActionMode(mSelectCallback) == null) { - // There is no ActionMode, so do not allow the user to modify a - // selection. - selectionDone(); - return false; - } - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - return true; - } - - private void showPasteWindow() { - ClipboardManager cm = (ClipboardManager)(mContext - .getSystemService(Context.CLIPBOARD_SERVICE)); - if (cm.hasPrimaryClip()) { - Rect cursorRect = contentToViewRect(mSelectCursorBase); - int[] location = new int[2]; - getLocationInWindow(location); - cursorRect.offset(location[0] - mScrollX, location[1] - mScrollY); - if (mPasteWindow == null) { - mPasteWindow = new PastePopupWindow(); - } - mPasteWindow.show(cursorRect, location[0], location[1]); - } - } - - private void hidePasteButton() { - if (mPasteWindow != null) { - mPasteWindow.hide(); - } - } - - private void syncSelectionCursors() { - mSelectCursorBaseLayerId = - nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, mSelectCursorBase); - mSelectCursorExtentLayerId = - nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT, mSelectCursorExtent); - } - - private boolean setupWebkitSelect() { - syncSelectionCursors(); - if (mIsCaretSelection) { - showPasteWindow(); - } else if (!startSelectActionMode()) { - selectionDone(); - return false; - } - mSelectingText = true; - mTouchMode = TOUCH_DRAG_MODE; - return true; - } - - private void updateWebkitSelection() { - int[] handles = null; - if (mIsCaretSelection) { - mSelectCursorExtent.set(mSelectCursorBase); - } - if (mSelectingText) { - handles = new int[4]; - handles[0] = mSelectCursorBase.centerX(); - handles[1] = mSelectCursorBase.centerY(); - handles[2] = mSelectCursorExtent.centerX(); - handles[3] = mSelectCursorExtent.centerY(); - } else { - nativeSetTextSelection(mNativeClass, 0); - } - mWebViewCore.removeMessages(EventHub.SELECT_TEXT); - mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SELECT_TEXT, handles); - } - - private void resetCaretTimer() { - mPrivateHandler.removeMessages(CLEAR_CARET_HANDLE); - if (!mSelectionStarted) { - mPrivateHandler.sendEmptyMessageDelayed(CLEAR_CARET_HANDLE, - CARET_HANDLE_STAMINA_MS); - } - } - /** * Use this method to put the WebView into text selection mode. * Do not rely on this functionality; it will be deprecated in the future. @@ -6149,165 +1433,7 @@ public class WebView extends AbsoluteLayout @Deprecated public void emulateShiftHeld() { checkThread(); - } - - /** - * Select all of the text in this WebView. - * - * @hide This is an implementation detail. - */ - public void selectAll() { - mWebViewCore.sendMessage(EventHub.SELECT_ALL); - } - - /** - * Called when the selection has been removed. - */ - void selectionDone() { - if (mSelectingText) { - hidePasteButton(); - mSelectingText = false; - // finish is idempotent, so this is fine even if selectionDone was - // called by mSelectCallback.onDestroyActionMode - if (mSelectCallback != null) { - mSelectCallback.finish(); - mSelectCallback = null; - } - if (!mIsCaretSelection) { - updateWebkitSelection(); - } - mIsCaretSelection = false; - invalidate(); // redraw without selection - mAutoScrollX = 0; - mAutoScrollY = 0; - mSentAutoScrollMessage = false; - } - } - - /** - * Copy the selection to the clipboard - * - * @hide This is an implementation detail. - */ - public boolean copySelection() { - boolean copiedSomething = false; - String selection = getSelection(); - if (selection != null && selection != "") { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "copySelection \"" + selection + "\""); - } - Toast.makeText(mContext - , com.android.internal.R.string.text_copied - , Toast.LENGTH_SHORT).show(); - copiedSomething = true; - ClipboardManager cm = (ClipboardManager)getContext() - .getSystemService(Context.CLIPBOARD_SERVICE); - cm.setText(selection); - int[] handles = new int[4]; - getSelectionHandles(handles); - mWebViewCore.sendMessage(EventHub.COPY_TEXT, handles); - } - invalidate(); // remove selection region and pointer - return copiedSomething; - } - - /** - * Cut the selected text into the clipboard - * - * @hide This is an implementation detail - */ - public void cutSelection() { - copySelection(); - int[] handles = new int[4]; - getSelectionHandles(handles); - mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles); - } - - /** - * Paste text from the clipboard to the cursor position. - * - * @hide This is an implementation detail - */ - public void pasteFromClipboard() { - ClipboardManager cm = (ClipboardManager)getContext() - .getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clipData = cm.getPrimaryClip(); - if (clipData != null) { - ClipData.Item clipItem = clipData.getItemAt(0); - CharSequence pasteText = clipItem.getText(); - if (mInputConnection != null) { - mInputConnection.replaceSelection(pasteText); - } - } - } - - /** - * @hide This is an implementation detail. - */ - public SearchBox getSearchBox() { - if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) { - return null; - } - return mWebViewCore.getBrowserFrame().getSearchBox(); - } - - /** - * Returns the currently highlighted text as a string. - */ - String getSelection() { - if (mNativeClass == 0) return ""; - return nativeGetSelection(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (hasWindowFocus()) setActive(true); - final ViewTreeObserver treeObserver = getViewTreeObserver(); - if (mGlobalLayoutListener == null) { - mGlobalLayoutListener = new InnerGlobalLayoutListener(); - treeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener); - } - if (mScrollChangedListener == null) { - mScrollChangedListener = new InnerScrollChangedListener(); - treeObserver.addOnScrollChangedListener(mScrollChangedListener); - } - - addAccessibilityApisToJavaScript(); - - mTouchEventQueue.reset(); - } - - @Override - protected void onDetachedFromWindow() { - clearHelpers(); - mZoomManager.dismissZoomPicker(); - if (hasWindowFocus()) setActive(false); - - final ViewTreeObserver treeObserver = getViewTreeObserver(); - if (mGlobalLayoutListener != null) { - treeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener); - mGlobalLayoutListener = null; - } - if (mScrollChangedListener != null) { - treeObserver.removeOnScrollChangedListener(mScrollChangedListener); - mScrollChangedListener = null; - } - - removeAccessibilityApisFromJavaScript(); - - super.onDetachedFromWindow(); - } - - @Override - protected void onVisibilityChanged(View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); - // The zoomManager may be null if the webview is created from XML that - // specifies the view's visibility param as not visible (see http://b/2794841) - if (visibility != View.VISIBLE && mZoomManager != null) { - mZoomManager.dismissZoomPicker(); - } - updateDrawingState(); + mProvider.emulateShiftHeld(); } /** @@ -6338,1571 +1464,15 @@ public class WebView extends AbsoluteLayout public void onGlobalFocusChanged(View oldFocus, View newFocus) { } - void setActive(boolean active) { - if (active) { - if (hasFocus()) { - // If our window regained focus, and we have focus, then begin - // drawing the cursor ring - mDrawCursorRing = !inEditingMode(); - setFocusControllerActive(true); - } else { - mDrawCursorRing = false; - if (!inEditingMode()) { - // If our window gained focus, but we do not have it, do not - // draw the cursor ring. - setFocusControllerActive(false); - } - // We do not call recordButtons here because we assume - // that when we lost focus, or window focus, it got called with - // false for the first parameter - } - } else { - if (!mZoomManager.isZoomPickerVisible()) { - /* - * The external zoom controls come in their own window, so our - * window loses focus. Our policy is to not draw the cursor ring - * if our window is not focused, but this is an exception since - * the user can still navigate the web page with the zoom - * controls showing. - */ - mDrawCursorRing = false; - } - mKeysPressed.clear(); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - mTouchMode = TOUCH_DONE_MODE; - setFocusControllerActive(false); - } - invalidate(); - } - - // To avoid drawing the cursor ring, and remove the TextView when our window - // loses focus. - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - setActive(hasWindowFocus); - if (hasWindowFocus) { - JWebCoreJavaBridge.setActiveWebView(this); - if (mPictureUpdatePausedForFocusChange) { - WebViewCore.resumeUpdatePicture(mWebViewCore); - mPictureUpdatePausedForFocusChange = false; - } - } else { - JWebCoreJavaBridge.removeActiveWebView(this); - final WebSettings settings = getSettings(); - if (settings != null && settings.enableSmoothTransition() && - mWebViewCore != null && !WebViewCore.isUpdatePicturePaused(mWebViewCore)) { - WebViewCore.pauseUpdatePicture(mWebViewCore); - mPictureUpdatePausedForFocusChange = true; - } - } - super.onWindowFocusChanged(hasWindowFocus); - } - - /* - * Pass a message to WebCore Thread, telling the WebCore::Page's - * FocusController to be "inactive" so that it will - * not draw the blinking cursor. It gets set to "active" to draw the cursor - * in WebViewCore.cpp, when the WebCore thread receives key events/clicks. - */ - /* package */ void setFocusControllerActive(boolean active) { - if (mWebViewCore == null) return; - mWebViewCore.sendMessage(EventHub.SET_ACTIVE, active ? 1 : 0, 0); - // Need to send this message after the document regains focus. - if (active && mListBoxMessage != null) { - mWebViewCore.sendMessage(mListBoxMessage); - mListBoxMessage = null; - } - } - - @Override - protected void onFocusChanged(boolean focused, int direction, - Rect previouslyFocusedRect) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction); - } - if (focused) { - // When we regain focus, if we have window focus, resume drawing - // the cursor ring - if (hasWindowFocus()) { - mDrawCursorRing = !inEditingMode(); - setFocusControllerActive(true); - //} else { - // The WebView has gained focus while we do not have - // windowfocus. When our window lost focus, we should have - // called recordButtons(false...) - } - } else { - // When we lost focus, unless focus went to the TextView (which is - // true if we are in editing mode), stop drawing the cursor ring. - mDrawCursorRing = false; - if (!inEditingMode()) { - setFocusControllerActive(false); - } - mKeysPressed.clear(); - } - - super.onFocusChanged(focused, direction, previouslyFocusedRect); - } - - void setGLRectViewport() { - // Use the getGlobalVisibleRect() to get the intersection among the parents - // visible == false means we're clipped - send a null rect down to indicate that - // we should not draw - boolean visible = getGlobalVisibleRect(mGLRectViewport); - if (visible) { - // Then need to invert the Y axis, just for GL - View rootView = getRootView(); - int rootViewHeight = rootView.getHeight(); - mViewRectViewport.set(mGLRectViewport); - int savedWebViewBottom = mGLRectViewport.bottom; - mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeightImpl(); - mGLRectViewport.top = rootViewHeight - savedWebViewBottom; - mGLViewportEmpty = false; - } else { - mGLViewportEmpty = true; - } - calcOurContentVisibleRectF(mVisibleContentRect); - nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport, - mGLViewportEmpty ? null : mViewRectViewport, - mVisibleContentRect, getScale()); - } - - /** - * @hide - */ - @Override - protected boolean setFrame(int left, int top, int right, int bottom) { - boolean changed = super.setFrame(left, top, right, bottom); - if (!changed && mHeightCanMeasure) { - // When mHeightCanMeasure is true, we will set mLastHeightSent to 0 - // in WebViewCore after we get the first layout. We do call - // requestLayout() when we get contentSizeChanged(). But the View - // system won't call onSizeChanged if the dimension is not changed. - // In this case, we need to call sendViewSizeZoom() explicitly to - // notify the WebKit about the new dimensions. - sendViewSizeZoom(false); - } - setGLRectViewport(); - return changed; - } - - @Override - protected void onSizeChanged(int w, int h, int ow, int oh) { - super.onSizeChanged(w, h, ow, oh); - - // adjust the max viewport width depending on the view dimensions. This - // is to ensure the scaling is not going insane. So do not shrink it if - // the view size is temporarily smaller, e.g. when soft keyboard is up. - int newMaxViewportWidth = (int) (Math.max(w, h) / mZoomManager.getDefaultMinZoomScale()); - if (newMaxViewportWidth > sMaxViewportWidth) { - sMaxViewportWidth = newMaxViewportWidth; - } - - mZoomManager.onSizeChanged(w, h, ow, oh); - - if (mLoadedPicture != null && mDelaySetPicture == null) { - // Size changes normally result in a new picture - // Re-set the loaded picture to simulate that - // However, do not update the base layer as that hasn't changed - setNewPicture(mLoadedPicture, false); - } - } - - @Override - protected void onScrollChanged(int l, int t, int oldl, int oldt) { - super.onScrollChanged(l, t, oldl, oldt); - if (!mInOverScrollMode) { - sendOurVisibleRect(); - // update WebKit if visible title bar height changed. The logic is same - // as getVisibleTitleHeightImpl. - int titleHeight = getTitleHeight(); - if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) { - sendViewSizeZoom(false); - } - } - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - switch (event.getAction()) { - case KeyEvent.ACTION_DOWN: - mKeysPressed.add(Integer.valueOf(event.getKeyCode())); - break; - case KeyEvent.ACTION_MULTIPLE: - // Always accept the action. - break; - case KeyEvent.ACTION_UP: - int location = mKeysPressed.indexOf(Integer.valueOf(event.getKeyCode())); - if (location == -1) { - // We did not receive the key down for this key, so do not - // handle the key up. - return false; - } else { - // We did receive the key down. Handle the key up, and - // remove it from our pressed keys. - mKeysPressed.remove(location); - } - break; - default: - // Accept the action. This should not happen, unless a new - // action is added to KeyEvent. - break; - } - if (inEditingMode() && mWebTextView.isFocused()) { - // Ensure that the WebTextView gets the event, even if it does - // not currently have a bounds. - return mWebTextView.dispatchKeyEvent(event); - } else { - return super.dispatchKeyEvent(event); - } - } - - /* - * Here is the snap align logic: - * 1. If it starts nearly horizontally or vertically, snap align; - * 2. If there is a dramitic direction change, let it go; - * - * Adjustable parameters. Angle is the radians on a unit circle, limited - * to quadrant 1. Values range from 0f (horizontal) to PI/2 (vertical) - */ - private static final float HSLOPE_TO_START_SNAP = .25f; - private static final float HSLOPE_TO_BREAK_SNAP = .4f; - private static final float VSLOPE_TO_START_SNAP = 1.25f; - private static final float VSLOPE_TO_BREAK_SNAP = .95f; - /* - * These values are used to influence the average angle when entering - * snap mode. If is is the first movement entering snap, we set the average - * to the appropriate ideal. If the user is entering into snap after the - * first movement, then we average the average angle with these values. - */ - private static final float ANGLE_VERT = 2f; - private static final float ANGLE_HORIZ = 0f; - /* - * The modified moving average weight. - * Formula: MAV[t]=MAV[t-1] + (P[t]-MAV[t-1])/n - */ - private static final float MMA_WEIGHT_N = 5; - - private boolean hitFocusedPlugin(int contentX, int contentY) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "nativeFocusIsPlugin()=" + nativeFocusIsPlugin()); - Rect r = nativeFocusNodeBounds(); - Log.v(LOGTAG, "nativeFocusNodeBounds()=(" + r.left + ", " + r.top - + ", " + r.right + ", " + r.bottom + ")"); - } - return nativeFocusIsPlugin() - && nativeFocusNodeBounds().contains(contentX, contentY); - } - - private boolean shouldForwardTouchEvent() { - if (mFullScreenHolder != null) return true; - if (mBlockWebkitViewMessages) return false; - return mForwardTouchEvents - && !mSelectingText - && mPreventDefault != PREVENT_DEFAULT_IGNORE - && mPreventDefault != PREVENT_DEFAULT_NO; - } - - private boolean inFullScreenMode() { - return mFullScreenHolder != null; - } - - private void dismissFullScreenMode() { - if (inFullScreenMode()) { - mFullScreenHolder.hide(); - mFullScreenHolder = null; - invalidate(); - } - } - - void onPinchToZoomAnimationStart() { - // cancel the single touch handling - cancelTouch(); - onZoomAnimationStart(); - } - - void onPinchToZoomAnimationEnd(ScaleGestureDetector detector) { - onZoomAnimationEnd(); - // start a drag, TOUCH_PINCH_DRAG, can't use TOUCH_INIT_MODE as - // it may trigger the unwanted click, can't use TOUCH_DRAG_MODE - // as it may trigger the unwanted fling. - mTouchMode = TOUCH_PINCH_DRAG; - mConfirmMove = true; - startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime); - } - - // See if there is a layer at x, y and switch to TOUCH_DRAG_LAYER_MODE if a - // layer is found. - private void startScrollingLayer(float x, float y) { - int contentX = viewToContentX((int) x + mScrollX); - int contentY = viewToContentY((int) y + mScrollY); - mCurrentScrollingLayerId = nativeScrollableLayer(contentX, contentY, - mScrollingLayerRect, mScrollingLayerBounds); - if (mCurrentScrollingLayerId != 0) { - mTouchMode = TOUCH_DRAG_LAYER_MODE; - } - } - - // 1/(density * density) used to compute the distance between points. - // Computed in init(). - private float DRAG_LAYER_INVERSE_DENSITY_SQUARED; - - // The distance between two points reported in onTouchEvent scaled by the - // density of the screen. - private static final int DRAG_LAYER_FINGER_DISTANCE = 20000; - - @Override - public boolean onHoverEvent(MotionEvent event) { - if (mNativeClass == 0) { - return false; - } - WebViewCore.CursorData data = cursorDataNoPosition(); - data.mX = viewToContentX((int) event.getX() + mScrollX); - data.mY = viewToContentY((int) event.getY() + mScrollY); - mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data); - return true; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (mNativeClass == 0 || (!isClickable() && !isLongClickable())) { - return false; - } - - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, ev + " at " + ev.getEventTime() - + " mTouchMode=" + mTouchMode - + " numPointers=" + ev.getPointerCount()); - } - - // If WebKit wasn't interested in this multitouch gesture, enqueue - // the event for handling directly rather than making the round trip - // to WebKit and back. - if (ev.getPointerCount() > 1 && mPreventDefault != PREVENT_DEFAULT_NO) { - passMultiTouchToWebKit(ev, mTouchEventQueue.nextTouchSequence()); - } else { - mTouchEventQueue.enqueueTouchEvent(ev); - } - - // Since all events are handled asynchronously, we always want the gesture stream. - return true; - } - - private float calculateDragAngle(int dx, int dy) { - dx = Math.abs(dx); - dy = Math.abs(dy); - return (float) Math.atan2(dy, dx); - } - - /* - * Common code for single touch and multi-touch. - * (x, y) denotes current focus point, which is the touch point for single touch - * and the middle point for multi-touch. - */ - private boolean handleTouchEventCommon(MotionEvent ev, int action, int x, int y) { - long eventTime = ev.getEventTime(); - - // Due to the touch screen edge effect, a touch closer to the edge - // always snapped to the edge. As getViewWidth() can be different from - // getWidth() due to the scrollbar, adjusting the point to match - // getViewWidth(). Same applied to the height. - x = Math.min(x, getViewWidth() - 1); - y = Math.min(y, getViewHeightWithTitle() - 1); - - int deltaX = mLastTouchX - x; - int deltaY = mLastTouchY - y; - int contentX = viewToContentX(x + mScrollX); - int contentY = viewToContentY(y + mScrollY); - - switch (action) { - case MotionEvent.ACTION_DOWN: { - mPreventDefault = PREVENT_DEFAULT_NO; - mConfirmMove = false; - mInitialHitTestResult = null; - if (!mScroller.isFinished()) { - // stop the current scroll animation, but if this is - // the start of a fling, allow it to add to the current - // fling's velocity - mScroller.abortAnimation(); - mTouchMode = TOUCH_DRAG_START_MODE; - mConfirmMove = true; - nativeSetIsScrolling(false); - } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) { - mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP); - if (sDisableNavcache) { - removeTouchHighlight(); - } - if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) { - mTouchMode = TOUCH_DOUBLE_TAP_MODE; - } else { - // commit the short press action for the previous tap - doShortPress(); - mTouchMode = TOUCH_INIT_MODE; - mDeferTouchProcess = !mBlockWebkitViewMessages - && (!inFullScreenMode() && mForwardTouchEvents) - ? hitFocusedPlugin(contentX, contentY) - : false; - } - } else { // the normal case - mTouchMode = TOUCH_INIT_MODE; - mDeferTouchProcess = !mBlockWebkitViewMessages - && (!inFullScreenMode() && mForwardTouchEvents) - ? hitFocusedPlugin(contentX, contentY) - : false; - if (!mBlockWebkitViewMessages) { - mWebViewCore.sendMessage( - EventHub.UPDATE_FRAME_CACHE_IF_LOADING); - } - if (sDisableNavcache) { - TouchHighlightData data = new TouchHighlightData(); - data.mX = contentX; - data.mY = contentY; - data.mNativeLayerRect = new Rect(); - data.mNativeLayer = nativeScrollableLayer( - contentX, contentY, data.mNativeLayerRect, null); - data.mSlop = viewToContentDimension(mNavSlop); - mTouchHighlightRegion.setEmpty(); - if (!mBlockWebkitViewMessages) { - mTouchHighlightRequested = System.currentTimeMillis(); - mWebViewCore.sendMessageAtFrontOfQueue( - EventHub.HIT_TEST, data); - } - if (DEBUG_TOUCH_HIGHLIGHT) { - if (getSettings().getNavDump()) { - mTouchHighlightX = x + mScrollX; - mTouchHighlightY = y + mScrollY; - mPrivateHandler.postDelayed(new Runnable() { - @Override - public void run() { - mTouchHighlightX = mTouchHighlightY = 0; - invalidate(); - } - }, TOUCH_HIGHLIGHT_ELAPSE_TIME); - } - } - } - if (mLogEvent && eventTime - mLastTouchUpTime < 1000) { - EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION, - (eventTime - mLastTouchUpTime), eventTime); - } - mSelectionStarted = false; - if (mSelectingText) { - int shiftedY = y - getTitleHeight() + mScrollY; - int shiftedX = x + mScrollX; - if (mSelectHandleCenter != null && mSelectHandleCenter.getBounds() - .contains(shiftedX, shiftedY)) { - mSelectionStarted = true; - mSelectDraggingCursor = mSelectCursorBase; - mPrivateHandler.removeMessages(CLEAR_CARET_HANDLE); - hidePasteButton(); - } else if (mSelectHandleLeft != null - && mSelectHandleLeft.getBounds() - .contains(shiftedX, shiftedY)) { - mSelectionStarted = true; - mSelectDraggingCursor = mSelectCursorBase; - } else if (mSelectHandleRight != null - && mSelectHandleRight.getBounds() - .contains(shiftedX, shiftedY)) { - mSelectionStarted = true; - mSelectDraggingCursor = mSelectCursorExtent; - } else if (mIsCaretSelection) { - selectionDone(); - } - if (mSelectDraggingCursor != null) { - mSelectDraggingOffset.set( - mSelectDraggingCursor.left - contentX, - mSelectDraggingCursor.top - contentY); - } - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "select=" + contentX + "," + contentY); - } - } - } - // Trigger the link - if (!mSelectingText && (mTouchMode == TOUCH_INIT_MODE - || mTouchMode == TOUCH_DOUBLE_TAP_MODE)) { - mPrivateHandler.sendEmptyMessageDelayed( - SWITCH_TO_SHORTPRESS, TAP_TIMEOUT); - mPrivateHandler.sendEmptyMessageDelayed( - SWITCH_TO_LONGPRESS, LONG_PRESS_TIMEOUT); - if (inFullScreenMode() || mDeferTouchProcess) { - mPreventDefault = PREVENT_DEFAULT_YES; - } else if (!mBlockWebkitViewMessages && mForwardTouchEvents) { - mPreventDefault = PREVENT_DEFAULT_MAYBE_YES; - } else { - mPreventDefault = PREVENT_DEFAULT_NO; - } - // pass the touch events from UI thread to WebCore thread - if (shouldForwardTouchEvent()) { - TouchEventData ted = new TouchEventData(); - ted.mAction = action; - ted.mIds = new int[1]; - ted.mIds[0] = ev.getPointerId(0); - ted.mPoints = new Point[1]; - ted.mPoints[0] = new Point(contentX, contentY); - ted.mPointsInView = new Point[1]; - ted.mPointsInView[0] = new Point(x, y); - ted.mMetaState = ev.getMetaState(); - ted.mReprocess = mDeferTouchProcess; - ted.mNativeLayer = nativeScrollableLayer( - contentX, contentY, ted.mNativeLayerRect, null); - ted.mSequence = mTouchEventQueue.nextTouchSequence(); - mTouchEventQueue.preQueueTouchEventData(ted); - mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - if (mDeferTouchProcess) { - // still needs to set them for compute deltaX/Y - mLastTouchX = x; - mLastTouchY = y; - break; - } - if (!inFullScreenMode()) { - mPrivateHandler.removeMessages(PREVENT_DEFAULT_TIMEOUT); - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(PREVENT_DEFAULT_TIMEOUT, - action, 0), TAP_TIMEOUT); - } - } - } - startTouch(x, y, eventTime); - break; - } - case MotionEvent.ACTION_MOVE: { - boolean firstMove = false; - if (!mConfirmMove && (deltaX * deltaX + deltaY * deltaY) - >= mTouchSlopSquare) { - mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - mConfirmMove = true; - firstMove = true; - if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) { - mTouchMode = TOUCH_INIT_MODE; - } - if (sDisableNavcache) { - removeTouchHighlight(); - } - } - if (mSelectingText && mSelectionStarted) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "extend=" + contentX + "," + contentY); - } - ViewParent parent = getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - if (deltaX != 0 || deltaY != 0) { - mSelectDraggingCursor.offsetTo( - contentX + mSelectDraggingOffset.x, - contentY + mSelectDraggingOffset.y); - updateWebkitSelection(); - mLastTouchX = x; - mLastTouchY = y; - invalidate(); - } - break; - } - - // pass the touch events from UI thread to WebCore thread - if (shouldForwardTouchEvent() && mConfirmMove && (firstMove - || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) { - TouchEventData ted = new TouchEventData(); - ted.mAction = action; - ted.mIds = new int[1]; - ted.mIds[0] = ev.getPointerId(0); - ted.mPoints = new Point[1]; - ted.mPoints[0] = new Point(contentX, contentY); - ted.mPointsInView = new Point[1]; - ted.mPointsInView[0] = new Point(x, y); - ted.mMetaState = ev.getMetaState(); - ted.mReprocess = mDeferTouchProcess; - ted.mNativeLayer = mCurrentScrollingLayerId; - ted.mNativeLayerRect.set(mScrollingLayerRect); - ted.mSequence = mTouchEventQueue.nextTouchSequence(); - mTouchEventQueue.preQueueTouchEventData(ted); - mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - mLastSentTouchTime = eventTime; - if (mDeferTouchProcess) { - break; - } - if (firstMove && !inFullScreenMode()) { - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(PREVENT_DEFAULT_TIMEOUT, - action, 0), TAP_TIMEOUT); - } - } - if (mTouchMode == TOUCH_DONE_MODE - || mPreventDefault == PREVENT_DEFAULT_YES) { - // no dragging during scroll zoom animation, or when prevent - // default is yes - break; - } - if (mVelocityTracker == null) { - Log.e(LOGTAG, "Got null mVelocityTracker when " - + "mPreventDefault = " + mPreventDefault - + " mDeferTouchProcess = " + mDeferTouchProcess - + " mTouchMode = " + mTouchMode); - } else { - mVelocityTracker.addMovement(ev); - } - - if (mTouchMode != TOUCH_DRAG_MODE && - mTouchMode != TOUCH_DRAG_LAYER_MODE) { - - if (!mConfirmMove) { - break; - } - - if (mPreventDefault == PREVENT_DEFAULT_MAYBE_YES - || mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) { - // track mLastTouchTime as we may need to do fling at - // ACTION_UP - mLastTouchTime = eventTime; - break; - } - - // Only lock dragging to one axis if we don't have a scale in progress. - // Scaling implies free-roaming movement. Note this is only ever a question - // if mZoomManager.supportsPanDuringZoom() is true. - final ScaleGestureDetector detector = - mZoomManager.getMultiTouchGestureDetector(); - mAverageAngle = calculateDragAngle(deltaX, deltaY); - if (detector == null || !detector.isInProgress()) { - // if it starts nearly horizontal or vertical, enforce it - if (mAverageAngle < HSLOPE_TO_START_SNAP) { - mSnapScrollMode = SNAP_X; - mSnapPositive = deltaX > 0; - mAverageAngle = ANGLE_HORIZ; - } else if (mAverageAngle > VSLOPE_TO_START_SNAP) { - mSnapScrollMode = SNAP_Y; - mSnapPositive = deltaY > 0; - mAverageAngle = ANGLE_VERT; - } - } - - mTouchMode = TOUCH_DRAG_MODE; - mLastTouchX = x; - mLastTouchY = y; - deltaX = 0; - deltaY = 0; - - startScrollingLayer(x, y); - startDrag(); - } - - // do pan - boolean done = false; - boolean keepScrollBarsVisible = false; - if (deltaX == 0 && deltaY == 0) { - keepScrollBarsVisible = done = true; - } else { - mAverageAngle += - (calculateDragAngle(deltaX, deltaY) - mAverageAngle) - / MMA_WEIGHT_N; - if (mSnapScrollMode != SNAP_NONE) { - if (mSnapScrollMode == SNAP_Y) { - // radical change means getting out of snap mode - if (mAverageAngle < VSLOPE_TO_BREAK_SNAP) { - mSnapScrollMode = SNAP_NONE; - } - } - if (mSnapScrollMode == SNAP_X) { - // radical change means getting out of snap mode - if (mAverageAngle > HSLOPE_TO_BREAK_SNAP) { - mSnapScrollMode = SNAP_NONE; - } - } - } else { - if (mAverageAngle < HSLOPE_TO_START_SNAP) { - mSnapScrollMode = SNAP_X; - mSnapPositive = deltaX > 0; - mAverageAngle = (mAverageAngle + ANGLE_HORIZ) / 2; - } else if (mAverageAngle > VSLOPE_TO_START_SNAP) { - mSnapScrollMode = SNAP_Y; - mSnapPositive = deltaY > 0; - mAverageAngle = (mAverageAngle + ANGLE_VERT) / 2; - } - } - if (mSnapScrollMode != SNAP_NONE) { - if ((mSnapScrollMode & SNAP_X) == SNAP_X) { - deltaY = 0; - } else { - deltaX = 0; - } - } - mLastTouchX = x; - mLastTouchY = y; - - if (deltaX * deltaX + deltaY * deltaY > mTouchSlopSquare) { - mHeldMotionless = MOTIONLESS_FALSE; - nativeSetIsScrolling(true); - } else { - mHeldMotionless = MOTIONLESS_TRUE; - nativeSetIsScrolling(false); - keepScrollBarsVisible = true; - } - - mLastTouchTime = eventTime; - } - - doDrag(deltaX, deltaY); - - // Turn off scrollbars when dragging a layer. - if (keepScrollBarsVisible && - mTouchMode != TOUCH_DRAG_LAYER_MODE) { - if (mHeldMotionless != MOTIONLESS_TRUE) { - mHeldMotionless = MOTIONLESS_TRUE; - invalidate(); - } - // keep the scrollbar on the screen even there is no scroll - awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(), - false); - // Post a message so that we'll keep them alive while we're not scrolling. - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(AWAKEN_SCROLL_BARS), - ViewConfiguration.getScrollDefaultDelay()); - // return false to indicate that we can't pan out of the - // view space - return !done; - } else { - mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS); - } - break; - } - case MotionEvent.ACTION_UP: { - if (!isFocused()) requestFocus(); - // pass the touch events from UI thread to WebCore thread - if (shouldForwardTouchEvent()) { - TouchEventData ted = new TouchEventData(); - ted.mIds = new int[1]; - ted.mIds[0] = ev.getPointerId(0); - ted.mAction = action; - ted.mPoints = new Point[1]; - ted.mPoints[0] = new Point(contentX, contentY); - ted.mPointsInView = new Point[1]; - ted.mPointsInView[0] = new Point(x, y); - ted.mMetaState = ev.getMetaState(); - ted.mReprocess = mDeferTouchProcess; - ted.mNativeLayer = mCurrentScrollingLayerId; - ted.mNativeLayerRect.set(mScrollingLayerRect); - ted.mSequence = mTouchEventQueue.nextTouchSequence(); - mTouchEventQueue.preQueueTouchEventData(ted); - mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - } - mLastTouchUpTime = eventTime; - if (mSentAutoScrollMessage) { - mAutoScrollX = mAutoScrollY = 0; - } - switch (mTouchMode) { - case TOUCH_DOUBLE_TAP_MODE: // double tap - mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - if (inFullScreenMode() || mDeferTouchProcess) { - TouchEventData ted = new TouchEventData(); - ted.mIds = new int[1]; - ted.mIds[0] = ev.getPointerId(0); - ted.mAction = WebViewCore.ACTION_DOUBLETAP; - ted.mPoints = new Point[1]; - ted.mPoints[0] = new Point(contentX, contentY); - ted.mPointsInView = new Point[1]; - ted.mPointsInView[0] = new Point(x, y); - ted.mMetaState = ev.getMetaState(); - ted.mReprocess = mDeferTouchProcess; - ted.mNativeLayer = nativeScrollableLayer( - contentX, contentY, - ted.mNativeLayerRect, null); - ted.mSequence = mTouchEventQueue.nextTouchSequence(); - mTouchEventQueue.preQueueTouchEventData(ted); - mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - } else if (mPreventDefault != PREVENT_DEFAULT_YES){ - mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY); - mTouchMode = TOUCH_DONE_MODE; - } - break; - case TOUCH_INIT_MODE: // tap - case TOUCH_SHORTPRESS_START_MODE: - case TOUCH_SHORTPRESS_MODE: - mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - if (mConfirmMove) { - Log.w(LOGTAG, "Miss a drag as we are waiting for" + - " WebCore's response for touch down."); - if (mPreventDefault != PREVENT_DEFAULT_YES - && (computeMaxScrollX() > 0 - || computeMaxScrollY() > 0)) { - // If the user has performed a very quick touch - // sequence it is possible that we may get here - // before WebCore has had a chance to process the events. - // In this case, any call to preventDefault in the - // JS touch handler will not have been executed yet. - // Hence we will see both the UI (now) and WebCore - // (when context switches) handling the event, - // regardless of whether the web developer actually - // doeses preventDefault in their touch handler. This - // is the nature of our asynchronous touch model. - - // we will not rewrite drag code here, but we - // will try fling if it applies. - WebViewCore.reducePriority(); - // to get better performance, pause updating the - // picture - WebViewCore.pauseUpdatePicture(mWebViewCore); - // fall through to TOUCH_DRAG_MODE - } else { - // WebKit may consume the touch event and modify - // DOM. drawContentPicture() will be called with - // animateSroll as true for better performance. - // Force redraw in high-quality. - invalidate(); - break; - } - } else { - if (mSelectingText) { - // tapping on selection or controls does nothing - if (!mSelectionStarted) { - selectionDone(); - } - break; - } - // only trigger double tap if the WebView is - // scalable - if (mTouchMode == TOUCH_INIT_MODE - && (canZoomIn() || canZoomOut())) { - mPrivateHandler.sendEmptyMessageDelayed( - RELEASE_SINGLE_TAP, ViewConfiguration - .getDoubleTapTimeout()); - } else { - doShortPress(); - } - break; - } - case TOUCH_DRAG_MODE: - case TOUCH_DRAG_LAYER_MODE: - mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS); - mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS); - // if the user waits a while w/o moving before the - // up, we don't want to do a fling - if (eventTime - mLastTouchTime <= MIN_FLING_TIME) { - if (mVelocityTracker == null) { - Log.e(LOGTAG, "Got null mVelocityTracker when " - + "mPreventDefault = " - + mPreventDefault - + " mDeferTouchProcess = " - + mDeferTouchProcess); - } else { - mVelocityTracker.addMovement(ev); - } - // set to MOTIONLESS_IGNORE so that it won't keep - // removing and sending message in - // drawCoreAndCursorRing() - mHeldMotionless = MOTIONLESS_IGNORE; - doFling(); - break; - } else { - if (mScroller.springBack(mScrollX, mScrollY, 0, - computeMaxScrollX(), 0, - computeMaxScrollY())) { - invalidate(); - } - } - // redraw in high-quality, as we're done dragging - mHeldMotionless = MOTIONLESS_TRUE; - invalidate(); - // fall through - case TOUCH_DRAG_START_MODE: - // TOUCH_DRAG_START_MODE should not happen for the real - // device as we almost certain will get a MOVE. But this - // is possible on emulator. - mLastVelocity = 0; - WebViewCore.resumePriority(); - if (!mSelectingText) { - WebViewCore.resumeUpdatePicture(mWebViewCore); - } - break; - } - stopTouch(); - break; - } - case MotionEvent.ACTION_CANCEL: { - if (mTouchMode == TOUCH_DRAG_MODE) { - mScroller.springBack(mScrollX, mScrollY, 0, - computeMaxScrollX(), 0, computeMaxScrollY()); - invalidate(); - } - cancelWebCoreTouchEvent(contentX, contentY, false); - cancelTouch(); - break; - } - } - return true; - } - - private void passMultiTouchToWebKit(MotionEvent ev, long sequence) { - TouchEventData ted = new TouchEventData(); - ted.mAction = ev.getActionMasked(); - final int count = ev.getPointerCount(); - ted.mIds = new int[count]; - ted.mPoints = new Point[count]; - ted.mPointsInView = new Point[count]; - for (int c = 0; c < count; c++) { - ted.mIds[c] = ev.getPointerId(c); - int x = viewToContentX((int) ev.getX(c) + mScrollX); - int y = viewToContentY((int) ev.getY(c) + mScrollY); - ted.mPoints[c] = new Point(x, y); - ted.mPointsInView[c] = new Point((int) ev.getX(c), (int) ev.getY(c)); - } - if (ted.mAction == MotionEvent.ACTION_POINTER_DOWN - || ted.mAction == MotionEvent.ACTION_POINTER_UP) { - ted.mActionIndex = ev.getActionIndex(); - } - ted.mMetaState = ev.getMetaState(); - ted.mReprocess = true; - ted.mMotionEvent = MotionEvent.obtain(ev); - ted.mSequence = sequence; - mTouchEventQueue.preQueueTouchEventData(ted); - mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - cancelLongPress(); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - } - - void handleMultiTouchInWebView(MotionEvent ev) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime() - + " mTouchMode=" + mTouchMode - + " numPointers=" + ev.getPointerCount() - + " scrolloffset=(" + mScrollX + "," + mScrollY + ")"); - } - - final ScaleGestureDetector detector = - mZoomManager.getMultiTouchGestureDetector(); - - // A few apps use WebView but don't instantiate gesture detector. - // We don't need to support multi touch for them. - if (detector == null) return; - - float x = ev.getX(); - float y = ev.getY(); - - if (mPreventDefault != PREVENT_DEFAULT_YES) { - detector.onTouchEvent(ev); - - if (detector.isInProgress()) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "detector is in progress"); - } - mLastTouchTime = ev.getEventTime(); - x = detector.getFocusX(); - y = detector.getFocusY(); - - cancelLongPress(); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - if (!mZoomManager.supportsPanDuringZoom()) { - return; - } - mTouchMode = TOUCH_DRAG_MODE; - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - } - } - - int action = ev.getActionMasked(); - if (action == MotionEvent.ACTION_POINTER_DOWN) { - cancelTouch(); - action = MotionEvent.ACTION_DOWN; - } else if (action == MotionEvent.ACTION_POINTER_UP && ev.getPointerCount() >= 2) { - // set mLastTouchX/Y to the remaining points for multi-touch. - mLastTouchX = Math.round(x); - mLastTouchY = Math.round(y); - } else if (action == MotionEvent.ACTION_MOVE) { - // negative x or y indicate it is on the edge, skip it. - if (x < 0 || y < 0) { - return; - } - } - - handleTouchEventCommon(ev, action, Math.round(x), Math.round(y)); - } - - private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) { - if (shouldForwardTouchEvent()) { - if (removeEvents) { - mWebViewCore.removeMessages(EventHub.TOUCH_EVENT); - } - TouchEventData ted = new TouchEventData(); - ted.mIds = new int[1]; - ted.mIds[0] = 0; - ted.mPoints = new Point[1]; - ted.mPoints[0] = new Point(x, y); - ted.mPointsInView = new Point[1]; - int viewX = contentToViewX(x) - mScrollX; - int viewY = contentToViewY(y) - mScrollY; - ted.mPointsInView[0] = new Point(viewX, viewY); - ted.mAction = MotionEvent.ACTION_CANCEL; - ted.mNativeLayer = nativeScrollableLayer( - x, y, ted.mNativeLayerRect, null); - ted.mSequence = mTouchEventQueue.nextTouchSequence(); - mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - mPreventDefault = PREVENT_DEFAULT_IGNORE; - - if (removeEvents) { - // Mark this after sending the message above; we should - // be willing to ignore the cancel event that we just sent. - mTouchEventQueue.ignoreCurrentlyMissingEvents(); - } - } - } - - private void startTouch(float x, float y, long eventTime) { - // Remember where the motion event started - mStartTouchX = mLastTouchX = Math.round(x); - mStartTouchY = mLastTouchY = Math.round(y); - mLastTouchTime = eventTime; - mVelocityTracker = VelocityTracker.obtain(); - mSnapScrollMode = SNAP_NONE; - mPrivateHandler.sendEmptyMessageDelayed(UPDATE_SELECTION, - ViewConfiguration.getTapTimeout()); - } - - private void startDrag() { - WebViewCore.reducePriority(); - // to get better performance, pause updating the picture - WebViewCore.pauseUpdatePicture(mWebViewCore); - nativeSetIsScrolling(true); - - if (!mDragFromTextInput) { - nativeHideCursor(); - } - - if (mHorizontalScrollBarMode != SCROLLBAR_ALWAYSOFF - || mVerticalScrollBarMode != SCROLLBAR_ALWAYSOFF) { - mZoomManager.invokeZoomPicker(); - } - } - - private void doDrag(int deltaX, int deltaY) { - if ((deltaX | deltaY) != 0) { - int oldX = mScrollX; - int oldY = mScrollY; - int rangeX = computeMaxScrollX(); - int rangeY = computeMaxScrollY(); - // Check for the original scrolling layer in case we change - // directions. mTouchMode might be TOUCH_DRAG_MODE if we have - // reached the edge of a layer but mScrollingLayer will be non-zero - // if we initiated the drag on a layer. - if (mCurrentScrollingLayerId != 0) { - final int contentX = viewToContentDimension(deltaX); - final int contentY = viewToContentDimension(deltaY); - - // Check the scrolling bounds to see if we will actually do any - // scrolling. The rectangle is in document coordinates. - final int maxX = mScrollingLayerRect.right; - final int maxY = mScrollingLayerRect.bottom; - final int resultX = Math.max(0, - Math.min(mScrollingLayerRect.left + contentX, maxX)); - final int resultY = Math.max(0, - Math.min(mScrollingLayerRect.top + contentY, maxY)); - - if (resultX != mScrollingLayerRect.left || - resultY != mScrollingLayerRect.top) { - // In case we switched to dragging the page. - mTouchMode = TOUCH_DRAG_LAYER_MODE; - deltaX = contentX; - deltaY = contentY; - oldX = mScrollingLayerRect.left; - oldY = mScrollingLayerRect.top; - rangeX = maxX; - rangeY = maxY; - } else { - // Scroll the main page if we are not going to scroll the - // layer. This does not reset mScrollingLayer in case the - // user changes directions and the layer can scroll the - // other way. - mTouchMode = TOUCH_DRAG_MODE; - } - } - - if (mOverScrollGlow != null) { - mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY); - } - - overScrollBy(deltaX, deltaY, oldX, oldY, - rangeX, rangeY, - mOverscrollDistance, mOverscrollDistance, true); - if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) { - invalidate(); - } - } - mZoomManager.keepZoomPickerVisible(); - } - - private void stopTouch() { - if (mScroller.isFinished() && !mSelectingText - && (mTouchMode == TOUCH_DRAG_MODE || mTouchMode == TOUCH_DRAG_LAYER_MODE)) { - WebViewCore.resumePriority(); - WebViewCore.resumeUpdatePicture(mWebViewCore); - nativeSetIsScrolling(false); - } - - // we also use mVelocityTracker == null to tell us that we are - // not "moving around", so we can take the slower/prettier - // mode in the drawing code - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - - // Release any pulled glows - if (mOverScrollGlow != null) { - mOverScrollGlow.releaseAll(); - } - - if (mSelectingText) { - mSelectionStarted = false; - syncSelectionCursors(); - if (mIsCaretSelection) { - resetCaretTimer(); - showPasteWindow(); - } - invalidate(); - } - } - - private void cancelTouch() { - // we also use mVelocityTracker == null to tell us that we are - // not "moving around", so we can take the slower/prettier - // mode in the drawing code - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - - if ((mTouchMode == TOUCH_DRAG_MODE - || mTouchMode == TOUCH_DRAG_LAYER_MODE) && !mSelectingText) { - WebViewCore.resumePriority(); - WebViewCore.resumeUpdatePicture(mWebViewCore); - nativeSetIsScrolling(false); - } - mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS); - mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS); - if (sDisableNavcache) { - removeTouchHighlight(); - } - mHeldMotionless = MOTIONLESS_TRUE; - mTouchMode = TOUCH_DONE_MODE; - nativeHideCursor(); - } - - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { - switch (event.getAction()) { - case MotionEvent.ACTION_SCROLL: { - final float vscroll; - final float hscroll; - if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) { - vscroll = 0; - hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); - } else { - vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL); - hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL); - } - if (hscroll != 0 || vscroll != 0) { - final int vdelta = (int) (vscroll * getVerticalScrollFactor()); - final int hdelta = (int) (hscroll * getHorizontalScrollFactor()); - if (pinScrollBy(hdelta, vdelta, false, 0)) { - return true; - } - } - } - } - } - return super.onGenericMotionEvent(event); - } - - private long mTrackballFirstTime = 0; - private long mTrackballLastTime = 0; - private float mTrackballRemainsX = 0.0f; - private float mTrackballRemainsY = 0.0f; - private int mTrackballXMove = 0; - private int mTrackballYMove = 0; - private boolean mSelectingText = false; - private boolean mSelectionStarted = false; - private static final int TRACKBALL_KEY_TIMEOUT = 1000; - private static final int TRACKBALL_TIMEOUT = 200; - private static final int TRACKBALL_WAIT = 100; - private static final int TRACKBALL_SCALE = 400; - private static final int TRACKBALL_SCROLL_COUNT = 5; - private static final int TRACKBALL_MOVE_COUNT = 10; - private static final int TRACKBALL_MULTIPLIER = 3; - private static final int SELECT_CURSOR_OFFSET = 16; - private static final int SELECT_SCROLL = 5; - private int mSelectX = 0; - private int mSelectY = 0; - private boolean mFocusSizeChanged = false; - private boolean mTrackballDown = false; - private long mTrackballUpTime = 0; - private long mLastCursorTime = 0; - private Rect mLastCursorBounds; - - // Set by default; BrowserActivity clears to interpret trackball data - // directly for movement. Currently, the framework only passes - // arrow key events, not trackball events, from one child to the next - private boolean mMapTrackballToArrowKeys = true; - - private DrawData mDelaySetPicture; - private DrawData mLoadedPicture; - public void setMapTrackballToArrowKeys(boolean setMap) { checkThread(); - mMapTrackballToArrowKeys = setMap; + mProvider.setMapTrackballToArrowKeys(setMap); } - void resetTrackballTime() { - mTrackballLastTime = 0; - } - - @Override - public boolean onTrackballEvent(MotionEvent ev) { - long time = ev.getEventTime(); - if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) { - if (ev.getY() > 0) pageDown(true); - if (ev.getY() < 0) pageUp(true); - return true; - } - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - if (mSelectingText) { - return true; // discard press if copy in progress - } - mTrackballDown = true; - if (mNativeClass == 0) { - return false; - } - if (time - mLastCursorTime <= TRACKBALL_TIMEOUT - && !mLastCursorBounds.equals(cursorRingBounds())) { - nativeSelectBestAt(mLastCursorBounds); - } - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "onTrackballEvent down ev=" + ev - + " time=" + time - + " mLastCursorTime=" + mLastCursorTime); - } - if (isInTouchMode()) requestFocusFromTouch(); - return false; // let common code in onKeyDown at it - } - if (ev.getAction() == MotionEvent.ACTION_UP) { - // LONG_PRESS_CENTER is set in common onKeyDown - mPrivateHandler.removeMessages(LONG_PRESS_CENTER); - mTrackballDown = false; - mTrackballUpTime = time; - if (mSelectingText) { - copySelection(); - selectionDone(); - return true; // discard press if copy in progress - } - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "onTrackballEvent up ev=" + ev - + " time=" + time - ); - } - return false; // let common code in onKeyUp at it - } - if ((mMapTrackballToArrowKeys && (ev.getMetaState() & KeyEvent.META_SHIFT_ON) == 0) || - AccessibilityManager.getInstance(mContext).isEnabled()) { - if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit"); - return false; - } - if (mTrackballDown) { - if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit"); - return true; // discard move if trackball is down - } - if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) { - if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent up timeout quit"); - return true; - } - // TODO: alternatively we can do panning as touch does - switchOutDrawHistory(); - if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) { - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "onTrackballEvent time=" - + time + " last=" + mTrackballLastTime); - } - mTrackballFirstTime = time; - mTrackballXMove = mTrackballYMove = 0; - } - mTrackballLastTime = time; - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time); - } - mTrackballRemainsX += ev.getX(); - mTrackballRemainsY += ev.getY(); - doTrackball(time, ev.getMetaState()); - return true; - } - - private int scaleTrackballX(float xRate, int width) { - int xMove = (int) (xRate / TRACKBALL_SCALE * width); - int nextXMove = xMove; - if (xMove > 0) { - if (xMove > mTrackballXMove) { - xMove -= mTrackballXMove; - } - } else if (xMove < mTrackballXMove) { - xMove -= mTrackballXMove; - } - mTrackballXMove = nextXMove; - return xMove; - } - - private int scaleTrackballY(float yRate, int height) { - int yMove = (int) (yRate / TRACKBALL_SCALE * height); - int nextYMove = yMove; - if (yMove > 0) { - if (yMove > mTrackballYMove) { - yMove -= mTrackballYMove; - } - } else if (yMove < mTrackballYMove) { - yMove -= mTrackballYMove; - } - mTrackballYMove = nextYMove; - return yMove; - } - - private int keyCodeToSoundsEffect(int keyCode) { - switch(keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - return SoundEffectConstants.NAVIGATION_UP; - case KeyEvent.KEYCODE_DPAD_RIGHT: - return SoundEffectConstants.NAVIGATION_RIGHT; - case KeyEvent.KEYCODE_DPAD_DOWN: - return SoundEffectConstants.NAVIGATION_DOWN; - case KeyEvent.KEYCODE_DPAD_LEFT: - return SoundEffectConstants.NAVIGATION_LEFT; - } - throw new IllegalArgumentException("keyCode must be one of " + - "{KEYCODE_DPAD_UP, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_DOWN, " + - "KEYCODE_DPAD_LEFT}."); - } - - private void doTrackball(long time, int metaState) { - int elapsed = (int) (mTrackballLastTime - mTrackballFirstTime); - if (elapsed == 0) { - elapsed = TRACKBALL_TIMEOUT; - } - float xRate = mTrackballRemainsX * 1000 / elapsed; - float yRate = mTrackballRemainsY * 1000 / elapsed; - int viewWidth = getViewWidth(); - int viewHeight = getViewHeight(); - float ax = Math.abs(xRate); - float ay = Math.abs(yRate); - float maxA = Math.max(ax, ay); - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "doTrackball elapsed=" + elapsed - + " xRate=" + xRate - + " yRate=" + yRate - + " mTrackballRemainsX=" + mTrackballRemainsX - + " mTrackballRemainsY=" + mTrackballRemainsY); - } - int width = mContentWidth - viewWidth; - int height = mContentHeight - viewHeight; - if (width < 0) width = 0; - if (height < 0) height = 0; - ax = Math.abs(mTrackballRemainsX * TRACKBALL_MULTIPLIER); - ay = Math.abs(mTrackballRemainsY * TRACKBALL_MULTIPLIER); - maxA = Math.max(ax, ay); - int count = Math.max(0, (int) maxA); - int oldScrollX = mScrollX; - int oldScrollY = mScrollY; - if (count > 0) { - int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ? - KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN : - mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT : - KeyEvent.KEYCODE_DPAD_RIGHT; - count = Math.min(count, TRACKBALL_MOVE_COUNT); - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode - + " count=" + count - + " mTrackballRemainsX=" + mTrackballRemainsX - + " mTrackballRemainsY=" + mTrackballRemainsY); - } - if (mNativeClass != 0 && nativePageShouldHandleShiftAndArrows()) { - for (int i = 0; i < count; i++) { - letPageHandleNavKey(selectKeyCode, time, true, metaState); - } - letPageHandleNavKey(selectKeyCode, time, false, metaState); - } else if (navHandledKey(selectKeyCode, count, false, time)) { - playSoundEffect(keyCodeToSoundsEffect(selectKeyCode)); - } - mTrackballRemainsX = mTrackballRemainsY = 0; - } - if (count >= TRACKBALL_SCROLL_COUNT) { - int xMove = scaleTrackballX(xRate, width); - int yMove = scaleTrackballY(yRate, height); - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "doTrackball pinScrollBy" - + " count=" + count - + " xMove=" + xMove + " yMove=" + yMove - + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX) - + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY) - ); - } - if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) { - xMove = 0; - } - if (Math.abs(mScrollY - oldScrollY) > Math.abs(yMove)) { - yMove = 0; - } - if (xMove != 0 || yMove != 0) { - pinScrollBy(xMove, yMove, true, 0); - } - } - } - - /** - * Compute the maximum horizontal scroll position. Used by {@link OverScrollGlow}. - * @return Maximum horizontal scroll position within real content - */ - int computeMaxScrollX() { - return Math.max(computeRealHorizontalScrollRange() - getViewWidth(), 0); - } - - /** - * Compute the maximum vertical scroll position. Used by {@link OverScrollGlow}. - * @return Maximum vertical scroll position within real content - */ - int computeMaxScrollY() { - return Math.max(computeRealVerticalScrollRange() + getTitleHeight() - - getViewHeightWithTitle(), 0); - } - - boolean updateScrollCoordinates(int x, int y) { - int oldX = mScrollX; - int oldY = mScrollY; - mScrollX = x; - mScrollY = y; - if (oldX != mScrollX || oldY != mScrollY) { - onScrollChanged(mScrollX, mScrollY, oldX, oldY); - return true; - } else { - return false; - } - } public void flingScroll(int vx, int vy) { checkThread(); - mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0, - computeMaxScrollY(), mOverflingDistance, mOverflingDistance); - invalidate(); - } - - private void doFling() { - if (mVelocityTracker == null) { - return; - } - int maxX = computeMaxScrollX(); - int maxY = computeMaxScrollY(); - - mVelocityTracker.computeCurrentVelocity(1000, mMaximumFling); - int vx = (int) mVelocityTracker.getXVelocity(); - int vy = (int) mVelocityTracker.getYVelocity(); - - int scrollX = mScrollX; - int scrollY = mScrollY; - int overscrollDistance = mOverscrollDistance; - int overflingDistance = mOverflingDistance; - - // Use the layer's scroll data if applicable. - if (mTouchMode == TOUCH_DRAG_LAYER_MODE) { - scrollX = mScrollingLayerRect.left; - scrollY = mScrollingLayerRect.top; - maxX = mScrollingLayerRect.right; - maxY = mScrollingLayerRect.bottom; - // No overscrolling for layers. - overscrollDistance = overflingDistance = 0; - } - - if (mSnapScrollMode != SNAP_NONE) { - if ((mSnapScrollMode & SNAP_X) == SNAP_X) { - vy = 0; - } else { - vx = 0; - } - } - if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) { - WebViewCore.resumePriority(); - if (!mSelectingText) { - WebViewCore.resumeUpdatePicture(mWebViewCore); - } - if (mScroller.springBack(scrollX, scrollY, 0, maxX, 0, maxY)) { - invalidate(); - } - return; - } - float currentVelocity = mScroller.getCurrVelocity(); - float velocity = (float) Math.hypot(vx, vy); - if (mLastVelocity > 0 && currentVelocity > 0 && velocity - > mLastVelocity * MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION) { - float deltaR = (float) (Math.abs(Math.atan2(mLastVelY, mLastVelX) - - Math.atan2(vy, vx))); - final float circle = (float) (Math.PI) * 2.0f; - if (deltaR > circle * 0.9f || deltaR < circle * 0.1f) { - vx += currentVelocity * mLastVelX / mLastVelocity; - vy += currentVelocity * mLastVelY / mLastVelocity; - velocity = (float) Math.hypot(vx, vy); - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "doFling vx= " + vx + " vy=" + vy); - } - } else if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "doFling missed " + deltaR / circle); - } - } else if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "doFling start last=" + mLastVelocity - + " current=" + currentVelocity - + " vx=" + vx + " vy=" + vy - + " maxX=" + maxX + " maxY=" + maxY - + " scrollX=" + scrollX + " scrollY=" + scrollY - + " layer=" + mCurrentScrollingLayerId); - } - - // Allow sloppy flings without overscrolling at the edges. - if ((scrollX == 0 || scrollX == maxX) && Math.abs(vx) < Math.abs(vy)) { - vx = 0; - } - if ((scrollY == 0 || scrollY == maxY) && Math.abs(vy) < Math.abs(vx)) { - vy = 0; - } - - if (overscrollDistance < overflingDistance) { - if ((vx > 0 && scrollX == -overscrollDistance) || - (vx < 0 && scrollX == maxX + overscrollDistance)) { - vx = 0; - } - if ((vy > 0 && scrollY == -overscrollDistance) || - (vy < 0 && scrollY == maxY + overscrollDistance)) { - vy = 0; - } - } - - mLastVelX = vx; - mLastVelY = vy; - mLastVelocity = velocity; - - // no horizontal overscroll if the content just fits - mScroller.fling(scrollX, scrollY, -vx, -vy, 0, maxX, 0, maxY, - maxX == 0 ? 0 : overflingDistance, overflingDistance); - // Duration is calculated based on velocity. With range boundaries and overscroll - // we may not know how long the final animation will take. (Hence the deprecation - // warning on the call below.) It's not a big deal for scroll bars but if webcore - // resumes during this effect we will take a performance hit. See computeScroll; - // we resume webcore there when the animation is finished. - final int time = mScroller.getDuration(); - - // Suppress scrollbars for layer scrolling. - if (mTouchMode != TOUCH_DRAG_LAYER_MODE) { - awakenScrollBars(time); - } - - invalidate(); + mProvider.flingScroll(vx, vy); } /** @@ -7921,27 +1491,7 @@ public class WebView extends AbsoluteLayout @Deprecated public View getZoomControls() { checkThread(); - if (!getSettings().supportZoom()) { - Log.w(LOGTAG, "This WebView doesn't support zoom."); - return null; - } - return mZoomManager.getExternalZoomPicker(); - } - - void dismissZoomControl() { - mZoomManager.dismissZoomPicker(); - } - - float getDefaultZoomScale() { - return mZoomManager.getDefaultScale(); - } - - /** - * Return the overview scale of the WebView - * @return The overview scale. - */ - float getZoomOverviewScale() { - return mZoomManager.getZoomOverviewScale(); + return mProvider.getZoomControls(); } /** @@ -7949,7 +1499,7 @@ public class WebView extends AbsoluteLayout */ public boolean canZoomIn() { checkThread(); - return mZoomManager.canZoomIn(); + return mProvider.canZoomIn(); } /** @@ -7957,7 +1507,7 @@ public class WebView extends AbsoluteLayout */ public boolean canZoomOut() { checkThread(); - return mZoomManager.canZoomOut(); + return mProvider.canZoomOut(); } /** @@ -7966,7 +1516,7 @@ public class WebView extends AbsoluteLayout */ public boolean zoomIn() { checkThread(); - return mZoomManager.zoomIn(); + return mProvider.zoomIn(); } /** @@ -7975,2576 +1525,434 @@ public class WebView extends AbsoluteLayout */ public boolean zoomOut() { checkThread(); - return mZoomManager.zoomOut(); - } - - /** - * This selects the best clickable target at mLastTouchX and mLastTouchY - * and calls showCursorTimed on the native side - */ - private void updateSelection() { - if (mNativeClass == 0 || sDisableNavcache) { - return; - } - mPrivateHandler.removeMessages(UPDATE_SELECTION); - // mLastTouchX and mLastTouchY are the point in the current viewport - int contentX = viewToContentX(mLastTouchX + mScrollX); - int contentY = viewToContentY(mLastTouchY + mScrollY); - int slop = viewToContentDimension(mNavSlop); - Rect rect = new Rect(contentX - slop, contentY - slop, - contentX + slop, contentY + slop); - nativeSelectBestAt(rect); - mInitialHitTestResult = hitTestResult(null); - } - - /** - * Scroll the focused text field to match the WebTextView - * @param xPercent New x position of the WebTextView from 0 to 1. - */ - /*package*/ void scrollFocusedTextInputX(float xPercent) { - if (!inEditingMode() || mWebViewCore == null) { - return; - } - mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0, - new Float(xPercent)); - } - - /** - * Scroll the focused textarea vertically to match the WebTextView - * @param y New y position of the WebTextView in view coordinates - */ - /* package */ void scrollFocusedTextInputY(int y) { - if (!inEditingMode() || mWebViewCore == null) { - return; - } - mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0, viewToContentDimension(y)); - } - - /** - * Set our starting point and time for a drag from the WebTextView. - */ - /*package*/ void initiateTextFieldDrag(float x, float y, long eventTime) { - if (!inEditingMode()) { - return; - } - mLastTouchX = Math.round(x + mWebTextView.getLeft() - mScrollX); - mLastTouchY = Math.round(y + mWebTextView.getTop() - mScrollY); - mLastTouchTime = eventTime; - if (!mScroller.isFinished()) { - abortAnimation(); - } - mSnapScrollMode = SNAP_NONE; - mVelocityTracker = VelocityTracker.obtain(); - mTouchMode = TOUCH_DRAG_START_MODE; + return mProvider.zoomOut(); } /** - * Given a motion event from the WebTextView, set its location to our - * coordinates, and handle the event. + * @deprecated This method is now obsolete. */ - /*package*/ boolean textFieldDrag(MotionEvent event) { - if (!inEditingMode()) { - return false; - } - mDragFromTextInput = true; - event.offsetLocation((mWebTextView.getLeft() - mScrollX), - (mWebTextView.getTop() - mScrollY)); - boolean result = onTouchEvent(event); - mDragFromTextInput = false; - return result; + @Deprecated + public void debugDump() { + checkThread(); + mProvider.debugDump(); } - /** - * Due a touch up from a WebTextView. This will be handled by webkit to - * change the selection. - * @param event MotionEvent in the WebTextView's coordinates. - */ - /*package*/ void touchUpOnTextField(MotionEvent event) { - if (!inEditingMode()) { - return; - } - int x = viewToContentX((int) event.getX() + mWebTextView.getLeft()); - int y = viewToContentY((int) event.getY() + mWebTextView.getTop()); - int slop = viewToContentDimension(mNavSlop); - nativeMotionUp(x, y, slop); - } + //------------------------------------------------------------------------- + // Interface for WebView providers + //------------------------------------------------------------------------- /** - * Called when pressing the center key or trackball on a textfield. + * Used by providers to obtain the underlying implementation, e.g. when the appliction + * responds to WebViewClient.onCreateWindow() request. + * + * @hide WebViewProvider is not public API. */ - /*package*/ void centerKeyPressOnTextField() { - mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(), - nativeCursorNodePointer()); - } - - private void doShortPress() { - if (mNativeClass == 0) { - return; - } - if (mPreventDefault == PREVENT_DEFAULT_YES) { - return; - } - mTouchMode = TOUCH_DONE_MODE; - updateSelection(); - switchOutDrawHistory(); - // mLastTouchX and mLastTouchY are the point in the current viewport - int contentX = viewToContentX(mLastTouchX + mScrollX); - int contentY = viewToContentY(mLastTouchY + mScrollY); - int slop = viewToContentDimension(mNavSlop); - if (sDisableNavcache && !mTouchHighlightRegion.isEmpty()) { - // set mTouchHighlightRequested to 0 to cause an immediate - // drawing of the touch rings - mTouchHighlightRequested = 0; - invalidate(mTouchHighlightRegion.getBounds()); - mPrivateHandler.postDelayed(new Runnable() { - @Override - public void run() { - removeTouchHighlight(); - } - }, ViewConfiguration.getPressedStateDuration()); - } - if (mFocusedNode != null && mFocusedNode.mIntentUrl != null) { - playSoundEffect(SoundEffectConstants.CLICK); - overrideLoading(mFocusedNode.mIntentUrl); - } else if (sDisableNavcache) { - WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData(); - // use "0" as generation id to inform WebKit to use the same x/y as - // it used when processing GET_TOUCH_HIGHLIGHT_RECTS - touchUpData.mMoveGeneration = 0; - mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData); - } else if (nativePointInNavCache(contentX, contentY, slop)) { - WebViewCore.MotionUpData motionUpData = new WebViewCore - .MotionUpData(); - motionUpData.mFrame = nativeCacheHitFramePointer(); - motionUpData.mNode = nativeCacheHitNodePointer(); - motionUpData.mBounds = nativeCacheHitNodeBounds(); - motionUpData.mX = contentX; - motionUpData.mY = contentY; - mWebViewCore.sendMessageAtFrontOfQueue(EventHub.VALID_NODE_BOUNDS, - motionUpData); - } else { - doMotionUp(contentX, contentY); - } - } - - private void doMotionUp(int contentX, int contentY) { - int slop = viewToContentDimension(mNavSlop); - if (nativeMotionUp(contentX, contentY, slop) && mLogEvent) { - EventLog.writeEvent(EventLogTags.BROWSER_SNAP_CENTER); - } - if (nativeHasCursorNode() && !nativeCursorIsTextInput()) { - playSoundEffect(SoundEffectConstants.CLICK); - } - } - - void sendPluginDrawMsg() { - mWebViewCore.sendMessage(EventHub.PLUGIN_SURFACE_READY); + public WebViewProvider getWebViewProvider() { + return mProvider; } /** - * Returns plugin bounds if x/y in content coordinates corresponds to a - * plugin. Otherwise a NULL rectangle is returned. + * Callback interface, allows the provider implementation to access non-public methods + * and fields, and make super-class calls in this WebView instance. + * @hide Only for use by WebViewProvider implementations */ - Rect getPluginBounds(int x, int y) { - int slop = viewToContentDimension(mNavSlop); - if (nativePointInNavCache(x, y, slop) && nativeCacheHitIsPlugin()) { - return nativeCacheHitNodeBounds(); - } else { - return null; - } - } - - /* - * Return true if the rect (e.g. plugin) is fully visible and maximized - * inside the WebView. - */ - boolean isRectFitOnScreen(Rect rect) { - final int rectWidth = rect.width(); - final int rectHeight = rect.height(); - final int viewWidth = getViewWidth(); - final int viewHeight = getViewHeightWithTitle(); - float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight / rectHeight); - scale = mZoomManager.computeScaleWithLimits(scale); - return !mZoomManager.willScaleTriggerZoom(scale) - && contentToViewX(rect.left) >= mScrollX - && contentToViewX(rect.right) <= mScrollX + viewWidth - && contentToViewY(rect.top) >= mScrollY - && contentToViewY(rect.bottom) <= mScrollY + viewHeight; - } - - /* - * Maximize and center the rectangle, specified in the document coordinate - * space, inside the WebView. If the zoom doesn't need to be changed, do an - * animated scroll to center it. If the zoom needs to be changed, find the - * zoom center and do a smooth zoom transition. The rect is in document - * coordinates - */ - void centerFitRect(Rect rect) { - final int rectWidth = rect.width(); - final int rectHeight = rect.height(); - final int viewWidth = getViewWidth(); - final int viewHeight = getViewHeightWithTitle(); - float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight - / rectHeight); - scale = mZoomManager.computeScaleWithLimits(scale); - if (!mZoomManager.willScaleTriggerZoom(scale)) { - pinScrollTo(contentToViewX(rect.left + rectWidth / 2) - viewWidth / 2, - contentToViewY(rect.top + rectHeight / 2) - viewHeight / 2, - true, 0); - } else { - float actualScale = mZoomManager.getScale(); - float oldScreenX = rect.left * actualScale - mScrollX; - float rectViewX = rect.left * scale; - float rectViewWidth = rectWidth * scale; - float newMaxWidth = mContentWidth * scale; - float newScreenX = (viewWidth - rectViewWidth) / 2; - // pin the newX to the WebView - if (newScreenX > rectViewX) { - newScreenX = rectViewX; - } else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) { - newScreenX = viewWidth - (newMaxWidth - rectViewX); - } - float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale) - / (scale - actualScale); - float oldScreenY = rect.top * actualScale + getTitleHeight() - - mScrollY; - float rectViewY = rect.top * scale + getTitleHeight(); - float rectViewHeight = rectHeight * scale; - float newMaxHeight = mContentHeight * scale + getTitleHeight(); - float newScreenY = (viewHeight - rectViewHeight) / 2; - // pin the newY to the WebView - if (newScreenY > rectViewY) { - newScreenY = rectViewY; - } else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) { - newScreenY = viewHeight - (newMaxHeight - rectViewY); - } - float zoomCenterY = (oldScreenY * scale - newScreenY * actualScale) - / (scale - actualScale); - mZoomManager.setZoomCenter(zoomCenterX, zoomCenterY); - mZoomManager.startZoomAnimation(scale, false); - } - } - - // Called by JNI to handle a touch on a node representing an email address, - // address, or phone number - private void overrideLoading(String url) { - mCallbackProxy.uiOverrideUrlLoading(url); - } - - @Override - public boolean requestFocus(int direction, Rect previouslyFocusedRect) { - // FIXME: If a subwindow is showing find, and the user touches the - // background window, it can steal focus. - if (mFindIsUp) return false; - boolean result = false; - if (inEditingMode()) { - result = mWebTextView.requestFocus(direction, - previouslyFocusedRect); - } else { - result = super.requestFocus(direction, previouslyFocusedRect); - if (mWebViewCore.getSettings().getNeedInitialFocus() && !isInTouchMode()) { - // For cases such as GMail, where we gain focus from a direction, - // we want to move to the first available link. - // FIXME: If there are no visible links, we may not want to - int fakeKeyDirection = 0; - switch(direction) { - case View.FOCUS_UP: - fakeKeyDirection = KeyEvent.KEYCODE_DPAD_UP; - break; - case View.FOCUS_DOWN: - fakeKeyDirection = KeyEvent.KEYCODE_DPAD_DOWN; - break; - case View.FOCUS_LEFT: - fakeKeyDirection = KeyEvent.KEYCODE_DPAD_LEFT; - break; - case View.FOCUS_RIGHT: - fakeKeyDirection = KeyEvent.KEYCODE_DPAD_RIGHT; - break; - default: - return result; - } - if (mNativeClass != 0 && !nativeHasCursorNode()) { - navHandledKey(fakeKeyDirection, 1, true, 0); - } - } + public class PrivateAccess { + // ---- Access to super-class methods ---- + public int super_getScrollBarStyle() { + return WebView.super.getScrollBarStyle(); } - return result; - } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - - int measuredHeight = heightSize; - int measuredWidth = widthSize; - - // Grab the content size from WebViewCore. - int contentHeight = contentToViewDimension(mContentHeight); - int contentWidth = contentToViewDimension(mContentWidth); - -// Log.d(LOGTAG, "------- measure " + heightMode); - - if (heightMode != MeasureSpec.EXACTLY) { - mHeightCanMeasure = true; - measuredHeight = contentHeight; - if (heightMode == MeasureSpec.AT_MOST) { - // If we are larger than the AT_MOST height, then our height can - // no longer be measured and we should scroll internally. - if (measuredHeight > heightSize) { - measuredHeight = heightSize; - mHeightCanMeasure = false; - measuredHeight |= MEASURED_STATE_TOO_SMALL; - } - } - } else { - mHeightCanMeasure = false; - } - if (mNativeClass != 0) { - nativeSetHeightCanMeasure(mHeightCanMeasure); - } - // For the width, always use the given size unless unspecified. - if (widthMode == MeasureSpec.UNSPECIFIED) { - mWidthCanMeasure = true; - measuredWidth = contentWidth; - } else { - if (measuredWidth < contentWidth) { - measuredWidth |= MEASURED_STATE_TOO_SMALL; - } - mWidthCanMeasure = false; + public void super_scrollTo(int scrollX, int scrollY) { + WebView.super.scrollTo(scrollX, scrollY); } - synchronized (this) { - setMeasuredDimension(measuredWidth, measuredHeight); + public void super_computeScroll() { + WebView.super.computeScroll(); } - } - @Override - public boolean requestChildRectangleOnScreen(View child, - Rect rect, - boolean immediate) { - if (mNativeClass == 0) { - return false; - } - // don't scroll while in zoom animation. When it is done, we will adjust - // the necessary components (e.g., WebTextView if it is in editing mode) - if (mZoomManager.isFixedLengthAnimationInProgress()) { - return false; + public boolean super_performLongClick() { + return WebView.super.performLongClick(); } - rect.offset(child.getLeft() - child.getScrollX(), - child.getTop() - child.getScrollY()); - - Rect content = new Rect(viewToContentX(mScrollX), - viewToContentY(mScrollY), - viewToContentX(mScrollX + getWidth() - - getVerticalScrollbarWidth()), - viewToContentY(mScrollY + getViewHeightWithTitle())); - content = nativeSubtractLayers(content); - int screenTop = contentToViewY(content.top); - int screenBottom = contentToViewY(content.bottom); - int height = screenBottom - screenTop; - int scrollYDelta = 0; - - if (rect.bottom > screenBottom) { - int oneThirdOfScreenHeight = height / 3; - if (rect.height() > 2 * oneThirdOfScreenHeight) { - // If the rectangle is too tall to fit in the bottom two thirds - // of the screen, place it at the top. - scrollYDelta = rect.top - screenTop; - } else { - // If the rectangle will still fit on screen, we want its - // top to be in the top third of the screen. - scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight); - } - } else if (rect.top < screenTop) { - scrollYDelta = rect.top - screenTop; + public boolean super_setFrame(int left, int top, int right, int bottom) { + return WebView.super.setFrame(left, top, right, bottom); } - int screenLeft = contentToViewX(content.left); - int screenRight = contentToViewX(content.right); - int width = screenRight - screenLeft; - int scrollXDelta = 0; - - if (rect.right > screenRight && rect.left > screenLeft) { - if (rect.width() > width) { - scrollXDelta += (rect.left - screenLeft); - } else { - scrollXDelta += (rect.right - screenRight); - } - } else if (rect.left < screenLeft) { - scrollXDelta -= (screenLeft - rect.left); + public boolean super_dispatchKeyEvent(KeyEvent event) { + return WebView.super.dispatchKeyEvent(event); } - if ((scrollYDelta | scrollXDelta) != 0) { - return pinScrollBy(scrollXDelta, scrollYDelta, !immediate, 0); + public boolean super_onGenericMotionEvent(MotionEvent event) { + return WebView.super.onGenericMotionEvent(event); } - return false; - } - - /* package */ void replaceTextfieldText(int oldStart, int oldEnd, - String replace, int newStart, int newEnd) { - WebViewCore.ReplaceTextData arg = new WebViewCore.ReplaceTextData(); - arg.mReplace = replace; - arg.mNewStart = newStart; - arg.mNewEnd = newEnd; - mTextGeneration++; - arg.mTextGeneration = mTextGeneration; - mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg); - } - - /* package */ void passToJavaScript(String currentText, KeyEvent event) { - // check if mWebViewCore has been destroyed - if (mWebViewCore == null) { - return; + public boolean super_requestFocus(int direction, Rect previouslyFocusedRect) { + return WebView.super.requestFocus(direction, previouslyFocusedRect); } - WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData(); - arg.mEvent = event; - arg.mCurrentText = currentText; - // Increase our text generation number, and pass it to webcore thread - mTextGeneration++; - mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg); - // WebKit's document state is not saved until about to leave the page. - // To make sure the host application, like Browser, has the up to date - // document state when it goes to background, we force to save the - // document state. - mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE); - mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE, - cursorData(), 1000); - } - - /** - * @hide - */ - public synchronized WebViewCore getWebViewCore() { - return mWebViewCore; - } - /** - * Used only by TouchEventQueue to store pending touch events. - */ - private static class QueuedTouch { - long mSequence; - MotionEvent mEvent; // Optional - TouchEventData mTed; // Optional - - QueuedTouch mNext; - - public QueuedTouch set(TouchEventData ted) { - mSequence = ted.mSequence; - mTed = ted; - mEvent = null; - mNext = null; - return this; + public void super_setLayoutParams(ViewGroup.LayoutParams params) { + WebView.super.setLayoutParams(params); } - public QueuedTouch set(MotionEvent ev, long sequence) { - mEvent = MotionEvent.obtain(ev); - mSequence = sequence; - mTed = null; - mNext = null; - return this; + // ---- Access to non-public methods ---- + public void overScrollBy(int deltaX, int deltaY, + int scrollX, int scrollY, + int scrollRangeX, int scrollRangeY, + int maxOverScrollX, int maxOverScrollY, + boolean isTouchEvent) { + WebView.this.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, + maxOverScrollX, maxOverScrollY, isTouchEvent); } - public QueuedTouch add(QueuedTouch other) { - if (other.mSequence < mSequence) { - other.mNext = this; - return other; - } - - QueuedTouch insertAt = this; - while (insertAt.mNext != null && insertAt.mNext.mSequence < other.mSequence) { - insertAt = insertAt.mNext; - } - other.mNext = insertAt.mNext; - insertAt.mNext = other; - return this; + public void awakenScrollBars(int duration) { + WebView.this.awakenScrollBars(duration); } - } - /** - * WebView handles touch events asynchronously since some events must be passed to WebKit - * for potentially slower processing. TouchEventQueue serializes touch events regardless - * of which path they take to ensure that no events are ever processed out of order - * by WebView. - */ - private class TouchEventQueue { - private long mNextTouchSequence = Long.MIN_VALUE + 1; - private long mLastHandledTouchSequence = Long.MIN_VALUE; - private long mIgnoreUntilSequence = Long.MIN_VALUE + 1; - - // Events waiting to be processed. - private QueuedTouch mTouchEventQueue; - - // Known events that are waiting on a response before being enqueued. - private QueuedTouch mPreQueue; - - // Pool of QueuedTouch objects saved for later use. - private QueuedTouch mQueuedTouchRecycleBin; - private int mQueuedTouchRecycleCount; - - private long mLastEventTime = Long.MAX_VALUE; - private static final int MAX_RECYCLED_QUEUED_TOUCH = 15; - - // milliseconds until we abandon hope of getting all of a previous gesture - private static final int QUEUED_GESTURE_TIMEOUT = 1000; - - private QueuedTouch obtainQueuedTouch() { - if (mQueuedTouchRecycleBin != null) { - QueuedTouch result = mQueuedTouchRecycleBin; - mQueuedTouchRecycleBin = result.mNext; - mQueuedTouchRecycleCount--; - return result; - } - return new QueuedTouch(); + public void awakenScrollBars(int duration, boolean invalidate) { + WebView.this.awakenScrollBars(duration, invalidate); } - /** - * Allow events with any currently missing sequence numbers to be skipped in processing. - */ - public void ignoreCurrentlyMissingEvents() { - mIgnoreUntilSequence = mNextTouchSequence; - - // Run any events we have available and complete, pre-queued or otherwise. - runQueuedAndPreQueuedEvents(); + public float getVerticalScrollFactor() { + return WebView.this.getVerticalScrollFactor(); } - private void runQueuedAndPreQueuedEvents() { - QueuedTouch qd = mPreQueue; - boolean fromPreQueue = true; - while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) { - handleQueuedTouch(qd); - QueuedTouch recycleMe = qd; - if (fromPreQueue) { - mPreQueue = qd.mNext; - } else { - mTouchEventQueue = qd.mNext; - } - recycleQueuedTouch(recycleMe); - mLastHandledTouchSequence++; - - long nextPre = mPreQueue != null ? mPreQueue.mSequence : Long.MAX_VALUE; - long nextQueued = mTouchEventQueue != null ? - mTouchEventQueue.mSequence : Long.MAX_VALUE; - fromPreQueue = nextPre < nextQueued; - qd = fromPreQueue ? mPreQueue : mTouchEventQueue; - } + public float getHorizontalScrollFactor() { + return WebView.this.getHorizontalScrollFactor(); } - /** - * Add a TouchEventData to the pre-queue. - * - * An event in the pre-queue is an event that we know about that - * has been sent to webkit, but that we haven't received back and - * enqueued into the normal touch queue yet. If webkit ever times - * out and we need to ignore currently missing events, we'll run - * events from the pre-queue to patch the holes. - * - * @param ted TouchEventData to pre-queue - */ - public void preQueueTouchEventData(TouchEventData ted) { - QueuedTouch newTouch = obtainQueuedTouch().set(ted); - if (mPreQueue == null) { - mPreQueue = newTouch; - } else { - QueuedTouch insertionPoint = mPreQueue; - while (insertionPoint.mNext != null && - insertionPoint.mNext.mSequence < newTouch.mSequence) { - insertionPoint = insertionPoint.mNext; - } - newTouch.mNext = insertionPoint.mNext; - insertionPoint.mNext = newTouch; - } + public void setMeasuredDimension(int measuredWidth, int measuredHeight) { + WebView.this.setMeasuredDimension(measuredWidth, measuredHeight); } - private void recycleQueuedTouch(QueuedTouch qd) { - if (mQueuedTouchRecycleCount < MAX_RECYCLED_QUEUED_TOUCH) { - qd.mNext = mQueuedTouchRecycleBin; - mQueuedTouchRecycleBin = qd; - mQueuedTouchRecycleCount++; - } + public void onScrollChanged(int l, int t, int oldl, int oldt) { + WebView.this.onScrollChanged(l, t, oldl, oldt); } - /** - * Reset the touch event queue. This will dump any pending events - * and reset the sequence numbering. - */ - public void reset() { - mNextTouchSequence = Long.MIN_VALUE + 1; - mLastHandledTouchSequence = Long.MIN_VALUE; - mIgnoreUntilSequence = Long.MIN_VALUE + 1; - while (mTouchEventQueue != null) { - QueuedTouch recycleMe = mTouchEventQueue; - mTouchEventQueue = mTouchEventQueue.mNext; - recycleQueuedTouch(recycleMe); - } - while (mPreQueue != null) { - QueuedTouch recycleMe = mPreQueue; - mPreQueue = mPreQueue.mNext; - recycleQueuedTouch(recycleMe); - } + public int getHorizontalScrollbarHeight() { + return WebView.this.getHorizontalScrollbarHeight(); } - /** - * Return the next valid sequence number for tagging incoming touch events. - * @return The next touch event sequence number - */ - public long nextTouchSequence() { - return mNextTouchSequence++; + // ---- Access to (non-public) fields ---- + /** Raw setter for the scroll X value, without invoking onScrollChanged handlers etc. */ + public void setScrollXRaw(int scrollX) { + WebView.this.mScrollX = scrollX; } - /** - * Enqueue a touch event in the form of TouchEventData. - * The sequence number will be read from the mSequence field of the argument. - * - * If the touch event's sequence number is the next in line to be processed, it will - * be handled before this method returns. Any subsequent events that have already - * been queued will also be processed in their proper order. - * - * @param ted Touch data to be processed in order. - * @return true if the event was processed before returning, false if it was just enqueued. - */ - public boolean enqueueTouchEvent(TouchEventData ted) { - // Remove from the pre-queue if present - QueuedTouch preQueue = mPreQueue; - if (preQueue != null) { - // On exiting this block, preQueue is set to the pre-queued QueuedTouch object - // if it was present in the pre-queue, and removed from the pre-queue itself. - if (preQueue.mSequence == ted.mSequence) { - mPreQueue = preQueue.mNext; - } else { - QueuedTouch prev = preQueue; - preQueue = null; - while (prev.mNext != null) { - if (prev.mNext.mSequence == ted.mSequence) { - preQueue = prev.mNext; - prev.mNext = preQueue.mNext; - break; - } else { - prev = prev.mNext; - } - } - } - } - - if (ted.mSequence < mLastHandledTouchSequence) { - // Stale event and we already moved on; drop it. (Should not be common.) - Log.w(LOGTAG, "Stale touch event " + MotionEvent.actionToString(ted.mAction) + - " received from webcore; ignoring"); - return false; - } - - if (dropStaleGestures(ted.mMotionEvent, ted.mSequence)) { - return false; - } - - // dropStaleGestures above might have fast-forwarded us to - // an event we have already. - runNextQueuedEvents(); - - if (mLastHandledTouchSequence + 1 == ted.mSequence) { - if (preQueue != null) { - recycleQueuedTouch(preQueue); - preQueue = null; - } - handleQueuedTouchEventData(ted); - - mLastHandledTouchSequence++; - - // Do we have any more? Run them if so. - runNextQueuedEvents(); - } else { - // Reuse the pre-queued object if we had it. - QueuedTouch qd = preQueue != null ? preQueue : obtainQueuedTouch().set(ted); - mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd); - } - return true; + /** Raw setter for the scroll Y value, without invoking onScrollChanged handlers etc. */ + public void setScrollYRaw(int scrollY) { + WebView.this.mScrollY = scrollY; } - /** - * Enqueue a touch event in the form of a MotionEvent from the framework. - * - * If the touch event's sequence number is the next in line to be processed, it will - * be handled before this method returns. Any subsequent events that have already - * been queued will also be processed in their proper order. - * - * @param ev MotionEvent to be processed in order - */ - public void enqueueTouchEvent(MotionEvent ev) { - final long sequence = nextTouchSequence(); - - if (dropStaleGestures(ev, sequence)) { - return; - } - - // dropStaleGestures above might have fast-forwarded us to - // an event we have already. - runNextQueuedEvents(); + } - if (mLastHandledTouchSequence + 1 == sequence) { - handleQueuedMotionEvent(ev); + //------------------------------------------------------------------------- + // Private internal stuff + //------------------------------------------------------------------------- - mLastHandledTouchSequence++; + // Cache the factory both for efficiency, and ensure any one process gets all webviews from the + // same provider. + private static WebViewFactoryProvider sProviderFactory; - // Do we have any more? Run them if so. - runNextQueuedEvents(); - } else { - QueuedTouch qd = obtainQueuedTouch().set(ev, sequence); - mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd); - } - } + private WebViewProvider mProvider; - private void runNextQueuedEvents() { - QueuedTouch qd = mTouchEventQueue; - while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) { - handleQueuedTouch(qd); - QueuedTouch recycleMe = qd; - qd = qd.mNext; - recycleQueuedTouch(recycleMe); - mLastHandledTouchSequence++; - } - mTouchEventQueue = qd; + private void ensureProviderCreated() { + checkThread(); + if (mProvider == null) { + if (DEBUG) Log.v(LOGTAG, "instantiating webview provider instance"); + // As this can get called during the base class constructor chain, pass the minimum + // number of dependencies here; the rest are deferred to init(). + mProvider = getFactory().createWebView(this, new PrivateAccess()); } + } - private boolean dropStaleGestures(MotionEvent ev, long sequence) { - if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && !mConfirmMove) { - // This is to make sure that we don't attempt to process a tap - // or long press when webkit takes too long to get back to us. - // The movement will be properly confirmed when we process the - // enqueued event later. - final int dx = Math.round(ev.getX()) - mLastTouchX; - final int dy = Math.round(ev.getY()) - mLastTouchY; - if (dx * dx + dy * dy > mTouchSlopSquare) { - mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); - mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - } - } - - if (mTouchEventQueue == null) { - return sequence <= mLastHandledTouchSequence; - } - - // If we have a new down event and it's been a while since the last event - // we saw, catch up as best we can and keep going. - if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) { - long eventTime = ev.getEventTime(); - long lastHandledEventTime = mLastEventTime; - if (eventTime > lastHandledEventTime + QUEUED_GESTURE_TIMEOUT) { - Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " + - "Catching up."); - runQueuedAndPreQueuedEvents(); - - // Drop leftovers that we truly don't have. - QueuedTouch qd = mTouchEventQueue; - while (qd != null && qd.mSequence < sequence) { - QueuedTouch recycleMe = qd; - qd = qd.mNext; - recycleQueuedTouch(recycleMe); - } - mTouchEventQueue = qd; - mLastHandledTouchSequence = sequence - 1; - } - } - - if (mIgnoreUntilSequence - 1 > mLastHandledTouchSequence) { - QueuedTouch qd = mTouchEventQueue; - while (qd != null && qd.mSequence < mIgnoreUntilSequence) { - QueuedTouch recycleMe = qd; - qd = qd.mNext; - recycleQueuedTouch(recycleMe); - } - mTouchEventQueue = qd; - mLastHandledTouchSequence = mIgnoreUntilSequence - 1; - } - - if (mPreQueue != null) { - // Drop stale prequeued events - QueuedTouch qd = mPreQueue; - while (qd != null && qd.mSequence < mIgnoreUntilSequence) { - QueuedTouch recycleMe = qd; - qd = qd.mNext; - recycleQueuedTouch(recycleMe); - } - mPreQueue = qd; - } - - return sequence <= mLastHandledTouchSequence; - } + private static synchronized WebViewFactoryProvider getFactory() { + // For now the main purpose of this function (and the factory abstration) is to keep + // us honest and minimize usage of WebViewClassic internals when binding the proxy. + checkThread(); + if (sProviderFactory != null) return sProviderFactory; - private void handleQueuedTouch(QueuedTouch qt) { - if (qt.mTed != null) { - handleQueuedTouchEventData(qt.mTed); - } else { - handleQueuedMotionEvent(qt.mEvent); - qt.mEvent.recycle(); - } + sProviderFactory = getFactoryByName(DEFAULT_WEB_VIEW_FACTORY); + if (sProviderFactory == null) { + if (DEBUG) Log.v (LOGTAG, "Falling back to explicit linkage"); + sProviderFactory = new WebViewClassic.Factory(); } + return sProviderFactory; + } - private void handleQueuedMotionEvent(MotionEvent ev) { - mLastEventTime = ev.getEventTime(); - int action = ev.getActionMasked(); - if (ev.getPointerCount() > 1) { // Multi-touch - handleMultiTouchInWebView(ev); - } else { - final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector(); - if (detector != null && mPreventDefault != PREVENT_DEFAULT_YES) { - // ScaleGestureDetector needs a consistent event stream to operate properly. - // It won't take any action with fewer than two pointers, but it needs to - // update internal bookkeeping state. - detector.onTouchEvent(ev); - } - - handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY())); - } + private static WebViewFactoryProvider getFactoryByName(String providerName) { + try { + if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName); + Class<?> c = Class.forName(providerName); + if (DEBUG) Log.v(LOGTAG, "instantiating factory"); + return (WebViewFactoryProvider) c.newInstance(); + } catch (ClassNotFoundException e) { + Log.e(LOGTAG, "error loading " + providerName, e); + } catch (IllegalAccessException e) { + Log.e(LOGTAG, "error loading " + providerName, e); + } catch (InstantiationException e) { + Log.e(LOGTAG, "error loading " + providerName, e); } + return null; + } - private void handleQueuedTouchEventData(TouchEventData ted) { - if (ted.mMotionEvent != null) { - mLastEventTime = ted.mMotionEvent.getEventTime(); - } - if (!ted.mReprocess) { - if (ted.mAction == MotionEvent.ACTION_DOWN - && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) { - // if prevent default is called from WebCore, UI - // will not handle the rest of the touch events any - // more. - mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES - : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN; - } else if (ted.mAction == MotionEvent.ACTION_MOVE - && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) { - // the return for the first ACTION_MOVE will decide - // whether UI will handle touch or not. Currently no - // support for alternating prevent default - mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES - : PREVENT_DEFAULT_NO; - } - if (mPreventDefault == PREVENT_DEFAULT_YES) { - mTouchHighlightRegion.setEmpty(); - } - } else { - if (ted.mPoints.length > 1) { // multi-touch - if (!ted.mNativeResult && mPreventDefault != PREVENT_DEFAULT_YES) { - mPreventDefault = PREVENT_DEFAULT_NO; - handleMultiTouchInWebView(ted.mMotionEvent); - } else { - mPreventDefault = PREVENT_DEFAULT_YES; - } - return; - } - - // prevent default is not called in WebCore, so the - // message needs to be reprocessed in UI - if (!ted.mNativeResult) { - // Following is for single touch. - switch (ted.mAction) { - case MotionEvent.ACTION_DOWN: - mLastDeferTouchX = ted.mPointsInView[0].x; - mLastDeferTouchY = ted.mPointsInView[0].y; - mDeferTouchMode = TOUCH_INIT_MODE; - break; - case MotionEvent.ACTION_MOVE: { - // no snapping in defer process - int x = ted.mPointsInView[0].x; - int y = ted.mPointsInView[0].y; - - if (mDeferTouchMode != TOUCH_DRAG_MODE) { - mDeferTouchMode = TOUCH_DRAG_MODE; - mLastDeferTouchX = x; - mLastDeferTouchY = y; - startScrollingLayer(x, y); - startDrag(); - } - int deltaX = pinLocX((int) (mScrollX - + mLastDeferTouchX - x)) - - mScrollX; - int deltaY = pinLocY((int) (mScrollY - + mLastDeferTouchY - y)) - - mScrollY; - doDrag(deltaX, deltaY); - if (deltaX != 0) mLastDeferTouchX = x; - if (deltaY != 0) mLastDeferTouchY = y; - break; - } - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - if (mDeferTouchMode == TOUCH_DRAG_MODE) { - // no fling in defer process - mScroller.springBack(mScrollX, mScrollY, 0, - computeMaxScrollX(), 0, - computeMaxScrollY()); - invalidate(); - WebViewCore.resumePriority(); - WebViewCore.resumeUpdatePicture(mWebViewCore); - } - mDeferTouchMode = TOUCH_DONE_MODE; - break; - case WebViewCore.ACTION_DOUBLETAP: - // doDoubleTap() needs mLastTouchX/Y as anchor - mLastDeferTouchX = ted.mPointsInView[0].x; - mLastDeferTouchY = ted.mPointsInView[0].y; - mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY); - mDeferTouchMode = TOUCH_DONE_MODE; - break; - case WebViewCore.ACTION_LONGPRESS: - HitTestResult hitTest = getHitTestResult(); - if (hitTest != null && hitTest.mType - != HitTestResult.UNKNOWN_TYPE) { - performLongClick(); - } - mDeferTouchMode = TOUCH_DONE_MODE; - break; - } - } - } + private static void checkThread() { + if (Looper.myLooper() != Looper.getMainLooper()) { + Throwable throwable = new Throwable( + "Warning: A WebView method was called on thread '" + + Thread.currentThread().getName() + "'. " + + "All WebView methods must be called on the UI thread. " + + "Future versions of WebView may not support use on other threads."); + Log.w(LOGTAG, Log.getStackTraceString(throwable)); + StrictMode.onWebViewMethodCalledOnWrongThread(throwable); } } //------------------------------------------------------------------------- - // Methods can be called from a separate thread, like WebViewCore - // If it needs to call the View system, it has to send message. + // Override View methods //------------------------------------------------------------------------- - /** - * General handler to receive message coming from webkit thread - */ - class PrivateHandler extends Handler { - @Override - public void handleMessage(Message msg) { - // exclude INVAL_RECT_MSG_ID since it is frequently output - if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) { - if (msg.what >= FIRST_PRIVATE_MSG_ID - && msg.what <= LAST_PRIVATE_MSG_ID) { - Log.v(LOGTAG, HandlerPrivateDebugString[msg.what - - FIRST_PRIVATE_MSG_ID]); - } else if (msg.what >= FIRST_PACKAGE_MSG_ID - && msg.what <= LAST_PACKAGE_MSG_ID) { - Log.v(LOGTAG, HandlerPackageDebugString[msg.what - - FIRST_PACKAGE_MSG_ID]); - } else { - Log.v(LOGTAG, Integer.toString(msg.what)); - } - } - if (mWebViewCore == null) { - // after WebView's destroy() is called, skip handling messages. - return; - } - if (mBlockWebkitViewMessages - && msg.what != WEBCORE_INITIALIZED_MSG_ID) { - // Blocking messages from webkit - return; - } - switch (msg.what) { - case REMEMBER_PASSWORD: { - mDatabase.setUsernamePassword( - msg.getData().getString("host"), - msg.getData().getString("username"), - msg.getData().getString("password")); - ((Message) msg.obj).sendToTarget(); - break; - } - case NEVER_REMEMBER_PASSWORD: { - mDatabase.setUsernamePassword( - msg.getData().getString("host"), null, null); - ((Message) msg.obj).sendToTarget(); - break; - } - case PREVENT_DEFAULT_TIMEOUT: { - // if timeout happens, cancel it so that it won't block UI - // to continue handling touch events - if ((msg.arg1 == MotionEvent.ACTION_DOWN - && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) - || (msg.arg1 == MotionEvent.ACTION_MOVE - && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN)) { - cancelWebCoreTouchEvent( - viewToContentX(mLastTouchX + mScrollX), - viewToContentY(mLastTouchY + mScrollY), - true); - } - break; - } - case SCROLL_SELECT_TEXT: { - if (mAutoScrollX == 0 && mAutoScrollY == 0) { - mSentAutoScrollMessage = false; - break; - } - if (mCurrentScrollingLayerId == 0) { - pinScrollBy(mAutoScrollX, mAutoScrollY, true, 0); - } else { - scrollLayerTo(mScrollingLayerRect.left + mAutoScrollX, - mScrollingLayerRect.top + mAutoScrollY); - } - sendEmptyMessageDelayed( - SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL); - break; - } - case UPDATE_SELECTION: { - if (mTouchMode == TOUCH_INIT_MODE - || mTouchMode == TOUCH_SHORTPRESS_MODE - || mTouchMode == TOUCH_SHORTPRESS_START_MODE) { - updateSelection(); - } - break; - } - case SWITCH_TO_SHORTPRESS: { - if (mTouchMode == TOUCH_INIT_MODE) { - if (!sDisableNavcache - && mPreventDefault != PREVENT_DEFAULT_YES) { - mTouchMode = TOUCH_SHORTPRESS_START_MODE; - updateSelection(); - } else { - // set to TOUCH_SHORTPRESS_MODE so that it won't - // trigger double tap any more - mTouchMode = TOUCH_SHORTPRESS_MODE; - } - } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) { - mTouchMode = TOUCH_DONE_MODE; - } - break; - } - case SWITCH_TO_LONGPRESS: { - if (sDisableNavcache) { - removeTouchHighlight(); - } - if (inFullScreenMode() || mDeferTouchProcess) { - TouchEventData ted = new TouchEventData(); - ted.mAction = WebViewCore.ACTION_LONGPRESS; - ted.mIds = new int[1]; - ted.mIds[0] = 0; - ted.mPoints = new Point[1]; - ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX), - viewToContentY(mLastTouchY + mScrollY)); - ted.mPointsInView = new Point[1]; - ted.mPointsInView[0] = new Point(mLastTouchX, mLastTouchY); - // metaState for long press is tricky. Should it be the - // state when the press started or when the press was - // released? Or some intermediary key state? For - // simplicity for now, we don't set it. - ted.mMetaState = 0; - ted.mReprocess = mDeferTouchProcess; - ted.mNativeLayer = nativeScrollableLayer( - ted.mPoints[0].x, ted.mPoints[0].y, - ted.mNativeLayerRect, null); - ted.mSequence = mTouchEventQueue.nextTouchSequence(); - mTouchEventQueue.preQueueTouchEventData(ted); - mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - } else if (mPreventDefault != PREVENT_DEFAULT_YES) { - mTouchMode = TOUCH_DONE_MODE; - performLongClick(); - } - break; - } - case RELEASE_SINGLE_TAP: { - doShortPress(); - break; - } - case SCROLL_TO_MSG_ID: { - // arg1 = animate, arg2 = onlyIfImeIsShowing - // obj = Point(x, y) - if (msg.arg2 == 1) { - // This scroll is intended to bring the textfield into - // view, but is only necessary if the IME is showing - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm == null || !imm.isAcceptingText() - || (!imm.isActive(WebView.this) && (!inEditingMode() - || !imm.isActive(mWebTextView)))) { - break; - } - } - final Point p = (Point) msg.obj; - if (msg.arg1 == 1) { - spawnContentScrollTo(p.x, p.y); - } else { - setContentScrollTo(p.x, p.y); - } - break; - } - case UPDATE_ZOOM_RANGE: { - WebViewCore.ViewState viewState = (WebViewCore.ViewState) msg.obj; - // mScrollX contains the new minPrefWidth - mZoomManager.updateZoomRange(viewState, getViewWidth(), viewState.mScrollX); - break; - } - case UPDATE_ZOOM_DENSITY: { - final float density = (Float) msg.obj; - mZoomManager.updateDefaultZoomDensity(density); - break; - } - case REPLACE_BASE_CONTENT: { - nativeReplaceBaseContent(msg.arg1); - break; - } - case NEW_PICTURE_MSG_ID: { - // called for new content - final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj; - setNewPicture(draw, true); - break; - } - case WEBCORE_INITIALIZED_MSG_ID: - // nativeCreate sets mNativeClass to a non-zero value - String drawableDir = BrowserFrame.getRawResFilename( - BrowserFrame.DRAWABLEDIR, mContext); - WindowManager windowManager = - (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - Display display = windowManager.getDefaultDisplay(); - nativeCreate(msg.arg1, drawableDir, - ActivityManager.isHighEndGfx(display)); - if (mDelaySetPicture != null) { - setNewPicture(mDelaySetPicture, true); - mDelaySetPicture = null; - } - if (mIsPaused) { - nativeSetPauseDrawing(mNativeClass, true); - } - break; - case UPDATE_TEXTFIELD_TEXT_MSG_ID: - // Make sure that the textfield is currently focused - // and representing the same node as the pointer. - if (msg.arg2 == mTextGeneration) { - String text = (String) msg.obj; - if (null == text) { - text = ""; - } - if (inEditingMode() && - mWebTextView.isSameTextField(msg.arg1)) { - mWebTextView.setTextAndKeepSelection(text); - } else if (mInputConnection != null && - mFieldPointer == msg.arg1) { - mInputConnection.setTextAndKeepSelection(text); - } - } - break; - case REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID: - displaySoftKeyboard(true); - // fall through to UPDATE_TEXT_SELECTION_MSG_ID - case UPDATE_TEXT_SELECTION_MSG_ID: - updateTextSelectionFromMessage(msg.arg1, msg.arg2, - (WebViewCore.TextSelectionData) msg.obj); - break; - case FORM_DID_BLUR: - if (inEditingMode() - && mWebTextView.isSameTextField(msg.arg1)) { - hideSoftKeyboard(); - } - break; - case RETURN_LABEL: - if (inEditingMode() - && mWebTextView.isSameTextField(msg.arg1)) { - mWebTextView.setHint((String) msg.obj); - InputMethodManager imm - = InputMethodManager.peekInstance(); - // The hint is propagated to the IME in - // onCreateInputConnection. If the IME is already - // active, restart it so that its hint text is updated. - if (imm != null && imm.isActive(mWebTextView)) { - imm.restartInput(mWebTextView); - } - } - break; - case UNHANDLED_NAV_KEY: - navHandledKey(msg.arg1, 1, false, 0); - break; - case UPDATE_TEXT_ENTRY_MSG_ID: - // this is sent after finishing resize in WebViewCore. Make - // sure the text edit box is still on the screen. - if (inEditingMode() && nativeCursorIsTextInput()) { - updateWebTextViewPosition(); - } - break; - case CLEAR_TEXT_ENTRY: - clearTextEntry(); - break; - case INVAL_RECT_MSG_ID: { - Rect r = (Rect)msg.obj; - if (r == null) { - invalidate(); - } else { - // we need to scale r from content into view coords, - // which viewInvalidate() does for us - viewInvalidate(r.left, r.top, r.right, r.bottom); - } - break; - } - case REQUEST_FORM_DATA: - AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj; - if (mWebTextView.isSameTextField(msg.arg1)) { - mWebTextView.setAdapterCustom(adapter); - } - break; - - case LONG_PRESS_CENTER: - // as this is shared by keydown and trackballdown, reset all - // the states - mGotCenterDown = false; - mTrackballDown = false; - performLongClick(); - break; - - case WEBCORE_NEED_TOUCH_EVENTS: - mForwardTouchEvents = (msg.arg1 != 0); - break; - - case PREVENT_TOUCH_ID: - if (inFullScreenMode()) { - break; - } - TouchEventData ted = (TouchEventData) msg.obj; - - if (mTouchEventQueue.enqueueTouchEvent(ted)) { - // WebCore is responding to us; remove pending timeout. - // It will be re-posted when needed. - removeMessages(PREVENT_DEFAULT_TIMEOUT); - } - break; - - case REQUEST_KEYBOARD: - if (msg.arg1 == 0) { - hideSoftKeyboard(); - } else { - displaySoftKeyboard(false); - } - break; - - case DRAG_HELD_MOTIONLESS: - mHeldMotionless = MOTIONLESS_TRUE; - invalidate(); - // fall through to keep scrollbars awake - - case AWAKEN_SCROLL_BARS: - if (mTouchMode == TOUCH_DRAG_MODE - && mHeldMotionless == MOTIONLESS_TRUE) { - awakenScrollBars(ViewConfiguration - .getScrollDefaultDelay(), false); - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(AWAKEN_SCROLL_BARS), - ViewConfiguration.getScrollDefaultDelay()); - } - break; - - case DO_MOTION_UP: - doMotionUp(msg.arg1, msg.arg2); - break; - - case SCREEN_ON: - setKeepScreenOn(msg.arg1 == 1); - break; - - case ENTER_FULLSCREEN_VIDEO: - int layerId = msg.arg1; - - String url = (String) msg.obj; - if (mHTML5VideoViewProxy != null) { - mHTML5VideoViewProxy.enterFullScreenVideo(layerId, url); - } - break; - - case EXIT_FULLSCREEN_VIDEO: - if (mHTML5VideoViewProxy != null) { - mHTML5VideoViewProxy.exitFullScreenVideo(); - } - break; - - case SHOW_FULLSCREEN: { - View view = (View) msg.obj; - int orientation = msg.arg1; - int npp = msg.arg2; - - if (inFullScreenMode()) { - Log.w(LOGTAG, "Should not have another full screen."); - dismissFullScreenMode(); - } - mFullScreenHolder = new PluginFullScreenHolder(WebView.this, orientation, npp); - mFullScreenHolder.setContentView(view); - mFullScreenHolder.show(); - invalidate(); - - break; - } - case HIDE_FULLSCREEN: - dismissFullScreenMode(); - break; - - case DOM_FOCUS_CHANGED: - if (inEditingMode()) { - nativeClearCursor(); - rebuildWebTextView(); - } - break; - - case SHOW_RECT_MSG_ID: { - WebViewCore.ShowRectData data = (WebViewCore.ShowRectData) msg.obj; - int x = mScrollX; - int left = contentToViewX(data.mLeft); - int width = contentToViewDimension(data.mWidth); - int maxWidth = contentToViewDimension(data.mContentWidth); - int viewWidth = getViewWidth(); - if (width < viewWidth) { - // center align - x += left + width / 2 - mScrollX - viewWidth / 2; - } else { - x += (int) (left + data.mXPercentInDoc * width - - mScrollX - data.mXPercentInView * viewWidth); - } - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "showRectMsg=(left=" + left + ",width=" + - width + ",maxWidth=" + maxWidth + - ",viewWidth=" + viewWidth + ",x=" - + x + ",xPercentInDoc=" + data.mXPercentInDoc + - ",xPercentInView=" + data.mXPercentInView+ ")"); - } - // use the passing content width to cap x as the current - // mContentWidth may not be updated yet - x = Math.max(0, - (Math.min(maxWidth, x + viewWidth)) - viewWidth); - int top = contentToViewY(data.mTop); - int height = contentToViewDimension(data.mHeight); - int maxHeight = contentToViewDimension(data.mContentHeight); - int viewHeight = getViewHeight(); - int y = (int) (top + data.mYPercentInDoc * height - - data.mYPercentInView * viewHeight); - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "showRectMsg=(top=" + top + ",height=" + - height + ",maxHeight=" + maxHeight + - ",viewHeight=" + viewHeight + ",y=" - + y + ",yPercentInDoc=" + data.mYPercentInDoc + - ",yPercentInView=" + data.mYPercentInView+ ")"); - } - // use the passing content height to cap y as the current - // mContentHeight may not be updated yet - y = Math.max(0, - (Math.min(maxHeight, y + viewHeight) - viewHeight)); - // We need to take into account the visible title height - // when scrolling since y is an absolute view position. - y = Math.max(0, y - getVisibleTitleHeightImpl()); - scrollTo(x, y); - } - break; - - case CENTER_FIT_RECT: - centerFitRect((Rect)msg.obj); - break; - - case SET_SCROLLBAR_MODES: - mHorizontalScrollBarMode = msg.arg1; - mVerticalScrollBarMode = msg.arg2; - break; - - case SELECTION_STRING_CHANGED: - if (mAccessibilityInjector != null) { - String selectionString = (String) msg.obj; - mAccessibilityInjector.onSelectionStringChange(selectionString); - } - break; - - case HIT_TEST_RESULT: - WebKitHitTest hit = (WebKitHitTest) msg.obj; - mFocusedNode = hit; - setTouchHighlightRects(hit); - setHitTestResult(hit); - break; - - case SAVE_WEBARCHIVE_FINISHED: - SaveWebArchiveMessage saveMessage = (SaveWebArchiveMessage)msg.obj; - if (saveMessage.mCallback != null) { - saveMessage.mCallback.onReceiveValue(saveMessage.mResultFile); - } - break; - - case SET_AUTOFILLABLE: - mAutoFillData = (WebViewCore.AutoFillData) msg.obj; - if (mWebTextView != null) { - mWebTextView.setAutoFillable(mAutoFillData.getQueryId()); - rebuildWebTextView(); - } - break; - - case AUTOFILL_COMPLETE: - if (mWebTextView != null) { - // Clear the WebTextView adapter when AutoFill finishes - // so that the drop down gets cleared. - mWebTextView.setAdapterCustom(null); - } - break; - - case SELECT_AT: - nativeSelectAt(msg.arg1, msg.arg2); - break; - - case COPY_TO_CLIPBOARD: - copyToClipboard((String) msg.obj); - break; - - case INIT_EDIT_FIELD: - if (mInputConnection != null) { - TextFieldInitData initData = (TextFieldInitData) msg.obj; - mTextGeneration = 0; - mFieldPointer = initData.mFieldPointer; - mInputConnection.initEditorInfo(initData); - mInputConnection.setTextAndKeepSelection(initData.mText); - } - break; - - case REPLACE_TEXT:{ - String text = (String)msg.obj; - int start = msg.arg1; - int end = msg.arg2; - int cursorPosition = start + text.length(); - replaceTextfieldText(start, end, text, - cursorPosition, cursorPosition); - break; - } - - case UPDATE_MATCH_COUNT: { - if (mFindCallback != null) { - mFindCallback.updateMatchCount(msg.arg1, msg.arg2, - (String) msg.obj); - } - break; - } - case CLEAR_CARET_HANDLE: - selectionDone(); - break; - - case KEY_PRESS: - mWebViewCore.sendMessage(EventHub.KEY_PRESS, msg.arg1); - break; - - default: - super.handleMessage(msg); - break; - } - } - } + // TODO: Add a test that enumerates all methods in ViewDelegte & ScrollDelegate, and ensures + // there's a corresponding override (or better, caller) for each of them in here. - private void setHitTestTypeFromUrl(String url) { - String substr = null; - if (url.startsWith(SCHEME_GEO)) { - mInitialHitTestResult.mType = HitTestResult.GEO_TYPE; - substr = url.substring(SCHEME_GEO.length()); - } else if (url.startsWith(SCHEME_TEL)) { - mInitialHitTestResult.mType = HitTestResult.PHONE_TYPE; - substr = url.substring(SCHEME_TEL.length()); - } else if (url.startsWith(SCHEME_MAILTO)) { - mInitialHitTestResult.mType = HitTestResult.EMAIL_TYPE; - substr = url.substring(SCHEME_MAILTO.length()); - } else { - mInitialHitTestResult.mType = HitTestResult.SRC_ANCHOR_TYPE; - mInitialHitTestResult.mExtra = url; - return; - } - try { - mInitialHitTestResult.mExtra = URLDecoder.decode(substr, "UTF-8"); - } catch (Throwable e) { - Log.w(LOGTAG, "Failed to decode URL! " + substr, e); - mInitialHitTestResult.mType = HitTestResult.UNKNOWN_TYPE; - } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mProvider.getViewDelegate().onAttachedToWindow(); } - private void setHitTestResult(WebKitHitTest hit) { - if (hit == null) { - mInitialHitTestResult = null; - return; - } - mInitialHitTestResult = new HitTestResult(); - if (hit.mLinkUrl != null) { - setHitTestTypeFromUrl(hit.mLinkUrl); - if (hit.mImageUrl != null - && mInitialHitTestResult.mType == HitTestResult.SRC_ANCHOR_TYPE) { - mInitialHitTestResult.mType = HitTestResult.SRC_IMAGE_ANCHOR_TYPE; - mInitialHitTestResult.mExtra = hit.mImageUrl; - } - } else if (hit.mImageUrl != null) { - mInitialHitTestResult.mType = HitTestResult.IMAGE_TYPE; - mInitialHitTestResult.mExtra = hit.mImageUrl; - } else if (hit.mEditable) { - mInitialHitTestResult.mType = HitTestResult.EDIT_TEXT_TYPE; - } else if (hit.mIntentUrl != null) { - setHitTestTypeFromUrl(hit.mIntentUrl); - } + @Override + protected void onDetachedFromWindow() { + mProvider.getViewDelegate().onDetachedFromWindow(); + super.onDetachedFromWindow(); } - private boolean shouldDrawHighlightRect() { - if (mFocusedNode == null || mInitialHitTestResult == null) { - return false; - } - if (mTouchHighlightRegion.isEmpty()) { - return false; - } - if (mFocusedNode.mHasFocus && !isInTouchMode()) { - return !mFocusedNode.mEditable; - } - if (mInitialHitTestResult.mType == HitTestResult.UNKNOWN_TYPE) { - return false; - } - long delay = System.currentTimeMillis() - mTouchHighlightRequested; - if (delay < ViewConfiguration.getTapTimeout()) { - Rect r = mTouchHighlightRegion.getBounds(); - postInvalidateDelayed(delay, r.left, r.top, r.right, r.bottom); - return false; - } - return true; + @Override + public void setLayoutParams(ViewGroup.LayoutParams params) { + mProvider.getViewDelegate().setLayoutParams(params); } - - private FocusTransitionDrawable mFocusTransition = null; - static class FocusTransitionDrawable extends Drawable { - Region mPreviousRegion; - Region mNewRegion; - float mProgress = 0; - WebView mWebView; - Paint mPaint; - int mMaxAlpha; - Point mTranslate; - - public FocusTransitionDrawable(WebView view) { - mWebView = view; - mPaint = new Paint(mWebView.mTouchHightlightPaint); - mMaxAlpha = mPaint.getAlpha(); - } - - @Override - public void setColorFilter(ColorFilter cf) { - } - - @Override - public void setAlpha(int alpha) { - } - - @Override - public int getOpacity() { - return 0; - } - - public void setProgress(float p) { - mProgress = p; - if (mWebView.mFocusTransition == this) { - if (mProgress == 1f) - mWebView.mFocusTransition = null; - mWebView.invalidate(); - } - } - - public float getProgress() { - return mProgress; - } - - @Override - public void draw(Canvas canvas) { - if (mTranslate == null) { - Rect bounds = mPreviousRegion.getBounds(); - Point from = new Point(bounds.centerX(), bounds.centerY()); - mNewRegion.getBounds(bounds); - Point to = new Point(bounds.centerX(), bounds.centerY()); - mTranslate = new Point(from.x - to.x, from.y - to.y); - } - int alpha = (int) (mProgress * mMaxAlpha); - RegionIterator iter = new RegionIterator(mPreviousRegion); - Rect r = new Rect(); - mPaint.setAlpha(mMaxAlpha - alpha); - float tx = mTranslate.x * mProgress; - float ty = mTranslate.y * mProgress; - int save = canvas.save(Canvas.MATRIX_SAVE_FLAG); - canvas.translate(-tx, -ty); - while (iter.next(r)) { - canvas.drawRect(r, mPaint); - } - canvas.restoreToCount(save); - iter = new RegionIterator(mNewRegion); - r = new Rect(); - mPaint.setAlpha(alpha); - save = canvas.save(Canvas.MATRIX_SAVE_FLAG); - tx = mTranslate.x - tx; - ty = mTranslate.y - ty; - canvas.translate(tx, ty); - while (iter.next(r)) { - canvas.drawRect(r, mPaint); - } - canvas.restoreToCount(save); - } - }; - - private boolean shouldAnimateTo(WebKitHitTest hit) { - // TODO: Don't be annoying or throw out the animation entirely - return false; + @Override + public void setOverScrollMode(int mode) { + super.setOverScrollMode(mode); + // This method may called in the constructor chain, before the WebView provider is + // created. (Fortunately, this is the only method we override that can get called by + // any of the base class constructors). + ensureProviderCreated(); + mProvider.getViewDelegate().setOverScrollMode(mode); } - private void setTouchHighlightRects(WebKitHitTest hit) { - FocusTransitionDrawable transition = null; - if (shouldAnimateTo(hit)) { - transition = new FocusTransitionDrawable(this); - } - Rect[] rects = hit != null ? hit.mTouchRects : null; - if (!mTouchHighlightRegion.isEmpty()) { - invalidate(mTouchHighlightRegion.getBounds()); - if (transition != null) { - transition.mPreviousRegion = new Region(mTouchHighlightRegion); - } - mTouchHighlightRegion.setEmpty(); - } - if (rects != null) { - mTouchHightlightPaint.setColor(hit.mTapHighlightColor); - for (Rect rect : rects) { - Rect viewRect = contentToViewRect(rect); - // some sites, like stories in nytimes.com, set - // mouse event handler in the top div. It is not - // user friendly to highlight the div if it covers - // more than half of the screen. - if (viewRect.width() < getWidth() >> 1 - || viewRect.height() < getHeight() >> 1) { - mTouchHighlightRegion.union(viewRect); - } else { - Log.w(LOGTAG, "Skip the huge selection rect:" - + viewRect); - } - } - invalidate(mTouchHighlightRegion.getBounds()); - if (transition != null && transition.mPreviousRegion != null) { - transition.mNewRegion = new Region(mTouchHighlightRegion); - mFocusTransition = transition; - ObjectAnimator animator = ObjectAnimator.ofFloat( - mFocusTransition, "progress", 1f); - animator.start(); - } - } + @Override + public void setScrollBarStyle(int style) { + mProvider.getViewDelegate().setScrollBarStyle(style); + super.setScrollBarStyle(style); } - /** @hide Called by JNI when pages are swapped (only occurs with hardware - * acceleration) */ - protected void pageSwapCallback(boolean notifyAnimationStarted) { - mWebViewCore.resumeWebKitDraw(); - if (inEditingMode()) { - didUpdateWebTextViewDimensions(ANYWHERE); - } - if (notifyAnimationStarted) { - mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED); - } + @Override + protected int computeHorizontalScrollRange() { + return mProvider.getScrollDelegate().computeHorizontalScrollRange(); } - void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) { - if (mNativeClass == 0) { - if (mDelaySetPicture != null) { - throw new IllegalStateException("Tried to setNewPicture with" - + " a delay picture already set! (memory leak)"); - } - // Not initialized yet, delay set - mDelaySetPicture = draw; - return; - } - WebViewCore.ViewState viewState = draw.mViewState; - boolean isPictureAfterFirstLayout = viewState != null; - - if (updateBaseLayer) { - setBaseLayer(draw.mBaseLayer, draw.mInvalRegion, - getSettings().getShowVisualIndicator(), - isPictureAfterFirstLayout); - } - final Point viewSize = draw.mViewSize; - // We update the layout (i.e. request a layout from the - // view system) if the last view size that we sent to - // WebCore matches the view size of the picture we just - // received in the fixed dimension. - final boolean updateLayout = viewSize.x == mLastWidthSent - && viewSize.y == mLastHeightSent; - // Don't send scroll event for picture coming from webkit, - // since the new picture may cause a scroll event to override - // the saved history scroll position. - mSendScrollEvent = false; - recordNewContentSize(draw.mContentSize.x, - draw.mContentSize.y, updateLayout); - if (isPictureAfterFirstLayout) { - // Reset the last sent data here since dealing with new page. - mLastWidthSent = 0; - mZoomManager.onFirstLayout(draw); - int scrollX = viewState.mShouldStartScrolledRight - ? getContentWidth() : viewState.mScrollX; - int scrollY = viewState.mScrollY; - setContentScrollTo(scrollX, scrollY); - if (!mDrawHistory) { - // As we are on a new page, remove the WebTextView. This - // is necessary for page loads driven by webkit, and in - // particular when the user was on a password field, so - // the WebTextView was visible. - clearTextEntry(); - } - } - mSendScrollEvent = true; - - if (DebugFlags.WEB_VIEW) { - Rect b = draw.mInvalRegion.getBounds(); - Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + - b.left+","+b.top+","+b.right+","+b.bottom+"}"); - } - invalidateContentRect(draw.mInvalRegion.getBounds()); - - if (mPictureListener != null) { - mPictureListener.onNewPicture(WebView.this, capturePicture()); - } - - // update the zoom information based on the new picture - mZoomManager.onNewPicture(draw); - - if (draw.mFocusSizeChanged && inEditingMode()) { - mFocusSizeChanged = true; - } - if (isPictureAfterFirstLayout) { - mViewManager.postReadyToDrawAll(); - } + @Override + protected int computeHorizontalScrollOffset() { + return mProvider.getScrollDelegate().computeHorizontalScrollOffset(); } - /** - * Used when receiving messages for REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID - * and UPDATE_TEXT_SELECTION_MSG_ID. Update the selection of WebTextView. - */ - private void updateTextSelectionFromMessage(int nodePointer, - int textGeneration, WebViewCore.TextSelectionData data) { - if (textGeneration == mTextGeneration) { - if (inEditingMode() - && mWebTextView.isSameTextField(nodePointer)) { - mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd); - } else if (mInputConnection != null && mFieldPointer == nodePointer) { - mInputConnection.setSelection(data.mStart, data.mEnd); - } - } - nativeSetTextSelection(mNativeClass, data.mSelectTextPtr); - - if (data.mSelectTextPtr != 0 && - (data.mStart != data.mEnd || - (mFieldPointer == nodePointer && mFieldPointer != 0))) { - mIsCaretSelection = (data.mStart == data.mEnd); - if (!mSelectingText) { - setupWebkitSelect(); - } else if (!mSelectionStarted) { - syncSelectionCursors(); - } - if (mIsCaretSelection) { - resetCaretTimer(); - } - } else { - selectionDone(); - } - invalidate(); - } - - // Class used to use a dropdown for a <select> element - private class InvokeListBox implements Runnable { - // Whether the listbox allows multiple selection. - private boolean mMultiple; - // Passed in to a list with multiple selection to tell - // which items are selected. - private int[] mSelectedArray; - // Passed in to a list with single selection to tell - // where the initial selection is. - private int mSelection; - - private Container[] mContainers; - - // Need these to provide stable ids to my ArrayAdapter, - // which normally does not have stable ids. (Bug 1250098) - private class Container extends Object { - /** - * Possible values for mEnabled. Keep in sync with OptionStatus in - * WebViewCore.cpp - */ - final static int OPTGROUP = -1; - final static int OPTION_DISABLED = 0; - final static int OPTION_ENABLED = 1; - - String mString; - int mEnabled; - int mId; - - @Override - public String toString() { - return mString; - } - } - - /** - * Subclass ArrayAdapter so we can disable OptionGroupLabels, - * and allow filtering. - */ - private class MyArrayListAdapter extends ArrayAdapter<Container> { - public MyArrayListAdapter() { - super(mContext, - mMultiple ? com.android.internal.R.layout.select_dialog_multichoice : - com.android.internal.R.layout.webview_select_singlechoice, - mContainers); - } - - @Override - public View getView(int position, View convertView, - ViewGroup parent) { - // Always pass in null so that we will get a new CheckedTextView - // Otherwise, an item which was previously used as an <optgroup> - // element (i.e. has no check), could get used as an <option> - // element, which needs a checkbox/radio, but it would not have - // one. - convertView = super.getView(position, null, parent); - Container c = item(position); - if (c != null && Container.OPTION_ENABLED != c.mEnabled) { - // ListView does not draw dividers between disabled and - // enabled elements. Use a LinearLayout to provide dividers - LinearLayout layout = new LinearLayout(mContext); - layout.setOrientation(LinearLayout.VERTICAL); - if (position > 0) { - View dividerTop = new View(mContext); - dividerTop.setBackgroundResource( - android.R.drawable.divider_horizontal_bright); - layout.addView(dividerTop); - } - - if (Container.OPTGROUP == c.mEnabled) { - // Currently select_dialog_multichoice uses CheckedTextViews. - // If that changes, the class cast will no longer be valid. - if (mMultiple) { - Assert.assertTrue(convertView instanceof CheckedTextView); - ((CheckedTextView) convertView).setCheckMarkDrawable(null); - } - } else { - // c.mEnabled == Container.OPTION_DISABLED - // Draw the disabled element in a disabled state. - convertView.setEnabled(false); - } - - layout.addView(convertView); - if (position < getCount() - 1) { - View dividerBottom = new View(mContext); - dividerBottom.setBackgroundResource( - android.R.drawable.divider_horizontal_bright); - layout.addView(dividerBottom); - } - return layout; - } - return convertView; - } - - @Override - public boolean hasStableIds() { - // AdapterView's onChanged method uses this to determine whether - // to restore the old state. Return false so that the old (out - // of date) state does not replace the new, valid state. - return false; - } - - private Container item(int position) { - if (position < 0 || position >= getCount()) { - return null; - } - return getItem(position); - } - - @Override - public long getItemId(int position) { - Container item = item(position); - if (item == null) { - return -1; - } - return item.mId; - } - - @Override - public boolean areAllItemsEnabled() { - return false; - } - - @Override - public boolean isEnabled(int position) { - Container item = item(position); - if (item == null) { - return false; - } - return Container.OPTION_ENABLED == item.mEnabled; - } - } - - private InvokeListBox(String[] array, int[] enabled, int[] selected) { - mMultiple = true; - mSelectedArray = selected; - - int length = array.length; - mContainers = new Container[length]; - for (int i = 0; i < length; i++) { - mContainers[i] = new Container(); - mContainers[i].mString = array[i]; - mContainers[i].mEnabled = enabled[i]; - mContainers[i].mId = i; - } - } - - private InvokeListBox(String[] array, int[] enabled, int selection) { - mSelection = selection; - mMultiple = false; - - int length = array.length; - mContainers = new Container[length]; - for (int i = 0; i < length; i++) { - mContainers[i] = new Container(); - mContainers[i].mString = array[i]; - mContainers[i].mEnabled = enabled[i]; - mContainers[i].mId = i; - } - } + @Override + protected int computeVerticalScrollRange() { + return mProvider.getScrollDelegate().computeVerticalScrollRange(); + } - /* - * Whenever the data set changes due to filtering, this class ensures - * that the checked item remains checked. - */ - private class SingleDataSetObserver extends DataSetObserver { - private long mCheckedId; - private ListView mListView; - private Adapter mAdapter; - - /* - * Create a new observer. - * @param id The ID of the item to keep checked. - * @param l ListView for getting and clearing the checked states - * @param a Adapter for getting the IDs - */ - public SingleDataSetObserver(long id, ListView l, Adapter a) { - mCheckedId = id; - mListView = l; - mAdapter = a; - } - - @Override - public void onChanged() { - // The filter may have changed which item is checked. Find the - // item that the ListView thinks is checked. - int position = mListView.getCheckedItemPosition(); - long id = mAdapter.getItemId(position); - if (mCheckedId != id) { - // Clear the ListView's idea of the checked item, since - // it is incorrect - mListView.clearChoices(); - // Search for mCheckedId. If it is in the filtered list, - // mark it as checked - int count = mAdapter.getCount(); - for (int i = 0; i < count; i++) { - if (mAdapter.getItemId(i) == mCheckedId) { - mListView.setItemChecked(i, true); - break; - } - } - } - } - } + @Override + protected int computeVerticalScrollOffset() { + return mProvider.getScrollDelegate().computeVerticalScrollOffset(); + } - @Override - public void run() { - final ListView listView = (ListView) LayoutInflater.from(mContext) - .inflate(com.android.internal.R.layout.select_dialog, null); - final MyArrayListAdapter adapter = new MyArrayListAdapter(); - AlertDialog.Builder b = new AlertDialog.Builder(mContext) - .setView(listView).setCancelable(true) - .setInverseBackgroundForced(true); - - if (mMultiple) { - b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mWebViewCore.sendMessage( - EventHub.LISTBOX_CHOICES, - adapter.getCount(), 0, - listView.getCheckedItemPositions()); - }}); - b.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mWebViewCore.sendMessage( - EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); - }}); - } - mListBoxDialog = b.create(); - listView.setAdapter(adapter); - listView.setFocusableInTouchMode(true); - // There is a bug (1250103) where the checks in a ListView with - // multiple items selected are associated with the positions, not - // the ids, so the items do not properly retain their checks when - // filtered. Do not allow filtering on multiple lists until - // that bug is fixed. - - listView.setTextFilterEnabled(!mMultiple); - if (mMultiple) { - listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - int length = mSelectedArray.length; - for (int i = 0; i < length; i++) { - listView.setItemChecked(mSelectedArray[i], true); - } - } else { - listView.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View v, - int position, long id) { - // Rather than sending the message right away, send it - // after the page regains focus. - mListBoxMessage = Message.obtain(null, - EventHub.SINGLE_LISTBOX_CHOICE, (int) id, 0); - mListBoxDialog.dismiss(); - mListBoxDialog = null; - } - }); - if (mSelection != -1) { - listView.setSelection(mSelection); - listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); - listView.setItemChecked(mSelection, true); - DataSetObserver observer = new SingleDataSetObserver( - adapter.getItemId(mSelection), listView, adapter); - adapter.registerDataSetObserver(observer); - } - } - mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - mWebViewCore.sendMessage( - EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); - mListBoxDialog = null; - } - }); - mListBoxDialog.show(); - } + @Override + protected int computeVerticalScrollExtent() { + return mProvider.getScrollDelegate().computeVerticalScrollExtent(); } - private Message mListBoxMessage; + @Override + public void computeScroll() { + mProvider.getScrollDelegate().computeScroll(); + } - /* - * Request a dropdown menu for a listbox with multiple selection. - * - * @param array Labels for the listbox. - * @param enabledArray State for each element in the list. See static - * integers in Container class. - * @param selectedArray Which positions are initally selected. - */ - void requestListBox(String[] array, int[] enabledArray, int[] - selectedArray) { - mPrivateHandler.post( - new InvokeListBox(array, enabledArray, selectedArray)); + @Override + public boolean onHoverEvent(MotionEvent event) { + return mProvider.getViewDelegate().onHoverEvent(event); } - /* - * Request a dropdown menu for a listbox with single selection or a single - * <select> element. - * - * @param array Labels for the listbox. - * @param enabledArray State for each element in the list. See static - * integers in Container class. - * @param selection Which position is initally selected. - */ - void requestListBox(String[] array, int[] enabledArray, int selection) { - mPrivateHandler.post( - new InvokeListBox(array, enabledArray, selection)); + @Override + public boolean onTouchEvent(MotionEvent event) { + return mProvider.getViewDelegate().onTouchEvent(event); } - // called by JNI - private void sendMoveFocus(int frame, int node) { - mWebViewCore.sendMessage(EventHub.SET_MOVE_FOCUS, - new WebViewCore.CursorData(frame, node, 0, 0)); + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + return mProvider.getViewDelegate().onGenericMotionEvent(event); } - // called by JNI - private void sendMoveMouse(int frame, int node, int x, int y) { - mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, - new WebViewCore.CursorData(frame, node, x, y)); + @Override + public boolean onTrackballEvent(MotionEvent event) { + return mProvider.getViewDelegate().onTrackballEvent(event); } - /* - * Send a mouse move event to the webcore thread. - * - * @param removeFocus Pass true to remove the WebTextView, if present. - * @param stopPaintingCaret Stop drawing the blinking caret if true. - * called by JNI - */ - @SuppressWarnings("unused") - private void sendMoveMouseIfLatest(boolean removeFocus, boolean stopPaintingCaret) { - if (removeFocus) { - clearTextEntry(); - } - mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST, - stopPaintingCaret ? 1 : 0, 0, - cursorData()); + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return mProvider.getViewDelegate().onKeyDown(keyCode, event); } - /** - * Called by JNI to send a message to the webcore thread that the user - * touched the webpage. - * @param touchGeneration Generation number of the touch, to ignore touches - * after a new one has been generated. - * @param frame Pointer to the frame holding the node that was touched. - * @param node Pointer to the node touched. - * @param x x-position of the touch. - * @param y y-position of the touch. - */ - private void sendMotionUp(int touchGeneration, - int frame, int node, int x, int y) { - WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData(); - touchUpData.mMoveGeneration = touchGeneration; - touchUpData.mFrame = frame; - touchUpData.mNode = node; - touchUpData.mX = x; - touchUpData.mY = y; - touchUpData.mNativeLayer = nativeScrollableLayer( - x, y, touchUpData.mNativeLayerRect, null); - mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData); - } - - - private int getScaledMaxXScroll() { - int width; - if (mHeightCanMeasure == false) { - width = getViewWidth() / 4; - } else { - Rect visRect = new Rect(); - calcOurVisibleRect(visRect); - width = visRect.width() / 2; - } - // FIXME the divisor should be retrieved from somewhere - return viewToContentX(width); - } - - private int getScaledMaxYScroll() { - int height; - if (mHeightCanMeasure == false) { - height = getViewHeight() / 4; - } else { - Rect visRect = new Rect(); - calcOurVisibleRect(visRect); - height = visRect.height() / 2; - } - // FIXME the divisor should be retrieved from somewhere - // the closest thing today is hard-coded into ScrollView.java - // (from ScrollView.java, line 363) int maxJump = height/2; - return Math.round(height * mZoomManager.getInvScale()); + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + return mProvider.getViewDelegate().onKeyUp(keyCode, event); } - /** - * Called by JNI to invalidate view - */ - private void viewInvalidate() { - invalidate(); + @Override + public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { + return mProvider.getViewDelegate().onKeyMultiple(keyCode, repeatCount, event); } - /** - * Pass the key directly to the page. This assumes that - * nativePageShouldHandleShiftAndArrows() returned true. - */ - private void letPageHandleNavKey(int keyCode, long time, boolean down, int metaState) { - int keyEventAction; - int eventHubAction; - if (down) { - keyEventAction = KeyEvent.ACTION_DOWN; - eventHubAction = EventHub.KEY_DOWN; - playSoundEffect(keyCodeToSoundsEffect(keyCode)); - } else { - keyEventAction = KeyEvent.ACTION_UP; - eventHubAction = EventHub.KEY_UP; - } + /* + TODO: These are not currently implemented in WebViewClassic, but it seems inconsistent not + to be delegating them too. - KeyEvent event = new KeyEvent(time, time, keyEventAction, keyCode, - 1, (metaState & KeyEvent.META_SHIFT_ON) - | (metaState & KeyEvent.META_ALT_ON) - | (metaState & KeyEvent.META_SYM_ON) - , KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0); - mWebViewCore.sendMessage(eventHubAction, event); + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + return mProvider.getViewDelegate().onKeyPreIme(keyCode, event); } - - // return true if the key was handled - private boolean navHandledKey(int keyCode, int count, boolean noScroll, - long time) { - if (mNativeClass == 0) { - return false; - } - mInitialHitTestResult = null; - mLastCursorTime = time; - mLastCursorBounds = cursorRingBounds(); - boolean keyHandled - = nativeMoveCursor(keyCode, count, noScroll) == false; - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "navHandledKey mLastCursorBounds=" + mLastCursorBounds - + " mLastCursorTime=" + mLastCursorTime - + " handled=" + keyHandled); - } - if (keyHandled == false) { - return keyHandled; - } - Rect contentCursorRingBounds = cursorRingBounds(); - if (contentCursorRingBounds.isEmpty()) return keyHandled; - Rect viewCursorRingBounds = contentToViewRect(contentCursorRingBounds); - // set last touch so that context menu related functions will work - mLastTouchX = (viewCursorRingBounds.left + viewCursorRingBounds.right) / 2; - mLastTouchY = (viewCursorRingBounds.top + viewCursorRingBounds.bottom) / 2; - if (mHeightCanMeasure == false) { - return keyHandled; - } - Rect visRect = new Rect(); - calcOurVisibleRect(visRect); - Rect outset = new Rect(visRect); - int maxXScroll = visRect.width() / 2; - int maxYScroll = visRect.height() / 2; - outset.inset(-maxXScroll, -maxYScroll); - if (Rect.intersects(outset, viewCursorRingBounds) == false) { - return keyHandled; - } - // FIXME: Necessary because ScrollView/ListView do not scroll left/right - int maxH = Math.min(viewCursorRingBounds.right - visRect.right, - maxXScroll); - if (maxH > 0) { - pinScrollBy(maxH, 0, true, 0); - } else { - maxH = Math.max(viewCursorRingBounds.left - visRect.left, - -maxXScroll); - if (maxH < 0) { - pinScrollBy(maxH, 0, true, 0); - } - } - if (mLastCursorBounds.isEmpty()) return keyHandled; - if (mLastCursorBounds.equals(contentCursorRingBounds)) { - return keyHandled; - } - if (DebugFlags.WEB_VIEW) { - Log.v(LOGTAG, "navHandledKey contentCursorRingBounds=" - + contentCursorRingBounds); - } - requestRectangleOnScreen(viewCursorRingBounds); - return keyHandled; + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + return mProvider.getViewDelegate().onKeyLongPress(keyCode, event); } - - /** - * @return Whether accessibility script has been injected. - */ - private boolean accessibilityScriptInjected() { - // TODO: Maybe the injected script should announce its presence in - // the page meta-tag so the nativePageShouldHandleShiftAndArrows - // will check that as one of the conditions it looks for - return mAccessibilityScriptInjected; + @Override + public boolean onKeyShortcut(int keyCode, KeyEvent event) { + return mProvider.getViewDelegate().onKeyShortcut(keyCode, event); } + */ - /** - * Set the background color. It's white by default. Pass - * zero to make the view transparent. - * @param color the ARGB color described by Color.java - */ + @Deprecated @Override - public void setBackgroundColor(int color) { - mBackgroundColor = color; - mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color); + public boolean shouldDelayChildPressedState() { + return mProvider.getViewDelegate().shouldDelayChildPressedState(); } - /** - * @deprecated This method is now obsolete. - */ - @Deprecated - public void debugDump() { - checkThread(); - nativeDebugDump(); - mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE); + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + mProvider.getViewDelegate().onInitializeAccessibilityNodeInfo(info); } - /** - * Draw the HTML page into the specified canvas. This call ignores any - * view-specific zoom, scroll offset, or other changes. It does not draw - * any view-specific chrome, such as progress or URL bars. - * - * @hide only needs to be accessible to Browser and testing - */ - public void drawPage(Canvas canvas) { - calcOurContentVisibleRectF(mVisibleContentRect); - nativeDraw(canvas, mVisibleContentRect, 0, 0, false); + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + mProvider.getViewDelegate().onInitializeAccessibilityEvent(event); } - /** - * Enable the communication b/t the webView and VideoViewProxy - * - * @hide only used by the Browser - */ - public void setHTML5VideoViewProxy(HTML5VideoViewProxy proxy) { - mHTML5VideoViewProxy = proxy; + /** @hide */ + @Override + protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, + int l, int t, int r, int b) { + mProvider.getViewDelegate().onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); } - /** - * Set the time to wait between passing touches to WebCore. See also the - * TOUCH_SENT_INTERVAL member for further discussion. - * - * @hide This is only used by the DRT test application. - */ - public void setTouchInterval(int interval) { - mCurrentTouchInterval = interval; + @Override + protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { + mProvider.getViewDelegate().onOverScrolled(scrollX, scrollY, clampedX, clampedY); } - /** - * Copy text into the clipboard. This is called indirectly from - * WebViewCore. - * @param text The text to put into the clipboard. - */ - private void copyToClipboard(String text) { - ClipboardManager cm = (ClipboardManager)getContext() - .getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText(getTitle(), text); - cm.setPrimaryClip(clip); + @Override + protected void onWindowVisibilityChanged(int visibility) { + super.onWindowVisibilityChanged(visibility); + mProvider.getViewDelegate().onWindowVisibilityChanged(visibility); } - /** - * Update our cache with updatedText. - * @param updatedText The new text to put in our cache. - * @hide - */ - protected void updateCachedTextfield(String updatedText) { - // Also place our generation number so that when we look at the cache - // we recognize that it is up to date. - nativeUpdateCachedTextfield(updatedText, mTextGeneration); + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + // Not using short-circuit OR: provider does suppress base-class call. + return mProvider.getViewDelegate().drawChild(canvas, child, drawingTime) | + super.drawChild(canvas, child, drawingTime); } - /*package*/ void autoFillForm(int autoFillQueryId) { - mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM, autoFillQueryId, /* unused */0); + @Override + protected void onDraw(Canvas canvas) { + mProvider.getViewDelegate().onDraw(canvas); } - /* package */ ViewManager getViewManager() { - return mViewManager; + @Override + public boolean performLongClick() { + return mProvider.getViewDelegate().performLongClick(); } - private static void checkThread() { - if (Looper.myLooper() != Looper.getMainLooper()) { - Throwable throwable = new Throwable( - "Warning: A WebView method was called on thread '" + - Thread.currentThread().getName() + "'. " + - "All WebView methods must be called on the UI thread. " + - "Future versions of WebView may not support use on other threads."); - Log.w(LOGTAG, Log.getStackTraceString(throwable)); - StrictMode.onWebViewMethodCalledOnWrongThread(throwable); - } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + mProvider.getViewDelegate().onConfigurationChanged(newConfig); } - /** @hide send content invalidate */ - protected void contentInvalidateAll() { - if (mWebViewCore != null && !mBlockWebkitViewMessages) { - mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL); - } + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + return mProvider.getViewDelegate().onCreateInputConnection(outAttrs); } - /** @hide discard all textures from tiles */ - protected void discardAllTextures() { - nativeDiscardAllTextures(); + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + mProvider.getViewDelegate().onVisibilityChanged(changedView, visibility); } - /** - * Begin collecting per-tile profiling data - * - * @hide only used by profiling tests - */ - public void tileProfilingStart() { - nativeTileProfilingStart(); + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + mProvider.getViewDelegate().onWindowFocusChanged(hasWindowFocus); + super.onWindowFocusChanged(hasWindowFocus); } - /** - * Return per-tile profiling data - * - * @hide only used by profiling tests - */ - public float tileProfilingStop() { - return nativeTileProfilingStop(); + + @Override + protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + mProvider.getViewDelegate().onFocusChanged(focused, direction, previouslyFocusedRect); + super.onFocusChanged(focused, direction, previouslyFocusedRect); } - /** @hide only used by profiling tests */ - public void tileProfilingClear() { - nativeTileProfilingClear(); + /** @hide */ + @Override + protected boolean setFrame(int left, int top, int right, int bottom) { + return mProvider.getViewDelegate().setFrame(left, top, right, bottom); } - /** @hide only used by profiling tests */ - public int tileProfilingNumFrames() { - return nativeTileProfilingNumFrames(); + + @Override + protected void onSizeChanged(int w, int h, int ow, int oh) { + super.onSizeChanged(w, h, ow, oh); + mProvider.getViewDelegate().onSizeChanged(w, h, ow, oh); } - /** @hide only used by profiling tests */ - public int tileProfilingNumTilesInFrame(int frame) { - return nativeTileProfilingNumTilesInFrame(frame); + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + mProvider.getViewDelegate().onScrollChanged(l, t, oldl, oldt); } - /** @hide only used by profiling tests */ - public int tileProfilingGetInt(int frame, int tile, String key) { - return nativeTileProfilingGetInt(frame, tile, key); + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + return mProvider.getViewDelegate().dispatchKeyEvent(event); } - /** @hide only used by profiling tests */ - public float tileProfilingGetFloat(int frame, int tile, String key) { - return nativeTileProfilingGetFloat(frame, tile, key); + + @Override + public boolean requestFocus(int direction, Rect previouslyFocusedRect) { + return mProvider.getViewDelegate().requestFocus(direction, previouslyFocusedRect); } - /** - * Checks the focused content for an editable text field. This can be - * text input or ContentEditable. - * @return true if the focused item is an editable text field. - */ - boolean focusCandidateIsEditableText() { - boolean isEditable = false; - // TODO: reverse sDisableNavcache so that its name is positive - boolean isNavcacheEnabled = !sDisableNavcache; - if (isNavcacheEnabled) { - isEditable = nativeFocusCandidateIsEditableText(mNativeClass); - } else if (mFocusedNode != null) { - isEditable = mFocusedNode.mEditable; - } - return isEditable; + @Deprecated + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mProvider.getViewDelegate().onMeasure(widthMeasureSpec, heightMeasureSpec); } - // TODO: Remove this - Rect cursorRingBounds() { - if (sDisableNavcache) { - return new Rect(); - } - return nativeGetCursorRingBounds(); - } - - private native int nativeCacheHitFramePointer(); - private native boolean nativeCacheHitIsPlugin(); - private native Rect nativeCacheHitNodeBounds(); - private native int nativeCacheHitNodePointer(); - /* package */ native void nativeClearCursor(); - private native void nativeCreate(int ptr, String drawableDir, boolean isHighEndGfx); - private native int nativeCursorFramePointer(); - private native Rect nativeCursorNodeBounds(); - private native int nativeCursorNodePointer(); - private native boolean nativeCursorIntersects(Rect visibleRect); - private native boolean nativeCursorIsAnchor(); - private native boolean nativeCursorIsTextInput(); - private native Point nativeCursorPosition(); - private native String nativeCursorText(); - /** - * Returns true if the native cursor node says it wants to handle key events - * (ala plugins). This can only be called if mNativeClass is non-zero! - */ - private native boolean nativeCursorWantsKeyEvents(); - private native void nativeDebugDump(); - private native void nativeDestroy(); + @Override + public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { + return mProvider.getViewDelegate().requestChildRectangleOnScreen(child, rect, immediate); + } - /** - * Draw the picture set with a background color and extra. If - * "splitIfNeeded" is true and the return value is not 0, the return value - * MUST be passed to WebViewCore with SPLIT_PICTURE_SET message so that the - * native allocation can be freed. - */ - private native int nativeDraw(Canvas canvas, RectF visibleRect, - int color, int extra, boolean splitIfNeeded); - private native void nativeDumpDisplayTree(String urlOrNull); - private native boolean nativeEvaluateLayersAnimations(int nativeInstance); - private native int nativeGetDrawGLFunction(int nativeInstance, Rect rect, - Rect viewRect, RectF visibleRect, float scale, int extras); - private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect, - RectF visibleRect, float scale); - private native void nativeExtendSelection(int x, int y); - /* package */ native int nativeFocusCandidateFramePointer(); - /* package */ native boolean nativeFocusCandidateHasNextTextfield(); - /* package */ native boolean nativeFocusCandidateIsPassword(); - private native boolean nativeFocusCandidateIsRtlText(); - private native boolean nativeFocusCandidateIsTextInput(); - private native boolean nativeFocusCandidateIsEditableText(int nativeClass); - /* package */ native int nativeFocusCandidateMaxLength(); - /* package */ native boolean nativeFocusCandidateIsAutoComplete(); - /* package */ native boolean nativeFocusCandidateIsSpellcheck(); - /* package */ native String nativeFocusCandidateName(); - private native Rect nativeFocusCandidateNodeBounds(); - /** - * @return A Rect with left, top, right, bottom set to the corresponding - * padding values in the focus candidate, if it is a textfield/textarea with - * a style. Otherwise return null. This is not actually a rectangle; Rect - * is being used to pass four integers. - */ - private native Rect nativeFocusCandidatePaddingRect(); - /* package */ native int nativeFocusCandidatePointer(); - private native String nativeFocusCandidateText(); - /* package */ native float nativeFocusCandidateTextSize(); - /* package */ native int nativeFocusCandidateLineHeight(); - /** - * Returns an integer corresponding to WebView.cpp::type. - * See WebTextView.setType() - */ - private native int nativeFocusCandidateType(); - private native int nativeFocusCandidateLayerId(); - private native boolean nativeFocusIsPlugin(); - private native Rect nativeFocusNodeBounds(); - /* package */ native int nativeFocusNodePointer(); - private native Rect nativeGetCursorRingBounds(); - private native String nativeGetSelection(); - private native boolean nativeHasCursorNode(); - private native boolean nativeHasFocusNode(); - private native void nativeHideCursor(); - private native boolean nativeHitSelection(int x, int y); - private native String nativeImageURI(int x, int y); - private native Rect nativeLayerBounds(int layer); - /* package */ native boolean nativeMoveCursorToNextTextInput(); - // return true if the page has been scrolled - private native boolean nativeMotionUp(int x, int y, int slop); - // returns false if it handled the key - private native boolean nativeMoveCursor(int keyCode, int count, - boolean noScroll); - private native int nativeMoveGeneration(); - /** - * @return true if the page should get the shift and arrow keys, rather - * than select text/navigation. - * - * If the focus is a plugin, or if the focus and cursor match and are - * a contentEditable element, then the page should handle these keys. - */ - private native boolean nativePageShouldHandleShiftAndArrows(); - private native boolean nativePointInNavCache(int x, int y, int slop); - private native void nativeSelectBestAt(Rect rect); - private native void nativeSelectAt(int x, int y); - private native void nativeSetExtendSelection(); - private native void nativeSetFindIsUp(boolean isUp); - private native void nativeSetHeightCanMeasure(boolean measure); - private native boolean nativeSetBaseLayer(int nativeInstance, - int layer, Region invalRegion, - boolean showVisualIndicator, boolean isPictureAfterFirstLayout); - private native int nativeGetBaseLayer(); - private native void nativeShowCursorTimed(); - private native void nativeReplaceBaseContent(int content); - private native void nativeCopyBaseContentToPicture(Picture pict); - private native boolean nativeHasContent(); - private native void nativeSetSelectionPointer(int nativeInstance, - boolean set, float scale, int x, int y); - private native boolean nativeStartSelection(int x, int y); - private native void nativeStopGL(); - private native Rect nativeSubtractLayers(Rect content); - private native int nativeTextGeneration(); - private native void nativeDiscardAllTextures(); - private native void nativeTileProfilingStart(); - private native float nativeTileProfilingStop(); - private native void nativeTileProfilingClear(); - private native int nativeTileProfilingNumFrames(); - private native int nativeTileProfilingNumTilesInFrame(int frame); - private native int nativeTileProfilingGetInt(int frame, int tile, String key); - private native float nativeTileProfilingGetFloat(int frame, int tile, String key); - // Never call this version except by updateCachedTextfield(String) - - // we always want to pass in our generation number. - private native void nativeUpdateCachedTextfield(String updatedText, - int generation); - private native boolean nativeWordSelection(int x, int y); - // return NO_LEFTEDGE means failure. - static final int NO_LEFTEDGE = -1; - native int nativeGetBlockLeftEdge(int x, int y, float scale); - - private native void nativeUseHardwareAccelSkia(boolean enabled); - - // Returns a pointer to the scrollable LayerAndroid at the given point. - private native int nativeScrollableLayer(int x, int y, Rect scrollRect, - Rect scrollBounds); - /** - * Scroll the specified layer. - * @param layer Id of the layer to scroll, as determined by nativeScrollableLayer. - * @param newX Destination x position to which to scroll. - * @param newY Destination y position to which to scroll. - * @return True if the layer is successfully scrolled. - */ - private native boolean nativeScrollLayer(int layer, int newX, int newY); - private native void nativeSetIsScrolling(boolean isScrolling); - private native int nativeGetBackgroundColor(); - native boolean nativeSetProperty(String key, String value); - native String nativeGetProperty(String key); - /** - * See {@link ComponentCallbacks2} for the trim levels and descriptions - */ - private static native void nativeOnTrimMemory(int level); - private static native void nativeSetPauseDrawing(int instance, boolean pause); - private static native boolean nativeDisableNavcache(); - private static native void nativeSetTextSelection(int instance, int selection); - private static native int nativeGetHandleLayerId(int instance, int handle, - Rect cursorLocation); - private static native boolean nativeIsBaseFirst(int instance); + @Override + public void setBackgroundColor(int color) { + mProvider.getViewDelegate().setBackgroundColor(color); + } } diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 46c8353..e6cee42 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * 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. @@ -84,6 +84,7 @@ import android.view.ScaleGestureDetector; import android.view.SoundEffectConstants; import android.view.VelocityTracker; import android.view.View; +import android.view.View.MeasureSpec; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; @@ -98,6 +99,8 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.webkit.HTML5VideoInline; import android.webkit.WebTextView.AutoCompleteAdapter; +import android.webkit.WebView.HitTestResult; +import android.webkit.WebView.PictureListener; import android.webkit.WebViewCore.DrawData; import android.webkit.WebViewCore.EventHub; import android.webkit.WebViewCore.TextFieldInitData; @@ -343,17 +346,19 @@ import java.util.regex.Pattern; * {@link WebChromeClient#getVideoLoadingProgressView()} is optional. * </p> * - * + * @hide */ +// TODO: Remove duplicated API documentation and @hide from fields and methods, and +// checkThread() call. (All left in for now to ease branch merging.) +// TODO: Check if any WebView published API methods are called from within here, and if so +// we should bounce the call out via the proxy to enable any sub-class to override it. @Widget -public class WebView extends AbsoluteLayout - implements ViewTreeObserver.OnGlobalFocusChangeListener, - ViewGroup.OnHierarchyChangeListener { - +public final class WebViewClassic implements WebViewProvider, WebViewProvider.ScrollDelegate, + WebViewProvider.ViewDelegate { private class InnerGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { @Override public void onGlobalLayout() { - if (isShown()) { + if (mWebView.isShown()) { setGLRectViewport(); } } @@ -362,7 +367,7 @@ public class WebView extends AbsoluteLayout private class InnerScrollChangedListener implements ViewTreeObserver.OnScrollChangedListener { @Override public void onScrollChanged() { - if (isShown()) { + if (mWebView.isShown()) { setGLRectViewport(); } } @@ -382,7 +387,7 @@ public class WebView extends AbsoluteLayout private int mMaxLength; public WebViewInputConnection() { - super(WebView.this, true); + super(mWebView, true); } @Override @@ -490,17 +495,17 @@ public class WebView extends AbsoluteLayout boolean handled = true; switch (editorAction) { case EditorInfo.IME_ACTION_NEXT: - WebView.this.requestFocus(FOCUS_FORWARD); + mWebView.requestFocus(View.FOCUS_FORWARD); break; case EditorInfo.IME_ACTION_PREVIOUS: - WebView.this.requestFocus(FOCUS_BACKWARD); + mWebView.requestFocus(View.FOCUS_BACKWARD); break; case EditorInfo.IME_ACTION_DONE: - WebView.this.hideSoftKeyboard(); + WebViewClassic.this.hideSoftKeyboard(); break; case EditorInfo.IME_ACTION_GO: case EditorInfo.IME_ACTION_SEARCH: - WebView.this.hideSoftKeyboard(); + WebViewClassic.this.hideSoftKeyboard(); String text = getEditable().toString(); passToJavaScript(text, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); @@ -686,26 +691,26 @@ public class WebView extends AbsoluteLayout if (imm != null) { // Since the text has changed, do not allow the IME to replace the // existing text as though it were a completion. - imm.restartInput(WebView.this); + imm.restartInput(mWebView); } } } - private class PastePopupWindow extends PopupWindow implements OnClickListener { + private class PastePopupWindow extends PopupWindow implements View.OnClickListener { private ViewGroup mContentView; private TextView mPasteTextView; public PastePopupWindow() { - super(WebView.this.mContext, null, + super(mContext, null, com.android.internal.R.attr.textSelectHandleWindowStyle); setClippingEnabled(true); - LinearLayout linearLayout = new LinearLayout(WebView.this.getContext()); + LinearLayout linearLayout = new LinearLayout(mContext); linearLayout.setOrientation(LinearLayout.HORIZONTAL); mContentView = linearLayout; mContentView.setBackgroundResource( com.android.internal.R.drawable.text_edit_paste_window); - LayoutInflater inflater = (LayoutInflater)WebView.this.mContext. + LayoutInflater inflater = (LayoutInflater)mContext. getSystemService(Context.LAYOUT_INFLATER_SERVICE); ViewGroup.LayoutParams wrapContent = new ViewGroup.LayoutParams( @@ -739,7 +744,7 @@ public class WebView extends AbsoluteLayout x = windowLeft; } if (!isShowing()) { - showAtLocation(WebView.this, Gravity.NO_GRAVITY, x, y); + showAtLocation(mWebView, Gravity.NO_GRAVITY, x, y); } update(x, y, width, height); } @@ -792,29 +797,6 @@ public class WebView extends AbsoluteLayout private int mFieldPointer; private PastePopupWindow mPasteWindow; - /** - * Transportation object for returning WebView across thread boundaries. - */ - public class WebViewTransport { - private WebView mWebview; - - /** - * Set the WebView to the transportation object. - * @param webview The WebView to transport. - */ - public synchronized void setWebView(WebView webview) { - mWebview = webview; - } - - /** - * Return the WebView object. - * @return WebView The transported WebView object. - */ - public synchronized WebView getWebView() { - return mWebview; - } - } - private static class OnTrimMemoryListener implements ComponentCallbacks2 { private static OnTrimMemoryListener sInstance = null; @@ -848,15 +830,15 @@ public class WebView extends AbsoluteLayout // at native side. // Here we just need to clean up the Surface Texture which is static. HTML5VideoInline.cleanupSurfaceTexture(); - WebView.nativeOnTrimMemory(level); + WebViewClassic.nativeOnTrimMemory(level); } } // A final CallbackProxy shared by WebViewCore and BrowserFrame. - private final CallbackProxy mCallbackProxy; + private CallbackProxy mCallbackProxy; - private final WebViewDatabase mDatabase; + private WebViewDatabase mDatabase; // SSL certificate for the main top-level page (if secure) private SslCertificate mCertificate; @@ -877,7 +859,7 @@ public class WebView extends AbsoluteLayout /* package */ void incrementTextGeneration() { mTextGeneration++; } // Used by WebViewCore to create child views. - /* package */ final ViewManager mViewManager; + /* package */ ViewManager mViewManager; // Used to display in full screen mode PluginFullScreenHolder mFullScreenHolder; @@ -1373,102 +1355,6 @@ public class WebView extends AbsoluteLayout // Used to notify listeners of a new picture. private PictureListener mPictureListener; - /** - * Interface to listen for new pictures as they change. - * @deprecated This interface is now obsolete. - */ - @Deprecated - public interface PictureListener { - /** - * Notify the listener that the picture has changed. - * @param view The WebView that owns the picture. - * @param picture The new picture. - * @deprecated Due to internal changes, the picture does not include - * composited layers such as fixed position elements or scrollable divs. - * While the PictureListener API can still be used to detect changes in - * the WebView content, you are advised against its usage until a replacement - * is provided in a future Android release - */ - @Deprecated - public void onNewPicture(WebView view, Picture picture); - } - - public static class HitTestResult { - /** - * Default HitTestResult, where the target is unknown - */ - public static final int UNKNOWN_TYPE = 0; - /** - * @deprecated This type is no longer used. - */ - @Deprecated - public static final int ANCHOR_TYPE = 1; - /** - * HitTestResult for hitting a phone number - */ - public static final int PHONE_TYPE = 2; - /** - * HitTestResult for hitting a map address - */ - public static final int GEO_TYPE = 3; - /** - * HitTestResult for hitting an email address - */ - public static final int EMAIL_TYPE = 4; - /** - * HitTestResult for hitting an HTML::img tag - */ - public static final int IMAGE_TYPE = 5; - /** - * @deprecated This type is no longer used. - */ - @Deprecated - public static final int IMAGE_ANCHOR_TYPE = 6; - /** - * HitTestResult for hitting a HTML::a tag with src=http - */ - public static final int SRC_ANCHOR_TYPE = 7; - /** - * HitTestResult for hitting a HTML::a tag with src=http + HTML::img - */ - public static final int SRC_IMAGE_ANCHOR_TYPE = 8; - /** - * HitTestResult for hitting an edit text area - */ - public static final int EDIT_TEXT_TYPE = 9; - - private int mType; - private String mExtra; - - HitTestResult() { - mType = UNKNOWN_TYPE; - } - - private void setType(int type) { - mType = type; - } - - private void setExtra(String extra) { - mExtra = extra; - } - - /** - * Gets the type of the hit test result. - * @return See the XXX_TYPE constants defined in this class. - */ - public int getType() { - return mType; - } - - /** - * Gets additional type-dependant information about the result, see - * {@link WebView#getHitTestResult()} for details. - * @return may either be null or contain extra information about this result. - */ - public String getExtra() { - return mExtra; - } - } /** * Refer to {@link WebView#requestFocusNodeHref(Message)} for more information @@ -1479,43 +1365,10 @@ public class WebView extends AbsoluteLayout static final String SRC = "src"; } - /** - * Construct a new WebView with a Context object. - * @param context A Context object used to access application assets. - */ - public WebView(Context context) { - this(context, null); - } - - /** - * Construct a new WebView with layout parameters. - * @param context A Context object used to access application assets. - * @param attrs An AttributeSet passed to our parent. - */ - public WebView(Context context, AttributeSet attrs) { - this(context, attrs, com.android.internal.R.attr.webViewStyle); - } - - /** - * Construct a new WebView with layout parameters and a default style. - * @param context A Context object used to access application assets. - * @param attrs An AttributeSet passed to our parent. - * @param defStyle The default style resource ID. - */ - public WebView(Context context, AttributeSet attrs, int defStyle) { - this(context, attrs, defStyle, false); - } - - /** - * Construct a new WebView with layout parameters and a default style. - * @param context A Context object used to access application assets. - * @param attrs An AttributeSet passed to our parent. - * @param defStyle The default style resource ID. - * @param privateBrowsing If true the web view will be initialized in private mode. - */ - public WebView(Context context, AttributeSet attrs, int defStyle, - boolean privateBrowsing) { - this(context, attrs, defStyle, null, privateBrowsing); + public WebViewClassic(WebView webView, WebView.PrivateAccess privateAccess) { + mWebView = webView; + mWebViewPrivate = privateAccess; + mContext = webView.getContext(); } /** @@ -1523,22 +1376,16 @@ public class WebView extends AbsoluteLayout * of custom Javscript interfaces to be added to the WebView at initialization * time. This guarantees that these interfaces will be available when the JS * context is initialized. - * @param context A Context object used to access application assets. - * @param attrs An AttributeSet passed to our parent. - * @param defStyle The default style resource ID. * @param javaScriptInterfaces is a Map of interface names, as keys, and * object implementing those interfaces, as values. * @param privateBrowsing If true the web view will be initialized in private mode. * @hide This is an implementation detail. */ - protected WebView(Context context, AttributeSet attrs, int defStyle, - Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) { - super(context, attrs, defStyle); + @Override + public void init(Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) { checkThread(); - if (context == null) { - throw new IllegalArgumentException("Invalid context argument"); - } + Context context = mContext; // Used by the chrome stack to find application paths JniUtil.setContext(context); @@ -1567,6 +1414,98 @@ public class WebView extends AbsoluteLayout mAutoFillData = new WebViewCore.AutoFillData(); } + // === START: WebView Proxy binding === + // Keep the webview proxy / SPI related stuff in this section, to minimize merge conflicts. + + static class Factory implements WebViewFactoryProvider, WebViewFactoryProvider.Statics { + @Override + public WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess) { + return new WebViewClassic(webView, privateAccess); + } + + @Override + public Statics getStatics() { return this; } + + @Override + public String findAddress(String addr) { + return WebViewClassic.findAddress(addr); + } + @Override + public void setPlatformNotificationsEnabled(boolean enable) { + if (enable) { + WebViewClassic.enablePlatformNotifications(); + } else { + WebViewClassic.disablePlatformNotifications(); + } + } + + } + + // The webview that is bound to this WebViewClassic instance. Primarily needed for supplying + // as the first param in the WebViewClient and WebChromeClient callbacks. + final private WebView mWebView; + // Callback interface, provides priviledged access into the WebView instance. + final private WebView.PrivateAccess mWebViewPrivate; + // Cached reference to mWebView.getContext(), for convenience. + final private Context mContext; + + /** + * @return The webview proxy that this classic webview is bound to. + */ + public WebView getWebView() { + return mWebView; + } + + @Override + public ViewDelegate getViewDelegate() { + return this; + } + + @Override + public ScrollDelegate getScrollDelegate() { + return this; + } + + public static WebViewClassic fromWebView(WebView webView) { + return webView == null ? null : (WebViewClassic) webView.getWebViewProvider(); + } + + // Accessors, purely for convenience (and to reduce code churn during webview proxy migration). + int getScrollX() { + return mWebView.getScrollX(); + } + + int getScrollY() { + return mWebView.getScrollY(); + } + + int getWidth() { + return mWebView.getWidth(); + } + + int getHeight() { + return mWebView.getHeight(); + } + + Context getContext() { + return mContext; + } + + void invalidate() { + mWebView.invalidate(); + } + + // Setters for the Scroll X & Y, without invoking the onScrollChanged etc code paths. + void setScrollXRaw(int mScrollX) { + mWebViewPrivate.setScrollXRaw(mScrollX); + } + + void setScrollYRaw(int mScrollY) { + mWebViewPrivate.setScrollYRaw(mScrollY); + } + + // === END: WebView Proxy binding === + private static class TrustStorageListener extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -1703,7 +1642,7 @@ public class WebView extends AbsoluteLayout * receiver to ensure that only ONE receiver exists for all WebView * instances. */ - synchronized (WebView.class) { + synchronized (WebViewClassic.class) { // if the receiver already exists then we do not need to register it // again @@ -1753,30 +1692,21 @@ public class WebView extends AbsoluteLayout mZoomManager.updateMultiTouchSupport(context); } - // Setters for the Scroll X & Y, without invoking the onScrollChanged etc code paths. - final void setScrollXRaw(int scrollX) { - mScrollX = scrollX; - } - - final void setScrollYRaw(int scrollY) { - mScrollY = scrollY; - } - private void init() { - OnTrimMemoryListener.init(getContext()); + OnTrimMemoryListener.init(mContext); sDisableNavcache = nativeDisableNavcache(); - setWillNotDraw(false); - setFocusable(true); - setFocusableInTouchMode(true); - setClickable(true); - setLongClickable(true); + mWebView.setWillNotDraw(false); + mWebView.setFocusable(true); + mWebView.setFocusableInTouchMode(true); + mWebView.setClickable(true); + mWebView.setLongClickable(true); - final ViewConfiguration configuration = ViewConfiguration.get(getContext()); + final ViewConfiguration configuration = ViewConfiguration.get(mContext); int slop = configuration.getScaledTouchSlop(); mTouchSlopSquare = slop * slop; slop = configuration.getScaledDoubleTapSlop(); mDoubleTapSlopSquare = slop * slop; - final float density = getContext().getResources().getDisplayMetrics().density; + final float density = mContext.getResources().getDisplayMetrics().density; // use one line height, 16 based on our current default font, for how // far we allow a touch be away from the edge of a link mNavSlop = (int) (16 * density); @@ -1789,7 +1719,7 @@ public class WebView extends AbsoluteLayout mOverscrollDistance = configuration.getScaledOverscrollDistance(); mOverflingDistance = configuration.getScaledOverflingDistance(); - setScrollBarStyle(super.getScrollBarStyle()); + setScrollBarStyle(mWebViewPrivate.super_getScrollBarStyle()); // Initially use a size of two, since the user is likely to only hold // down two keys at a time (shift + another key) mKeysPressed = new Vector<Integer>(2); @@ -1811,11 +1741,11 @@ public class WebView extends AbsoluteLayout if (AccessibilityManager.getInstance(mContext).isEnabled() && getSettings().getJavaScriptEnabled()) { // exposing the TTS for now ... - final Context ctx = getContext(); + final Context ctx = mContext; if (ctx != null) { final String packageName = ctx.getPackageName(); if (packageName != null) { - mTextToSpeech = new TextToSpeech(getContext(), null, null, + mTextToSpeech = new TextToSpeech(ctx, null, null, packageName + ".**webview**", true); addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE); } @@ -1837,33 +1767,34 @@ public class WebView extends AbsoluteLayout @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); info.setScrollable(isScrollableForAccessibility()); } @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); event.setScrollable(isScrollableForAccessibility()); event.setScrollX(getScrollX()); event.setScrollY(getScrollY()); final int convertedContentWidth = contentToViewX(getContentWidth()); - final int adjustedViewWidth = getWidth() - mPaddingLeft - mPaddingRight; + final int adjustedViewWidth = getWidth() - mWebView.getPaddingLeft() + - mWebView.getPaddingLeft(); event.setMaxScrollX(Math.max(convertedContentWidth - adjustedViewWidth, 0)); final int convertedContentHeight = contentToViewY(getContentHeight()); - final int adjustedViewHeight = getHeight() - mPaddingTop - mPaddingBottom; + final int adjustedViewHeight = getHeight() - mWebView.getPaddingTop() + - mWebView.getPaddingBottom(); event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0)); } private boolean isScrollableForAccessibility() { - return (contentToViewX(getContentWidth()) > getWidth() - mPaddingLeft - mPaddingRight - || contentToViewY(getContentHeight()) > getHeight() - mPaddingTop - mPaddingBottom); + return (contentToViewX(getContentWidth()) > getWidth() - mWebView.getPaddingLeft() + - mWebView.getPaddingRight() + || contentToViewY(getContentHeight()) > getHeight() - mWebView.getPaddingTop() + - mWebView.getPaddingBottom()); } @Override public void setOverScrollMode(int mode) { - super.setOverScrollMode(mode); - if (mode != OVER_SCROLL_NEVER) { + if (mode != View.OVER_SCROLL_NEVER) { if (mOverScrollGlow == null) { mOverScrollGlow = new OverScrollGlow(this); } @@ -1904,7 +1835,7 @@ public class WebView extends AbsoluteLayout neverRemember.getData().putString("password", password); neverRemember.obj = resumeMsg; - new AlertDialog.Builder(getContext()) + new AlertDialog.Builder(mContext) .setTitle(com.android.internal.R.string.save_password_label) .setMessage(com.android.internal.R.string.save_password_message) .setPositiveButton(com.android.internal.R.string.save_password_notnow, @@ -1949,7 +1880,6 @@ public class WebView extends AbsoluteLayout } else { mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true; } - super.setScrollBarStyle(style); } /** @@ -1994,19 +1924,28 @@ public class WebView extends AbsoluteLayout * Note: this can be called from WebCoreThread. */ /* package */ int getViewWidth() { - if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) { + if (!mWebView.isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) { return getWidth(); } else { - return Math.max(0, getWidth() - getVerticalScrollbarWidth()); + return Math.max(0, getWidth() - mWebView.getVerticalScrollbarWidth()); } } + // Interface to enable the browser to override title bar handling. + public interface TitleBarDelegate { + int getTitleHeight(); + public void onSetEmbeddedTitleBar(final View title); + } + /** * Returns the height (in pixels) of the embedded title bar (if any). Does not care about * scrolling * @hide */ protected int getTitleHeight() { + if (mWebView instanceof TitleBarDelegate) { + return ((TitleBarDelegate) mWebView).getTitleHeight(); + } return mTitleBar != null ? mTitleBar.getHeight() : 0; } @@ -2037,7 +1976,7 @@ public class WebView extends AbsoluteLayout return 0; } if (mCachedOverlappingActionModeHeight < 0) { - getGlobalVisibleRect(mGlobalVisibleRect, mGlobalVisibleOffset); + mWebView.getGlobalVisibleRect(mGlobalVisibleRect, mGlobalVisibleOffset); mCachedOverlappingActionModeHeight = Math.max(0, mFindCallback.getActionModeGlobalBottom() - mGlobalVisibleRect.top); } @@ -2055,8 +1994,8 @@ public class WebView extends AbsoluteLayout int getViewHeightWithTitle() { int height = getHeight(); - if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) { - height -= getHorizontalScrollbarHeight(); + if (mWebView.isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) { + height -= mWebViewPrivate.getHorizontalScrollbarHeight(); } return height; } @@ -2215,7 +2154,7 @@ public class WebView extends AbsoluteLayout @Deprecated public static void enablePlatformNotifications() { checkThread(); - synchronized (WebView.class) { + synchronized (WebViewClassic.class) { sNotificationsEnabled = true; Context context = JniUtil.getContext(); if (context != null) @@ -2232,7 +2171,7 @@ public class WebView extends AbsoluteLayout @Deprecated public static void disablePlatformNotifications() { checkThread(); - synchronized (WebView.class) { + synchronized (WebViewClassic.class) { sNotificationsEnabled = false; Context context = JniUtil.getContext(); if (context != null) @@ -3268,12 +3207,15 @@ public class WebView extends AbsoluteLayout * @hide */ public void setEmbeddedTitleBar(View v) { + if (mWebView instanceof TitleBarDelegate) { + ((TitleBarDelegate) mWebView).onSetEmbeddedTitleBar(v); + } if (mTitleBar == v) return; if (mTitleBar != null) { - removeView(mTitleBar); + mWebView.removeView(mTitleBar); } if (null != v) { - addView(v, new AbsoluteLayout.LayoutParams( + mWebView.addView(v, new AbsoluteLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0)); } @@ -3387,10 +3329,10 @@ public class WebView extends AbsoluteLayout private void viewInvalidate(int l, int t, int r, int b) { final float scale = mZoomManager.getScale(); final int dy = getTitleHeight(); - invalidate((int)Math.floor(l * scale), - (int)Math.floor(t * scale) + dy, - (int)Math.ceil(r * scale), - (int)Math.ceil(b * scale) + dy); + mWebView.invalidate((int)Math.floor(l * scale), + (int)Math.floor(t * scale) + dy, + (int)Math.ceil(r * scale), + (int)Math.ceil(b * scale) + dy); } // Called by JNI to invalidate the View after a delay, given rectangle @@ -3398,11 +3340,11 @@ public class WebView extends AbsoluteLayout private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) { final float scale = mZoomManager.getScale(); final int dy = getTitleHeight(); - postInvalidateDelayed(delay, - (int)Math.floor(l * scale), - (int)Math.floor(t * scale) + dy, - (int)Math.ceil(r * scale), - (int)Math.ceil(b * scale) + dy); + mWebView.postInvalidateDelayed(delay, + (int)Math.floor(l * scale), + (int)Math.floor(t * scale) + dy, + (int)Math.ceil(r * scale), + (int)Math.ceil(b * scale) + dy); } private void invalidateContentRect(Rect r) { @@ -3467,7 +3409,7 @@ public class WebView extends AbsoluteLayout mLastVisibleRectSent.set(mVisibleRect); mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); } - if (getGlobalVisibleRect(mGlobalVisibleRect) + if (mWebView.getGlobalVisibleRect(mGlobalVisibleRect) && !mGlobalVisibleRect.equals(mLastGlobalRect)) { if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "sendOurVisibleRect=(" + mGlobalVisibleRect.left + "," @@ -3488,7 +3430,7 @@ public class WebView extends AbsoluteLayout private Point mGlobalVisibleOffset = new Point(); // Sets r to be the visible rectangle of our webview in view coordinates private void calcOurVisibleRect(Rect r) { - getGlobalVisibleRect(r, mGlobalVisibleOffset); + mWebView.getGlobalVisibleRect(r, mGlobalVisibleOffset); r.offset(-mGlobalVisibleOffset.x, -mGlobalVisibleOffset.y); } @@ -3610,7 +3552,7 @@ public class WebView extends AbsoluteLayout } @Override - protected int computeHorizontalScrollRange() { + public int computeHorizontalScrollRange() { int range = computeRealHorizontalScrollRange(); // Adjust reported range if overscrolled to compress the scroll bars @@ -3626,7 +3568,7 @@ public class WebView extends AbsoluteLayout } @Override - protected int computeHorizontalScrollOffset() { + public int computeHorizontalScrollOffset() { return Math.max(getScrollX(), 0); } @@ -3640,7 +3582,7 @@ public class WebView extends AbsoluteLayout } @Override - protected int computeVerticalScrollRange() { + public int computeVerticalScrollRange() { int range = computeRealVerticalScrollRange(); // Adjust reported range if overscrolled to compress the scroll bars @@ -3656,18 +3598,18 @@ public class WebView extends AbsoluteLayout } @Override - protected int computeVerticalScrollOffset() { + public int computeVerticalScrollOffset() { return Math.max(getScrollY() - getTitleHeight(), 0); } @Override - protected int computeVerticalScrollExtent() { + public int computeVerticalScrollExtent() { return getViewHeight(); } /** @hide */ @Override - protected void onDrawVerticalScrollBar(Canvas canvas, + public void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) { if (getScrollY() < 0) { @@ -3678,7 +3620,7 @@ public class WebView extends AbsoluteLayout } @Override - protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, + public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { // Special-case layer scrolling so that we do not trigger normal scroll // updating. @@ -3702,7 +3644,7 @@ public class WebView extends AbsoluteLayout int oldX = getScrollX(); int oldY = getScrollY(); - super.scrollTo(scrollX, scrollY); + mWebViewPrivate.super_scrollTo(scrollX, scrollY); if (mOverScrollGlow != null) { mOverScrollGlow.pullGlow(getScrollX(), getScrollY(), oldX, oldY, maxX, maxY); @@ -3847,16 +3789,15 @@ public class WebView extends AbsoluteLayout } @Override - protected void onWindowVisibilityChanged(int visibility) { - super.onWindowVisibilityChanged(visibility); + public void onWindowVisibilityChanged(int visibility) { updateDrawingState(); } void updateDrawingState() { if (mNativeClass == 0 || mIsPaused) return; - if (getWindowVisibility() != VISIBLE) { + if (mWebView.getWindowVisibility() != View.VISIBLE) { nativeSetPauseDrawing(mNativeClass, true); - } else if (getVisibility() != VISIBLE) { + } else if (mWebView.getVisibility() != View.VISIBLE) { nativeSetPauseDrawing(mNativeClass, true); } else { nativeSetPauseDrawing(mNativeClass, false); @@ -4030,7 +3971,7 @@ public class WebView extends AbsoluteLayout public boolean showFindDialog(String text, boolean showIme) { checkThread(); FindActionModeCallback callback = new FindActionModeCallback(mContext); - if (getParent() == null || startActionMode(callback) == null) { + if (mWebView.getParent() == null || mWebView.startActionMode(callback) == null) { // Could not start the action mode, so end Find on page return false; } @@ -4206,7 +4147,7 @@ public class WebView extends AbsoluteLayout overflingDistance = 0; } - overScrollBy(x - oldX, y - oldY, oldX, oldY, + mWebViewPrivate.overScrollBy(x - oldX, y - oldY, oldX, oldY, rangeX, rangeY, overflingDistance, overflingDistance, false); @@ -4234,7 +4175,7 @@ public class WebView extends AbsoluteLayout } } } else { - super.computeScroll(); + mWebViewPrivate.super_computeScroll(); } } @@ -4257,7 +4198,7 @@ public class WebView extends AbsoluteLayout mScrollingLayerRect.top = y; mWebViewCore.sendMessage(WebViewCore.EventHub.SCROLL_LAYER, mCurrentScrollingLayerId, mScrollingLayerRect); - onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY()); + mWebViewPrivate.onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY()); invalidate(); } @@ -4288,10 +4229,10 @@ public class WebView extends AbsoluteLayout // Log.d(LOGTAG, "startScroll: " + dx + " " + dy); mScroller.startScroll(getScrollX(), getScrollY(), dx, dy, animationDuration > 0 ? animationDuration : computeDuration(dx, dy)); - awakenScrollBars(mScroller.getDuration()); + mWebViewPrivate.awakenScrollBars(mScroller.getDuration()); invalidate(); } else { - scrollTo(x, y); + mWebView.scrollTo(x, y); } return true; } @@ -4314,7 +4255,7 @@ public class WebView extends AbsoluteLayout Rect tempRect = new Rect(); calcOurVisibleRect(tempRect); tempRect.offset(cx, cy); - requestRectangleOnScreen(tempRect); + mWebView.requestRectangleOnScreen(tempRect); } // FIXME: We scroll horizontally no matter what because currently // ScrollView and ListView will not scroll horizontally. @@ -4337,7 +4278,7 @@ public class WebView extends AbsoluteLayout // will reload it and get a new certificate set; // if the new site is not secure, the certificate must be // null, and that will be the case - setCertificate(null); + mWebView.setCertificate(null); // reset the flag since we set to true in if need after // loading is see onPageFinished(Url) @@ -4407,7 +4348,7 @@ public class WebView extends AbsoluteLayout if (onDeviceScriptInjectionEnabled) { ensureAccessibilityScriptInjectorInstance(false); // neither script injected nor script injection opted out => we inject - loadUrl(getScreenReaderInjectingJs()); + mWebView.loadUrl(getScreenReaderInjectingJs()); // TODO: Set this flag after successfull script injection. Maybe upon injection // the chooser should update the meta tag and we check it to declare success mAccessibilityScriptInjected = true; @@ -4421,7 +4362,7 @@ public class WebView extends AbsoluteLayout } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) { ensureAccessibilityScriptInjectorInstance(false); // the URL provides accessibility but we still need to add our generic script - loadUrl(getScreenReaderInjectingJs()); + mWebView.loadUrl(getScreenReaderInjectingJs()); } else { Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue); } @@ -4573,14 +4514,14 @@ public class WebView extends AbsoluteLayout } if (mHeightCanMeasure) { - if (getMeasuredHeight() != contentToViewDimension(mContentHeight) + if (mWebView.getMeasuredHeight() != contentToViewDimension(mContentHeight) || updateLayout) { - requestLayout(); + mWebView.requestLayout(); } } else if (mWidthCanMeasure) { - if (getMeasuredWidth() != contentToViewDimension(mContentWidth) + if (mWebView.getMeasuredWidth() != contentToViewDimension(mContentWidth) || updateLayout) { - requestLayout(); + mWebView.requestLayout(); } } else { // If we don't request a layout, try to send our view size to the @@ -4744,7 +4685,7 @@ public class WebView extends AbsoluteLayout * @return A WebSettings object that can be used to control this WebView's * settings. */ - public WebSettings getSettings() { + public WebSettingsClassic getSettings() { checkThread(); return (mWebViewCore != null) ? mWebViewCore.getSettings() : null; } @@ -4792,7 +4733,7 @@ public class WebView extends AbsoluteLayout } @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + public boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == mTitleBar) { // When drawing the title bar, move it horizontally to always show // at the top of the WebView. @@ -4806,7 +4747,7 @@ public class WebView extends AbsoluteLayout mTitleBar.setBottom(newTop + mTitleBar.getHeight()); mTitleBar.setTop(newTop); } - return super.drawChild(canvas, child, drawingTime); + return false; // We never call invalidate(), so unconditionally returning false. } private void drawContent(Canvas canvas, boolean drawRings) { @@ -4849,7 +4790,7 @@ public class WebView extends AbsoluteLayout } @Override - protected void onDraw(Canvas canvas) { + public void onDraw(Canvas canvas) { if (inFullScreenMode()) { return; // no need to draw anything if we aren't visible. } @@ -4933,10 +4874,10 @@ public class WebView extends AbsoluteLayout @Override public void setLayoutParams(ViewGroup.LayoutParams params) { - if (params.height == LayoutParams.WRAP_CONTENT) { + if (params.height == AbsoluteLayout.LayoutParams.WRAP_CONTENT) { mWrapContent = true; } - super.setLayoutParams(params); + mWebViewPrivate.super_setLayoutParams(params); } @Override @@ -4944,7 +4885,7 @@ public class WebView extends AbsoluteLayout // performLongClick() is the result of a delayed message. If we switch // to windows overview, the WebView will be temporarily removed from the // view system. In that case, do nothing. - if (getParent() == null) return false; + if (mWebView.getParent() == null) return false; // A multi-finger gesture can look like a long press; make sure we don't take // long press actions if we're scaling. @@ -4979,7 +4920,7 @@ public class WebView extends AbsoluteLayout /* if long click brings up a context menu, the super function * returns true and we're done. Otherwise, nothing happened when * the user clicked. */ - if (super.performLongClick()) { + if (mWebViewPrivate.super_performLongClick()) { return true; } /* In the case where the application hasn't already handled the long @@ -4988,12 +4929,12 @@ public class WebView extends AbsoluteLayout * FIXME: no animation code yet */ final boolean isSelecting = selectText(); if (isSelecting) { - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + mWebView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); } else if (focusCandidateIsEditableText()) { mSelectCallback = new SelectActionModeCallback(); mSelectCallback.setWebView(this); mSelectCallback.setTextSelected(false); - startActionMode(mSelectCallback); + mWebView.startActionMode(mSelectCallback); } return isSelecting; } @@ -5020,7 +4961,7 @@ public class WebView extends AbsoluteLayout private int mOrientation = Configuration.ORIENTATION_UNDEFINED; @Override - protected void onConfigurationChanged(Configuration newConfig) { + public void onConfigurationChanged(Configuration newConfig) { mCachedOverlappingActionModeHeight = -1; if (mSelectingText && mOrientation != newConfig.orientation) { selectionDone(); @@ -5131,7 +5072,7 @@ public class WebView extends AbsoluteLayout private void onZoomAnimationStart() { // If it is in password mode, turn it off so it does not draw misplaced. if (inEditingMode()) { - mWebTextView.setVisibility(INVISIBLE); + mWebTextView.setVisibility(View.INVISIBLE); } } @@ -5141,7 +5082,7 @@ public class WebView extends AbsoluteLayout && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)) { // If it is a password field, start drawing the WebTextView once // again. - mWebTextView.setVisibility(VISIBLE); + mWebTextView.setVisibility(View.VISIBLE); } } @@ -5381,7 +5322,7 @@ public class WebView extends AbsoluteLayout setScrollXRaw(pinLocX(getScrollX())); setScrollYRaw(pinLocY(getScrollY())); if (oldScrollX != getScrollX() || oldScrollY != getScrollY()) { - onScrollChanged(getScrollX(), getScrollY(), oldScrollX, oldScrollY); + mWebViewPrivate.onScrollChanged(getScrollX(), getScrollY(), oldScrollX, oldScrollY); } else { sendOurVisibleRect(); } @@ -5449,7 +5390,7 @@ public class WebView extends AbsoluteLayout */ private void displaySoftKeyboard(boolean isTextView) { InputMethodManager imm = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + mContext.getSystemService(Context.INPUT_METHOD_SERVICE); // bring it back to the default level scale so that user can enter text boolean zoom = mZoomManager.getScale() < mZoomManager.getDefaultScale(); @@ -5472,15 +5413,15 @@ public class WebView extends AbsoluteLayout // does not recognize that a textfield is in focus. In that // case, use WebView as the targeted view. // see http://b/issue?id=2457459 - imm.showSoftInput(this, 0); + imm.showSoftInput(mWebView, 0); } // Called by WebKit to instruct the UI to hide the keyboard private void hideSoftKeyboard() { InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null && (imm.isActive(this) + if (imm != null && (imm.isActive(mWebView) || (inEditingMode() && imm.isActive(mWebTextView)))) { - imm.hideSoftInputFromWindow(this.getWindowToken(), 0); + imm.hideSoftInputFromWindow(mWebView.getWindowToken(), 0); } } @@ -5494,7 +5435,7 @@ public class WebView extends AbsoluteLayout return; // always use WebKit's text entry } // If the WebView does not have focus, do nothing until it gains focus. - if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) { + if (!mWebView.hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) { return; } boolean alreadyThere = inEditingMode(); @@ -5509,7 +5450,7 @@ public class WebView extends AbsoluteLayout // At this point, we know we have found an input field, so go ahead // and create the WebTextView if necessary. if (mWebTextView == null) { - mWebTextView = new WebTextView(mContext, WebView.this, mAutoFillData.getQueryId()); + mWebTextView = new WebTextView(mContext, WebViewClassic.this, mAutoFillData.getQueryId()); // Initialize our generation number. mTextGeneration = 0; } @@ -5535,7 +5476,7 @@ public class WebView extends AbsoluteLayout imm.restartInput(mWebTextView); mWebTextView.clearComposingText(); } - if (isFocused()) { + if (mWebView.isFocused()) { mWebTextView.requestFocus(); } } @@ -5626,7 +5567,7 @@ public class WebView extends AbsoluteLayout private Message mUpdateMessage; private boolean mAutoFillable; private boolean mAutoComplete; - private WebSettings mWebSettings; + private WebSettingsClassic mWebSettings; public RequestFormData(String name, String url, Message msg, boolean autoFillable, boolean autoComplete) { @@ -5647,7 +5588,7 @@ public class WebView extends AbsoluteLayout // on the AutoFill item being at the top of the drop down list. If you change // the order, make sure to do it there too! if (mWebSettings != null && mWebSettings.getAutoFillProfile() != null) { - pastEntries.add(getResources().getText( + pastEntries.add(mWebView.getResources().getText( com.android.internal.R.string.autofill_this_form).toString() + " " + mAutoFillData.getPreviewString()); @@ -5655,7 +5596,7 @@ public class WebView extends AbsoluteLayout } else { // There is no autofill profile set up yet, so add an option that // will invite the user to set their profile up. - pastEntries.add(getResources().getText( + pastEntries.add(mWebView.getResources().getText( com.android.internal.R.string.setup_autofill).toString()); mWebTextView.setAutoFillProfileIsSet(false); } @@ -5869,7 +5810,7 @@ public class WebView extends AbsoluteLayout } } if (navHandledKey(keyCode, 1, false, event.getEventTime())) { - playSoundEffect(keyCodeToSoundsEffect(keyCode)); + mWebView.playSoundEffect(keyCodeToSoundsEffect(keyCode)); return true; } // Bubble up the key event as WebView doesn't handle it @@ -5964,7 +5905,7 @@ public class WebView extends AbsoluteLayout if (!nativeCursorIsTextInput() && text != null && text.startsWith(SCHEME_TEL)) { Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text)); - getContext().startActivity(intent); + mContext.startActivity(intent); return true; } } @@ -6035,7 +5976,7 @@ public class WebView extends AbsoluteLayout } WebViewCore.CursorData data = cursorData(); mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data); - playSoundEffect(SoundEffectConstants.CLICK); + mWebView.playSoundEffect(SoundEffectConstants.CLICK); if (nativeCursorIsTextInput()) { rebuildWebTextView(); centerKeyPressOnTextField(); @@ -6073,13 +6014,13 @@ public class WebView extends AbsoluteLayout mSelectCallback = new SelectActionModeCallback(); mSelectCallback.setTextSelected(!mIsCaretSelection); mSelectCallback.setWebView(this); - if (startActionMode(mSelectCallback) == null) { + if (mWebView.startActionMode(mSelectCallback) == null) { // There is no ActionMode, so do not allow the user to modify a // selection. selectionDone(); return false; } - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + mWebView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); return true; } @@ -6089,8 +6030,8 @@ public class WebView extends AbsoluteLayout if (cm.hasPrimaryClip()) { Rect cursorRect = contentToViewRect(mSelectCursorBase); int[] location = new int[2]; - getLocationInWindow(location); - cursorRect.offset(location[0] - mScrollX, location[1] - mScrollY); + mWebView.getLocationInWindow(location); + cursorRect.offset(location[0] - getScrollX(), location[1] - getScrollY()); if (mPasteWindow == null) { mPasteWindow = new PastePopupWindow(); } @@ -6209,7 +6150,7 @@ public class WebView extends AbsoluteLayout , com.android.internal.R.string.text_copied , Toast.LENGTH_SHORT).show(); copiedSomething = true; - ClipboardManager cm = (ClipboardManager)getContext() + ClipboardManager cm = (ClipboardManager)mContext .getSystemService(Context.CLIPBOARD_SERVICE); cm.setText(selection); int[] handles = new int[4]; @@ -6238,7 +6179,7 @@ public class WebView extends AbsoluteLayout * @hide This is an implementation detail */ public void pasteFromClipboard() { - ClipboardManager cm = (ClipboardManager)getContext() + ClipboardManager cm = (ClipboardManager)mContext .getSystemService(Context.CLIPBOARD_SERVICE); ClipData clipData = cm.getPrimaryClip(); if (clipData != null) { @@ -6269,10 +6210,9 @@ public class WebView extends AbsoluteLayout } @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (hasWindowFocus()) setActive(true); - final ViewTreeObserver treeObserver = getViewTreeObserver(); + public void onAttachedToWindow() { + if (mWebView.hasWindowFocus()) setActive(true); + final ViewTreeObserver treeObserver = mWebView.getViewTreeObserver(); if (mGlobalLayoutListener == null) { mGlobalLayoutListener = new InnerGlobalLayoutListener(); treeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener); @@ -6288,12 +6228,12 @@ public class WebView extends AbsoluteLayout } @Override - protected void onDetachedFromWindow() { + public void onDetachedFromWindow() { clearHelpers(); mZoomManager.dismissZoomPicker(); - if (hasWindowFocus()) setActive(false); + if (mWebView.hasWindowFocus()) setActive(false); - final ViewTreeObserver treeObserver = getViewTreeObserver(); + final ViewTreeObserver treeObserver = mWebView.getViewTreeObserver(); if (mGlobalLayoutListener != null) { treeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener); mGlobalLayoutListener = null; @@ -6304,13 +6244,10 @@ public class WebView extends AbsoluteLayout } removeAccessibilityApisFromJavaScript(); - - super.onDetachedFromWindow(); } @Override - protected void onVisibilityChanged(View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); + public void onVisibilityChanged(View changedView, int visibility) { // The zoomManager may be null if the webview is created from XML that // specifies the view's visibility param as not visible (see http://b/2794841) if (visibility != View.VISIBLE && mZoomManager != null) { @@ -6319,37 +6256,9 @@ public class WebView extends AbsoluteLayout updateDrawingState(); } - /** - * @deprecated WebView no longer needs to implement - * ViewGroup.OnHierarchyChangeListener. This method does nothing now. - */ - @Override - // Cannot add @hide as this can always be accessed via the interface. - @Deprecated - public void onChildViewAdded(View parent, View child) {} - - /** - * @deprecated WebView no longer needs to implement - * ViewGroup.OnHierarchyChangeListener. This method does nothing now. - */ - @Override - // Cannot add @hide as this can always be accessed via the interface. - @Deprecated - public void onChildViewRemoved(View p, View child) {} - - /** - * @deprecated WebView should not have implemented - * ViewTreeObserver.OnGlobalFocusChangeListener. This method does nothing now. - */ - @Override - // Cannot add @hide as this can always be accessed via the interface. - @Deprecated - public void onGlobalFocusChanged(View oldFocus, View newFocus) { - } - void setActive(boolean active) { if (active) { - if (hasFocus()) { + if (mWebView.hasFocus()) { // If our window regained focus, and we have focus, then begin // drawing the cursor ring mDrawCursorRing = !inEditingMode(); @@ -6404,7 +6313,6 @@ public class WebView extends AbsoluteLayout mPictureUpdatePausedForFocusChange = true; } } - super.onWindowFocusChanged(hasWindowFocus); } /* @@ -6424,7 +6332,7 @@ public class WebView extends AbsoluteLayout } @Override - protected void onFocusChanged(boolean focused, int direction, + public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction); @@ -6432,7 +6340,7 @@ public class WebView extends AbsoluteLayout if (focused) { // When we regain focus, if we have window focus, resume drawing // the cursor ring - if (hasWindowFocus()) { + if (mWebView.hasWindowFocus()) { mDrawCursorRing = !inEditingMode(); setFocusControllerActive(true); //} else { @@ -6449,18 +6357,16 @@ public class WebView extends AbsoluteLayout } mKeysPressed.clear(); } - - super.onFocusChanged(focused, direction, previouslyFocusedRect); } void setGLRectViewport() { // Use the getGlobalVisibleRect() to get the intersection among the parents // visible == false means we're clipped - send a null rect down to indicate that // we should not draw - boolean visible = getGlobalVisibleRect(mGLRectViewport); + boolean visible = mWebView.getGlobalVisibleRect(mGLRectViewport); if (visible) { // Then need to invert the Y axis, just for GL - View rootView = getRootView(); + View rootView = mWebView.getRootView(); int rootViewHeight = rootView.getHeight(); mViewRectViewport.set(mGLRectViewport); int savedWebViewBottom = mGLRectViewport.bottom; @@ -6480,8 +6386,8 @@ public class WebView extends AbsoluteLayout * @hide */ @Override - protected boolean setFrame(int left, int top, int right, int bottom) { - boolean changed = super.setFrame(left, top, right, bottom); + public boolean setFrame(int left, int top, int right, int bottom) { + boolean changed = mWebViewPrivate.super_setFrame(left, top, right, bottom); if (!changed && mHeightCanMeasure) { // When mHeightCanMeasure is true, we will set mLastHeightSent to 0 // in WebViewCore after we get the first layout. We do call @@ -6496,9 +6402,7 @@ public class WebView extends AbsoluteLayout } @Override - protected void onSizeChanged(int w, int h, int ow, int oh) { - super.onSizeChanged(w, h, ow, oh); - + public void onSizeChanged(int w, int h, int ow, int oh) { // adjust the max viewport width depending on the view dimensions. This // is to ensure the scaling is not going insane. So do not shrink it if // the view size is temporarily smaller, e.g. when soft keyboard is up. @@ -6518,8 +6422,7 @@ public class WebView extends AbsoluteLayout } @Override - protected void onScrollChanged(int l, int t, int oldl, int oldt) { - super.onScrollChanged(l, t, oldl, oldt); + public void onScrollChanged(int l, int t, int oldl, int oldt) { if (!mInOverScrollMode) { sendOurVisibleRect(); // update WebKit if visible title bar height changed. The logic is same @@ -6562,7 +6465,7 @@ public class WebView extends AbsoluteLayout // not currently have a bounds. return mWebTextView.dispatchKeyEvent(event); } else { - return super.dispatchKeyEvent(event); + return mWebViewPrivate.super_dispatchKeyEvent(event); } } @@ -6674,7 +6577,7 @@ public class WebView extends AbsoluteLayout @Override public boolean onTouchEvent(MotionEvent ev) { - if (mNativeClass == 0 || (!isClickable() && !isLongClickable())) { + if (mNativeClass == 0 || (!mWebView.isClickable() && !mWebView.isLongClickable())) { return false; } @@ -6894,7 +6797,7 @@ public class WebView extends AbsoluteLayout if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "extend=" + contentX + "," + contentY); } - ViewParent parent = getParent(); + ViewParent parent = mWebView.getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } @@ -7062,7 +6965,7 @@ public class WebView extends AbsoluteLayout invalidate(); } // keep the scrollbar on the screen even there is no scroll - awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(), + mWebViewPrivate.awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(), false); // Post a message so that we'll keep them alive while we're not scrolling. mPrivateHandler.sendMessageDelayed(mPrivateHandler @@ -7077,7 +6980,7 @@ public class WebView extends AbsoluteLayout break; } case MotionEvent.ACTION_UP: { - if (!isFocused()) requestFocus(); + if (!mWebView.isFocused()) mWebView.requestFocus(); // pass the touch events from UI thread to WebCore thread if (shouldForwardTouchEvent()) { TouchEventData ted = new TouchEventData(); @@ -7268,7 +7171,7 @@ public class WebView extends AbsoluteLayout ted.mSequence = sequence; mTouchEventQueue.preQueueTouchEventData(ted); mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); - cancelLongPress(); + mWebView.cancelLongPress(); mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); } @@ -7301,7 +7204,7 @@ public class WebView extends AbsoluteLayout x = detector.getFocusX(); y = detector.getFocusY(); - cancelLongPress(); + mWebView.cancelLongPress(); mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); if (!mZoomManager.supportsPanDuringZoom()) { return; @@ -7433,7 +7336,7 @@ public class WebView extends AbsoluteLayout mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY); } - overScrollBy(deltaX, deltaY, oldX, oldY, + mWebViewPrivate.overScrollBy(deltaX, deltaY, oldX, oldY, rangeX, rangeY, mOverscrollDistance, mOverscrollDistance, true); if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) { @@ -7517,8 +7420,10 @@ public class WebView extends AbsoluteLayout hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL); } if (hscroll != 0 || vscroll != 0) { - final int vdelta = (int) (vscroll * getVerticalScrollFactor()); - final int hdelta = (int) (hscroll * getHorizontalScrollFactor()); + final int vdelta = (int) (vscroll * + mWebViewPrivate.getVerticalScrollFactor()); + final int hdelta = (int) (hscroll * + mWebViewPrivate.getHorizontalScrollFactor()); if (pinScrollBy(hdelta, vdelta, false, 0)) { return true; } @@ -7526,7 +7431,7 @@ public class WebView extends AbsoluteLayout } } } - return super.onGenericMotionEvent(event); + return mWebViewPrivate.super_onGenericMotionEvent(event); } private long mTrackballFirstTime = 0; @@ -7596,7 +7501,7 @@ public class WebView extends AbsoluteLayout + " time=" + time + " mLastCursorTime=" + mLastCursorTime); } - if (isInTouchMode()) requestFocusFromTouch(); + if (mWebView.isInTouchMode()) mWebView.requestFocusFromTouch(); return false; // let common code in onKeyDown at it } if (ev.getAction() == MotionEvent.ACTION_UP) { @@ -7740,7 +7645,7 @@ public class WebView extends AbsoluteLayout } letPageHandleNavKey(selectKeyCode, time, false, metaState); } else if (navHandledKey(selectKeyCode, count, false, time)) { - playSoundEffect(keyCodeToSoundsEffect(selectKeyCode)); + mWebView.playSoundEffect(keyCodeToSoundsEffect(selectKeyCode)); } mTrackballRemainsX = mTrackballRemainsY = 0; } @@ -7790,7 +7695,7 @@ public class WebView extends AbsoluteLayout setScrollXRaw(x); setScrollYRaw(y); if (oldX != getScrollX() || oldY != getScrollY()) { - onScrollChanged(getScrollX(), getScrollY(), oldX, oldY); + mWebViewPrivate.onScrollChanged(getScrollX(), getScrollY(), oldX, oldY); return true; } else { return false; @@ -7908,7 +7813,7 @@ public class WebView extends AbsoluteLayout // Suppress scrollbars for layer scrolling. if (mTouchMode != TOUCH_DRAG_LAYER_MODE) { - awakenScrollBars(time); + mWebViewPrivate.awakenScrollBars(time); } invalidate(); @@ -8104,7 +8009,7 @@ public class WebView extends AbsoluteLayout // set mTouchHighlightRequested to 0 to cause an immediate // drawing of the touch rings mTouchHighlightRequested = 0; - invalidate(mTouchHighlightRegion.getBounds()); + mWebView.invalidate(mTouchHighlightRegion.getBounds()); mPrivateHandler.postDelayed(new Runnable() { @Override public void run() { @@ -8113,7 +8018,7 @@ public class WebView extends AbsoluteLayout }, ViewConfiguration.getPressedStateDuration()); } if (mFocusedNode != null && mFocusedNode.mIntentUrl != null) { - playSoundEffect(SoundEffectConstants.CLICK); + mWebView.playSoundEffect(SoundEffectConstants.CLICK); overrideLoading(mFocusedNode.mIntentUrl); } else if (sDisableNavcache) { WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData(); @@ -8142,7 +8047,7 @@ public class WebView extends AbsoluteLayout EventLog.writeEvent(EventLogTags.BROWSER_SNAP_CENTER); } if (nativeHasCursorNode() && !nativeCursorIsTextInput()) { - playSoundEffect(SoundEffectConstants.CLICK); + mWebView.playSoundEffect(SoundEffectConstants.CLICK); } } @@ -8250,8 +8155,8 @@ public class WebView extends AbsoluteLayout result = mWebTextView.requestFocus(direction, previouslyFocusedRect); } else { - result = super.requestFocus(direction, previouslyFocusedRect); - if (mWebViewCore.getSettings().getNeedInitialFocus() && !isInTouchMode()) { + result = mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect); + if (mWebViewCore.getSettings().getNeedInitialFocus() && !mWebView.isInTouchMode()) { // For cases such as GMail, where we gain focus from a direction, // we want to move to the first available link. // FIXME: If there are no visible links, we may not want to @@ -8281,9 +8186,7 @@ public class WebView extends AbsoluteLayout } @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); @@ -8307,7 +8210,7 @@ public class WebView extends AbsoluteLayout if (measuredHeight > heightSize) { measuredHeight = heightSize; mHeightCanMeasure = false; - measuredHeight |= MEASURED_STATE_TOO_SMALL; + measuredHeight |= View.MEASURED_STATE_TOO_SMALL; } } } else { @@ -8322,13 +8225,13 @@ public class WebView extends AbsoluteLayout measuredWidth = contentWidth; } else { if (measuredWidth < contentWidth) { - measuredWidth |= MEASURED_STATE_TOO_SMALL; + measuredWidth |= View.MEASURED_STATE_TOO_SMALL; } mWidthCanMeasure = false; } synchronized (this) { - setMeasuredDimension(measuredWidth, measuredHeight); + mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight); } } @@ -8351,7 +8254,7 @@ public class WebView extends AbsoluteLayout Rect content = new Rect(viewToContentX(getScrollX()), viewToContentY(getScrollY()), viewToContentX(getScrollX() + getWidth() - - getVerticalScrollbarWidth()), + - mWebView.getVerticalScrollbarWidth()), viewToContentY(getScrollY() + getViewHeightWithTitle())); content = nativeSubtractLayers(content); int screenTop = contentToViewY(content.top); @@ -8901,7 +8804,7 @@ public class WebView extends AbsoluteLayout break; case WebViewCore.ACTION_LONGPRESS: HitTestResult hitTest = getHitTestResult(); - if (hitTest != null && hitTest.mType + if (hitTest != null && hitTest.getType() != HitTestResult.UNKNOWN_TYPE) { performLongClick(); } @@ -9059,7 +8962,7 @@ public class WebView extends AbsoluteLayout // view, but is only necessary if the IME is showing InputMethodManager imm = InputMethodManager.peekInstance(); if (imm == null || !imm.isAcceptingText() - || (!imm.isActive(WebView.this) && (!inEditingMode() + || (!imm.isActive(mWebView) && (!inEditingMode() || !imm.isActive(mWebTextView)))) { break; } @@ -9226,7 +9129,7 @@ public class WebView extends AbsoluteLayout case AWAKEN_SCROLL_BARS: if (mTouchMode == TOUCH_DRAG_MODE && mHeldMotionless == MOTIONLESS_TRUE) { - awakenScrollBars(ViewConfiguration + mWebViewPrivate.awakenScrollBars(ViewConfiguration .getScrollDefaultDelay(), false); mPrivateHandler.sendMessageDelayed(mPrivateHandler .obtainMessage(AWAKEN_SCROLL_BARS), @@ -9239,7 +9142,7 @@ public class WebView extends AbsoluteLayout break; case SCREEN_ON: - setKeepScreenOn(msg.arg1 == 1); + mWebView.setKeepScreenOn(msg.arg1 == 1); break; case ENTER_FULLSCREEN_VIDEO: @@ -9266,7 +9169,7 @@ public class WebView extends AbsoluteLayout Log.w(LOGTAG, "Should not have another full screen."); dismissFullScreenMode(); } - mFullScreenHolder = new PluginFullScreenHolder(WebView.this, orientation, npp); + mFullScreenHolder = new PluginFullScreenHolder(WebViewClassic.this, orientation, npp); mFullScreenHolder.setContentView(view); mFullScreenHolder.show(); invalidate(); @@ -9329,7 +9232,7 @@ public class WebView extends AbsoluteLayout // We need to take into account the visible title height // when scrolling since y is an absolute view position. y = Math.max(0, y - getVisibleTitleHeightImpl()); - scrollTo(x, y); + mWebView.scrollTo(x, y); } break; @@ -9432,24 +9335,24 @@ public class WebView extends AbsoluteLayout private void setHitTestTypeFromUrl(String url) { String substr = null; if (url.startsWith(SCHEME_GEO)) { - mInitialHitTestResult.mType = HitTestResult.GEO_TYPE; + mInitialHitTestResult.setType(HitTestResult.GEO_TYPE); substr = url.substring(SCHEME_GEO.length()); } else if (url.startsWith(SCHEME_TEL)) { - mInitialHitTestResult.mType = HitTestResult.PHONE_TYPE; + mInitialHitTestResult.setType(HitTestResult.PHONE_TYPE); substr = url.substring(SCHEME_TEL.length()); } else if (url.startsWith(SCHEME_MAILTO)) { - mInitialHitTestResult.mType = HitTestResult.EMAIL_TYPE; + mInitialHitTestResult.setType(HitTestResult.EMAIL_TYPE); substr = url.substring(SCHEME_MAILTO.length()); } else { - mInitialHitTestResult.mType = HitTestResult.SRC_ANCHOR_TYPE; - mInitialHitTestResult.mExtra = url; + mInitialHitTestResult.setType(HitTestResult.SRC_ANCHOR_TYPE); + mInitialHitTestResult.setExtra(url); return; } try { - mInitialHitTestResult.mExtra = URLDecoder.decode(substr, "UTF-8"); + mInitialHitTestResult.setExtra(URLDecoder.decode(substr, "UTF-8")); } catch (Throwable e) { Log.w(LOGTAG, "Failed to decode URL! " + substr, e); - mInitialHitTestResult.mType = HitTestResult.UNKNOWN_TYPE; + mInitialHitTestResult.setType(HitTestResult.UNKNOWN_TYPE); } } @@ -9462,15 +9365,15 @@ public class WebView extends AbsoluteLayout if (hit.mLinkUrl != null) { setHitTestTypeFromUrl(hit.mLinkUrl); if (hit.mImageUrl != null - && mInitialHitTestResult.mType == HitTestResult.SRC_ANCHOR_TYPE) { - mInitialHitTestResult.mType = HitTestResult.SRC_IMAGE_ANCHOR_TYPE; - mInitialHitTestResult.mExtra = hit.mImageUrl; + && mInitialHitTestResult.getType() == HitTestResult.SRC_ANCHOR_TYPE) { + mInitialHitTestResult.setType(HitTestResult.SRC_IMAGE_ANCHOR_TYPE); + mInitialHitTestResult.setExtra(hit.mImageUrl); } } else if (hit.mImageUrl != null) { - mInitialHitTestResult.mType = HitTestResult.IMAGE_TYPE; - mInitialHitTestResult.mExtra = hit.mImageUrl; + mInitialHitTestResult.setType(HitTestResult.IMAGE_TYPE); + mInitialHitTestResult.setExtra(hit.mImageUrl); } else if (hit.mEditable) { - mInitialHitTestResult.mType = HitTestResult.EDIT_TEXT_TYPE; + mInitialHitTestResult.setType(HitTestResult.EDIT_TEXT_TYPE); } else if (hit.mIntentUrl != null) { setHitTestTypeFromUrl(hit.mIntentUrl); } @@ -9483,16 +9386,16 @@ public class WebView extends AbsoluteLayout if (mTouchHighlightRegion.isEmpty()) { return false; } - if (mFocusedNode.mHasFocus && !isInTouchMode()) { + if (mFocusedNode.mHasFocus && !mWebView.isInTouchMode()) { return !mFocusedNode.mEditable; } - if (mInitialHitTestResult.mType == HitTestResult.UNKNOWN_TYPE) { + if (mInitialHitTestResult.getType() == HitTestResult.UNKNOWN_TYPE) { return false; } long delay = System.currentTimeMillis() - mTouchHighlightRequested; if (delay < ViewConfiguration.getTapTimeout()) { Rect r = mTouchHighlightRegion.getBounds(); - postInvalidateDelayed(delay, r.left, r.top, r.right, r.bottom); + mWebView.postInvalidateDelayed(delay, r.left, r.top, r.right, r.bottom); return false; } return true; @@ -9504,12 +9407,12 @@ public class WebView extends AbsoluteLayout Region mPreviousRegion; Region mNewRegion; float mProgress = 0; - WebView mWebView; + WebViewClassic mWebView; Paint mPaint; int mMaxAlpha; Point mTranslate; - public FocusTransitionDrawable(WebView view) { + public FocusTransitionDrawable(WebViewClassic view) { mWebView = view; mPaint = new Paint(mWebView.mTouchHightlightPaint); mMaxAlpha = mPaint.getAlpha(); @@ -9588,7 +9491,7 @@ public class WebView extends AbsoluteLayout } Rect[] rects = hit != null ? hit.mTouchRects : null; if (!mTouchHighlightRegion.isEmpty()) { - invalidate(mTouchHighlightRegion.getBounds()); + mWebView.invalidate(mTouchHighlightRegion.getBounds()); if (transition != null) { transition.mPreviousRegion = new Region(mTouchHighlightRegion); } @@ -9610,7 +9513,7 @@ public class WebView extends AbsoluteLayout + viewRect); } } - invalidate(mTouchHighlightRegion.getBounds()); + mWebView.invalidate(mTouchHighlightRegion.getBounds()); if (transition != null && transition.mPreviousRegion != null) { transition.mNewRegion = new Region(mTouchHighlightRegion); mFocusTransition = transition; @@ -9621,6 +9524,11 @@ public class WebView extends AbsoluteLayout } } + // Interface to allow the profiled WebView to hook the page swap notifications. + public interface PageSwapDelegate { + void onPageSwapOccurred(boolean notifyAnimationStarted); + } + /** @hide Called by JNI when pages are swapped (only occurs with hardware * acceleration) */ protected void pageSwapCallback(boolean notifyAnimationStarted) { @@ -9631,6 +9539,10 @@ public class WebView extends AbsoluteLayout if (notifyAnimationStarted) { mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED); } + if (mWebView instanceof PageSwapDelegate) { + // This provides a hook for ProfiledWebView to observe the tile page swaps. + ((PageSwapDelegate) mWebView).onPageSwapOccurred(notifyAnimationStarted); + } } void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) { @@ -9690,7 +9602,7 @@ public class WebView extends AbsoluteLayout invalidateContentRect(draw.mInvalRegion.getBounds()); if (mPictureListener != null) { - mPictureListener.onNewPicture(WebView.this, capturePicture()); + mPictureListener.onNewPicture(getWebView(), capturePicture()); } // update the zoom information based on the new picture @@ -9778,7 +9690,7 @@ public class WebView extends AbsoluteLayout */ private class MyArrayListAdapter extends ArrayAdapter<Container> { public MyArrayListAdapter() { - super(mContext, + super(WebViewClassic.this.mContext, mMultiple ? com.android.internal.R.layout.select_dialog_multichoice : com.android.internal.R.layout.webview_select_singlechoice, mContainers); @@ -10146,7 +10058,7 @@ public class WebView extends AbsoluteLayout if (down) { keyEventAction = KeyEvent.ACTION_DOWN; eventHubAction = EventHub.KEY_DOWN; - playSoundEffect(keyCodeToSoundsEffect(keyCode)); + mWebView.playSoundEffect(keyCodeToSoundsEffect(keyCode)); } else { keyEventAction = KeyEvent.ACTION_UP; eventHubAction = EventHub.KEY_UP; @@ -10217,7 +10129,7 @@ public class WebView extends AbsoluteLayout Log.v(LOGTAG, "navHandledKey contentCursorRingBounds=" + contentCursorRingBounds); } - requestRectangleOnScreen(viewCursorRingBounds); + mWebView.requestRectangleOnScreen(viewCursorRingBounds); return keyHandled; } @@ -10289,7 +10201,7 @@ public class WebView extends AbsoluteLayout * @param text The text to put into the clipboard. */ private void copyToClipboard(String text) { - ClipboardManager cm = (ClipboardManager)getContext() + ClipboardManager cm = (ClipboardManager)mContext .getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText(getTitle(), text); cm.setPrimaryClip(clip); @@ -10333,8 +10245,8 @@ public class WebView extends AbsoluteLayout } } - /** @hide discard all textures from tiles */ - protected void discardAllTextures() { + /** @hide discard all textures from tiles. Used in Profiled WebView */ + public void discardAllTextures() { nativeDiscardAllTextures(); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 93fd92b..4bda5ef 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -39,7 +39,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceView; import android.view.View; -import android.webkit.WebView.FocusNodeHref; +import android.webkit.WebViewClassic.FocusNodeHref; import junit.framework.Assert; @@ -72,11 +72,12 @@ public final class WebViewCore { */ // The WebView that corresponds to this WebViewCore. - private WebView mWebView; + // TODO: rename this field (and its getter) to mWebViewClassic or mWebViewImpl. + private WebViewClassic mWebView; // Proxy for handling callbacks from native code private final CallbackProxy mCallbackProxy; // Settings object for maintaining all settings - private final WebSettings mSettings; + private final WebSettingsClassic mSettings; // Context for initializing the BrowserFrame with the proper assets. private final Context mContext; // The pointer to a native view object. @@ -142,7 +143,7 @@ public final class WebViewCore { // debugging other classes that require operation within the WebCore thread. /* package */ static final String THREAD_NAME = "WebViewCoreThread"; - public WebViewCore(Context context, WebView w, CallbackProxy proxy, + public WebViewCore(Context context, WebViewClassic w, CallbackProxy proxy, Map<String, Object> javascriptInterfaces) { // No need to assign this in the WebCore thread. mCallbackProxy = proxy; @@ -179,7 +180,7 @@ public final class WebViewCore { // ready. mEventHub = new EventHub(); // Create a WebSettings object for maintaining all settings - mSettings = new WebSettings(mContext, mWebView); + mSettings = new WebSettingsClassic(mContext, mWebView); // The WebIconDatabase needs to be initialized within the UI thread so // just request the instance here. WebIconDatabase.getInstance(); @@ -234,7 +235,7 @@ public final class WebViewCore { // WebCore thread. if (mWebView != null) { Message.obtain(mWebView.mPrivateHandler, - WebView.WEBCORE_INITIALIZED_MSG_ID, + WebViewClassic.WEBCORE_INITIALIZED_MSG_ID, mNativeClass, 0).sendToTarget(); } @@ -284,7 +285,7 @@ public final class WebViewCore { BrowserFrame.sJavaBridge.resume(); } - public WebSettings getSettings() { + public WebSettingsClassic getSettings() { return mSettings; } @@ -329,7 +330,7 @@ public final class WebViewCore { */ private void formDidBlur(int nodePointer) { if (mWebView == null) return; - Message.obtain(mWebView.mPrivateHandler, WebView.FORM_DID_BLUR, + Message.obtain(mWebView.mPrivateHandler, WebViewClassic.FORM_DID_BLUR, nodePointer, 0).sendToTarget(); } @@ -338,7 +339,7 @@ public final class WebViewCore { */ private void focusNodeChanged(WebKitHitTest hitTest) { if (mWebView == null) return; - mWebView.mPrivateHandler.obtainMessage(WebView.HIT_TEST_RESULT, hitTest) + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.HIT_TEST_RESULT, hitTest) .sendToTarget(); } @@ -508,7 +509,7 @@ public final class WebViewCore { protected void enterFullscreenForVideoLayer(int layerId, String url) { if (mWebView == null) return; Message message = Message.obtain(mWebView.mPrivateHandler, - WebView.ENTER_FULLSCREEN_VIDEO, layerId, 0); + WebViewClassic.ENTER_FULLSCREEN_VIDEO, layerId, 0); message.obj = url; message.sendToTarget(); } @@ -520,7 +521,7 @@ public final class WebViewCore { protected void exitFullscreenVideo() { if (mWebView == null) return; Message message = Message.obtain(mWebView.mPrivateHandler, - WebView.EXIT_FULLSCREEN_VIDEO); + WebViewClassic.EXIT_FULLSCREEN_VIDEO); message.sendToTarget(); } @@ -886,7 +887,7 @@ public final class WebViewCore { String mTitle; Rect[] mTouchRects; boolean mEditable; - int mTapHighlightColor = WebView.HIGHLIGHT_COLOR; + int mTapHighlightColor = WebViewClassic.HIGHLIGHT_COLOR; Rect[] mEnclosingParentRects; boolean mHasFocus; @@ -1270,7 +1271,7 @@ public final class WebViewCore { msg.arg1, nodePointer); if (label != null && label.length() > 0) { Message.obtain(mWebView.mPrivateHandler, - WebView.RETURN_LABEL, nodePointer, + WebViewClassic.RETURN_LABEL, nodePointer, 0, label).sendToTarget(); } } @@ -1373,7 +1374,7 @@ public final class WebViewCore { break; case VIEW_SIZE_CHANGED: { - viewSizeChanged((WebView.ViewSizeData) msg.obj); + viewSizeChanged((WebViewClassic.ViewSizeData) msg.obj); break; } case SET_SCROLL_OFFSET: @@ -1529,7 +1530,7 @@ public final class WebViewCore { ted.mMetaState); Message.obtain( mWebView.mPrivateHandler, - WebView.PREVENT_TOUCH_ID, + WebViewClassic.PREVENT_TOUCH_ID, ted.mAction, ted.mNativeResult ? 1 : 0, ted).sendToTarget(); @@ -1594,7 +1595,7 @@ public final class WebViewCore { nativeUpdateFrameCache(mNativeClass); // FIXME: this should provide a minimal rectangle if (mWebView != null) { - mWebView.postInvalidate(); + mWebView.getWebView().postInvalidate(); } sendUpdateTextEntry(); break; @@ -1621,7 +1622,8 @@ public final class WebViewCore { String modifiedSelectionString = nativeModifySelection(mNativeClass, msg.arg1, msg.arg2); - mWebView.mPrivateHandler.obtainMessage(WebView.SELECTION_STRING_CHANGED, + mWebView.mPrivateHandler.obtainMessage( + WebViewClassic.SELECTION_STRING_CHANGED, modifiedSelectionString).sendToTarget(); break; @@ -1666,12 +1668,12 @@ public final class WebViewCore { break; case SAVE_WEBARCHIVE: - WebView.SaveWebArchiveMessage saveMessage = - (WebView.SaveWebArchiveMessage)msg.obj; + WebViewClassic.SaveWebArchiveMessage saveMessage = + (WebViewClassic.SaveWebArchiveMessage)msg.obj; saveMessage.mResultFile = saveWebArchive(saveMessage.mBasename, saveMessage.mAutoname); mWebView.mPrivateHandler.obtainMessage( - WebView.SAVE_WEBARCHIVE_FINISHED, saveMessage).sendToTarget(); + WebViewClassic.SAVE_WEBARCHIVE_FINISHED, saveMessage).sendToTarget(); break; case GEOLOCATION_PERMISSIONS_PROVIDE: @@ -1684,7 +1686,7 @@ public final class WebViewCore { case SPLIT_PICTURE_SET: nativeSplitContent(mNativeClass, msg.arg1); mWebView.mPrivateHandler.obtainMessage( - WebView.REPLACE_BASE_CONTENT, msg.arg1, 0); + WebViewClassic.REPLACE_BASE_CONTENT, msg.arg1, 0); mSplitPictureIsScheduled = false; break; @@ -1711,7 +1713,7 @@ public final class WebViewCore { nativeUpdateFrameCache(mNativeClass); } Message message = mWebView.mPrivateHandler - .obtainMessage(WebView.DO_MOTION_UP, + .obtainMessage(WebViewClassic.DO_MOTION_UP, motionUpData.mX, motionUpData.mY); mWebView.mPrivateHandler.sendMessageAtFrontOfQueue( message); @@ -1747,7 +1749,7 @@ public final class WebViewCore { } WebKitHitTest hit = performHitTest(d.mX, d.mY, d.mSlop, true); mWebView.mPrivateHandler.obtainMessage( - WebView.HIT_TEST_RESULT, hit) + WebViewClassic.HIT_TEST_RESULT, hit) .sendToTarget(); break; @@ -1757,7 +1759,7 @@ public final class WebViewCore { case AUTOFILL_FORM: nativeAutoFillForm(mNativeClass, msg.arg1); - mWebView.mPrivateHandler.obtainMessage(WebView.AUTOFILL_COMPLETE, null) + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.AUTOFILL_COMPLETE, null) .sendToTarget(); break; @@ -1788,7 +1790,7 @@ public final class WebViewCore { handles[0], handles[1], handles[2], handles[3]); if (copiedText != null) { - mWebView.mPrivateHandler.obtainMessage(WebView.COPY_TO_CLIPBOARD, copiedText) + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.COPY_TO_CLIPBOARD, copiedText) .sendToTarget(); } break; @@ -2058,7 +2060,7 @@ public final class WebViewCore { } if (mWebView != null && evt.isDown()) { Message.obtain(mWebView.mPrivateHandler, - WebView.UNHANDLED_NAV_KEY, keyCode, + WebViewClassic.UNHANDLED_NAV_KEY, keyCode, 0).sendToTarget(); } return; @@ -2081,7 +2083,7 @@ public final class WebViewCore { private float mCurrentViewScale = 1.0f; // notify webkit that our virtual view size changed size (after inv-zoom) - private void viewSizeChanged(WebView.ViewSizeData data) { + private void viewSizeChanged(WebViewClassic.ViewSizeData data) { int w = data.mWidth; int h = data.mHeight; int textwrapWidth = data.mTextWrapWidth; @@ -2125,7 +2127,7 @@ public final class WebViewCore { if (mSettings.getUseWideViewPort()) { if (mViewportWidth == -1) { // Fixed viewport width. - width = WebView.DEFAULT_VIEWPORT_WIDTH; + width = WebViewClassic.DEFAULT_VIEWPORT_WIDTH; } else if (mViewportWidth > 0) { // Use website specified or desired fixed viewport width. width = mViewportWidth; @@ -2140,7 +2142,7 @@ public final class WebViewCore { private void sendUpdateTextEntry() { if (mWebView != null) { Message.obtain(mWebView.mPrivateHandler, - WebView.UPDATE_TEXT_ENTRY_MSG_ID).sendToTarget(); + WebViewClassic.UPDATE_TEXT_ENTRY_MSG_ID).sendToTarget(); } } @@ -2230,9 +2232,9 @@ public final class WebViewCore { // If anything more complex than position has been touched, let's do a full draw webkitDraw(); } - mWebView.mPrivateHandler.removeMessages(WebView.INVAL_RECT_MSG_ID); + mWebView.mPrivateHandler.removeMessages(WebViewClassic.INVAL_RECT_MSG_ID); mWebView.mPrivateHandler.sendMessageAtFrontOfQueue(mWebView.mPrivateHandler - .obtainMessage(WebView.INVAL_RECT_MSG_ID)); + .obtainMessage(WebViewClassic.INVAL_RECT_MSG_ID)); } private Boolean m_skipDrawFlag = false; @@ -2289,7 +2291,7 @@ public final class WebViewCore { draw.mViewSize = new Point(mCurrentViewWidth, mCurrentViewHeight); if (mSettings.getUseWideViewPort()) { draw.mMinPrefWidth = Math.max( - mViewportWidth == -1 ? WebView.DEFAULT_VIEWPORT_WIDTH + mViewportWidth == -1 ? WebViewClassic.DEFAULT_VIEWPORT_WIDTH : (mViewportWidth == 0 ? mCurrentViewWidth : mViewportWidth), nativeGetContentMinPrefWidth(mNativeClass)); @@ -2304,7 +2306,7 @@ public final class WebViewCore { } if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID"); Message.obtain(mWebView.mPrivateHandler, - WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget(); + WebViewClassic.NEW_PICTURE_MSG_ID, draw).sendToTarget(); } } @@ -2433,7 +2435,7 @@ public final class WebViewCore { } if (mWebView != null) { Message msg = Message.obtain(mWebView.mPrivateHandler, - WebView.SCROLL_TO_MSG_ID, animate ? 1 : 0, + WebViewClassic.SCROLL_TO_MSG_ID, animate ? 1 : 0, onlyIfImeIsShowing ? 1 : 0, new Point(x, y)); if (mDrawIsScheduled) { mEventHub.sendMessage(Message.obtain(null, @@ -2457,7 +2459,7 @@ public final class WebViewCore { private void sendViewInvalidate(int left, int top, int right, int bottom) { if (mWebView != null) { Message.obtain(mWebView.mPrivateHandler, - WebView.INVAL_RECT_MSG_ID, + WebViewClassic.INVAL_RECT_MSG_ID, new Rect(left, top, right, bottom)).sendToTarget(); } } @@ -2473,7 +2475,7 @@ public final class WebViewCore { // Gets the WebView corresponding to this WebViewCore. Note that the // WebView object must only be used on the UI thread. - /* package */ WebView getWebView() { + /* package */ WebViewClassic getWebView() { return mWebView; } @@ -2499,9 +2501,9 @@ public final class WebViewCore { } // remove the touch highlight when moving to a new page - if (WebView.sDisableNavcache) { + if (WebViewClassic.sDisableNavcache) { mWebView.mPrivateHandler.sendEmptyMessage( - WebView.HIT_TEST_RESULT); + WebViewClassic.HIT_TEST_RESULT); } // reset the scroll position, the restored offset and scales @@ -2567,7 +2569,7 @@ public final class WebViewCore { } if (adjust != mWebView.getDefaultZoomScale()) { Message.obtain(mWebView.mPrivateHandler, - WebView.UPDATE_ZOOM_DENSITY, adjust).sendToTarget(); + WebViewClassic.UPDATE_ZOOM_DENSITY, adjust).sendToTarget(); } int defaultScale = (int) (adjust * 100); @@ -2618,7 +2620,7 @@ public final class WebViewCore { viewState.mScrollX = 0; viewState.mShouldStartScrolledRight = false; Message.obtain(mWebView.mPrivateHandler, - WebView.UPDATE_ZOOM_RANGE, viewState).sendToTarget(); + WebViewClassic.UPDATE_ZOOM_RANGE, viewState).sendToTarget(); return; } @@ -2689,7 +2691,7 @@ public final class WebViewCore { mWebView.mLastHeightSent = 0; // Send a negative scale to indicate that WebCore should reuse // the current scale - WebView.ViewSizeData data = new WebView.ViewSizeData(); + WebViewClassic.ViewSizeData data = new WebViewClassic.ViewSizeData(); data.mWidth = mWebView.mLastWidthSent; data.mHeight = 0; // if mHeightCanMeasure is true, getUseWideViewPort() can't be @@ -2713,7 +2715,7 @@ public final class WebViewCore { // to WebViewCore mWebView.mLastWidthSent = 0; } else { - WebView.ViewSizeData data = new WebView.ViewSizeData(); + WebViewClassic.ViewSizeData data = new WebViewClassic.ViewSizeData(); // mViewScale as 0 means it is in zoom overview mode. So we don't // know the exact scale. If mRestoredScale is non-zero, use it; // otherwise just use mTextWrapScale as the initial scale. @@ -2791,7 +2793,7 @@ public final class WebViewCore { private void needTouchEvents(boolean need) { if (mWebView != null) { Message.obtain(mWebView.mPrivateHandler, - WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0) + WebViewClassic.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0) .sendToTarget(); } } @@ -2801,7 +2803,7 @@ public final class WebViewCore { String text, int textGeneration) { if (mWebView != null) { Message msg = Message.obtain(mWebView.mPrivateHandler, - WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr, + WebViewClassic.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr, textGeneration, text); msg.getData().putBoolean("password", changeToPassword); msg.sendToTarget(); @@ -2813,7 +2815,7 @@ public final class WebViewCore { int textGeneration, int selectionPtr) { if (mWebView != null) { Message.obtain(mWebView.mPrivateHandler, - WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration, + WebViewClassic.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration, new TextSelectionData(start, end, selectionPtr)).sendToTarget(); } } @@ -2822,7 +2824,7 @@ public final class WebViewCore { private void clearTextEntry() { if (mWebView == null) return; Message.obtain(mWebView.mPrivateHandler, - WebView.CLEAR_TEXT_ENTRY).sendToTarget(); + WebViewClassic.CLEAR_TEXT_ENTRY).sendToTarget(); } // called by JNI @@ -2836,9 +2838,9 @@ public final class WebViewCore { text, inputType, isSpellCheckEnabled, nextFieldIsText, label, maxLength); Message.obtain(mWebView.mPrivateHandler, - WebView.INIT_EDIT_FIELD, initData).sendToTarget(); + WebViewClassic.INIT_EDIT_FIELD, initData).sendToTarget(); Message.obtain(mWebView.mPrivateHandler, - WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer, + WebViewClassic.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer, 0, new TextSelectionData(start, end, selectionPtr)) .sendToTarget(); } @@ -2850,7 +2852,7 @@ public final class WebViewCore { return; } Message.obtain(mWebView.mPrivateHandler, - WebView.UPDATE_MATCH_COUNT, matchIndex, matchCount, + WebViewClassic.UPDATE_MATCH_COUNT, matchIndex, matchCount, findText).sendToTarget(); } @@ -2892,14 +2894,14 @@ public final class WebViewCore { private void requestKeyboard(boolean showKeyboard) { if (mWebView != null) { Message.obtain(mWebView.mPrivateHandler, - WebView.REQUEST_KEYBOARD, showKeyboard ? 1 : 0, 0) + WebViewClassic.REQUEST_KEYBOARD, showKeyboard ? 1 : 0, 0) .sendToTarget(); } } private void setWebTextViewAutoFillable(int queryId, String preview) { if (mWebView != null) { - Message.obtain(mWebView.mPrivateHandler, WebView.SET_AUTOFILLABLE, + Message.obtain(mWebView.mPrivateHandler, WebViewClassic.SET_AUTOFILLABLE, new AutoFillData(queryId, preview)) .sendToTarget(); } @@ -2912,7 +2914,7 @@ public final class WebViewCore { // called by JNI private void keepScreenOn(boolean screenOn) { if (mWebView != null) { - Message message = mWebView.mPrivateHandler.obtainMessage(WebView.SCREEN_ON); + Message message = mWebView.mPrivateHandler.obtainMessage(WebViewClassic.SCREEN_ON); message.arg1 = screenOn ? 1 : 0; message.sendToTarget(); } @@ -2952,7 +2954,7 @@ public final class WebViewCore { return; } - Message message = mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN); + Message message = mWebView.mPrivateHandler.obtainMessage(WebViewClassic.SHOW_FULLSCREEN); message.obj = childView.mView; message.arg1 = orientation; message.arg2 = npp; @@ -2964,7 +2966,7 @@ public final class WebViewCore { if (mWebView == null) { return; } - mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN) + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.HIDE_FULLSCREEN) .sendToTarget(); } @@ -3036,7 +3038,7 @@ public final class WebViewCore { data.mXPercentInView = xPercentInView; data.mYPercentInDoc = yPercentInDoc; data.mYPercentInView = yPercentInView; - Message.obtain(mWebView.mPrivateHandler, WebView.SHOW_RECT_MSG_ID, + Message.obtain(mWebView.mPrivateHandler, WebViewClassic.SHOW_RECT_MSG_ID, data).sendToTarget(); } } @@ -3046,7 +3048,7 @@ public final class WebViewCore { if (mWebView == null) { return; } - mWebView.mPrivateHandler.obtainMessage(WebView.CENTER_FIT_RECT, + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.CENTER_FIT_RECT, new Rect(x, y, x + width, y + height)).sendToTarget(); } @@ -3055,7 +3057,7 @@ public final class WebViewCore { if (mWebView == null) { return; } - mWebView.mPrivateHandler.obtainMessage(WebView.SET_SCROLLBAR_MODES, + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.SET_SCROLLBAR_MODES, hMode, vMode).sendToTarget(); } @@ -3063,7 +3065,7 @@ public final class WebViewCore { @SuppressWarnings("unused") private void selectAt(int x, int y) { if (mWebView != null) { - mWebView.mPrivateHandler.obtainMessage(WebView.SELECT_AT, x, y).sendToTarget(); + mWebView.mPrivateHandler.obtainMessage(WebViewClassic.SELECT_AT, x, y).sendToTarget(); } } diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java new file mode 100644 index 0000000..22bf0bf --- /dev/null +++ b/core/java/android/webkit/WebViewFactoryProvider.java @@ -0,0 +1,56 @@ +/* + * 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 android.webkit; + +/** + * This is the main entry-point into the WebView back end implementations, which the WebView + * proxy class uses to instantiate all the other objects as needed. The backend must provide an + * implementation of this interface, and make it available to the WebView via mechanism TBD. + * @hide + */ +public interface WebViewFactoryProvider { + + /** + * Construct a new WebView provider. + * @param webView the WebView instance bound to this implementation instance. Note it will not + * necessarily be fully constructed at the point of this call: defer real initialization to + * WebViewProvider.init(). + * @param privateAccess provides access into WebView internal methods. + */ + WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess); + + Statics getStatics(); + + /** + * This Interface provides glue for implementing the backend of WebView static methods which + * cannot be implemented in-situ in the proxy class. + */ + interface Statics { + /** + * Implements the API method: + * {@link android.webkit.WebView#findAddress(String)} + */ + String findAddress(String addr); + + /** + * Implements the API methods: + * {@link android.webkit.WebView#enablePlatformNotifications()} + * {@link android.webkit.WebView#disablePlatformNotifications()} + */ + void setPlatformNotificationsEnabled(boolean enable); + } +} diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java new file mode 100644 index 0000000..2e8ad6d --- /dev/null +++ b/core/java/android/webkit/WebViewProvider.java @@ -0,0 +1,372 @@ +/* + * 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 android.webkit; + +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Picture; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.net.http.SslCertificate; +import android.os.Bundle; +import android.os.Message; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.webkit.WebView.HitTestResult; +import android.webkit.WebView.PictureListener; + +import java.io.File; +import java.util.Map; + +/** + * WebView backend provider interface: this interface is the abstract backend to a WebView + * instance; each WebView object is bound to exactly one WebViewProvider object which implements + * the runtime behavior of that WebView. + * + * All methods must behave as per their namesake in {@link WebView}, unless otherwise noted. + * + * @hide Not part of the public API; only required by system implementors. + */ +public interface WebViewProvider { + //------------------------------------------------------------------------- + // Main interface for backend provider of the WebView class. + //------------------------------------------------------------------------- + /** + * Initialize this WebViewProvider instance. Called after the WebView has fully constructed. + * @param javaScriptInterfaces is a Map of interface names, as keys, and + * object implementing those interfaces, as values. + * @param privateBrowsing If true the web view will be initialized in private / incognito mode. + */ + public void init(Map<String, Object> javaScriptInterfaces, + boolean privateBrowsing); + + public void setHorizontalScrollbarOverlay(boolean overlay); + + public void setVerticalScrollbarOverlay(boolean overlay); + + public boolean overlayHorizontalScrollbar(); + + public boolean overlayVerticalScrollbar(); + + public int getVisibleTitleHeight(); + + public SslCertificate getCertificate(); + + public void setCertificate(SslCertificate certificate); + + public void savePassword(String host, String username, String password); + + public void setHttpAuthUsernamePassword(String host, String realm, + String username, String password); + + public String[] getHttpAuthUsernamePassword(String host, String realm); + + /** + * See {@link WebView#destroy()}. + * As well as releasing the internal state and resources held by the implementation, + * the provider should null all references it holds on the WebView proxy class, and ensure + * no further method calls are made to it. + */ + public void destroy(); + + public void setNetworkAvailable(boolean networkUp); + + public WebBackForwardList saveState(Bundle outState); + + public boolean savePicture(Bundle b, final File dest); + + public boolean restorePicture(Bundle b, File src); + + public WebBackForwardList restoreState(Bundle inState); + + public void loadUrl(String url, Map<String, String> additionalHttpHeaders); + + public void loadUrl(String url); + + public void postUrl(String url, byte[] postData); + + public void loadData(String data, String mimeType, String encoding); + + public void loadDataWithBaseURL(String baseUrl, String data, + String mimeType, String encoding, String historyUrl); + + public void saveWebArchive(String filename); + + public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback); + + public void stopLoading(); + + public void reload(); + + public boolean canGoBack(); + + public void goBack(); + + public boolean canGoForward(); + + public void goForward(); + + public boolean canGoBackOrForward(int steps); + + public void goBackOrForward(int steps); + + public boolean isPrivateBrowsingEnabled(); + + public boolean pageUp(boolean top); + + public boolean pageDown(boolean bottom); + + public void clearView(); + + public Picture capturePicture(); + + public float getScale(); + + public void setInitialScale(int scaleInPercent); + + public void invokeZoomPicker(); + + public HitTestResult getHitTestResult(); + + public void requestFocusNodeHref(Message hrefMsg); + + public void requestImageRef(Message msg); + + public String getUrl(); + + public String getOriginalUrl(); + + public String getTitle(); + + public Bitmap getFavicon(); + + public String getTouchIconUrl(); + + public int getProgress(); + + public int getContentHeight(); + + public int getContentWidth(); + + public void pauseTimers(); + + public void resumeTimers(); + + public void onPause(); + + public void onResume(); + + public boolean isPaused(); + + public void freeMemory(); + + public void clearCache(boolean includeDiskFiles); + + public void clearFormData(); + + public void clearHistory(); + + public void clearSslPreferences(); + + public WebBackForwardList copyBackForwardList(); + + public void findNext(boolean forward); + + public int findAll(String find); + + public boolean showFindDialog(String text, boolean showIme); + + public void clearMatches(); + + public void documentHasImages(Message response); + + public void setWebViewClient(WebViewClient client); + + public void setDownloadListener(DownloadListener listener); + + public void setWebChromeClient(WebChromeClient client); + + public void setPictureListener(PictureListener listener); + + public void addJavascriptInterface(Object obj, String interfaceName); + + public void removeJavascriptInterface(String interfaceName); + + public WebSettings getSettings(); + + public void emulateShiftHeld(); + + public void setMapTrackballToArrowKeys(boolean setMap); + + public void flingScroll(int vx, int vy); + + public View getZoomControls(); + + public boolean canZoomIn(); + + public boolean canZoomOut(); + + public boolean zoomIn(); + + public boolean zoomOut(); + + public void debugDump(); + + //------------------------------------------------------------------------- + // Provider glue methods + //------------------------------------------------------------------------- + + /** + * @return the ViewDelegate implementation. This provides the functionality to back all of + * the name-sake functions from the View and ViewGroup base classes of WebView. + */ + /* package */ ViewDelegate getViewDelegate(); + + /** + * @return a ScrollDelegate implementation. Normally this would be same object as is + * returned by getViewDelegate(). + */ + /* package */ ScrollDelegate getScrollDelegate(); + + //------------------------------------------------------------------------- + // View / ViewGroup delegation methods + //------------------------------------------------------------------------- + + /** + * Provides mechanism for the name-sake methods declared in View and ViewGroup to be delegated + * into the WebViewProvider instance. + * NOTE For many of these methods, the WebView will provide a super.Foo() call before or after + * making the call into the provider instance. This is done for convenience in the common case + * of maintaining backward compatibility. For remaining super class calls (e.g. where the + * provider may need to only conditionally make the call based on some internal state) see the + * {@link WebView.PrivateAccess} callback class. + */ + // TODO: See if the pattern of the super-class calls can be rationalized at all, and document + // the remainder on the methods below. + interface ViewDelegate { + public boolean shouldDelayChildPressedState(); + + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info); + + public void onInitializeAccessibilityEvent(AccessibilityEvent event); + + public void setOverScrollMode(int mode); + + public void setScrollBarStyle(int style); + + public void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, + int r, int b); + + public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY); + + public void onWindowVisibilityChanged(int visibility); + + public boolean drawChild(Canvas canvas, View child, long drawingTime); + + public void onDraw(Canvas canvas); + + public void setLayoutParams(LayoutParams layoutParams); + + public boolean performLongClick(); + + public void onConfigurationChanged(Configuration newConfig); + + public InputConnection onCreateInputConnection(EditorInfo outAttrs); + + public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event); + + public boolean onKeyDown(int keyCode, KeyEvent event); + + public boolean onKeyUp(int keyCode, KeyEvent event); + + public void onAttachedToWindow(); + + public void onDetachedFromWindow(); + + public void onVisibilityChanged(View changedView, int visibility); + + public void onWindowFocusChanged(boolean hasWindowFocus); + + public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect); + + public boolean setFrame(int left, int top, int right, int bottom); + + public void onSizeChanged(int w, int h, int ow, int oh); + + public void onScrollChanged(int l, int t, int oldl, int oldt); + + public boolean dispatchKeyEvent(KeyEvent event); + + public boolean onTouchEvent(MotionEvent ev); + + public boolean onHoverEvent(MotionEvent event); + + public boolean onGenericMotionEvent(MotionEvent event); + + public boolean onTrackballEvent(MotionEvent ev); + + public boolean requestFocus(int direction, Rect previouslyFocusedRect); + + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec); + + public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate); + + public void setBackgroundColor(int color); + } + + interface ScrollDelegate { + // These methods are declared protected in the ViewGroup base class. This interface + // exists to promote them to public so they may be called by the WebView proxy class. + // TODO: Combine into ViewDelegate? + /** + * See {@link android.webkit.WebView#computeHorizontalScrollRange} + */ + public int computeHorizontalScrollRange(); + + /** + * See {@link android.webkit.WebView#computeHorizontalScrollOffset} + */ + public int computeHorizontalScrollOffset(); + + /** + * See {@link android.webkit.WebView#computeVerticalScrollRange} + */ + public int computeVerticalScrollRange(); + + /** + * See {@link android.webkit.WebView#computeVerticalScrollOffset} + */ + public int computeVerticalScrollOffset(); + + /** + * See {@link android.webkit.WebView#computeVerticalScrollExtent} + */ + public int computeVerticalScrollExtent(); + + /** + * See {@link android.webkit.WebView#computeScroll} + */ + public void computeScroll(); + } +} diff --git a/core/java/android/webkit/ZoomControlEmbedded.java b/core/java/android/webkit/ZoomControlEmbedded.java index e505614..d2a0561 100644 --- a/core/java/android/webkit/ZoomControlEmbedded.java +++ b/core/java/android/webkit/ZoomControlEmbedded.java @@ -25,12 +25,12 @@ import android.widget.ZoomButtonsController; class ZoomControlEmbedded implements ZoomControlBase { private final ZoomManager mZoomManager; - private final WebView mWebView; + private final WebViewClassic mWebView; // The controller is lazily initialized in getControls() for performance. private ZoomButtonsController mZoomButtonsController; - public ZoomControlEmbedded(ZoomManager zoomManager, WebView webView) { + public ZoomControlEmbedded(ZoomManager zoomManager, WebViewClassic webView) { mZoomManager = zoomManager; mWebView = webView; } @@ -41,7 +41,7 @@ class ZoomControlEmbedded implements ZoomControlBase { mZoomButtonsController.setVisible(true); if (mZoomManager.isDoubleTapEnabled()) { - WebSettings settings = mWebView.getSettings(); + WebSettingsClassic settings = mWebView.getSettings(); int count = settings.getDoubleTapToastCount(); if (mZoomManager.isInZoomOverview() && count > 0) { settings.setDoubleTapToastCount(--count); @@ -82,7 +82,7 @@ class ZoomControlEmbedded implements ZoomControlBase { private ZoomButtonsController getControls() { if (mZoomButtonsController == null) { - mZoomButtonsController = new ZoomButtonsController(mWebView); + mZoomButtonsController = new ZoomButtonsController(mWebView.getWebView()); mZoomButtonsController.setOnZoomListener(new ZoomListener()); // ZoomButtonsController positions the buttons at the bottom, but in // the middle. Change their layout parameters so they appear on the diff --git a/core/java/android/webkit/ZoomControlExternal.java b/core/java/android/webkit/ZoomControlExternal.java index d75313e..f5bfc05 100644 --- a/core/java/android/webkit/ZoomControlExternal.java +++ b/core/java/android/webkit/ZoomControlExternal.java @@ -35,9 +35,9 @@ class ZoomControlExternal implements ZoomControlBase { private Runnable mZoomControlRunnable; private final Handler mPrivateHandler = new Handler(); - private final WebView mWebView; + private final WebViewClassic mWebView; - public ZoomControlExternal(WebView webView) { + public ZoomControlExternal(WebViewClassic webView) { mWebView = webView; } diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 369e883..e7b049e 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -50,7 +50,7 @@ class ZoomManager { static final String LOGTAG = "webviewZoom"; - private final WebView mWebView; + private final WebViewClassic mWebView; private final CallbackProxy mCallbackProxy; // Widgets responsible for the on-screen zoom functions of the WebView. @@ -211,7 +211,7 @@ class ZoomManager { private boolean mHardwareAccelerated = false; private boolean mInHWAcceleratedZoom = false; - public ZoomManager(WebView webView, CallbackProxy callbackProxy) { + public ZoomManager(WebViewClassic webView, CallbackProxy callbackProxy) { mWebView = webView; mCallbackProxy = callbackProxy; @@ -220,7 +220,7 @@ class ZoomManager { * ESPN and Engadget always have wider mContentWidth no matter what the * viewport size is. */ - setZoomOverviewWidth(WebView.DEFAULT_VIEWPORT_WIDTH); + setZoomOverviewWidth(WebViewClassic.DEFAULT_VIEWPORT_WIDTH); mFocusMovementQueue = new FocusMovementQueue(); } @@ -487,13 +487,13 @@ class ZoomManager { // zoomScale, we can't use the WebView's pinLocX/Y functions directly. float scale = zoomScale * mInvInitialZoomScale; int tx = Math.round(scale * (mInitialScrollX + mZoomCenterX) - mZoomCenterX); - tx = -WebView.pinLoc(tx, mWebView.getViewWidth(), Math.round(mWebView.getContentWidth() + tx = -WebViewClassic.pinLoc(tx, mWebView.getViewWidth(), Math.round(mWebView.getContentWidth() * zoomScale)) + mWebView.getScrollX(); int titleHeight = mWebView.getTitleHeight(); int ty = Math.round(scale * (mInitialScrollY + mZoomCenterY - titleHeight) - (mZoomCenterY - titleHeight)); - ty = -(ty <= titleHeight ? Math.max(ty, 0) : WebView.pinLoc(ty + ty = -(ty <= titleHeight ? Math.max(ty, 0) : WebViewClassic.pinLoc(ty - titleHeight, mWebView.getViewHeight(), Math.round(mWebView.getContentHeight() * zoomScale)) + titleHeight) + mWebView.getScrollY(); @@ -630,7 +630,7 @@ class ZoomManager { public void handleDoubleTap(float lastTouchX, float lastTouchY) { // User takes action, set initial zoom overview to false. mInitialZoomOverview = false; - WebSettings settings = mWebView.getSettings(); + WebSettingsClassic settings = mWebView.getSettings(); if (!isDoubleTapEnabled()) { return; } @@ -690,7 +690,7 @@ class ZoomManager { private void setZoomOverviewWidth(int width) { if (width == 0) { - mZoomOverviewWidth = WebView.DEFAULT_VIEWPORT_WIDTH; + mZoomOverviewWidth = WebViewClassic.DEFAULT_VIEWPORT_WIDTH; } else { mZoomOverviewWidth = width; } @@ -719,7 +719,7 @@ class ZoomManager { final float readingScale = getReadingLevelScale(); int left = mWebView.getBlockLeftEdge(mAnchorX, mAnchorY, readingScale); - if (left != WebView.NO_LEFTEDGE) { + if (left != WebViewClassic.NO_LEFTEDGE) { // add a 5pt padding to the left edge. int viewLeft = mWebView.contentToViewX(left < 5 ? 0 : (left - 5)) - mWebView.getScrollX(); @@ -728,7 +728,7 @@ class ZoomManager { if (viewLeft > 0) { mZoomCenterX = viewLeft * readingScale / (readingScale - mActualScale); } else { - mWebView.scrollBy(viewLeft, 0); + mWebView.getWebView().scrollBy(viewLeft, 0); mZoomCenterX = 0; } } @@ -955,7 +955,7 @@ class ZoomManager { // cause its child View to reposition itself through ViewManager's // scaleAll(), we need to post a Runnable to ensure requestLayout(). // Additionally, only update the text wrap scale if the width changed. - mWebView.post(new PostScale(w != ow && + mWebView.getWebView().post(new PostScale(w != ow && !mWebView.getSettings().getUseFixedViewport(), mInZoomOverview, w < ow)); } @@ -1027,7 +1027,7 @@ class ZoomManager { final int viewWidth = mWebView.getViewWidth(); final boolean zoomOverviewWidthChanged = setupZoomOverviewWidth(drawData, viewWidth); final float newZoomOverviewScale = getZoomOverviewScale(); - WebSettings settings = mWebView.getSettings(); + WebSettingsClassic settings = mWebView.getSettings(); if (zoomOverviewWidthChanged && settings.isNarrowColumnLayout() && settings.getUseFixedViewport() && (mInitialZoomOverview || mInZoomOverview)) { @@ -1085,7 +1085,7 @@ class ZoomManager { if (drawData.mContentSize.x > 0) { // The webkitDraw for layers will not populate contentSize, and it'll be // ignored for zoom overview width update. - newZoomOverviewWidth = Math.min(WebView.sMaxViewportWidth, + newZoomOverviewWidth = Math.min(WebViewClassic.sMaxViewportWidth, drawData.mContentSize.x); } } else { @@ -1117,7 +1117,7 @@ class ZoomManager { updateZoomRange(viewState, viewSize.x, drawData.mMinPrefWidth); setupZoomOverviewWidth(drawData, mWebView.getViewWidth()); final float overviewScale = getZoomOverviewScale(); - WebSettings settings = mWebView.getSettings(); + WebSettingsClassic settings = mWebView.getSettings(); if (!mMinZoomScaleFixed || settings.getUseWideViewPort()) { mMinZoomScale = (mInitialScale > 0) ? Math.min(mInitialScale, overviewScale) : overviewScale; diff --git a/core/tests/coretests/src/android/webkit/ZoomManagerTest.java b/core/tests/coretests/src/android/webkit/ZoomManagerTest.java index 1c9defe..7e0e0b2 100644 --- a/core/tests/coretests/src/android/webkit/ZoomManagerTest.java +++ b/core/tests/coretests/src/android/webkit/ZoomManagerTest.java @@ -24,8 +24,9 @@ public class ZoomManagerTest extends AndroidTestCase { @Override public void setUp() { WebView webView = new WebView(this.getContext()); - CallbackProxy callbackProxy = new CallbackProxy(this.getContext(), webView); - zoomManager = new ZoomManager(webView, callbackProxy); + WebViewClassic webViewClassic = WebViewClassic.fromWebView(webView); + CallbackProxy callbackProxy = new CallbackProxy(this.getContext(), webViewClassic); + zoomManager = new ZoomManager(webViewClassic, callbackProxy); zoomManager.init(1.00f); } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 83c9c3d..856ebcc 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -45,8 +45,10 @@ import android.webkit.JsResult; import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebSettings; +import android.webkit.WebSettingsClassic; import android.webkit.WebStorage; import android.webkit.WebView; +import android.webkit.WebViewClassic; import android.webkit.WebViewClient; import android.widget.LinearLayout; @@ -112,10 +114,10 @@ public class TestShellActivity extends Activity implements LayoutTestController case DUMP_AS_TEXT: callback.arg1 = mDumpTopFrameAsText ? 1 : 0; callback.arg2 = mDumpChildFramesAsText ? 1 : 0; - mWebView.documentAsText(callback); + mWebViewClassic.documentAsText(callback); break; case EXT_REPR: - mWebView.externalRepresentation(callback); + mWebViewClassic.externalRepresentation(callback); break; default: finished(); @@ -144,6 +146,7 @@ public class TestShellActivity extends Activity implements LayoutTestController CookieManager.setAcceptFileSchemeCookies(true); mWebView = new WebView(this); + mWebViewClassic = WebViewClassic.fromWebView(mWebView); mEventSender = new WebViewEventSender(mWebView); mCallbackProxy = new CallbackProxy(mEventSender, this); @@ -158,7 +161,7 @@ public class TestShellActivity extends Activity implements LayoutTestController // Expose window.gc function to JavaScript. JSC build exposes // this function by default, but V8 requires the flag to turn it on. // WebView::setJsFlags is noop in JSC build. - mWebView.setJsFlags("--expose_gc"); + mWebViewClassic.setJsFlags("--expose_gc"); mHandler = new AsyncHandler(); @@ -168,7 +171,7 @@ public class TestShellActivity extends Activity implements LayoutTestController } // This is asynchronous, but it gets processed by WebCore before it starts loading pages. - mWebView.useMockDeviceOrientation(); + mWebViewClassic.useMockDeviceOrientation(); } @Override @@ -290,6 +293,7 @@ public class TestShellActivity extends Activity implements LayoutTestController super.onDestroy(); mWebView.destroy(); mWebView = null; + mWebViewClassic = null; } @Override @@ -531,8 +535,8 @@ public class TestShellActivity extends Activity implements LayoutTestController public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha, boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) { - mWebView.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, - canProvideGamma, gamma); + WebViewClassic.fromWebView(mWebView).setMockDeviceOrientation(canProvideAlpha, alpha, + canProvideBeta, beta, canProvideGamma, gamma); } public void overridePreference(String key, boolean value) { @@ -541,10 +545,10 @@ public class TestShellActivity extends Activity implements LayoutTestController // WebView for the main frame. EventSender suffers from the same // problem. if (WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED.equals(key)) { - mWebView.getSettings().setAppCacheEnabled(value); + mWebViewClassic.getSettings().setAppCacheEnabled(value); } else if (WEBKIT_USES_PAGE_CACHE_PREFERENCE_KEY.equals(key)) { // Cache the maximum possible number of pages. - mWebView.getSettings().setPageCacheCapacity(Integer.MAX_VALUE); + mWebViewClassic.getSettings().setPageCacheCapacity(Integer.MAX_VALUE); } else { Log.w(LOGTAG, "LayoutTestController.overridePreference(): " + "Unsupported preference '" + key + "'"); @@ -552,7 +556,7 @@ public class TestShellActivity extends Activity implements LayoutTestController } public void setXSSAuditorEnabled (boolean flag) { - mWebView.getSettings().setXSSAuditorEnabled(flag); + mWebViewClassic.getSettings().setXSSAuditorEnabled(flag); } private final WebViewClient mViewClient = new WebViewClient(){ @@ -855,7 +859,7 @@ public class TestShellActivity extends Activity implements LayoutTestController Bitmap bitmap = Bitmap.createBitmap(view.getContentWidth(), view.getContentHeight(), Config.ARGB_8888); canvas.setBitmap(bitmap); - view.drawPage(canvas); + WebViewClassic.fromWebView(view).drawPage(canvas); try { FileOutputStream fos = new FileOutputStream(fileName); if(!bitmap.compress(CompressFormat.PNG, 90, fos)) { @@ -885,11 +889,11 @@ public class TestShellActivity extends Activity implements LayoutTestController // single event rather than a stream of events (like what would generally happen in // a real use of touch events in a WebView) and so if the WebView drops the event, // the test will fail as the test expects one callback for every touch it synthesizes. - webview.setTouchInterval(-1); + WebViewClassic.fromWebView(webview).setTouchInterval(-1); } public void setDefaultWebSettings(WebView webview) { - WebSettings settings = webview.getSettings(); + WebSettingsClassic settings = WebViewClassic.fromWebView(webview).getSettings(); settings.setAppCacheEnabled(true); settings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); settings.setAppCacheMaxSize(Long.MAX_VALUE); @@ -906,6 +910,7 @@ public class TestShellActivity extends Activity implements LayoutTestController settings.setProperty("use_minimal_memory", "false"); } + private WebViewClassic mWebViewClassic; private WebView mWebView; private WebViewEventSender mEventSender; private AsyncHandler mHandler; diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java index f59da37..fc22472 100644 --- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java @@ -41,9 +41,11 @@ import android.webkit.JsResult; import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebSettings; +import android.webkit.WebSettingsClassic; import android.webkit.WebStorage; import android.webkit.WebStorage.QuotaUpdater; import android.webkit.WebView; +import android.webkit.WebViewClassic; import android.webkit.WebViewClient; import java.lang.Thread.UncaughtExceptionHandler; @@ -369,11 +371,12 @@ public class LayoutTestsExecutor extends Activity { * a real use of touch events in a WebView) and so if the WebView drops the event, * the test will fail as the test expects one callback for every touch it synthesizes. */ - webView.setTouchInterval(-1); + WebViewClassic webViewClassic = WebViewClassic.fromWebView(webView); + webViewClassic.setTouchInterval(-1); - webView.clearCache(true); + webViewClassic.clearCache(true); - WebSettings webViewSettings = webView.getSettings(); + WebSettingsClassic webViewSettings = webViewClassic.getSettings(); webViewSettings.setAppCacheEnabled(true); webViewSettings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); // Use of larger values causes unexplained AppCache database corruption. @@ -391,7 +394,7 @@ public class LayoutTestsExecutor extends Activity { webViewSettings.setPageCacheCapacity(0); // This is asynchronous, but it gets processed by WebCore before it starts loading pages. - mCurrentWebView.useMockDeviceOrientation(); + WebViewClassic.fromWebView(mCurrentWebView).useMockDeviceOrientation(); // Must do this after setting the AppCache path. WebStorage.getInstance().deleteAllData(); @@ -625,10 +628,12 @@ public class LayoutTestsExecutor extends Activity { String key = msg.getData().getString("key"); boolean value = msg.getData().getBoolean("value"); if (WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED.equals(key)) { - mCurrentWebView.getSettings().setAppCacheEnabled(value); + WebViewClassic.fromWebView(mCurrentWebView).getSettings(). + setAppCacheEnabled(value); } else if (WEBKIT_USES_PAGE_CACHE_PREFERENCE_KEY.equals(key)) { // Cache the maximum possible number of pages. - mCurrentWebView.getSettings().setPageCacheCapacity(Integer.MAX_VALUE); + WebViewClassic.fromWebView(mCurrentWebView).getSettings(). + setPageCacheCapacity(Integer.MAX_VALUE); } else { Log.w(LOG_TAG, "LayoutTestController.overridePreference(): " + "Unsupported preference '" + key + "'"); @@ -656,7 +661,8 @@ public class LayoutTestsExecutor extends Activity { break; case MSG_SET_XSS_AUDITOR_ENABLED: - mCurrentWebView.getSettings().setXSSAuditorEnabled(msg.arg1 == 1); + WebViewClassic.fromWebView(mCurrentWebView).getSettings(). + setXSSAuditorEnabled(msg.arg1 == 1); break; case MSG_WAIT_UNTIL_DONE: @@ -728,8 +734,8 @@ public class LayoutTestsExecutor extends Activity { Log.i(LOG_TAG, mCurrentTestRelativePath + ": setMockDeviceOrientation(" + canProvideAlpha + ", " + alpha + ", " + canProvideBeta + ", " + beta + ", " + canProvideGamma + ", " + gamma + ")"); - mCurrentWebView.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, - canProvideGamma, gamma); + WebViewClassic.fromWebView(mCurrentWebView).setMockDeviceOrientation(canProvideAlpha, + alpha, canProvideBeta, beta, canProvideGamma, gamma); } public void setXSSAuditorEnabled(boolean flag) { diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java index 3d2b98b..fd1c0ad 100644 --- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java @@ -20,6 +20,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.webkit.WebView; +import android.webkit.WebViewClassic; import name.fraser.neil.plaintext.diff_match_patch; @@ -233,7 +234,7 @@ public class TextResult extends AbstractResult { */ msg.arg1 = 1; msg.arg2 = mDumpChildFramesAsText ? 1 : 0; - webview.documentAsText(msg); + WebViewClassic.fromWebView(webview).documentAsText(msg); } @Override diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java index a38ac25..87baf76 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java @@ -20,8 +20,9 @@ import android.content.Context; import android.os.CountDownTimer; import android.util.AttributeSet; import android.util.Log; -import android.webkit.WebSettings; +import android.webkit.WebSettingsClassic; import android.webkit.WebView; +import android.webkit.WebViewClassic; import android.widget.Toast; import java.util.ArrayList; @@ -29,7 +30,7 @@ import java.util.ArrayList; import com.test.tilebenchmark.ProfileActivity.ProfileCallback; import com.test.tilebenchmark.RunData.TileData; -public class ProfiledWebView extends WebView { +public class ProfiledWebView extends WebView implements WebViewClassic.PageSwapDelegate { private static final String LOGTAG = "ProfiledWebView"; private int mSpeed; @@ -80,7 +81,7 @@ public class ProfiledWebView extends WebView { } public void init(Context c) { - WebSettings settings = getSettings(); + WebSettingsClassic settings = getWebViewClassic().getSettings(); settings.setJavaScriptEnabled(true); settings.setSupportZoom(true); settings.setEnableSmoothTransition(true); @@ -118,7 +119,7 @@ public class ProfiledWebView extends WebView { mCallback = callback; mIsTesting = false; mIsScrolling = false; - WebSettings settings = getSettings(); + WebSettingsClassic settings = getWebViewClassic().getSettings(); settings.setProperty("tree_updates", "0"); @@ -134,7 +135,7 @@ public class ProfiledWebView extends WebView { // invalidate all content, and kick off redraw Log.d("ProfiledWebView", "kicking off test with callback registration, and tile discard..."); - discardAllTextures(); + getWebViewClassic().discardAllTextures(); invalidate(); mIsScrolling = true; mContentInvalMillis = System.currentTimeMillis(); @@ -142,30 +143,29 @@ public class ProfiledWebView extends WebView { }.start(); } else { mIsTesting = true; - tileProfilingStart(); + getWebViewClassic().tileProfilingStart(); } } /* * Called after the manual contentInvalidateAll, after the tiles have all * been redrawn. + * From PageSwapDelegate. */ @Override - protected void pageSwapCallback(boolean startAnim) { - super.pageSwapCallback(startAnim); - + public void onPageSwapOccurred(boolean startAnim) { if (!mIsTesting && mIsScrolling) { // kick off testing mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis; Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis"); mIsTesting = true; invalidate(); // ensure a redraw so that auto-scrolling can occur - tileProfilingStart(); + getWebViewClassic().tileProfilingStart(); } } private double animFramerate() { - WebSettings settings = getSettings(); + WebSettingsClassic settings = getWebViewClassic().getSettings(); String updatesString = settings.getProperty("tree_updates"); int updates = (updatesString == null) ? -1 : Integer.parseInt(updatesString); @@ -180,7 +180,7 @@ public class ProfiledWebView extends WebView { } public void setDoubleBuffering(boolean useDoubleBuffering) { - WebSettings settings = getSettings(); + WebSettingsClassic settings = getWebViewClassic().getSettings(); settings.setProperty("use_double_buffering", useDoubleBuffering ? "true" : "false"); } @@ -188,15 +188,15 @@ public class ProfiledWebView extends WebView { * Called once the page has stopped scrolling */ public void stopScrollTest() { - tileProfilingStop(); + getWebViewClassic().tileProfilingStop(); mIsTesting = false; if (mCallback == null) { - tileProfilingClear(); + getWebViewClassic().tileProfilingClear(); return; } - RunData data = new RunData(super.tileProfilingNumFrames()); + RunData data = new RunData(getWebViewClassic().tileProfilingNumFrames()); // record the time spent (before scrolling) rendering the page data.singleStats.put(getResources().getString(R.string.render_millis), (double)mContentInvalMillis); @@ -209,24 +209,24 @@ public class ProfiledWebView extends WebView { for (int frame = 0; frame < data.frames.length; frame++) { data.frames[frame] = new TileData[ - tileProfilingNumTilesInFrame(frame)]; + getWebViewClassic().tileProfilingNumTilesInFrame(frame)]; for (int tile = 0; tile < data.frames[frame].length; tile++) { - int left = tileProfilingGetInt(frame, tile, "left"); - int top = tileProfilingGetInt(frame, tile, "top"); - int right = tileProfilingGetInt(frame, tile, "right"); - int bottom = tileProfilingGetInt(frame, tile, "bottom"); + int left = getWebViewClassic().tileProfilingGetInt(frame, tile, "left"); + int top = getWebViewClassic().tileProfilingGetInt(frame, tile, "top"); + int right = getWebViewClassic().tileProfilingGetInt(frame, tile, "right"); + int bottom = getWebViewClassic().tileProfilingGetInt(frame, tile, "bottom"); - boolean isReady = super.tileProfilingGetInt( + boolean isReady = getWebViewClassic().tileProfilingGetInt( frame, tile, "isReady") == 1; - int level = tileProfilingGetInt(frame, tile, "level"); + int level = getWebViewClassic().tileProfilingGetInt(frame, tile, "level"); - float scale = tileProfilingGetFloat(frame, tile, "scale"); + float scale = getWebViewClassic().tileProfilingGetFloat(frame, tile, "scale"); data.frames[frame][tile] = data.new TileData(left, top, right, bottom, isReady, level, scale); } } - tileProfilingClear(); + getWebViewClassic().tileProfilingClear(); mCallback.profileCallback(data); } @@ -244,4 +244,8 @@ public class ProfiledWebView extends WebView { public void setAutoScrollSpeed(int speedInt) { mSpeed = speedInt; } + + public WebViewClassic getWebViewClassic() { + return WebViewClassic.fromWebView(this); + } } |