diff options
Diffstat (limited to 'core/java/android/webkit/WebView.java')
-rw-r--r-- | core/java/android/webkit/WebView.java | 1357 |
1 files changed, 720 insertions, 637 deletions
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 563d819..2940983 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -58,7 +58,7 @@ import android.view.ViewParent; import android.view.ViewTreeObserver; import android.view.animation.AlphaAnimation; import android.view.inputmethod.InputMethodManager; -import android.webkit.TextDialog.AutoCompleteAdapter; +import android.webkit.WebTextView.AutoCompleteAdapter; import android.webkit.WebViewCore.EventHub; import android.widget.AbsoluteLayout; import android.widget.Adapter; @@ -84,7 +84,7 @@ import java.util.HashMap; import java.util.List; /** - * <p>A View that displays web pages. This class is the basis upon which you + * <p>A View that displays web pages. This class is the basis upon which you * can roll your own web browser or simply display some online content within your Activity. * It uses the WebKit rendering engine to display * web pages and includes methods to navigate forward and backward @@ -93,12 +93,109 @@ import java.util.List; * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)} * (introduced in API version 3). * <p>Note that, in order for your Activity to access the Internet and load web pages - * in a WebView, you must add the <var>INTERNET</var> permissions to your + * in a WebView, you must add the <var>INTERNET</var> permissions to your * Android Manifest file:</p> * <pre><uses-permission android:name="android.permission.INTERNET" /></pre> + * * <p>This must be a child of the <code><manifest></code> element.</p> + * + * <h3>Basic usage</h3> + * + * <p>By default, a WebView provides no browser-like widgets, does not + * enable JavaScript and errors will be ignored. If your goal is only + * to display some HTML as a part of your UI, this is probably fine; + * the user won't need to interact with the web page beyond reading + * it, and the web page won't need to interact with the user. If you + * actually want a fully blown web browser, then you probably want to + * invoke the Browser application with your URL rather than show it + * with a WebView. See {@link android.content.Intent} for more information.</p> + * + * <pre class="prettyprint"> + * WebView webview = new WebView(this); + * setContentView(webview); + * + * // Simplest usage: note that an exception will NOT be thrown + * // if there is an error loading this page (see below). + * webview.loadUrl("http://slashdot.org/"); + * + * // Of course you can also load from any string: + * String summary = "<html><body>You scored <b>192</b> points.</body></html>"; + * webview.loadData(summary, "text/html", "utf-8"); + * // ... although note that there are restrictions on what this HTML can do. + * // See the JavaDocs for loadData and loadDataWithBaseUrl for more info. + * </pre> + * + * <p>A WebView has several customization points where you can add your + * own behavior. These are:</p> + * + * <ul> + * <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass. + * This class is called when something that might impact a + * browser UI happens, for instance, progress updates and + * JavaScript alerts are sent here. + * </li> + * <li>Creating and setting a {@link android.webkit.WebViewClient} subclass. + * It will be called when things happen that impact the + * rendering of the content, eg, errors or form submissions. You + * can also intercept URL loading here.</li> + * <li>Via the {@link android.webkit.WebSettings} class, which contains + * miscellaneous configuration. </li> + * <li>With the {@link android.webkit.WebView#addJavascriptInterface} method. + * This lets you bind Java objects into the WebView so they can be + * controlled from the web pages JavaScript.</li> + * </ul> + * + * <p>Here's a more complicated example, showing error handling, + * settings, and progress notification:</p> + * + * <pre class="prettyprint"> + * // Let's display the progress in the activity title bar, like the + * // browser app does. + * getWindow().requestFeature(Window.FEATURE_PROGRESS); + * + * webview.getSettings().setJavaScriptEnabled(true); + * + * final Activity activity = this; + * webview.setWebChromeClient(new WebChromeClient() { + * public void onProgressChanged(WebView view, int progress) { + * // Activities and WebViews measure progress with different scales. + * // The progress meter will automatically disappear when we reach 100% + * activity.setProgress(progress * 1000); + * } + * }); + * webview.setWebViewClient(new WebViewClient() { + * public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + * Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show(); + * } + * }); + * + * webview.loadUrl("http://slashdot.org/"); + * </pre> + * + * <h3>Cookie and window management</h3> + * + * <p>For obvious security reasons, your application has its own + * cache, cookie store etc - it does not share the Browser + * applications data. Cookies are managed on a separate thread, so + * operations like index building don't block the UI + * thread. Follow the instructions in {@link android.webkit.CookieSyncManager} + * if you want to use cookies in your application. + * </p> + * + * <p>By default, requests by the HTML to open new windows are + * ignored. This is true whether they be opened by JavaScript or by + * the target attribute on a link. You can customize your + * WebChromeClient to provide your own behaviour for opening multiple windows, + * and render them in whatever manner you want.</p> + * + * <p>Standard behavior for an Activity is to be destroyed and + * recreated when the devices orientation is changed. This will cause + * the WebView to reload the current page. If you don't want that, you + * can set your Activity to handle the orientation and keyboardHidden + * changes, and then just leave the WebView alone. It'll automatically + * re-orient itself as appropriate.</p> */ -public class WebView extends AbsoluteLayout +public class WebView extends AbsoluteLayout implements ViewTreeObserver.OnGlobalFocusChangeListener, ViewGroup.OnHierarchyChangeListener { @@ -108,12 +205,9 @@ public class WebView extends AbsoluteLayout // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK private boolean mAutoRedraw; - // keep debugging parameters near the top of the file static final String LOGTAG = "webview"; - static final boolean DEBUG = false; - static final boolean LOGV_ENABLED = DEBUG; - private class ExtendedZoomControls extends FrameLayout { + private static class ExtendedZoomControls extends FrameLayout { public ExtendedZoomControls(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater inflater = (LayoutInflater) @@ -122,40 +216,40 @@ public class WebView extends AbsoluteLayout mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls); mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify); } - + public void show(boolean showZoom, boolean canZoomOut) { mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE); mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE); fade(View.VISIBLE, 0.0f, 1.0f); } - + public void hide() { fade(View.GONE, 1.0f, 0.0f); } - + private void fade(int visibility, float startAlpha, float endAlpha) { AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha); anim.setDuration(500); startAnimation(anim); setVisibility(visibility); } - + public void setIsZoomMagnifyEnabled(boolean isEnabled) { mZoomMagnify.setEnabled(isEnabled); } - + public boolean hasFocus() { return mZoomControls.hasFocus() || mZoomMagnify.hasFocus(); } - + public void setOnZoomInClickListener(OnClickListener listener) { mZoomControls.setOnZoomInClickListener(listener); } - + public void setOnZoomOutClickListener(OnClickListener listener) { mZoomControls.setOnZoomOutClickListener(listener); } - + public void setOnZoomMagnifyClickListener(OnClickListener listener) { mZoomMagnify.setOnClickListener(listener); } @@ -163,7 +257,7 @@ public class WebView extends AbsoluteLayout ZoomControls mZoomControls; ImageView mZoomMagnify; } - + /** * Transportation object for returning WebView across thread boundaries. */ @@ -203,7 +297,7 @@ public class WebView extends AbsoluteLayout private WebViewCore mWebViewCore; // Handler for dispatching UI messages. /* package */ final Handler mPrivateHandler = new PrivateHandler(); - private TextDialog mTextEntry; + private WebTextView mWebTextView; // Used to ignore changes to webkit text that arrives to the UI side after // more key events. private int mTextGeneration; @@ -266,12 +360,15 @@ public class WebView extends AbsoluteLayout // take control of touch events unless it says no for touch down event. private boolean mPreventDrag; - // If updateTextEntry gets called while we are out of focus, use this + // If rebuildWebTextView gets called while we are out of focus, use this // variable to remember to do it next time we gain focus. - private boolean mNeedsUpdateTextEntry = false; - - // Whether or not to draw the focus ring. - private boolean mDrawFocusRing = true; + private boolean mNeedsRebuildWebTextView = false; + + // Whether or not to draw the cursor ring. + private boolean mDrawCursorRing = true; + + // true if onPause has been called (and not onResume) + private boolean mIsPaused; /** * Customizable constant @@ -291,7 +388,7 @@ public class WebView extends AbsoluteLayout // needed to avoid flinging after a pause of no movement private static final int MIN_FLING_TIME = 250; // The time that the Zoom Controls are visible before fading away - private static final long ZOOM_CONTROLS_TIMEOUT = + private static final long ZOOM_CONTROLS_TIMEOUT = ViewConfiguration.getZoomControlsTimeout(); // The amount of content to overlap between two screens when going through // pages with the space bar, in pixels. @@ -312,7 +409,7 @@ public class WebView extends AbsoluteLayout 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 + // 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; @@ -327,51 +424,48 @@ public class WebView extends AbsoluteLayout private boolean mWrapContent; - // true if we should call webcore to draw the content, false means we have - // requested something but it isn't ready to draw yet. - private WebViewCore.FocusData mFocusData; /** * 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 UPDATE_TEXT_ENTRY_ADAPTER = 6; - private static final int SWITCH_TO_ENTER = 7; - private static final int RESUME_WEBCORE_UPDATE = 8; + 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 REQUEST_FORM_DATA = 6; + private static final int SWITCH_TO_CLICK = 7; + private static final int RESUME_WEBCORE_UPDATE = 8; //! arg1=x, arg2=y - static final int SCROLL_TO_MSG_ID = 10; - static final int SCROLL_BY_MSG_ID = 11; + static final int SCROLL_TO_MSG_ID = 10; + static final int SCROLL_BY_MSG_ID = 11; //! arg1=x, arg2=y - static final int SPAWN_SCROLL_TO_MSG_ID = 12; + static final int SPAWN_SCROLL_TO_MSG_ID = 12; //! arg1=x, arg2=y - static final int SYNC_SCROLL_TO_MSG_ID = 13; - static final int NEW_PICTURE_MSG_ID = 14; - static final int UPDATE_TEXT_ENTRY_MSG_ID = 15; - static final int WEBCORE_INITIALIZED_MSG_ID = 16; - static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17; - static final int DID_FIRST_LAYOUT_MSG_ID = 18; - static final int RECOMPUTE_FOCUS_MSG_ID = 19; - static final int NOTIFY_FOCUS_SET_MSG_ID = 20; - static final int MARK_NODE_INVALID_ID = 21; - static final int UPDATE_CLIPBOARD = 22; - static final int LONG_PRESS_ENTER = 23; - static final int PREVENT_TOUCH_ID = 24; - static final int WEBCORE_NEED_TOUCH_EVENTS = 25; + static final int SYNC_SCROLL_TO_MSG_ID = 13; + static final int NEW_PICTURE_MSG_ID = 14; + static final int UPDATE_TEXT_ENTRY_MSG_ID = 15; + static final int WEBCORE_INITIALIZED_MSG_ID = 16; + static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17; + static final int DID_FIRST_LAYOUT_MSG_ID = 18; + static final int RECOMPUTE_FOCUS_MSG_ID = 19; + + static final int MARK_NODE_INVALID_ID = 21; + static final int UPDATE_CLIPBOARD = 22; + static final int LONG_PRESS_CENTER = 23; + static final int PREVENT_TOUCH_ID = 24; + static final int WEBCORE_NEED_TOUCH_EVENTS = 25; // obj=Rect in doc coordinates - static final int INVAL_RECT_MSG_ID = 26; - + static final int INVAL_RECT_MSG_ID = 26; + static final String[] HandlerDebugString = { - "REMEMBER_PASSWORD", // = 1; - "NEVER_REMEMBER_PASSWORD", // = 2; - "SWITCH_TO_SHORTPRESS", // = 3; - "SWITCH_TO_LONGPRESS", // = 4; + "REMEMBER_PASSWORD", // = 1; + "NEVER_REMEMBER_PASSWORD", // = 2; + "SWITCH_TO_SHORTPRESS", // = 3; + "SWITCH_TO_LONGPRESS", // = 4; "5", - "UPDATE_TEXT_ENTRY_ADAPTER", // = 6; - "SWITCH_TO_ENTER", // = 7; - "RESUME_WEBCORE_UPDATE", // = 8; + "REQUEST_FORM_DATA", // = 6; + "SWITCH_TO_CLICK", // = 7; + "RESUME_WEBCORE_UPDATE", // = 8; "9", "SCROLL_TO_MSG_ID", // = 10; "SCROLL_BY_MSG_ID", // = 11; @@ -383,10 +477,10 @@ public class WebView extends AbsoluteLayout "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 17; "DID_FIRST_LAYOUT_MSG_ID", // = 18; "RECOMPUTE_FOCUS_MSG_ID", // = 19; - "NOTIFY_FOCUS_SET_MSG_ID", // = 20; + "20", "MARK_NODE_INVALID_ID", // = 21; "UPDATE_CLIPBOARD", // = 22; - "LONG_PRESS_ENTER", // = 23; + "LONG_PRESS_CENTER", // = 23; "PREVENT_TOUCH_ID", // = 24; "WEBCORE_NEED_TOUCH_EVENTS", // = 25; "INVAL_RECT_MSG_ID" // = 26; @@ -427,7 +521,7 @@ public class WebView extends AbsoluteLayout private static final int SNAP_X_LOCK = 4; private static final int SNAP_Y_LOCK = 5; private boolean mSnapPositive; - + // Used to match key downs and key ups private boolean mGotKeyDown; @@ -450,7 +544,7 @@ public class WebView extends AbsoluteLayout * URI scheme for map address */ public static final String SCHEME_GEO = "geo:0,0?q="; - + private int mBackgroundColor = Color.WHITE; // Used to notify listeners of a new picture. @@ -467,7 +561,8 @@ public class WebView extends AbsoluteLayout public void onNewPicture(WebView view, Picture picture); } - public class HitTestResult { + // FIXME: Want to make this public, but need to change the API file. + public /*static*/ class HitTestResult { /** * Default HitTestResult, where the target is unknown */ @@ -537,7 +632,7 @@ public class WebView extends AbsoluteLayout private ExtendedZoomControls mZoomControls; private Runnable mZoomControlRunnable; - private ZoomButtonsController mZoomButtonsController; + private ZoomButtonsController mZoomButtonsController; private ImageView mZoomOverviewButton; private ImageView mZoomFitPageButton; @@ -562,11 +657,11 @@ public class WebView extends AbsoluteLayout } else { zoomOut(); } - + updateZoomButtonsEnabled(); } }; - + /** * Construct a new WebView with a Context object. * @param context A Context object used to access application assets. @@ -597,11 +692,6 @@ public class WebView extends AbsoluteLayout mCallbackProxy = new CallbackProxy(context, this); mWebViewCore = new WebViewCore(context, this, mCallbackProxy); mDatabase = WebViewDatabase.getInstance(context); - mFocusData = new WebViewCore.FocusData(); - mFocusData.mFrame = 0; - mFocusData.mNode = 0; - mFocusData.mX = 0; - mFocusData.mY = 0; mScroller = new Scroller(context); initZoomController(context); @@ -868,7 +958,7 @@ public class WebView extends AbsoluteLayout clearTextEntry(); if (mWebViewCore != null) { // Set the handlers to null before destroying WebViewCore so no - // more messages will be posted. + // more messages will be posted. mCallbackProxy.setWebViewClient(null); mCallbackProxy.setWebChromeClient(null); // Tell WebViewCore to destroy itself @@ -899,12 +989,12 @@ public class WebView extends AbsoluteLayout /** * If platform notifications are enabled, this should be called - * from onPause() or onStop(). + * from the Activity's onPause() or onStop(). */ public static void disablePlatformNotifications() { Network.disablePlatformNotifications(); } - + /** * Inform WebView of the network state. This is used to set * the javascript property window.navigator.isOnline and @@ -917,7 +1007,7 @@ public class WebView extends AbsoluteLayout } /** - * Save the state of this WebView used in + * 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 * behavior could potentially leak files if {@link #restoreState} was never @@ -1048,10 +1138,10 @@ public class WebView extends AbsoluteLayout /** * Restore the state of this WebView from the given map used in - * {@link android.app.Activity#onRestoreInstanceState}. This method should - * be called to restore the state of the WebView before using the object. If - * it is called after the WebView has had a chance to build state (load - * pages, create a back/forward list, etc.) there may be undesirable + * {@link android.app.Activity#onRestoreInstanceState}. This method should + * be called to restore the state of the WebView before using the object. If + * it is called after the WebView has had a chance to build state (load + * pages, create a back/forward list, etc.) there may be undesirable * side-effects. Please note that this method no longer restores the * display data for this WebView. See {@link #savePicture} and {@link * #restorePicture} for saving and restoring the display data. @@ -1118,6 +1208,29 @@ public class WebView extends AbsoluteLayout } /** + * Load the url with postData using "POST" method into the WebView. If url + * is not a network url, it will be loaded with {link + * {@link #loadUrl(String)} instead. + * + * @param url The url of the resource to load. + * @param postData The data will be passed to "POST" request. + * + * @hide pending API solidification + */ + public void postUrl(String url, byte[] postData) { + if (URLUtil.isNetworkUrl(url)) { + switchOutDrawHistory(); + HashMap arg = new HashMap(); + arg.put("url", url); + arg.put("data", postData); + mWebViewCore.sendMessage(EventHub.POST_URL, arg); + clearTextEntry(); + } else { + loadUrl(url); + } + } + + /** * Load the given data into the WebView. This will load the data into * WebView using the data: scheme. Content loaded through this mechanism * does not have the ability to load content from the network. @@ -1143,7 +1256,7 @@ public class WebView extends AbsoluteLayout * able to access asset files. If the baseUrl is anything other than * http(s)/ftp(s)/about/javascript as scheme, you can access asset files for * sub resources. - * + * * @param baseUrl Url to resolve relative paths with, if null defaults to * "about:blank" * @param data A String of data in the given encoding. @@ -1154,7 +1267,7 @@ public class WebView extends AbsoluteLayout */ public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String failUrl) { - + if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) { loadData(data, mimeType, encoding); return; @@ -1275,7 +1388,7 @@ public class WebView extends AbsoluteLayout ignoreSnapshot ? 1 : 0); } } - + private boolean extendScroll(int y) { int finalY = mScroller.getFinalY(); int newY = pinLocY(finalY + y); @@ -1284,7 +1397,7 @@ public class WebView extends AbsoluteLayout mScroller.extendDuration(computeDuration(0, y)); return true; } - + /** * Scroll the contents of the view up by half the view size * @param top true to jump to the top of the page @@ -1308,10 +1421,10 @@ public class WebView extends AbsoluteLayout y = -h / 2; } mUserScroll = true; - return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) + return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) : extendScroll(y); } - + /** * Scroll the contents of the view down by half the page size * @param bottom true to jump to bottom of page @@ -1334,7 +1447,7 @@ public class WebView extends AbsoluteLayout y = h / 2; } mUserScroll = true; - return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) + return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) : extendScroll(y); } @@ -1347,7 +1460,7 @@ public class WebView extends AbsoluteLayout mContentHeight = 0; mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT); } - + /** * Return a new picture that captures the current display of the webview. * This is a copy of the display, and will be unaffected if the webview @@ -1358,7 +1471,7 @@ public class WebView extends AbsoluteLayout * bounds of the view. */ public Picture capturePicture() { - if (null == mWebViewCore) return null; // check for out of memory tab + if (null == mWebViewCore) return null; // check for out of memory tab return mWebViewCore.copyContentPicture(); } @@ -1366,17 +1479,17 @@ public class WebView extends AbsoluteLayout * Return true if the browser is displaying a TextView for text input. */ private boolean inEditingMode() { - return mTextEntry != null && mTextEntry.getParent() != null - && mTextEntry.hasFocus(); + return mWebTextView != null && mWebTextView.getParent() != null + && mWebTextView.hasFocus(); } private void clearTextEntry() { if (inEditingMode()) { - mTextEntry.remove(); + mWebTextView.remove(); } } - /** + /** * Return the current scale of the WebView * @return The current scale. */ @@ -1440,26 +1553,26 @@ public class WebView extends AbsoluteLayout } HitTestResult result = new HitTestResult(); - - if (nativeUpdateFocusNode()) { - FocusNode node = mFocusNode; - if (node.mIsTextField || node.mIsTextArea) { + if (nativeHasCursorNode()) { + if (nativeCursorIsTextInput()) { result.setType(HitTestResult.EDIT_TEXT_TYPE); - } else if (node.mText != null) { - String text = node.mText; - if (text.startsWith(SCHEME_TEL)) { - result.setType(HitTestResult.PHONE_TYPE); - result.setExtra(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 (node.mIsAnchor) { - result.setType(HitTestResult.SRC_ANCHOR_TYPE); - result.setExtra(text); + } else { + String text = nativeCursorText(); + if (text != null) { + if (text.startsWith(SCHEME_TEL)) { + result.setType(HitTestResult.PHONE_TYPE); + result.setExtra(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); + } } } } @@ -1471,8 +1584,8 @@ public class WebView extends AbsoluteLayout int contentY = viewToContent((int) mLastTouchY + mScrollY); String text = nativeImageURI(contentX, contentY); if (text != null) { - result.setType(type == HitTestResult.UNKNOWN_TYPE ? - HitTestResult.IMAGE_TYPE : + result.setType(type == HitTestResult.UNKNOWN_TYPE ? + HitTestResult.IMAGE_TYPE : HitTestResult.SRC_IMAGE_ANCHOR_TYPE); result.setExtra(text); } @@ -1484,7 +1597,7 @@ public class WebView extends AbsoluteLayout * Request the href of an anchor element due to getFocusNodePath returning * "href." If hrefMsg is null, this method returns immediately and does not * dispatch hrefMsg to its target. - * + * * @param hrefMsg This message will be dispatched with the result of the * request as the data member with "url" as key. The result can * be null. @@ -1493,22 +1606,20 @@ public class WebView extends AbsoluteLayout if (hrefMsg == null || mNativeClass == 0) { return; } - if (nativeUpdateFocusNode()) { - FocusNode node = mFocusNode; - if (node.mIsAnchor) { - // NOTE: We may already have the url of the anchor stored in - // node.mText but it may be out of date or the caller may want - // to know about javascript urls. - mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF, - node.mFramePointer, node.mNodePointer, hrefMsg); - } + if (nativeCursorIsAnchor()) { + // NOTE: We may already have the url of the anchor stored in + // node.mText but it may be out of date or the caller may want + // to know about javascript urls. + mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF, + nativeCursorFramePointer(), nativeCursorNodePointer(), + hrefMsg); } } - + /** * Request the url of the image last touched by the user. msg will be sent * to its target with a String representing the url as its object. - * + * * @param msg This message will be dispatched with the result of the request * as the data member with "url" as key. The result can be null. */ @@ -1583,7 +1694,7 @@ public class WebView extends AbsoluteLayout 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 @@ -1643,7 +1754,7 @@ public class WebView extends AbsoluteLayout mActualScale = scale; mInvActualScale = 1 / scale; - // as we don't have animation for scaling, don't do animation + // as we don't have animation for scaling, don't do animation // for scrolling, as it causes weird intermediate state // pinScrollTo(Math.round(sx), Math.round(sy)); mScrollX = pinLocX(Math.round(sx)); @@ -1767,10 +1878,10 @@ public class WebView extends AbsoluteLayout WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); return h != null ? h.getUrl() : null; } - + /** - * Get the original url for the current page. This is not always the same - * as the url passed to WebViewClient.onPageStarted because although the + * Get the original url for the current page. This is not always the same + * as the url passed to WebViewClient.onPageStarted because although the * load for that url has begun, the current page may not have changed. * Also, there may have been redirects resulting in a different url to that * originally requested. @@ -1808,7 +1919,7 @@ public class WebView extends AbsoluteLayout public int getProgress() { return mCallbackProxy.getProgress(); } - + /** * @return the height of the HTML content. */ @@ -1817,30 +1928,68 @@ public class WebView extends AbsoluteLayout } /** - * Pause all layout, parsing, and javascript timers. This can be useful if - * the WebView is not visible or the application has been paused. + * Pause all layout, parsing, and javascript timers for all webviews. This + * is a global requests, not restricted to just this webview. This can be + * useful if the application has been paused. */ public void pauseTimers() { mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS); } /** - * Resume all layout, parsing, and javascript timers. This will resume - * dispatching all timers. + * Resume all layout, parsing, and javascript timers for all webviews. + * This will resume dispatching all timers. */ public void resumeTimers() { mWebViewCore.sendMessage(EventHub.RESUME_TIMERS); } /** - * Clear the resource cache. This will cause resources to be re-downloaded - * if accessed again. - * <p> - * 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. + * Call this to pause any extra processing associated with this view and + * its associated DOM/plugins/javascript/etc. For example, if the view is + * taken offscreen, this could be called to reduce unnecessary CPU and/or + * network traffic. When the view is again "active", call onResume(). + * + * Note that this differs from pauseTimers(), which affects all views/DOMs + * @hide + */ + public void onPause() { + if (!mIsPaused) { + mIsPaused = true; + mWebViewCore.sendMessage(EventHub.ON_PAUSE); + } + } + + /** + * Call this to balanace a previous call to onPause() + * @hide + */ + public void onResume() { + if (mIsPaused) { + mIsPaused = false; + mWebViewCore.sendMessage(EventHub.ON_RESUME); + } + } + + /** + * Returns true if the view is paused, meaning onPause() was called. Calling + * onResume() sets the paused state back to false. + * @hide + */ + public boolean isPaused() { + return mIsPaused; + } + + /** + * Clear the resource cache. Note that the cache is per-application, so + * this will clear the cache for all WebViews used. + * + * @param includeDiskFiles If false, only the RAM cache is cleared. */ public void clearCache(boolean includeDiskFiles) { + // 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); } @@ -1852,7 +2001,7 @@ public class WebView extends AbsoluteLayout public void clearFormData() { if (inEditingMode()) { AutoCompleteAdapter adapter = null; - mTextEntry.setAdapterCustom(adapter); + mWebTextView.setAdapterCustom(adapter); } } @@ -1886,7 +2035,7 @@ public class WebView extends AbsoluteLayout /* * Highlight and scroll to the next occurance of String in findAll. - * Wraps the page infinitely, and scrolls. Must be called after + * Wraps the page infinitely, and scrolls. Must be called after * calling findAll. * * @param forward Direction to search. @@ -1912,11 +2061,8 @@ public class WebView extends AbsoluteLayout // or not we draw the highlights for matches. private boolean mFindIsUp; - private native int nativeFindAll(String findLower, String findUpper); - private native void nativeFindNext(boolean forward); - /** - * Return the first substring consisting of the address of a physical + * 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 @@ -1929,7 +2075,7 @@ public class WebView extends AbsoluteLayout * All names must be correctly 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 + * or abbreviated using USPS standards. The house number may not exceed * five digits. * @param addr The string to search for addresses. * @@ -2220,16 +2366,10 @@ public class WebView extends AbsoluteLayout } /** - * Signal the WebCore thread to refresh its list of plugins. Use - * this if the directory contents of one of the plugin directories - * has been modified and needs its changes reflecting. May cause - * plugin load and/or unload. - * @param reloadOpenPages Set to true to reload all open pages. + * TODO: need to add @Deprecated */ public void refreshPlugins(boolean reloadOpenPages) { - if (mWebViewCore != null) { - mWebViewCore.sendMessage(EventHub.REFRESH_PLUGINS, reloadOpenPages); - } + PluginManager.getInstance(mContext).refreshPlugins(reloadOpenPages); } //------------------------------------------------------------------------- @@ -2240,7 +2380,7 @@ public class WebView extends AbsoluteLayout protected void finalize() throws Throwable { destroy(); } - + @Override protected void onDraw(Canvas canvas) { // if mNativeClass is 0, the WebView has been destroyed. Do nothing. @@ -2249,7 +2389,7 @@ public class WebView extends AbsoluteLayout } if (mWebViewCore.mEndScaleZoom) { mWebViewCore.mEndScaleZoom = false; - if (mTouchMode >= FIRST_SCROLL_ZOOM + if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) { setHorizontalScrollBarEnabled(true); setVerticalScrollBarEnabled(true); @@ -2271,11 +2411,11 @@ public class WebView extends AbsoluteLayout // need to check it again. nativeRecordButtons(hasFocus() && hasWindowFocus(), mTouchMode == TOUCH_SHORTPRESS_START_MODE - || mTrackballDown || mGotEnterDown, false); - drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing); + || mTrackballDown || mGotCenterDown, false); + drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing); } canvas.restoreToCount(sc); - + if (AUTO_REDRAW_HACK && mAutoRedraw) { invalidate(); } @@ -2292,13 +2432,13 @@ public class WebView extends AbsoluteLayout @Override public boolean performLongClick() { if (inEditingMode()) { - return mTextEntry.performLongClick(); + return mWebTextView.performLongClick(); } else { return super.performLongClick(); } } - private void drawCoreAndFocusRing(Canvas canvas, int color, + private void drawCoreAndCursorRing(Canvas canvas, int color, boolean drawFocus) { if (mDrawHistory) { canvas.scale(mActualScale, mActualScale); @@ -2307,14 +2447,14 @@ public class WebView extends AbsoluteLayout } boolean animateZoom = mZoomScale != 0; - boolean animateScroll = !mScroller.isFinished() + boolean animateScroll = !mScroller.isFinished() || mVelocityTracker != null; if (animateZoom) { float zoomScale; int interval = (int) (SystemClock.uptimeMillis() - mZoomStart); if (interval < ZOOM_ANIMATION_LENGTH) { float ratio = (float) interval / ZOOM_ANIMATION_LENGTH; - zoomScale = 1.0f / (mInvInitialZoomScale + zoomScale = 1.0f / (mInvInitialZoomScale + (mInvFinalZoomScale - mInvInitialZoomScale) * ratio); invalidate(); } else { @@ -2354,7 +2494,7 @@ public class WebView extends AbsoluteLayout if (mTouchSelection) { nativeDrawSelectionRegion(canvas); } else { - nativeDrawSelection(canvas, mSelectX, mSelectY, + nativeDrawSelection(canvas, mSelectX, mSelectY, mExtendSelection); } } else if (drawFocus) { @@ -2368,7 +2508,7 @@ public class WebView extends AbsoluteLayout LONG_PRESS_TIMEOUT); } } - nativeDrawFocusRing(canvas); + nativeDrawCursorRing(canvas); } // When the FindDialog is up, only draw the matches if we are not in // the process of scrolling them into view. @@ -2377,14 +2517,12 @@ public class WebView extends AbsoluteLayout } } - private native void nativeDrawMatches(Canvas canvas); - private float scrollZoomGridScale(float invScale) { - float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID) + float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID) / (float) SCROLL_ZOOM_GRID; return 1.0f / griddedInvScale; } - + private float scrollZoomX(float scale) { int width = getViewWidth(); float maxScrollZoomX = mContentWidth * scale - width; @@ -2400,7 +2538,7 @@ public class WebView extends AbsoluteLayout return -(maxScrollZoomY > 0 ? mZoomScrollY * maxScrollZoomY / maxY : maxScrollZoomY / 2); } - + private void drawMagnifyFrame(Canvas canvas, Rect frame, Paint paint) { final float ADORNMENT_LEN = 16.0f; float width = frame.width(); @@ -2421,13 +2559,13 @@ public class WebView extends AbsoluteLayout path.offset(frame.left, frame.top); canvas.drawPath(path, paint); } - - // Returns frame surrounding magified portion of screen while + + // Returns frame surrounding magified portion of screen while // scroll-zoom is enabled. The frame is also used to center the // zoom-in zoom-out points at the start and end of the animation. private Rect scrollZoomFrame(int width, int height, float halfScale) { Rect scrollFrame = new Rect(); - scrollFrame.set(mZoomScrollX, mZoomScrollY, + scrollFrame.set(mZoomScrollX, mZoomScrollY, mZoomScrollX + width, mZoomScrollY + height); if (mContentWidth * mZoomScrollLimit < width) { float scale = zoomFrameScaleX(width, halfScale, 1.0f); @@ -2443,37 +2581,37 @@ public class WebView extends AbsoluteLayout } return scrollFrame; } - + private float zoomFrameScaleX(int width, float halfScale, float noScale) { // mContentWidth > width > mContentWidth * mZoomScrollLimit if (mContentWidth <= width) { return halfScale; } - float part = (width - mContentWidth * mZoomScrollLimit) + float part = (width - mContentWidth * mZoomScrollLimit) / (width * (1 - mZoomScrollLimit)); return halfScale * part + noScale * (1.0f - part); } - + private float zoomFrameScaleY(int height, float halfScale, float noScale) { if (mContentHeight <= height) { return halfScale; } - float part = (height - mContentHeight * mZoomScrollLimit) + float part = (height - mContentHeight * mZoomScrollLimit) / (height * (1 - mZoomScrollLimit)); return halfScale * part + noScale * (1.0f - part); } - + private float scrollZoomMagScale(float invScale) { return (invScale * 2 + mInvActualScale) / 3; } - + private void scrollZoomDraw(Canvas canvas) { - float invScale = mZoomScrollInvLimit; + float invScale = mZoomScrollInvLimit; int elapsed = 0; if (mTouchMode != SCROLL_ZOOM_OUT) { - elapsed = (int) Math.min(System.currentTimeMillis() + elapsed = (int) Math.min(System.currentTimeMillis() - mZoomScrollStart, SCROLL_ZOOM_DURATION); - float transitionScale = (mZoomScrollInvLimit - mInvActualScale) + float transitionScale = (mZoomScrollInvLimit - mInvActualScale) * elapsed / SCROLL_ZOOM_DURATION; if (mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) { invScale = mInvActualScale + transitionScale; @@ -2491,9 +2629,9 @@ public class WebView extends AbsoluteLayout if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) { setHorizontalScrollBarEnabled(true); setVerticalScrollBarEnabled(true); - updateTextEntry(); - scrollTo((int) (scrollFrame.centerX() * mActualScale) - - (width >> 1), (int) (scrollFrame.centerY() + rebuildWebTextView(); + scrollTo((int) (scrollFrame.centerX() * mActualScale) + - (width >> 1), (int) (scrollFrame.centerY() * mActualScale) - (height >> 1)); mTouchMode = TOUCH_DONE_MODE; } else { @@ -2502,10 +2640,10 @@ public class WebView extends AbsoluteLayout } float newX = scrollZoomX(scale); float newY = scrollZoomY(scale); - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "scrollZoomDraw scale=" + scale + " + (" + newX + ", " + newY + ") mZoomScroll=(" + mZoomScrollX + ", " - + mZoomScrollY + ")" + " invScale=" + invScale + " scale=" + + mZoomScrollY + ")" + " invScale=" + invScale + " scale=" + scale); } canvas.translate(newX, newY); @@ -2549,8 +2687,8 @@ public class WebView extends AbsoluteLayout } canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX , mZoomScrollY + height * halfY); - if (LOGV_ENABLED) { - Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=(" + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=(" + width + ", " + height + ") half=(" + halfX + ", " + halfY + ")"); } @@ -2578,7 +2716,7 @@ public class WebView extends AbsoluteLayout , Math.max(0, (int) ((x - left) / scale))); mZoomScrollY = Math.min(mContentHeight - height , Math.max(0, (int) ((y - top) / scale))); - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "zoomScrollTap scale=" + scale + " + (" + left + ", " + top + ") mZoomScroll=(" + mZoomScrollX + ", " + mZoomScrollY + ")" + " x=" + x + " y=" + y); @@ -2595,7 +2733,7 @@ public class WebView extends AbsoluteLayout float y = (float) height / (float) mContentHeight; mZoomScrollLimit = Math.max(DEFAULT_MIN_ZOOM_SCALE, Math.min(x, y)); mZoomScrollInvLimit = 1.0f / mZoomScrollLimit; - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "canZoomScrollOut" + " mInvActualScale=" + mInvActualScale + " mZoomScrollLimit=" + mZoomScrollLimit @@ -2610,7 +2748,7 @@ public class WebView extends AbsoluteLayout return mContentWidth >= width * limit || mContentHeight >= height * limit; } - + private void startZoomScrollOut() { setHorizontalScrollBarEnabled(false); setVerticalScrollBarEnabled(false); @@ -2636,18 +2774,18 @@ public class WebView extends AbsoluteLayout mZoomScrollStart = System.currentTimeMillis(); Rect zoomFrame = scrollZoomFrame(width, height , scrollZoomMagScale(mZoomScrollInvLimit)); - mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale) + mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale) - (zoomFrame.width() >> 1)); - mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale) + mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale) - (zoomFrame.height() >> 1)); scrollTo(0, 0); // triggers inval, starts animation clearTextEntry(); - if (LOGV_ENABLED) { - Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=(" + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=(" + mZoomScrollX + ", " + mZoomScrollY +")"); } } - + private void zoomScrollOut() { if (canZoomScrollOut() == false) { mTouchMode = TOUCH_DONE_MODE; @@ -2659,7 +2797,7 @@ public class WebView extends AbsoluteLayout } private void moveZoomScrollWindow(float x, float y) { - if (Math.abs(x - mLastZoomScrollRawX) < 1.5f + if (Math.abs(x - mLastZoomScrollRawX) < 1.5f && Math.abs(y - mLastZoomScrollRawY) < 1.5f) { return; } @@ -2671,12 +2809,12 @@ public class WebView extends AbsoluteLayout int height = getViewHeight(); int maxZoomX = mContentWidth - width; if (maxZoomX > 0) { - int maxScreenX = width - (int) Math.ceil(width + int maxScreenX = width - (int) Math.ceil(width * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER; - if (LOGV_ENABLED) { - Log.v(LOGTAG, "moveZoomScrollWindow-X" + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "moveZoomScrollWindow-X" + " maxScreenX=" + maxScreenX + " width=" + width - + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x); + + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x); } x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX; x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit); @@ -2684,12 +2822,12 @@ public class WebView extends AbsoluteLayout } int maxZoomY = mContentHeight - height; if (maxZoomY > 0) { - int maxScreenY = height - (int) Math.ceil(height + int maxScreenY = height - (int) Math.ceil(height * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER; - if (LOGV_ENABLED) { - Log.v(LOGTAG, "moveZoomScrollWindow-Y" + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "moveZoomScrollWindow-Y" + " maxScreenY=" + maxScreenY + " height=" + height - + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y); + + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y); } y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY; y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit); @@ -2698,12 +2836,12 @@ public class WebView extends AbsoluteLayout if (oldX != mZoomScrollX || oldY != mZoomScrollY) { invalidate(); } - if (LOGV_ENABLED) { - Log.v(LOGTAG, "moveZoomScrollWindow" - + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")" - + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")" - + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")" - + " last=("+mLastScrollX+", "+mLastScrollY+")" + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "moveZoomScrollWindow" + + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")" + + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")" + + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")" + + " last=("+mLastScrollX+", "+mLastScrollY+")" + " x=" + x + " y=" + y); } } @@ -2748,7 +2886,7 @@ public class WebView extends AbsoluteLayout // Should only be called in UI thread void switchOutDrawHistory() { if (null == mWebViewCore) return; // CallbackProxy may trigger this - if (mDrawHistory) { + if (mDrawHistory && mWebViewCore.pictureReady()) { mDrawHistory = false; invalidate(); int oldScrollX = mScrollX; @@ -2764,72 +2902,27 @@ public class WebView extends AbsoluteLayout } } - /** - * Class representing the node which is focused. - */ - private class FocusNode { - public FocusNode() { - mBounds = new Rect(); - } - // Only to be called by JNI - private void setAll(boolean isTextField, boolean isTextArea, boolean - isPassword, boolean isAnchor, boolean isRtlText, int maxLength, - int textSize, int boundsX, int boundsY, int boundsRight, int - boundsBottom, int nodePointer, int framePointer, String text, - String name, int rootTextGeneration) { - mIsTextField = isTextField; - mIsTextArea = isTextArea; - mIsPassword = isPassword; - mIsAnchor = isAnchor; - mIsRtlText = isRtlText; - - mMaxLength = maxLength; - mTextSize = textSize; - - mBounds.set(boundsX, boundsY, boundsRight, boundsBottom); - - - mNodePointer = nodePointer; - mFramePointer = framePointer; - mText = text; - mName = name; - mRootTextGeneration = rootTextGeneration; - } - public boolean mIsTextField; - public boolean mIsTextArea; - public boolean mIsPassword; - public boolean mIsAnchor; - public boolean mIsRtlText; - - public int mSelectionStart; - public int mSelectionEnd; - public int mMaxLength; - public int mTextSize; - - public Rect mBounds; - - public int mNodePointer; - public int mFramePointer; - public String mText; - public String mName; - public int mRootTextGeneration; - } - - // Warning: ONLY use mFocusNode AFTER calling nativeUpdateFocusNode(), - // and ONLY if it returns true; - private FocusNode mFocusNode = new FocusNode(); - + WebViewCore.CursorData cursorData() { + WebViewCore.CursorData result = new WebViewCore.CursorData(); + result.mMoveGeneration = nativeMoveGeneration(); + result.mFrame = nativeCursorFramePointer(); + result.mNode = nativeCursorNodePointer(); + Rect bounds = nativeCursorNodeBounds(); + result.mX = bounds.centerX(); + result.mY = bounds.centerY(); + 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 + * 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++; - mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end, - new WebViewCore.FocusData(mFocusData)); + mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end); } /** @@ -2839,119 +2932,121 @@ public class WebView extends AbsoluteLayout * @param end End of selection. */ /* package */ void setSelection(int start, int end) { - mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end, - new WebViewCore.FocusData(mFocusData)); + mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end); } // Called by JNI when a touch event puts a textfield into focus. private void displaySoftKeyboard() { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(mTextEntry, 0); - mTextEntry.enableScrollOnScreen(true); + imm.showSoftInput(mWebTextView, 0); + mWebTextView.enableScrollOnScreen(true); // Now we need to fake a touch event to place the cursor where the // user touched. AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) - mTextEntry.getLayoutParams(); + mWebTextView.getLayoutParams(); if (lp != null) { // Take the last touch and adjust for the location of the - // TextDialog. + // WebTextView. float x = mLastTouchX + (float) (mScrollX - lp.x); float y = mLastTouchY + (float) (mScrollY - lp.y); - mTextEntry.fakeTouchEvent(x, y); + mWebTextView.fakeTouchEvent(x, y); } } - private void updateTextEntry() { - if (mTextEntry == null) { - mTextEntry = new TextDialog(mContext, WebView.this); - // Initialize our generation number. - mTextGeneration = 0; - } + /* + * This method checks the current focus and potentially rebuilds + * mWebTextView to have the appropriate properties, such as password, + * multiline, and what text it contains. It also removes it if necessary. + */ + private void rebuildWebTextView() { // If we do not have focus, do nothing until we gain focus. - if (!hasFocus() && !mTextEntry.hasFocus() - || (mTouchMode >= FIRST_SCROLL_ZOOM + if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus()) + || (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM)) { - mNeedsUpdateTextEntry = true; + mNeedsRebuildWebTextView = true; return; } boolean alreadyThere = inEditingMode(); - if (0 == mNativeClass || !nativeUpdateFocusNode()) { + // inEditingMode can only return true if mWebTextView is non-null, + // so we can safely call remove() if (alreadyThere) + if (0 == mNativeClass || (!nativeFocusIsTextInput() + && !nativeCursorIsTextInput())) { if (alreadyThere) { - mTextEntry.remove(); + mWebTextView.remove(); } return; } - FocusNode node = mFocusNode; - if (!node.mIsTextField && !node.mIsTextArea) { - if (alreadyThere) { - mTextEntry.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); + // Initialize our generation number. + mTextGeneration = 0; } - mTextEntry.setTextSize(contentToView(node.mTextSize)); + mWebTextView.setTextSize(contentToView(nativeFocusTextSize())); Rect visibleRect = sendOurVisibleRect(); // Note that sendOurVisibleRect calls viewToContent, so the coordinates // should be in content coordinates. - if (!Rect.intersects(node.mBounds, visibleRect)) { + Rect bounds = nativeFocusNodeBounds(); + if (!Rect.intersects(bounds, visibleRect)) { // Node is not on screen, so do not bother. return; } - int x = node.mBounds.left; - int y = node.mBounds.top; - int width = node.mBounds.width(); - int height = node.mBounds.height(); - if (alreadyThere && mTextEntry.isSameTextField(node.mNodePointer)) { + String text = nativeFocusText(); + int nodePointer = nativeFocusNodePointer(); + if (alreadyThere && mWebTextView.isSameTextField(nodePointer)) { // It is possible that we have the same textfield, but it has moved, // i.e. In the case of opening/closing the screen. // In that case, we need to set the dimensions, but not the other // aspects. // We also need to restore the selection, which gets wrecked by // calling setTextEntryRect. - Spannable spannable = (Spannable) mTextEntry.getText(); + Spannable spannable = (Spannable) mWebTextView.getText(); int start = Selection.getSelectionStart(spannable); int end = Selection.getSelectionEnd(spannable); - setTextEntryRect(x, y, width, height); // If the text has been changed by webkit, update it. However, if // there has been more UI text input, ignore it. We will receive // another update when that text is recognized. - if (node.mText != null && !node.mText.equals(spannable.toString()) - && node.mRootTextGeneration == mTextGeneration) { - mTextEntry.setTextAndKeepSelection(node.mText); + if (text != null && !text.equals(spannable.toString()) + && nativeTextGeneration() == mTextGeneration) { + mWebTextView.setTextAndKeepSelection(text); } else { Selection.setSelection(spannable, start, end); } } else { - String text = node.mText; - setTextEntryRect(x, y, width, height); - mTextEntry.setGravity(node.mIsRtlText ? Gravity.RIGHT : + Rect vBox = contentToView(bounds); + mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), + vBox.height()); + mWebTextView.setGravity(nativeFocusIsRtlText() ? Gravity.RIGHT : Gravity.NO_GRAVITY); // this needs to be called before update adapter thread starts to - // ensure the mTextEntry has the same node pointer - mTextEntry.setNodePointer(node.mNodePointer); + // ensure the mWebTextView has the same node pointer + mWebTextView.setNodePointer(nodePointer); int maxLength = -1; - if (node.mIsTextField) { - maxLength = node.mMaxLength; + boolean isTextField = nativeFocusIsTextField(); + if (isTextField) { + maxLength = nativeFocusMaxLength(); + String name = nativeFocusName(); if (mWebViewCore.getSettings().getSaveFormData() - && node.mName != null) { + && name != null) { HashMap data = new HashMap(); - data.put("text", node.mText); + data.put("text", text); Message update = mPrivateHandler.obtainMessage( - UPDATE_TEXT_ENTRY_ADAPTER, node.mNodePointer, 0, - data); - UpdateTextEntryAdapter updater = new UpdateTextEntryAdapter( - node.mName, getUrl(), update); + REQUEST_FORM_DATA, nodePointer, 0, data); + RequestFormData updater = new RequestFormData(name, + getUrl(), update); Thread t = new Thread(updater); t.start(); } } - mTextEntry.setMaxLength(maxLength); + mWebTextView.setMaxLength(maxLength); AutoCompleteAdapter adapter = null; - mTextEntry.setAdapterCustom(adapter); - mTextEntry.setSingleLine(node.mIsTextField); - mTextEntry.setInPassword(node.mIsPassword); + mWebTextView.setAdapterCustom(adapter); + mWebTextView.setSingleLine(isTextField); + mWebTextView.setInPassword(nativeFocusIsPassword()); if (null == text) { - mTextEntry.setText("", 0, 0); + mWebTextView.setText("", 0, 0); } else { // Change to true to enable the old style behavior, where // entering a textfield/textarea always set the selection to the @@ -2962,24 +3057,29 @@ public class WebView extends AbsoluteLayout // textarea. Testing out a new behavior, where textfields set // selection at the end, and textareas at the beginning. if (false) { - mTextEntry.setText(text, 0, text.length()); - } else if (node.mIsTextField) { + mWebTextView.setText(text, 0, text.length()); + } else if (isTextField) { int length = text.length(); - mTextEntry.setText(text, length, length); + mWebTextView.setText(text, length, length); } else { - mTextEntry.setText(text, 0, 0); + mWebTextView.setText(text, 0, 0); } } - mTextEntry.requestFocus(); + mWebTextView.requestFocus(); } } - private class UpdateTextEntryAdapter implements Runnable { + /* + * 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; - public UpdateTextEntryAdapter(String name, String url, Message msg) { + public RequestFormData(String name, String url, Message msg) { mName = name; mUrl = url; mUpdateMessage = msg; @@ -2996,21 +3096,13 @@ public class WebView extends AbsoluteLayout } } - private void setTextEntryRect(int x, int y, int width, int height) { - x = contentToView(x); - y = contentToView(y); - width = contentToView(width); - height = contentToView(height); - mTextEntry.setRect(x, y, width, height); - } - - // This is used to determine long press with the enter key, or - // a center key. Does not affect long press with the trackball/touch. - private boolean mGotEnterDown = false; + // 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 onKeyDown(int keyCode, KeyEvent event) { - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis() + ", " + event); } @@ -3038,15 +3130,15 @@ public class WebView extends AbsoluteLayout return false; } - if (mShiftIsPressed == false && nativeFocusNodeWantsKeyEvents() == false - && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT + if (mShiftIsPressed == false && nativeCursorWantsKeyEvents() == false + && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) { mExtendSelection = false; mShiftIsPressed = true; - if (nativeUpdateFocusNode()) { - FocusNode node = mFocusNode; - mSelectX = contentToView(node.mBounds.left); - mSelectY = contentToView(node.mBounds.top); + if (nativeHasCursorNode()) { + Rect rect = nativeCursorNodeBounds(); + mSelectX = contentToView(rect.left); + mSelectY = contentToView(rect.top); } else { mSelectX = mScrollX + (int) mLastTouchX; mSelectY = mScrollY + (int) mLastTouchY; @@ -3068,13 +3160,12 @@ public class WebView extends AbsoluteLayout return false; } - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER - || keyCode == KeyEvent.KEYCODE_ENTER) { + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { switchOutDrawHistory(); if (event.getRepeatCount() == 0) { - mGotEnterDown = true; + mGotCenterDown = true; mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT); + .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT); // Already checked mNativeClass, so we do not need to check it // again. nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true); @@ -3084,6 +3175,15 @@ public class WebView extends AbsoluteLayout return false; } + if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT + && keyCode != KeyEvent.KEYCODE_SHIFT_RIGHT) { + // turn off copy select if a shift-key combo is pressed + mExtendSelection = mShiftIsPressed = false; + if (mTouchMode == TOUCH_SELECT_MODE) { + mTouchMode = TOUCH_INIT_MODE; + } + } + if (getSettings().getNavDump()) { switch (keyCode) { case KeyEvent.KEYCODE_4: @@ -3113,7 +3213,7 @@ public class WebView extends AbsoluteLayout } // TODO: should we pass all the keys to DOM or check the meta tag - if (nativeFocusNodeWantsKeyEvents() || true) { + if (nativeCursorWantsKeyEvents() || true) { // pass the key to DOM mWebViewCore.sendMessage(EventHub.KEY_DOWN, event); // return true as DOM handles the key @@ -3126,7 +3226,7 @@ public class WebView extends AbsoluteLayout @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis() + ", " + event); } @@ -3136,10 +3236,9 @@ public class WebView extends AbsoluteLayout } // special CALL handling when focus node's href is "tel:XXX" - if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) { - FocusNode node = mFocusNode; - String text = node.mText; - if (!node.mIsTextField && !node.mIsTextArea && text != null + 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); @@ -3166,7 +3265,7 @@ public class WebView extends AbsoluteLayout return false; } - if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT + if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { if (commitCopy()) { return true; @@ -3180,55 +3279,30 @@ public class WebView extends AbsoluteLayout return false; } - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER - || keyCode == KeyEvent.KEYCODE_ENTER) { + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // remove the long press message first - mPrivateHandler.removeMessages(LONG_PRESS_ENTER); - mGotEnterDown = false; + mPrivateHandler.removeMessages(LONG_PRESS_CENTER); + mGotCenterDown = false; - if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) { - if (mShiftIsPressed) { - return false; - } - if (getSettings().supportZoom()) { - if (mTouchMode == TOUCH_DOUBLECLICK_MODE) { - zoomScrollOut(); - } else { - if (LOGV_ENABLED) { - Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE"); - } - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT); - mTouchMode = TOUCH_DOUBLECLICK_MODE; - } - return true; - } + if (mShiftIsPressed) { + return false; } - - Rect visibleRect = sendOurVisibleRect(); - // Note that sendOurVisibleRect calls viewToContent, so the - // coordinates should be in content coordinates. - if (nativeUpdateFocusNode()) { - if (Rect.intersects(mFocusNode.mBounds, visibleRect)) { - nativeSetFollowedLink(true); - mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS, - EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0, - new WebViewCore.FocusData(mFocusData)); - playSoundEffect(SoundEffectConstants.CLICK); - if (!mCallbackProxy.uiOverrideUrlLoading(mFocusNode.mText)) { - // use CLICK instead of KEY_DOWN/KEY_UP so that we can - // trigger mouse click events - mWebViewCore.sendMessage(EventHub.CLICK); - } + if (getSettings().supportZoom() + && mTouchMode == TOUCH_DOUBLECLICK_MODE) { + zoomScrollOut(); + } else { + mPrivateHandler.sendMessageDelayed(mPrivateHandler + .obtainMessage(SWITCH_TO_CLICK), TAP_TIMEOUT); + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE"); } - return true; + mTouchMode = TOUCH_DOUBLECLICK_MODE; } - // Bubble up the key event as WebView doesn't handle it - return false; + return true; } // TODO: should we pass all the keys to DOM or check the meta tag - if (nativeFocusNodeWantsKeyEvents() || true) { + if (nativeCursorWantsKeyEvents() || true) { // pass the key to DOM mWebViewCore.sendMessage(EventHub.KEY_UP, event); // return true as DOM handles the key @@ -3238,7 +3312,7 @@ public class WebView extends AbsoluteLayout // Bubble up the key event as WebView doesn't handle it return false; } - + /** * @hide */ @@ -3295,15 +3369,15 @@ public class WebView extends AbsoluteLayout // Clean up the zoom controller mZoomButtonsController.setVisible(false); } - + // Implementation for OnHierarchyChangeListener public void onChildViewAdded(View parent, View child) {} - + public void onChildViewRemoved(View p, View child) { if (child == this) { if (inEditingMode()) { clearTextEntry(); - mNeedsUpdateTextEntry = true; + mNeedsRebuildWebTextView = true; } } } @@ -3317,26 +3391,27 @@ public class WebView extends AbsoluteLayout public void onGlobalFocusChanged(View oldFocus, View newFocus) { } - // To avoid drawing the focus ring, and remove the TextView when our window + // To avoid drawing the cursor ring, and remove the TextView when our window // loses focus. @Override public void onWindowFocusChanged(boolean hasWindowFocus) { if (hasWindowFocus) { if (hasFocus()) { // If our window regained focus, and we have focus, then begin - // drawing the focus ring, and restore the TextView if + // drawing the cursor ring, and restore the TextView if // necessary. - mDrawFocusRing = true; - if (mNeedsUpdateTextEntry) { - updateTextEntry(); + mDrawCursorRing = true; + if (mNeedsRebuildWebTextView) { + rebuildWebTextView(); } if (mNativeClass != 0) { nativeRecordButtons(true, false, true); } + setFocusControllerActive(true); } else { // If our window gained focus, but we do not have it, do not - // draw the focus ring. - mDrawFocusRing = false; + // draw the cursor ring. + mDrawCursorRing = false; // We do not call nativeRecordButtons here because we assume // that when we lost focus, or window focus, it got called with // false for the first parameter @@ -3345,42 +3420,57 @@ public class WebView extends AbsoluteLayout if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) { /* * The zoom controls come in their own window, so our window - * loses focus. Our policy is to not draw the focus ring if + * 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. */ - // If our window has lost focus, stop drawing the focus ring - mDrawFocusRing = false; + // If our window has lost focus, stop drawing the cursor ring + mDrawCursorRing = false; } mGotKeyDown = false; mShiftIsPressed = false; if (mNativeClass != 0) { nativeRecordButtons(false, false, true); } + setFocusControllerActive(false); } invalidate(); super.onWindowFocusChanged(hasWindowFocus); } + /* + * Pass a message to WebCore Thread, determining whether the WebCore::Page's + * FocusController is "active" so that it will draw the blinking cursor. + */ + private void setFocusControllerActive(boolean active) { + if (mWebViewCore != null) { + mWebViewCore.sendMessage(EventHub.SET_ACTIVE, active ? 1 : 0, 0); + } + } + @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { - if (LOGV_ENABLED) { + 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 focus ring, and add the TextView if necessary. + // the cursor ring, and add the TextView if necessary. if (hasWindowFocus()) { - mDrawFocusRing = true; - if (mNeedsUpdateTextEntry) { - updateTextEntry(); - mNeedsUpdateTextEntry = false; + mDrawCursorRing = true; + if (mNeedsRebuildWebTextView) { + rebuildWebTextView(); + mNeedsRebuildWebTextView = false; } if (mNativeClass != 0) { nativeRecordButtons(true, false, true); } + // FIXME: This is unnecessary if we are gaining focus from the + // WebTextView. How can we tell if it was the last thing in + // focus? + setFocusControllerActive(true); //} else { // The WebView has gained focus while we do not have // windowfocus. When our window lost focus, we should have @@ -3388,12 +3478,13 @@ public class WebView extends AbsoluteLayout } } else { // When we lost focus, unless focus went to the TextView (which is - // true if we are in editing mode), stop drawing the focus ring. + // true if we are in editing mode), stop drawing the cursor ring. if (!inEditingMode()) { - mDrawFocusRing = false; + mDrawCursorRing = false; if (mNativeClass != 0) { nativeRecordButtons(false, false, true); } + setFocusControllerActive(false); } mGotKeyDown = false; } @@ -3424,8 +3515,8 @@ public class WebView extends AbsoluteLayout super.onScrollChanged(l, t, oldl, oldt); sendOurVisibleRect(); } - - + + @Override public boolean dispatchKeyEvent(KeyEvent event) { boolean dispatch = true; @@ -3469,7 +3560,7 @@ public class WebView extends AbsoluteLayout return false; } - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, ev + " at " + ev.getEventTime() + " mTouchMode=" + mTouchMode); } @@ -3494,7 +3585,7 @@ public class WebView extends AbsoluteLayout if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT && mTouchMode != SCROLL_ZOOM_ANIMATION_IN && mTouchMode != SCROLL_ZOOM_ANIMATION_OUT - && (action != MotionEvent.ACTION_MOVE || + && (action != MotionEvent.ACTION_MOVE || eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) { WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData(); ted.mAction = action; @@ -3525,7 +3616,7 @@ public class WebView extends AbsoluteLayout mSelectX = mScrollX + (int) x; mSelectY = mScrollY + (int) y; mTouchMode = TOUCH_SELECT_MODE; - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY); } nativeMoveSelection(viewToContent(mSelectX) @@ -3553,7 +3644,7 @@ public class WebView extends AbsoluteLayout break; } case MotionEvent.ACTION_MOVE: { - if (mTouchMode == TOUCH_DONE_MODE + if (mTouchMode == TOUCH_DONE_MODE || mTouchMode == SCROLL_ZOOM_ANIMATION_IN || mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) { // no dragging during scroll zoom animation @@ -3570,7 +3661,7 @@ public class WebView extends AbsoluteLayout if (mTouchMode == TOUCH_SELECT_MODE) { mSelectX = mScrollX + (int) x; mSelectY = mScrollY + (int) y; - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY); } nativeMoveSelection(viewToContent(mSelectX) @@ -3605,9 +3696,6 @@ public class WebView extends AbsoluteLayout WebViewCore.pauseUpdate(mWebViewCore); int contentX = viewToContent((int) x + mScrollX); int contentY = viewToContent((int) y + mScrollY); - if (inEditingMode()) { - mTextEntry.updateCachedTextfield(); - } nativeClearFocus(contentX, contentY); // remove the zoom anchor if there is any if (mZoomScale != 0) { @@ -3618,7 +3706,7 @@ public class WebView extends AbsoluteLayout if (settings.supportZoom() && settings.getBuiltInZoomControls() && !mZoomButtonsController.isVisible() - && (canZoomScrollOut() || + && (canZoomScrollOut() || mMinZoomScale < mMaxZoomScale)) { mZoomButtonsController.setVisible(true); } @@ -3644,7 +3732,7 @@ public class WebView extends AbsoluteLayout } // reverse direction means lock in the snap mode if ((ax > MAX_SLOPE_FOR_DIAG * ay) && - ((mSnapPositive && + ((mSnapPositive && deltaX < -mMinLockSnapReverseDistance) || (!mSnapPositive && deltaX > mMinLockSnapReverseDistance))) { @@ -3658,9 +3746,9 @@ public class WebView extends AbsoluteLayout } // reverse direction means lock in the snap mode if ((ay > MAX_SLOPE_FOR_DIAG * ax) && - ((mSnapPositive && + ((mSnapPositive && deltaY < -mMinLockSnapReverseDistance) - || (!mSnapPositive && + || (!mSnapPositive && deltaY > mMinLockSnapReverseDistance))) { mSnapScrollMode = SNAP_Y_LOCK; } @@ -3725,7 +3813,7 @@ public class WebView extends AbsoluteLayout // no action during scroll animation break; case SCROLL_ZOOM_OUT: - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "ACTION_UP SCROLL_ZOOM_OUT" + " eventTime - mLastTouchTime=" + (eventTime - mLastTouchTime)); @@ -3785,16 +3873,13 @@ public class WebView extends AbsoluteLayout mTouchMode = TOUCH_DONE_MODE; int contentX = viewToContent((int) mLastTouchX + mScrollX); int contentY = viewToContent((int) mLastTouchY + mScrollY); - if (inEditingMode()) { - mTextEntry.updateCachedTextfield(); - } nativeClearFocus(contentX, contentY); break; } } return true; } - + private long mTrackballFirstTime = 0; private long mTrackballLastTime = 0; private float mTrackballRemainsX = 0.0f; @@ -3820,10 +3905,10 @@ public class WebView extends AbsoluteLayout private Rect mLastFocusBounds; // Set by default; BrowserActivity clears to interpret trackball data - // directly for movement. Currently, the framework only passes + // directly for movement. Currently, the framework only passes // arrow key events, not trackball events, from one child to the next private boolean mMapTrackballToArrowKeys = true; - + public void setMapTrackballToArrowKeys(boolean setMap) { mMapTrackballToArrowKeys = setMap; } @@ -3841,26 +3926,26 @@ public class WebView extends AbsoluteLayout return true; } if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mPrivateHandler.removeMessages(SWITCH_TO_ENTER); + mPrivateHandler.removeMessages(SWITCH_TO_CLICK); mTrackballDown = true; if (mNativeClass != 0) { nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true); } if (time - mLastFocusTime <= TRACKBALL_TIMEOUT - && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) { + && !mLastFocusBounds.equals(nativeGetCursorRingBounds())) { nativeSelectBestAt(mLastFocusBounds); } - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "onTrackballEvent down ev=" + ev - + " time=" + time + + " time=" + time + " mLastFocusTime=" + mLastFocusTime); } if (isInTouchMode()) requestFocusFromTouch(); return false; // let common code in onKeyDown at it - } + } if (ev.getAction() == MotionEvent.ACTION_UP) { - // LONG_PRESS_ENTER is set in common onKeyDown - mPrivateHandler.removeMessages(LONG_PRESS_ENTER); + // LONG_PRESS_CENTER is set in common onKeyDown + mPrivateHandler.removeMessages(LONG_PRESS_CENTER); mTrackballDown = false; mTrackballUpTime = time; if (mShiftIsPressed) { @@ -3870,42 +3955,42 @@ public class WebView extends AbsoluteLayout mExtendSelection = true; } } - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "onTrackballEvent up ev=" + ev - + " time=" + time + + " time=" + time ); } return false; // let common code in onKeyUp at it } if (mMapTrackballToArrowKeys && mShiftIsPressed == false) { - if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent gmail quit"); + if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit"); return false; } - // no move if we're still waiting on SWITCH_TO_ENTER timeout + // no move if we're still waiting on SWITCH_TO_CLICK timeout if (mTouchMode == TOUCH_DOUBLECLICK_MODE) { - if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent 2 click quit"); + if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent 2 click quit"); return true; } if (mTrackballDown) { - if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent down quit"); + if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit"); return true; // discard move if trackball is down } if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) { - if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent up timeout quit"); + 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 (LOGV_ENABLED) { - Log.v(LOGTAG, "onTrackballEvent time=" + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "onTrackballEvent time=" + time + " last=" + mTrackballLastTime); } mTrackballFirstTime = time; mTrackballXMove = mTrackballYMove = 0; } mTrackballLastTime = time; - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time); } mTrackballRemainsX += ev.getX(); @@ -3913,7 +3998,7 @@ public class WebView extends AbsoluteLayout doTrackball(time); return true; } - + void moveSelection(float xRate, float yRate) { if (mNativeClass == 0) return; @@ -3927,8 +4012,8 @@ public class WebView extends AbsoluteLayout , mSelectX)); mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET , mSelectY)); - if (LOGV_ENABLED) { - Log.v(LOGTAG, "moveSelection" + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "moveSelection" + " mSelectX=" + mSelectX + " mSelectY=" + mSelectY + " mScrollX=" + mScrollX @@ -3940,10 +4025,10 @@ public class WebView extends AbsoluteLayout nativeMoveSelection(viewToContent(mSelectX) , viewToContent(mSelectY), mExtendSelection); int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET - : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET + : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET : 0; int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET - : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET + : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET : 0; pinScrollBy(scrollX, scrollY, true, 0); Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1); @@ -4000,7 +4085,7 @@ public class WebView extends AbsoluteLayout if (elapsed == 0) { elapsed = TRACKBALL_TIMEOUT; } - float xRate = mTrackballRemainsX * 1000 / elapsed; + float xRate = mTrackballRemainsX * 1000 / elapsed; float yRate = mTrackballRemainsY * 1000 / elapsed; if (mShiftIsPressed) { moveSelection(xRate, yRate); @@ -4010,7 +4095,7 @@ public class WebView extends AbsoluteLayout float ax = Math.abs(xRate); float ay = Math.abs(yRate); float maxA = Math.max(ax, ay); - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "doTrackball elapsed=" + elapsed + " xRate=" + xRate + " yRate=" + yRate @@ -4027,9 +4112,9 @@ public class WebView extends AbsoluteLayout int maxWH = Math.max(width, height); mZoomScrollX += scaleTrackballX(xRate, maxWH); mZoomScrollY += scaleTrackballY(yRate, maxWH); - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "doTrackball SCROLL_ZOOM_OUT" - + " mZoomScrollX=" + mZoomScrollX + + " mZoomScrollX=" + mZoomScrollX + " mZoomScrollY=" + mZoomScrollY); } mZoomScrollX = Math.min(width, Math.max(0, mZoomScrollX)); @@ -4047,13 +4132,13 @@ public class WebView extends AbsoluteLayout int oldScrollX = mScrollX; int oldScrollY = mScrollY; if (count > 0) { - int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ? - KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN : + 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 (LOGV_ENABLED) { - Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode + " count=" + count + " mTrackballRemainsX=" + mTrackballRemainsX + " mTrackballRemainsY=" + mTrackballRemainsY); @@ -4066,12 +4151,12 @@ public class WebView extends AbsoluteLayout if (count >= TRACKBALL_SCROLL_COUNT) { int xMove = scaleTrackballX(xRate, width); int yMove = scaleTrackballY(yRate, height); - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "doTrackball pinScrollBy" + " count=" + count + " xMove=" + xMove + " yMove=" + yMove - + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX) - + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY) + + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX) + + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY) ); } if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) { @@ -4084,18 +4169,18 @@ public class WebView extends AbsoluteLayout pinScrollBy(xMove, yMove, true, 0); } mUserScroll = true; - } - mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS); + } + mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS); } public void flingScroll(int vx, int vy) { int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0); int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0); - + mScroller.fling(mScrollX, mScrollY, vx, vy, 0, maxX, 0, maxY); invalidate(); } - + private void doFling() { if (mVelocityTracker == null) { return; @@ -4114,7 +4199,7 @@ public class WebView extends AbsoluteLayout vx = 0; } } - + if (true /* EMG release: make our fling more like Maps' */) { // maps cuts their velocity in half vx = vx * 3 / 4; @@ -4175,7 +4260,7 @@ public class WebView extends AbsoluteLayout } if (mZoomControls == null) { mZoomControls = createZoomControls(); - + /* * need to be set to VISIBLE first so that getMeasuredHeight() in * {@link #onSizeChanged()} can return the measured value for proper @@ -4184,7 +4269,7 @@ public class WebView extends AbsoluteLayout mZoomControls.setVisibility(View.VISIBLE); mZoomControlRunnable = new Runnable() { public void run() { - + /* Don't dismiss the controls if the user has * focus on them. Wait and check again later. */ @@ -4236,7 +4321,7 @@ public class WebView extends AbsoluteLayout /** * Gets the {@link ZoomButtonsController} which can be used to add * additional buttons to the zoom controls window. - * + * * @return The instance of {@link ZoomButtonsController} used by this class, * or null if it is unavailable. * @hide @@ -4274,19 +4359,15 @@ public class WebView extends AbsoluteLayout int contentY = viewToContent((int) mLastTouchY + mScrollY); Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop, contentX + mNavSlop, contentY + mNavSlop); - // If we were already focused on a textfield, update its cache. - if (inEditingMode()) { - mTextEntry.updateCachedTextfield(); - } nativeSelectBestAt(rect); } /*package*/ void shortPressOnTextField() { if (inEditingMode()) { - View v = mTextEntry; + View v = mWebTextView; int x = viewToContent((v.getLeft() + v.getRight()) >> 1); int y = viewToContent((v.getTop() + v.getBottom()) >> 1); - nativeMotionUp(x, y, mNavSlop, true); + nativeMotionUp(x, y, mNavSlop); } } @@ -4298,14 +4379,13 @@ public class WebView extends AbsoluteLayout // mLastTouchX and mLastTouchY are the point in the current viewport int contentX = viewToContent((int) mLastTouchX + mScrollX); int contentY = viewToContent((int) mLastTouchY + mScrollY); - if (nativeMotionUp(contentX, contentY, mNavSlop, true)) { + if (nativeMotionUp(contentX, contentY, mNavSlop)) { if (mLogEvent) { Checkin.updateStats(mContext.getContentResolver(), Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0); } } - if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField - && !mFocusNode.mIsTextArea) { + if (nativeHasCursorNode() && !nativeCursorIsTextInput()) { playSoundEffect(SoundEffectConstants.CLICK); } } @@ -4320,7 +4400,8 @@ public class WebView extends AbsoluteLayout public boolean requestFocus(int direction, Rect previouslyFocusedRect) { boolean result = false; if (inEditingMode()) { - result = mTextEntry.requestFocus(direction, previouslyFocusedRect); + result = mWebTextView.requestFocus(direction, + previouslyFocusedRect); } else { result = super.requestFocus(direction, previouslyFocusedRect); if (mWebViewCore.getSettings().getNeedInitialFocus()) { @@ -4344,7 +4425,7 @@ public class WebView extends AbsoluteLayout default: return result; } - if (mNativeClass != 0 && !nativeUpdateFocusNode()) { + if (mNativeClass != 0 && !nativeHasCursorNode()) { navHandledKey(fakeKeyDirection, 1, true, 0); } } @@ -4413,14 +4494,19 @@ public class WebView extends AbsoluteLayout int scrollYDelta = 0; - if (rect.bottom > screenBottom && rect.top > screenTop) { - if (rect.height() > height) { - scrollYDelta += (rect.top - screenTop); + 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 { - scrollYDelta += (rect.bottom - screenBottom); + // 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 -= (screenTop - rect.top); + scrollYDelta = rect.top - screenTop; } int width = getWidth() - getVerticalScrollbarWidth(); @@ -4445,33 +4531,31 @@ public class WebView extends AbsoluteLayout return false; } - + /* package */ void replaceTextfieldText(int oldStart, int oldEnd, String replace, int newStart, int newEnd) { HashMap arg = new HashMap(); - arg.put("focusData", new WebViewCore.FocusData(mFocusData)); arg.put("replace", replace); - arg.put("start", new Integer(newStart)); - arg.put("end", new Integer(newEnd)); + arg.put("start", Integer.valueOf(newStart)); + arg.put("end", Integer.valueOf(newEnd)); mTextGeneration++; mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg); } /* package */ void passToJavaScript(String currentText, KeyEvent event) { HashMap arg = new HashMap(); - arg.put("focusData", new WebViewCore.FocusData(mFocusData)); arg.put("event", event); arg.put("currentText", 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 + // 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, - new WebViewCore.FocusData(mFocusData), 1000); + cursorData(), 1000); } /* package */ WebViewCore getWebViewCore() { @@ -4489,9 +4573,9 @@ public class WebView extends AbsoluteLayout class PrivateHandler extends Handler { @Override public void handleMessage(Message msg) { - if (LOGV_ENABLED) { - Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what - > INVAL_RECT_MSG_ID ? Integer.toString(msg.what) + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what + > INVAL_RECT_MSG_ID ? Integer.toString(msg.what) : HandlerDebugString[msg.what - REMEMBER_PASSWORD]); } switch (msg.what) { @@ -4519,22 +4603,31 @@ public class WebView extends AbsoluteLayout case SWITCH_TO_LONGPRESS: { mTouchMode = TOUCH_DONE_MODE; performLongClick(); - updateTextEntry(); + rebuildWebTextView(); break; } - case SWITCH_TO_ENTER: - if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER"); + case SWITCH_TO_CLICK: mTouchMode = TOUCH_DONE_MODE; - onKeyUp(KeyEvent.KEYCODE_ENTER - , new KeyEvent(KeyEvent.ACTION_UP - , KeyEvent.KEYCODE_ENTER)); + Rect visibleRect = sendOurVisibleRect(); + // Note that sendOurVisibleRect calls viewToContent, so the + // coordinates should be in content coordinates. + if (!nativeCursorIntersects(visibleRect)) { + break; + } + nativeSetFollowedLink(true); + mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, + cursorData()); + playSoundEffect(SoundEffectConstants.CLICK); + if (!mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) { + mWebViewCore.sendMessage(EventHub.CLICK); + } break; case SCROLL_BY_MSG_ID: setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj); break; case SYNC_SCROLL_TO_MSG_ID: if (mUserScroll) { - // if user has scrolled explicitly, don't sync the + // if user has scrolled explicitly, don't sync the // scroll position any more mUserScroll = false; break; @@ -4543,7 +4636,7 @@ public class WebView extends AbsoluteLayout case SCROLL_TO_MSG_ID: if (setContentScrollTo(msg.arg1, msg.arg2)) { // if we can't scroll to the exact position due to pin, - // send a message to WebCore to re-scroll when we get a + // send a message to WebCore to re-scroll when we get a // new picture mUserScroll = false; mWebViewCore.sendMessage(EventHub.SYNC_SCROLL, @@ -4555,7 +4648,7 @@ public class WebView extends AbsoluteLayout break; case NEW_PICTURE_MSG_ID: // called for new content - final WebViewCore.DrawData draw = + final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj; final Point viewSize = draw.mViewPoint; if (mZoomScale > 0) { @@ -4578,9 +4671,9 @@ public class WebView extends AbsoluteLayout // received in the fixed dimension. final boolean updateLayout = viewSize.x == mLastWidthSent && viewSize.y == mLastHeightSent; - recordNewContentSize(draw.mWidthHeight.x, + recordNewContentSize(draw.mWidthHeight.x, draw.mWidthHeight.y, updateLayout); - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Rect b = draw.mInvalRegion.getBounds(); Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + b.left+","+b.top+","+b.right+","+b.bottom+"}"); @@ -4596,22 +4689,23 @@ public class WebView extends AbsoluteLayout break; case UPDATE_TEXTFIELD_TEXT_MSG_ID: // Make sure that the textfield is currently focused - // and representing the same node as the pointer. - if (inEditingMode() && - mTextEntry.isSameTextField(msg.arg1)) { + // and representing the same node as the pointer. + if (inEditingMode() && + mWebTextView.isSameTextField(msg.arg1)) { if (msg.getData().getBoolean("password")) { - Spannable text = (Spannable) mTextEntry.getText(); + Spannable text = (Spannable) mWebTextView.getText(); int start = Selection.getSelectionStart(text); int end = Selection.getSelectionEnd(text); - mTextEntry.setInPassword(true); + mWebTextView.setInPassword(true); // Restore the selection, which may have been // ruined by setInPassword. - Spannable pword = (Spannable) mTextEntry.getText(); + Spannable pword = + (Spannable) mWebTextView.getText(); Selection.setSelection(pword, start, end); // If the text entry has created more events, ignore // this one. } else if (msg.arg2 == mTextGeneration) { - mTextEntry.setTextAndKeepSelection( + mWebTextView.setTextAndKeepSelection( (String) msg.obj); } } @@ -4621,7 +4715,7 @@ public class WebView extends AbsoluteLayout break; } // Do not reset the focus or clear the text; the user may have already -// navigated or entered text at this point. The focus should have gotten +// navigated or entered text at this point. The focus should have gotten // reset, if need be, when the focus cache was built. Similarly, the text // view should already be torn down and rebuilt if needed. // nativeResetFocus(); @@ -4656,6 +4750,7 @@ public class WebView extends AbsoluteLayout if (mInitialScale > 0) { scale = mInitialScale / 100.0f; } else { + if (initialScale < 0) break; if (mWebViewCore.getSettings().getUseWideViewPort()) { // force viewSizeChanged by setting mLastWidthSent // to 0 @@ -4676,22 +4771,13 @@ public class WebView extends AbsoluteLayout case MARK_NODE_INVALID_ID: nativeMarkNodeInvalid(msg.arg1); break; - case NOTIFY_FOCUS_SET_MSG_ID: - if (mNativeClass != 0) { - nativeNotifyFocusSet(inEditingMode()); - } - break; case UPDATE_TEXT_ENTRY_MSG_ID: - // this is sent after finishing resize in WebViewCore. Make + // this is sent after finishing resize in WebViewCore. Make // sure the text edit box is still on the screen. - boolean alreadyThere = inEditingMode(); - if (alreadyThere && nativeUpdateFocusNode()) { - FocusNode node = mFocusNode; - if (node.mIsTextField || node.mIsTextArea) { - mTextEntry.bringIntoView(); - } + if (inEditingMode() && nativeCursorIsTextInput()) { + mWebTextView.bringIntoView(); } - updateTextEntry(); + rebuildWebTextView(); break; case RECOMPUTE_FOCUS_MSG_ID: if (mNativeClass != 0) { @@ -4709,17 +4795,17 @@ public class WebView extends AbsoluteLayout } break; } - case UPDATE_TEXT_ENTRY_ADAPTER: + case REQUEST_FORM_DATA: HashMap data = (HashMap) msg.obj; - if (mTextEntry.isSameTextField(msg.arg1)) { + if (mWebTextView.isSameTextField(msg.arg1)) { AutoCompleteAdapter adapter = (AutoCompleteAdapter) data.get("adapter"); - mTextEntry.setAdapterCustom(adapter); + mWebTextView.setAdapterCustom(adapter); } break; case UPDATE_CLIPBOARD: String str = (String) msg.obj; - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "UPDATE_CLIPBOARD " + str); } try { @@ -4734,12 +4820,12 @@ public class WebView extends AbsoluteLayout WebViewCore.resumeUpdate(mWebViewCore); break; - case LONG_PRESS_ENTER: + case LONG_PRESS_CENTER: // as this is shared by keydown and trackballdown, reset all // the states - mGotEnterDown = false; + mGotCenterDown = false; mTrackballDown = false; - // LONG_PRESS_ENTER is sent as a delayed message. If we + // LONG_PRESS_CENTER is sent as a delayed message. If we // switch to windows overview, the WebView will be // temporarily removed from the view system. In that case, // do nothing. @@ -4770,16 +4856,12 @@ public class WebView extends AbsoluteLayout // Class used to use a dropdown for a <select> element private class InvokeListBox implements Runnable { - // Strings for the labels in the listbox. - private String[] mArray; - // Array representing whether each item is enabled. - private boolean[] mEnableArray; // 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 + // Passed in to a list with single selection to tell // where the initial selection is. private int mSelection; @@ -4798,14 +4880,14 @@ public class WebView extends AbsoluteLayout } /** - * Subclass ArrayAdapter so we can disable OptionGroupLabels, + * Subclass ArrayAdapter so we can disable OptionGroupLabels, * and allow filtering. */ private class MyArrayListAdapter extends ArrayAdapter<Container> { public MyArrayListAdapter(Context context, Container[] objects, boolean multiple) { - super(context, + super(context, multiple ? com.android.internal.R.layout.select_dialog_multichoice : - com.android.internal.R.layout.select_dialog_singlechoice, + com.android.internal.R.layout.select_dialog_singlechoice, objects); } @@ -4863,7 +4945,7 @@ public class WebView extends AbsoluteLayout } } - private InvokeListBox(String[] array, boolean[] enabled, int + private InvokeListBox(String[] array, boolean[] enabled, int selection) { mSelection = selection; mMultiple = false; @@ -4926,31 +5008,36 @@ public class WebView extends AbsoluteLayout public void run() { final ListView listView = (ListView) LayoutInflater.from(mContext) .inflate(com.android.internal.R.layout.select_dialog, null); - final MyArrayListAdapter adapter = new + final MyArrayListAdapter adapter = new MyArrayListAdapter(mContext, mContainers, mMultiple); AlertDialog.Builder b = new AlertDialog.Builder(mContext) .setView(listView).setCancelable(true) .setInverseBackgroundForced(true); - + if (mMultiple) { b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mWebViewCore.sendMessage( - EventHub.LISTBOX_CHOICES, + EventHub.LISTBOX_CHOICES, adapter.getCount(), 0, listView.getCheckedItemPositions()); }}); - b.setNegativeButton(android.R.string.cancel, null); + b.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mWebViewCore.sendMessage( + EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); + }}); } final AlertDialog dialog = 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 + // 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); @@ -5013,48 +5100,26 @@ public class WebView extends AbsoluteLayout } // called by JNI - private void sendFinalFocus(int frame, int node, int x, int y) { - WebViewCore.FocusData focusData = new WebViewCore.FocusData(); - focusData.mFrame = frame; - focusData.mNode = node; - focusData.mX = x; - focusData.mY = y; - mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS, - EventHub.NO_FOCUS_CHANGE_BLOCK, 0, focusData); + private void sendMoveMouse(int frame, int node, int x, int y) { + mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, + new WebViewCore.CursorData(frame, node, x, y)); } // called by JNI - private void setFocusData(int moveGeneration, int buildGeneration, - int frame, int node, int x, int y, boolean ignoreNullFocus) { - mFocusData.mMoveGeneration = moveGeneration; - mFocusData.mBuildGeneration = buildGeneration; - mFocusData.mFrame = frame; - mFocusData.mNode = node; - mFocusData.mX = x; - mFocusData.mY = y; - mFocusData.mIgnoreNullFocus = ignoreNullFocus; - } - - // called by JNI - private void sendKitFocus() { - WebViewCore.FocusData focusData = new WebViewCore.FocusData(mFocusData); - mWebViewCore.sendMessage(EventHub.SET_KIT_FOCUS, focusData); + private void sendMoveMouseIfLatest() { + mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST, cursorData()); } // called by JNI - private void sendMotionUp(int touchGeneration, int buildGeneration, - int frame, int node, int x, int y, int size, boolean isClick, - boolean retry) { + private void sendMotionUp(int touchGeneration, + int frame, int node, int x, int y, int size) { WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData(); touchUpData.mMoveGeneration = touchGeneration; - touchUpData.mBuildGeneration = buildGeneration; touchUpData.mSize = size; - touchUpData.mIsClick = isClick; - touchUpData.mRetry = retry; - mFocusData.mFrame = touchUpData.mFrame = frame; - mFocusData.mNode = touchUpData.mNode = node; - mFocusData.mX = touchUpData.mX = x; - mFocusData.mY = touchUpData.mY = y; + touchUpData.mFrame = frame; + touchUpData.mNode = node; + touchUpData.mX = x; + touchUpData.mY = y; mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData); } @@ -5093,7 +5158,7 @@ public class WebView extends AbsoluteLayout private void viewInvalidate() { invalidate(); } - + // return true if the key was handled private boolean navHandledKey(int keyCode, int count, boolean noScroll , long time) { @@ -5101,9 +5166,9 @@ public class WebView extends AbsoluteLayout return false; } mLastFocusTime = time; - mLastFocusBounds = nativeGetFocusRingBounds(); + mLastFocusBounds = nativeGetCursorRingBounds(); boolean keyHandled = nativeMoveFocus(keyCode, count, noScroll) == false; - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "navHandledKey mLastFocusBounds=" + mLastFocusBounds + " mLastFocusTime=" + mLastFocusTime + " handled=" + keyHandled); @@ -5111,7 +5176,7 @@ public class WebView extends AbsoluteLayout if (keyHandled == false || mHeightCanMeasure == false) { return keyHandled; } - Rect contentFocus = nativeGetFocusRingBounds(); + Rect contentFocus = nativeGetCursorRingBounds(); if (contentFocus.isEmpty()) return keyHandled; Rect viewFocus = contentToView(contentFocus); Rect visRect = new Rect(); @@ -5135,14 +5200,14 @@ public class WebView extends AbsoluteLayout } if (mLastFocusBounds.isEmpty()) return keyHandled; if (mLastFocusBounds.equals(contentFocus)) return keyHandled; - if (LOGV_ENABLED) { + if (DebugFlags.WEB_VIEW) { Log.v(LOGTAG, "navHandledKey contentFocus=" + contentFocus); } requestRectangleOnScreen(viewFocus); mUserScroll = true; return keyHandled; } - + /** * Set the background color. It's white by default. Pass * zero to make the view transparent. @@ -5157,7 +5222,7 @@ public class WebView extends AbsoluteLayout nativeDebugDump(); mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE); } - + /** * Update our cache with updatedText. * @param updatedText The new text to put in our cache. @@ -5167,52 +5232,70 @@ public class WebView extends AbsoluteLayout // we recognize that it is up to date. nativeUpdateCachedTextfield(updatedText, mTextGeneration); } - - // 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 void nativeClearFocus(int x, int y); private native void nativeCreate(int ptr); + private native int nativeCursorFramePointer(); + private native Rect nativeCursorNodeBounds(); + /* package */ native int nativeCursorNodePointer(); + /* package */ native boolean nativeCursorMatchesFocus(); + private native boolean nativeCursorIntersects(Rect visibleRect); + private native boolean nativeCursorIsAnchor(); + private native boolean nativeCursorIsTextInput(); + private native String nativeCursorText(); + private native boolean nativeCursorWantsKeyEvents(); private native void nativeDebugDump(); private native void nativeDestroy(); - private native void nativeDrawFocusRing(Canvas content); + private native void nativeDrawCursorRing(Canvas content); + private native void nativeDrawMatches(Canvas canvas); private native void nativeDrawSelection(Canvas content , int x, int y, boolean extendSelection); private native void nativeDrawSelectionRegion(Canvas content); - private native boolean nativeUpdateFocusNode(); - private native Rect nativeGetFocusRingBounds(); - private native Rect nativeGetNavBounds(); + private native void nativeDumpDisplayTree(String urlOrNull); + private native int nativeFindAll(String findLower, String findUpper); + private native void nativeFindNext(boolean forward); + private native boolean nativeFocusIsPassword(); + private native boolean nativeFocusIsRtlText(); + private native boolean nativeFocusIsTextField(); + private native boolean nativeFocusIsTextInput(); + private native int nativeFocusMaxLength(); + private native String nativeFocusName(); + private native Rect nativeFocusNodeBounds(); + /* package */ native int nativeFocusNodePointer(); + private native String nativeFocusText(); + private native int nativeFocusTextSize(); + /** + * Returns true if the native focus nodes says it wants to handle key events + * (ala plugins). This can only be called if mNativeClass is non-zero! + */ + private native Rect nativeGetCursorRingBounds(); + private native Region nativeGetSelection(); + private native boolean nativeHasCursorNode(); + private native boolean nativeHasFocusNode(); + private native String nativeImageURI(int x, int y); private native void nativeInstrumentReport(); private native void nativeMarkNodeInvalid(int node); // return true if the page has been scrolled - private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick); + private native boolean nativeMotionUp(int x, int y, int slop); // returns false if it handled the key - private native boolean nativeMoveFocus(int keyCode, int count, + private native boolean nativeMoveFocus(int keyCode, int count, boolean noScroll); - private native void nativeNotifyFocusSet(boolean inEditingMode); + private native int nativeMoveGeneration(); + private native void nativeMoveSelection(int x, int y, + boolean extendSelection); private native void nativeRecomputeFocus(); // Like many other of our native methods, you must make sure that // mNativeClass is not null before calling this method. private native void nativeRecordButtons(boolean focused, boolean pressed, boolean invalidate); - private native void nativeResetFocus(); - private native void nativeResetNavClipBounds(); private native void nativeSelectBestAt(Rect rect); private native void nativeSetFindIsDown(); private native void nativeSetFollowedLink(boolean followed); private native void nativeSetHeightCanMeasure(boolean measure); - private native void nativeSetNavBounds(Rect rect); - private native void nativeSetNavClipBounds(Rect rect); - private native String nativeImageURI(int x, int y); - /** - * Returns true if the native focus nodes says it wants to handle key events - * (ala plugins). This can only be called if mNativeClass is non-zero! - */ - private native boolean nativeFocusNodeWantsKeyEvents(); - private native void nativeMoveSelection(int x, int y - , boolean extendSelection); - private native Region nativeGetSelection(); + private native int nativeTextGeneration(); + // 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 void nativeDumpDisplayTree(String urlOrNull); } |