blob: a284a17dad91c82babe2b65eb5664f211276a7ea [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
Raphael30df2372010-03-06 10:09:54 -080019import android.annotation.Widget;
John Reck0507ac42011-11-21 13:30:32 -080020import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.AlertDialog;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040022import android.content.BroadcastReceiver;
Dianne Hackborn90d5e8c2010-08-05 13:47:55 -070023import android.content.ClipboardManager;
John Reckfaa42db2011-09-07 11:33:34 -070024import android.content.ComponentCallbacks2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
26import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.DialogInterface.OnCancelListener;
Adam Powell637d3372010-08-25 14:37:03 -070028import android.content.Intent;
29import android.content.IntentFilter;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040030import android.content.pm.PackageInfo;
31import android.content.pm.PackageManager;
Cary Clarkc5cd5e92010-11-22 15:20:02 -050032import android.content.res.Configuration;
Leon Scroggins3667ce42009-05-13 15:58:03 -040033import android.database.DataSetObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.graphics.Bitmap;
Adam Powell637d3372010-08-25 14:37:03 -070035import android.graphics.BitmapFactory;
36import android.graphics.BitmapShader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.graphics.Canvas;
38import android.graphics.Color;
Grace Kloba8abd50b2010-07-08 15:02:14 -070039import android.graphics.DrawFilter;
Grace Kloba178db412010-05-18 22:22:23 -070040import android.graphics.Paint;
Grace Kloba8abd50b2010-07-08 15:02:14 -070041import android.graphics.PaintFlagsDrawFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.graphics.Picture;
43import android.graphics.Point;
44import android.graphics.Rect;
Nicolas Roard46318cf2010-05-10 15:15:51 -070045import android.graphics.RectF;
Grace Kloba178db412010-05-18 22:22:23 -070046import android.graphics.Region;
John Reck335f4542011-08-25 18:25:09 -070047import android.graphics.RegionIterator;
Adam Powell637d3372010-08-25 14:37:03 -070048import android.graphics.Shader;
Mike Reede8853fc2009-09-04 14:01:48 -040049import android.graphics.drawable.Drawable;
Kristian Monsen41e7e6f2010-12-21 12:51:11 +000050import android.net.Proxy;
51import android.net.ProxyProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.net.Uri;
Adam Powell9d32d242010-03-29 16:02:07 -070053import android.net.http.SslCertificate;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040054import android.os.AsyncTask;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.Bundle;
56import android.os.Handler;
Steve Block08d584c2011-05-17 19:05:03 +010057import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Message;
Steve Block08d584c2011-05-17 19:05:03 +010059import android.os.StrictMode;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -070060import android.provider.Settings;
Svetoslav Ganovda355512010-05-12 22:04:44 -070061import android.speech.tts.TextToSpeech;
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -080062import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.util.EventLog;
65import android.util.Log;
John Reck0507ac42011-11-21 13:30:32 -080066import android.view.Display;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.view.Gravity;
Adam Powellad804e32011-09-14 19:11:08 -070068import android.view.HapticFeedbackConstants;
Svetoslav Ganov9504f572011-01-14 11:38:17 -080069import android.view.HardwareCanvas;
Jeff Brown33bbfd22011-02-24 20:55:35 -080070import android.view.InputDevice;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080071import android.view.KeyCharacterMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.view.KeyEvent;
73import android.view.LayoutInflater;
74import android.view.MotionEvent;
Grace Kloba3a0def22010-01-23 21:11:54 -080075import android.view.ScaleGestureDetector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.view.SoundEffectConstants;
77import android.view.VelocityTracker;
78import android.view.View;
79import android.view.ViewConfiguration;
80import android.view.ViewGroup;
Leon Scroggins7f7bd522010-11-05 11:23:31 -040081import android.view.ViewParent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.view.ViewTreeObserver;
John Reck0507ac42011-11-21 13:30:32 -080083import android.view.WindowManager;
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -070084import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganovda355512010-05-12 22:04:44 -070085import android.view.accessibility.AccessibilityManager;
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -070086import android.view.accessibility.AccessibilityNodeInfo;
Derek Sollenberger7cabb032010-01-21 10:37:38 -050087import android.view.inputmethod.EditorInfo;
88import android.view.inputmethod.InputConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.view.inputmethod.InputMethodManager;
Leon Scrogginsd3465f62009-06-02 10:57:54 -040090import android.webkit.WebTextView.AutoCompleteAdapter;
John Reck816c0de2011-06-02 16:04:53 -070091import android.webkit.WebViewCore.DrawData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.webkit.WebViewCore.EventHub;
Grace Klobac2242f22010-03-05 14:00:26 -080093import android.webkit.WebViewCore.TouchEventData;
Grace Kloba178db412010-05-18 22:22:23 -070094import android.webkit.WebViewCore.TouchHighlightData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.widget.AbsoluteLayout;
Leon Scroggins3667ce42009-05-13 15:58:03 -040096import android.widget.Adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.widget.AdapterView;
Michael Kolb73980a92010-08-05 16:32:51 -070098import android.widget.AdapterView.OnItemClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import android.widget.ArrayAdapter;
Leon Scrogginsa8da1732009-10-19 19:04:30 -0400100import android.widget.CheckedTextView;
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -0400101import android.widget.LinearLayout;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import android.widget.ListView;
Adam Powell637d3372010-08-25 14:37:03 -0700103import android.widget.OverScroller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import android.widget.Toast;
Michael Kolb73980a92010-08-05 16:32:51 -0700105
Steve Blockf95d4902011-06-09 11:53:26 +0100106import junit.framework.Assert;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
111import java.io.FileOutputStream;
John Reck816c0de2011-06-02 16:04:53 -0700112import java.io.IOException;
113import java.io.InputStream;
114import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.net.URLDecoder;
116import java.util.ArrayList;
Andrei Popescuf5dba882010-01-12 22:42:41 +0000117import java.util.HashMap;
Derek Sollenberger41d5e932010-08-23 14:51:41 -0400118import java.util.HashSet;
Adam Powell9d32d242010-03-29 16:02:07 -0700119import java.util.List;
Andrei Popescu4950b2b2009-09-03 13:56:07 +0100120import java.util.Map;
Andrei Popescua6d747d2010-02-11 13:19:21 +0000121import java.util.Set;
Leon Scroggins115626a2011-02-17 12:00:48 -0500122import java.util.Vector;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700123import java.util.regex.Matcher;
124import java.util.regex.Pattern;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
Nicolas Roard2bc0b012011-11-16 19:26:25 -0800126import javax.microedition.khronos.egl.EGL10;
127import javax.microedition.khronos.egl.EGLContext;
128import javax.microedition.khronos.egl.EGLDisplay;
129import static javax.microedition.khronos.egl.EGL10.*;
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131/**
Cary Clarkd6982c92009-05-29 11:02:22 -0400132 * <p>A View that displays web pages. This class is the basis upon which you
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 * can roll your own web browser or simply display some online content within your Activity.
134 * It uses the WebKit rendering engine to display
135 * web pages and includes methods to navigate forward and backward
136 * through a history, zoom in and out, perform text searches and more.</p>
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 * <p>To enable the built-in zoom, set
138 * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
139 * (introduced in API version 3).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 * <p>Note that, in order for your Activity to access the Internet and load web pages
Scott Main8b3cea02010-05-14 14:12:43 -0700141 * in a WebView, you must add the {@code INTERNET} permissions to your
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 * Android Manifest file:</p>
143 * <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100144 *
Scott Main8b3cea02010-05-14 14:12:43 -0700145 * <p>This must be a child of the <a
Ben Dodson4e8620f2010-08-25 10:55:47 -0700146 * href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code <manifest>}</a>
Scott Main8b3cea02010-05-14 14:12:43 -0700147 * element.</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100148 *
Scott Main41ec6532010-08-19 16:57:07 -0700149 * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-webview.html">Web View
150 * tutorial</a>.</p>
151 *
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100152 * <h3>Basic usage</h3>
153 *
154 * <p>By default, a WebView provides no browser-like widgets, does not
Scott Main8b3cea02010-05-14 14:12:43 -0700155 * enable JavaScript and web page errors are ignored. If your goal is only
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100156 * to display some HTML as a part of your UI, this is probably fine;
157 * the user won't need to interact with the web page beyond reading
158 * it, and the web page won't need to interact with the user. If you
Scott Main8b3cea02010-05-14 14:12:43 -0700159 * actually want a full-blown web browser, then you probably want to
160 * invoke the Browser application with a URL Intent rather than show it
161 * with a WebView. For example:
162 * <pre>
163 * Uri uri = Uri.parse("http://www.example.com");
164 * Intent intent = new Intent(Intent.ACTION_VIEW, uri);
165 * startActivity(intent);
166 * </pre>
167 * <p>See {@link android.content.Intent} for more information.</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100168 *
Ben Dodson4e8620f2010-08-25 10:55:47 -0700169 * <p>To provide a WebView in your own Activity, include a {@code <WebView>} in your layout,
Scott Main8b3cea02010-05-14 14:12:43 -0700170 * or set the entire Activity window as a WebView during {@link
171 * android.app.Activity#onCreate(Bundle) onCreate()}:</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100172 * <pre class="prettyprint">
173 * WebView webview = new WebView(this);
174 * setContentView(webview);
Scott Main8b3cea02010-05-14 14:12:43 -0700175 * </pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100176 *
Scott Main8b3cea02010-05-14 14:12:43 -0700177 * <p>Then load the desired web page:</p>
Scott Maine3b9f8b2010-05-18 08:41:36 -0700178 * <pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100179 * // Simplest usage: note that an exception will NOT be thrown
180 * // if there is an error loading this page (see below).
181 * webview.loadUrl("http://slashdot.org/");
182 *
Scott Main8b3cea02010-05-14 14:12:43 -0700183 * // OR, you can also load from an HTML string:
Scott Maine3b9f8b2010-05-18 08:41:36 -0700184 * String summary = "&lt;html>&lt;body>You scored &lt;b>192&lt;/b> points.&lt;/body>&lt;/html>";
Steve Blockf95d4902011-06-09 11:53:26 +0100185 * webview.loadData(summary, "text/html", null);
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100186 * // ... although note that there are restrictions on what this HTML can do.
Scott Main8b3cea02010-05-14 14:12:43 -0700187 * // See the JavaDocs for {@link #loadData(String,String,String) loadData()} and {@link
188 * #loadDataWithBaseURL(String,String,String,String,String) loadDataWithBaseURL()} for more info.
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100189 * </pre>
190 *
191 * <p>A WebView has several customization points where you can add your
192 * own behavior. These are:</p>
193 *
194 * <ul>
195 * <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass.
196 * This class is called when something that might impact a
197 * browser UI happens, for instance, progress updates and
Scott Main8b3cea02010-05-14 14:12:43 -0700198 * JavaScript alerts are sent here (see <a
199 * href="{@docRoot}guide/developing/debug-tasks.html#DebuggingWebPages">Debugging Tasks</a>).
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100200 * </li>
201 * <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
202 * It will be called when things happen that impact the
203 * rendering of the content, eg, errors or form submissions. You
Scott Main8b3cea02010-05-14 14:12:43 -0700204 * can also intercept URL loading here (via {@link
205 * android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String)
206 * shouldOverrideUrlLoading()}).</li>
207 * <li>Modifying the {@link android.webkit.WebSettings}, such as
208 * enabling JavaScript with {@link android.webkit.WebSettings#setJavaScriptEnabled(boolean)
209 * setJavaScriptEnabled()}. </li>
Steve Block4cd73c52011-11-09 13:06:52 +0000210 * <li>Injecting Java objects into the WebView using the
211 * {@link android.webkit.WebView#addJavascriptInterface} method. This
212 * method allows you to inject Java objects into a page's JavaScript
213 * context, so that they can be accessed by JavaScript in the page.</li>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100214 * </ul>
215 *
216 * <p>Here's a more complicated example, showing error handling,
217 * settings, and progress notification:</p>
218 *
219 * <pre class="prettyprint">
220 * // Let's display the progress in the activity title bar, like the
221 * // browser app does.
222 * getWindow().requestFeature(Window.FEATURE_PROGRESS);
223 *
224 * webview.getSettings().setJavaScriptEnabled(true);
225 *
226 * final Activity activity = this;
227 * webview.setWebChromeClient(new WebChromeClient() {
228 * public void onProgressChanged(WebView view, int progress) {
229 * // Activities and WebViews measure progress with different scales.
230 * // The progress meter will automatically disappear when we reach 100%
231 * activity.setProgress(progress * 1000);
232 * }
233 * });
234 * webview.setWebViewClient(new WebViewClient() {
235 * public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
236 * Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
237 * }
238 * });
239 *
240 * webview.loadUrl("http://slashdot.org/");
241 * </pre>
242 *
243 * <h3>Cookie and window management</h3>
244 *
245 * <p>For obvious security reasons, your application has its own
Scott Main8b3cea02010-05-14 14:12:43 -0700246 * cache, cookie store etc.&mdash;it does not share the Browser
247 * application's data. Cookies are managed on a separate thread, so
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100248 * operations like index building don't block the UI
249 * thread. Follow the instructions in {@link android.webkit.CookieSyncManager}
250 * if you want to use cookies in your application.
251 * </p>
252 *
253 * <p>By default, requests by the HTML to open new windows are
254 * ignored. This is true whether they be opened by JavaScript or by
255 * the target attribute on a link. You can customize your
Scott Main8b3cea02010-05-14 14:12:43 -0700256 * {@link WebChromeClient} to provide your own behaviour for opening multiple windows,
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100257 * and render them in whatever manner you want.</p>
258 *
Scott Main8b3cea02010-05-14 14:12:43 -0700259 * <p>The standard behavior for an Activity is to be destroyed and
260 * recreated when the device orientation or any other configuration changes. This will cause
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100261 * the WebView to reload the current page. If you don't want that, you
Scott Main8b3cea02010-05-14 14:12:43 -0700262 * can set your Activity to handle the {@code orientation} and {@code keyboardHidden}
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100263 * changes, and then just leave the WebView alone. It'll automatically
Scott Main8b3cea02010-05-14 14:12:43 -0700264 * re-orient itself as appropriate. Read <a
265 * href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a> for
266 * more information about how to handle configuration changes during runtime.</p>
267 *
268 *
269 * <h3>Building web pages to support different screen densities</h3>
270 *
271 * <p>The screen density of a device is based on the screen resolution. A screen with low density
272 * has fewer available pixels per inch, where a screen with high density
Brad Fitzpatrick438d0592010-06-10 12:19:19 -0700273 * has more &mdash; sometimes significantly more &mdash; pixels per inch. The density of a
Scott Main8b3cea02010-05-14 14:12:43 -0700274 * screen is important because, other things being equal, a UI element (such as a button) whose
275 * height and width are defined in terms of screen pixels will appear larger on the lower density
276 * screen and smaller on the higher density screen.
277 * For simplicity, Android collapses all actual screen densities into three generalized densities:
278 * high, medium, and low.</p>
279 * <p>By default, WebView scales a web page so that it is drawn at a size that matches the default
280 * appearance on a medium density screen. So, it applies 1.5x scaling on a high density screen
281 * (because its pixels are smaller) and 0.75x scaling on a low density screen (because its pixels
282 * are bigger).
283 * Starting with API Level 5 (Android 2.0), WebView supports DOM, CSS, and meta tag features to help
284 * you (as a web developer) target screens with different screen densities.</p>
285 * <p>Here's a summary of the features you can use to handle different screen densities:</p>
286 * <ul>
287 * <li>The {@code window.devicePixelRatio} DOM property. The value of this property specifies the
288 * default scaling factor used for the current device. For example, if the value of {@code
289 * window.devicePixelRatio} is "1.0", then the device is considered a medium density (mdpi) device
290 * and default scaling is not applied to the web page; if the value is "1.5", then the device is
291 * considered a high density device (hdpi) and the page content is scaled 1.5x; if the
292 * value is "0.75", then the device is considered a low density device (ldpi) and the content is
293 * scaled 0.75x. However, if you specify the {@code "target-densitydpi"} meta property
294 * (discussed below), then you can stop this default scaling behavior.</li>
295 * <li>The {@code -webkit-device-pixel-ratio} CSS media query. Use this to specify the screen
296 * densities for which this style sheet is to be used. The corresponding value should be either
297 * "0.75", "1", or "1.5", to indicate that the styles are for devices with low density, medium
298 * density, or high density screens, respectively. For example:
299 * <pre>
300 * &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" /&gt;</pre>
301 * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5,
302 * which is the high density pixel ratio.</p>
303 * </li>
304 * <li>The {@code target-densitydpi} property for the {@code viewport} meta tag. You can use
305 * this to specify the target density for which the web page is designed, using the following
306 * values:
307 * <ul>
308 * <li>{@code device-dpi} - Use the device's native dpi as the target dpi. Default scaling never
309 * occurs.</li>
310 * <li>{@code high-dpi} - Use hdpi as the target dpi. Medium and low density screens scale down
311 * as appropriate.</li>
312 * <li>{@code medium-dpi} - Use mdpi as the target dpi. High density screens scale up and
313 * low density screens scale down. This is also the default behavior.</li>
314 * <li>{@code low-dpi} - Use ldpi as the target dpi. Medium and high density screens scale up
315 * as appropriate.</li>
Ben Dodson4e8620f2010-08-25 10:55:47 -0700316 * <li><em>{@code <value>}</em> - Specify a dpi value to use as the target dpi (accepted
Scott Main8b3cea02010-05-14 14:12:43 -0700317 * values are 70-400).</li>
318 * </ul>
319 * <p>Here's an example meta tag to specify the target density:</p>
320 * <pre>&lt;meta name="viewport" content="target-densitydpi=device-dpi" /&gt;</pre></li>
321 * </ul>
322 * <p>If you want to modify your web page for different densities, by using the {@code
323 * -webkit-device-pixel-ratio} CSS media query and/or the {@code
324 * window.devicePixelRatio} DOM property, then you should set the {@code target-densitydpi} meta
325 * property to {@code device-dpi}. This stops Android from performing scaling in your web page and
326 * allows you to make the necessary adjustments for each density via CSS and JavaScript.</p>
327 *
Michael Kolb73980a92010-08-05 16:32:51 -0700328 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 */
Raphael30df2372010-03-06 10:09:54 -0800330@Widget
Cary Clarkd6982c92009-05-29 11:02:22 -0400331public class WebView extends AbsoluteLayout
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 implements ViewTreeObserver.OnGlobalFocusChangeListener,
333 ViewGroup.OnHierarchyChangeListener {
334
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800335 private class InnerGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
336 public void onGlobalLayout() {
337 if (isShown()) {
338 setGLRectViewport();
339 }
340 }
341 }
342
Teng-Hui Zhu55133372010-12-07 17:19:16 -0800343 private class InnerScrollChangedListener implements ViewTreeObserver.OnScrollChangedListener {
344 public void onScrollChanged() {
345 if (isShown()) {
346 setGLRectViewport();
347 }
348 }
349 }
350
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800351 // The listener to capture global layout change event.
Teng-Hui Zhu55133372010-12-07 17:19:16 -0800352 private InnerGlobalLayoutListener mGlobalLayoutListener = null;
353
354 // The listener to capture scroll event.
355 private InnerScrollChangedListener mScrollChangedListener = null;
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 // if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing
358 // the screen all-the-time. Good for profiling our drawing code
359 static private final boolean AUTO_REDRAW_HACK = false;
360 // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
361 private boolean mAutoRedraw;
362
Mattias Falk0ae2ec82010-09-16 16:24:46 +0200363 // Reference to the AlertDialog displayed by InvokeListBox.
364 // It's used to dismiss the dialog in destroy if not done before.
365 private AlertDialog mListBoxDialog = null;
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 static final String LOGTAG = "webview";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368
Derek Sollenberger90b6e482010-05-10 12:38:54 -0400369 private ZoomManager mZoomManager;
Cary Clarkd6982c92009-05-29 11:02:22 -0400370
Romain Guycabfcc12011-03-07 18:06:46 -0800371 private final Rect mGLRectViewport = new Rect();
372 private final Rect mViewRectViewport = new Rect();
George Mount82ed95f2011-11-15 11:27:47 -0800373 private final RectF mVisibleContentRect = new RectF();
Chet Haase91fc3cf2011-01-28 00:20:04 -0800374 private boolean mGLViewportEmpty = false;
Nicolas Roard12c18e62010-10-13 20:14:31 -0700375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 /**
377 * Transportation object for returning WebView across thread boundaries.
378 */
379 public class WebViewTransport {
380 private WebView mWebview;
381
382 /**
383 * Set the WebView to the transportation object.
384 * @param webview The WebView to transport.
385 */
386 public synchronized void setWebView(WebView webview) {
387 mWebview = webview;
388 }
389
390 /**
391 * Return the WebView object.
392 * @return WebView The transported WebView object.
393 */
394 public synchronized WebView getWebView() {
395 return mWebview;
396 }
397 }
398
John Reck34a676b2011-09-07 13:41:17 -0700399 private static class OnTrimMemoryListener implements ComponentCallbacks2 {
400 private static OnTrimMemoryListener sInstance = null;
401
402 static void init(Context c) {
403 if (sInstance == null) {
404 sInstance = new OnTrimMemoryListener(c.getApplicationContext());
405 }
406 }
407
408 private OnTrimMemoryListener(Context c) {
409 c.registerComponentCallbacks(this);
410 }
411
412 @Override
413 public void onConfigurationChanged(Configuration newConfig) {
414 // Ignore
415 }
416
417 @Override
418 public void onLowMemory() {
419 // Ignore
420 }
421
422 @Override
423 public void onTrimMemory(int level) {
424 if (DebugFlags.WEB_VIEW) {
425 Log.d("WebView", "onTrimMemory: " + level);
426 }
427 WebView.nativeOnTrimMemory(level);
428 }
429
430 }
431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 // A final CallbackProxy shared by WebViewCore and BrowserFrame.
433 private final CallbackProxy mCallbackProxy;
434
435 private final WebViewDatabase mDatabase;
436
437 // SSL certificate for the main top-level page (if secure)
438 private SslCertificate mCertificate;
439
440 // Native WebView pointer that is 0 until the native object has been
441 // created.
442 private int mNativeClass;
443 // This would be final but it needs to be set to null when the WebView is
444 // destroyed.
445 private WebViewCore mWebViewCore;
446 // Handler for dispatching UI messages.
447 /* package */ final Handler mPrivateHandler = new PrivateHandler();
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400448 private WebTextView mWebTextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 // Used to ignore changes to webkit text that arrives to the UI side after
450 // more key events.
451 private int mTextGeneration;
452
Leon Scroggins IIIb24e18b2010-04-20 17:07:28 -0400453 /* package */ void incrementTextGeneration() { mTextGeneration++; }
454
Patrick Scott0a5ce012009-07-02 08:56:10 -0400455 // Used by WebViewCore to create child views.
456 /* package */ final ViewManager mViewManager;
457
Grace Kloba11438c32009-12-16 11:39:12 -0800458 // Used to display in full screen mode
459 PluginFullScreenHolder mFullScreenHolder;
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 /**
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -0800462 * Position of the last touch event in pixels.
463 * Use integer to prevent loss of dragging delta calculation accuracy;
464 * which was done in float and converted to integer, and resulted in gradual
465 * and compounding touch position and view dragging mismatch.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 */
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -0800467 private int mLastTouchX;
468 private int mLastTouchY;
John Reck75738722011-06-10 11:28:53 -0700469 private int mStartTouchX;
470 private int mStartTouchY;
471 private float mAverageAngle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472
473 /**
474 * Time of the last touch event.
475 */
476 private long mLastTouchTime;
477
478 /**
479 * Time of the last time sending touch event to WebViewCore
480 */
481 private long mLastSentTouchTime;
482
483 /**
484 * The minimum elapsed time before sending another ACTION_MOVE event to
Grace Kloba53d3c1e2009-06-26 11:36:03 -0700485 * WebViewCore. This really should be tuned for each type of the devices.
486 * For example in Google Map api test case, it takes Dream device at least
487 * 150ms to do a full cycle in the WebViewCore by processing a touch event,
488 * triggering the layout and drawing the picture. While the same process
489 * takes 60+ms on the current high speed device. If we make
490 * TOUCH_SENT_INTERVAL too small, there will be multiple touch events sent
491 * to WebViewCore queue and the real layout and draw events will be pushed
492 * to further, which slows down the refresh rate. Choose 50 to favor the
493 * current high speed devices. For Dream like devices, 100 is a better
494 * choice. Maybe make this in the buildspec later.
Huahui Wue2975f12010-12-14 13:45:28 -0800495 * (Update 12/14/2010: changed to 0 since current device should be able to
496 * handle the raw events and Map team voted to have the raw events too.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 */
Huahui Wue2975f12010-12-14 13:45:28 -0800498 private static final int TOUCH_SENT_INTERVAL = 0;
Ben Murdochecbc65c2010-01-13 10:54:56 +0000499 private int mCurrentTouchInterval = TOUCH_SENT_INTERVAL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500
501 /**
502 * Helper class to get velocity for fling
503 */
504 VelocityTracker mVelocityTracker;
Romain Guy4296fc42009-07-06 11:48:52 -0700505 private int mMaximumFling;
Cary Clark278ce052009-08-31 16:08:42 -0400506 private float mLastVelocity;
507 private float mLastVelX;
508 private float mLastVelY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509
Patrick Scott62310912010-12-06 17:44:50 -0500510 // The id of the native layer being scrolled.
Michael Kolb5da91bd2011-11-29 15:29:03 -0800511 private int mCurrentScrollingLayerId;
Patrick Scott62310912010-12-06 17:44:50 -0500512 private Rect mScrollingLayerRect = new Rect();
Patrick Scotta3ebcc92010-07-16 11:52:22 -0400513
Grace Kloba3c19d992010-05-17 19:19:06 -0700514 // only trigger accelerated fling if the new velocity is at least
515 // MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION times of the previous velocity
516 private static final float MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION = 0.2f;
517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 /**
519 * Touch mode
520 */
521 private int mTouchMode = TOUCH_DONE_MODE;
522 private static final int TOUCH_INIT_MODE = 1;
523 private static final int TOUCH_DRAG_START_MODE = 2;
524 private static final int TOUCH_DRAG_MODE = 3;
525 private static final int TOUCH_SHORTPRESS_START_MODE = 4;
526 private static final int TOUCH_SHORTPRESS_MODE = 5;
Grace Kloba04b28682009-09-14 14:38:37 -0700527 private static final int TOUCH_DOUBLE_TAP_MODE = 6;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 private static final int TOUCH_DONE_MODE = 7;
Cary Clark924af702010-06-04 16:37:43 -0400529 private static final int TOUCH_PINCH_DRAG = 8;
Patrick Scotta3ebcc92010-07-16 11:52:22 -0400530 private static final int TOUCH_DRAG_LAYER_MODE = 9;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531
532 // Whether to forward the touch events to WebCore
Huahui Wu5d4064c2011-01-21 16:10:23 -0800533 // Can only be set by WebKit via JNI.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 private boolean mForwardTouchEvents = false;
535
Grace Klobac2242f22010-03-05 14:00:26 -0800536 // Whether to prevent default during touch. The initial value depends on
537 // mForwardTouchEvents. If WebCore wants all the touch events, it says yes
538 // for touch down. Otherwise UI will wait for the answer of the first
539 // confirmed move before taking over the control.
540 private static final int PREVENT_DEFAULT_NO = 0;
541 private static final int PREVENT_DEFAULT_MAYBE_YES = 1;
542 private static final int PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN = 2;
543 private static final int PREVENT_DEFAULT_YES = 3;
544 private static final int PREVENT_DEFAULT_IGNORE = 4;
545 private int mPreventDefault = PREVENT_DEFAULT_IGNORE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546
Grace Klobac2242f22010-03-05 14:00:26 -0800547 // true when the touch movement exceeds the slop
548 private boolean mConfirmMove;
Grace Kloba5f68d6f2009-12-08 18:42:54 -0800549
Grace Klobac2242f22010-03-05 14:00:26 -0800550 // if true, touch events will be first processed by WebCore, if prevent
551 // default is not set, the UI will continue handle them.
552 private boolean mDeferTouchProcess;
553
554 // to avoid interfering with the current touch events, track them
555 // separately. Currently no snapping or fling in the deferred process mode
556 private int mDeferTouchMode = TOUCH_DONE_MODE;
557 private float mLastDeferTouchX;
558 private float mLastDeferTouchY;
Grace Kloba5f68d6f2009-12-08 18:42:54 -0800559
Leon Scroggins72543e12009-07-23 15:29:45 -0400560 // To keep track of whether the current drag was initiated by a WebTextView,
561 // so that we know not to hide the cursor
562 boolean mDragFromTextInput;
563
Cary Clarkd6982c92009-05-29 11:02:22 -0400564 // Whether or not to draw the cursor ring.
565 private boolean mDrawCursorRing = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566
Mike Reedd205d5b2009-05-27 11:02:29 -0400567 // true if onPause has been called (and not onResume)
568 private boolean mIsPaused;
569
Cary Clarkb8491342010-11-29 16:23:19 -0500570 private HitTestResult mInitialHitTestResult;
571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 /**
573 * Customizable constant
574 */
575 // pre-computed square of ViewConfiguration.getScaledTouchSlop()
576 private int mTouchSlopSquare;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700577 // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
578 private int mDoubleTapSlopSquare;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700579 // pre-computed density adjusted navigation slop
580 private int mNavSlop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 // This should be ViewConfiguration.getTapTimeout()
582 // But system time out is 100ms, which is too short for the browser.
583 // In the browser, if it switches out of tap too soon, jump tap won't work.
Ben Murdochadf096c2011-08-12 12:37:15 +0100584 // In addition, a double tap on a trackpad will always have a duration of
585 // 300ms, so this value must be at least that (otherwise we will timeout the
586 // first tap and convert it to a long press).
587 private static final int TAP_TIMEOUT = 300;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 // This should be ViewConfiguration.getLongPressTimeout()
589 // But system time out is 500ms, which is too short for the browser.
590 // With a short timeout, it's difficult to treat trigger a short press.
591 private static final int LONG_PRESS_TIMEOUT = 1000;
592 // needed to avoid flinging after a pause of no movement
593 private static final int MIN_FLING_TIME = 250;
Cary Clark25415e22009-10-12 13:41:28 -0400594 // draw unfiltered after drag is held without movement
595 private static final int MOTIONLESS_TIME = 100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 // The amount of content to overlap between two screens when going through
597 // pages with the space bar, in pixels.
598 private static final int PAGE_SCROLL_OVERLAP = 24;
599
600 /**
601 * These prevent calling requestLayout if either dimension is fixed. This
602 * depends on the layout parameters and the measure specs.
603 */
604 boolean mWidthCanMeasure;
605 boolean mHeightCanMeasure;
606
607 // Remember the last dimensions we sent to the native side so we can avoid
608 // sending the same dimensions more than once.
609 int mLastWidthSent;
610 int mLastHeightSent;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -0800611 // Since view height sent to webkit could be fixed to avoid relayout, this
612 // value records the last sent actual view height.
613 int mLastActualHeightSent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614
615 private int mContentWidth; // cache of value from WebViewCore
616 private int mContentHeight; // cache of value from WebViewCore
617
Cary Clarkd6982c92009-05-29 11:02:22 -0400618 // Need to have the separate control for horizontal and vertical scrollbar
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 // style than the View's single scrollbar style
620 private boolean mOverlayHorizontalScrollbar = true;
621 private boolean mOverlayVerticalScrollbar = false;
622
623 // our standard speed. this way small distances will be traversed in less
624 // time than large distances, but we cap the duration, so that very large
625 // distances won't take too long to get there.
626 private static final int STD_SPEED = 480; // pixels per second
627 // time for the longest scroll animation
628 private static final int MAX_DURATION = 750; // milliseconds
Leon Scroggins03c87bf2009-09-18 15:05:59 -0400629 private static final int SLIDE_TITLE_DURATION = 500; // milliseconds
Adam Powell637d3372010-08-25 14:37:03 -0700630
631 // Used by OverScrollGlow
632 OverScroller mScroller;
633
634 private boolean mInOverScrollMode = false;
635 private static Paint mOverScrollBackground;
636 private static Paint mOverScrollBorder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637
638 private boolean mWrapContent;
Cary Clark25415e22009-10-12 13:41:28 -0400639 private static final int MOTIONLESS_FALSE = 0;
640 private static final int MOTIONLESS_PENDING = 1;
641 private static final int MOTIONLESS_TRUE = 2;
Grace Kloba9b657802010-04-08 13:46:23 -0700642 private static final int MOTIONLESS_IGNORE = 3;
Cary Clark25415e22009-10-12 13:41:28 -0400643 private int mHeldMotionless;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644
Svetoslav Ganovda355512010-05-12 22:04:44 -0700645 // An instance for injecting accessibility in WebViews with disabled
646 // JavaScript or ones for which no accessibility script exists
647 private AccessibilityInjector mAccessibilityInjector;
648
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700649 // flag indicating if accessibility script is injected so we
650 // know to handle Shift and arrows natively first
651 private boolean mAccessibilityScriptInjected;
652
John Reck086a5142011-08-31 16:59:10 -0700653 static final boolean USE_JAVA_TEXT_SELECTION = true;
John Reckeffabe82011-10-27 09:09:36 -0700654 static final boolean DEBUG_TEXT_HANDLES = false;
John Reck086a5142011-08-31 16:59:10 -0700655 private Region mTextSelectionRegion = new Region();
656 private Paint mTextSelectionPaint;
657 private Drawable mSelectHandleLeft;
658 private Drawable mSelectHandleRight;
659
John Reck0966dd22011-09-18 11:03:00 -0700660 static final boolean USE_WEBKIT_RINGS = false;
Grace Kloba178db412010-05-18 22:22:23 -0700661 // the color used to highlight the touch rectangles
John Reck086a5142011-08-31 16:59:10 -0700662 private static final int HIGHLIGHT_COLOR = 0x6633b5e5;
Grace Kloba178db412010-05-18 22:22:23 -0700663 // the round corner for the highlight path
664 private static final float TOUCH_HIGHLIGHT_ARC = 5.0f;
665 // the region indicating where the user touched on the screen
666 private Region mTouchHighlightRegion = new Region();
667 // the paint for the touch highlight
668 private Paint mTouchHightlightPaint;
669 // debug only
670 private static final boolean DEBUG_TOUCH_HIGHLIGHT = true;
671 private static final int TOUCH_HIGHLIGHT_ELAPSE_TIME = 2000;
672 private Paint mTouchCrossHairColor;
673 private int mTouchHighlightX;
674 private int mTouchHighlightY;
John Reck335f4542011-08-25 18:25:09 -0700675 private long mTouchHighlightRequested;
Grace Kloba178db412010-05-18 22:22:23 -0700676
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -0800677 // Basically this proxy is used to tell the Video to update layer tree at
678 // SetBaseLayer time and to pause when WebView paused.
679 private HTML5VideoViewProxy mHTML5VideoViewProxy;
680
John Reck95b7d6f2011-06-03 15:23:43 -0700681 // If we are using a set picture, don't send view updates to webkit
682 private boolean mBlockWebkitViewMessages = false;
683
Derek Sollenberger1d335f32011-07-08 11:28:23 -0400684 // cached value used to determine if we need to switch drawing models
685 private boolean mHardwareAccelSkia = false;
686
Grace Klobac2242f22010-03-05 14:00:26 -0800687 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 * Private message ids
689 */
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400690 private static final int REMEMBER_PASSWORD = 1;
691 private static final int NEVER_REMEMBER_PASSWORD = 2;
692 private static final int SWITCH_TO_SHORTPRESS = 3;
693 private static final int SWITCH_TO_LONGPRESS = 4;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700694 private static final int RELEASE_SINGLE_TAP = 5;
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400695 private static final int REQUEST_FORM_DATA = 6;
Cary Clark25415e22009-10-12 13:41:28 -0400696 private static final int DRAG_HELD_MOTIONLESS = 8;
697 private static final int AWAKEN_SCROLL_BARS = 9;
Grace Klobac2242f22010-03-05 14:00:26 -0800698 private static final int PREVENT_DEFAULT_TIMEOUT = 10;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500699 private static final int SCROLL_SELECT_TEXT = 11;
700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701
Grace Klobac2242f22010-03-05 14:00:26 -0800702 private static final int FIRST_PRIVATE_MSG_ID = REMEMBER_PASSWORD;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500703 private static final int LAST_PRIVATE_MSG_ID = SCROLL_SELECT_TEXT;
Grace Klobac2242f22010-03-05 14:00:26 -0800704
705 /*
706 * Package message ids
707 */
Grace Klobac2242f22010-03-05 14:00:26 -0800708 static final int SCROLL_TO_MSG_ID = 101;
Grace Klobac2242f22010-03-05 14:00:26 -0800709 static final int NEW_PICTURE_MSG_ID = 105;
710 static final int UPDATE_TEXT_ENTRY_MSG_ID = 106;
711 static final int WEBCORE_INITIALIZED_MSG_ID = 107;
712 static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 108;
713 static final int UPDATE_ZOOM_RANGE = 109;
Leon Scroggins9ab32b62010-05-03 14:19:50 +0100714 static final int UNHANDLED_NAV_KEY = 110;
Grace Klobac2242f22010-03-05 14:00:26 -0800715 static final int CLEAR_TEXT_ENTRY = 111;
716 static final int UPDATE_TEXT_SELECTION_MSG_ID = 112;
717 static final int SHOW_RECT_MSG_ID = 113;
718 static final int LONG_PRESS_CENTER = 114;
719 static final int PREVENT_TOUCH_ID = 115;
720 static final int WEBCORE_NEED_TOUCH_EVENTS = 116;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 // obj=Rect in doc coordinates
Grace Klobac2242f22010-03-05 14:00:26 -0800722 static final int INVAL_RECT_MSG_ID = 117;
723 static final int REQUEST_KEYBOARD = 118;
724 static final int DO_MOTION_UP = 119;
725 static final int SHOW_FULLSCREEN = 120;
726 static final int HIDE_FULLSCREEN = 121;
727 static final int DOM_FOCUS_CHANGED = 122;
Grace Kloba8abd50b2010-07-08 15:02:14 -0700728 static final int REPLACE_BASE_CONTENT = 123;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -0400729 static final int FORM_DID_BLUR = 124;
Grace Klobac2242f22010-03-05 14:00:26 -0800730 static final int RETURN_LABEL = 125;
731 static final int FIND_AGAIN = 126;
Grace Klobae8300a12010-03-12 13:32:55 -0800732 static final int CENTER_FIT_RECT = 127;
Leon Scrogginsb4157792010-03-18 12:42:33 -0400733 static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128;
Grace Kloba50004bc2010-04-13 22:58:51 -0700734 static final int SET_SCROLLBAR_MODES = 129;
Svetoslav Ganovda355512010-05-12 22:04:44 -0700735 static final int SELECTION_STRING_CHANGED = 130;
Grace Kloba178db412010-05-18 22:22:23 -0700736 static final int SET_TOUCH_HIGHLIGHT_RECTS = 131;
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -0700737 static final int SAVE_WEBARCHIVE_FINISHED = 132;
Cary Clarkd6982c92009-05-29 11:02:22 -0400738
Ben Murdoch62275a42010-09-07 11:27:28 +0100739 static final int SET_AUTOFILLABLE = 133;
Ben Murdoch961d55f2010-12-02 13:58:24 +0000740 static final int AUTOFILL_COMPLETE = 134;
Ben Murdoch62275a42010-09-07 11:27:28 +0100741
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800742 static final int SELECT_AT = 135;
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -0500743 static final int SCREEN_ON = 136;
Nicolas Roard0e778a12011-03-11 14:29:05 -0800744 static final int ENTER_FULLSCREEN_VIDEO = 137;
John Reck0966dd22011-09-18 11:03:00 -0700745 static final int UPDATE_SELECTION = 138;
Mangesh Ghiware31f263d2011-11-21 16:54:20 -0800746 static final int UPDATE_ZOOM_DENSITY = 139;
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800747
Grace Klobac2242f22010-03-05 14:00:26 -0800748 private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
Grace Kloba178db412010-05-18 22:22:23 -0700749 private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
Grace Klobac2242f22010-03-05 14:00:26 -0800750
751 static final String[] HandlerPrivateDebugString = {
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400752 "REMEMBER_PASSWORD", // = 1;
753 "NEVER_REMEMBER_PASSWORD", // = 2;
754 "SWITCH_TO_SHORTPRESS", // = 3;
755 "SWITCH_TO_LONGPRESS", // = 4;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700756 "RELEASE_SINGLE_TAP", // = 5;
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400757 "REQUEST_FORM_DATA", // = 6;
Grace Kloba96949ef2010-01-25 09:53:01 -0800758 "RESUME_WEBCORE_PRIORITY", // = 7;
Cary Clark25415e22009-10-12 13:41:28 -0400759 "DRAG_HELD_MOTIONLESS", // = 8;
760 "AWAKEN_SCROLL_BARS", // = 9;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500761 "PREVENT_DEFAULT_TIMEOUT", // = 10;
762 "SCROLL_SELECT_TEXT" // = 11;
Grace Klobac2242f22010-03-05 14:00:26 -0800763 };
764
765 static final String[] HandlerPackageDebugString = {
766 "SCROLL_TO_MSG_ID", // = 101;
Patrick Scottfa8be1c2011-02-02 14:09:34 -0500767 "102", // = 102;
768 "103", // = 103;
769 "104", // = 104;
Grace Klobac2242f22010-03-05 14:00:26 -0800770 "NEW_PICTURE_MSG_ID", // = 105;
771 "UPDATE_TEXT_ENTRY_MSG_ID", // = 106;
772 "WEBCORE_INITIALIZED_MSG_ID", // = 107;
773 "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 108;
774 "UPDATE_ZOOM_RANGE", // = 109;
Leon Scroggins9ab32b62010-05-03 14:19:50 +0100775 "UNHANDLED_NAV_KEY", // = 110;
Grace Klobac2242f22010-03-05 14:00:26 -0800776 "CLEAR_TEXT_ENTRY", // = 111;
777 "UPDATE_TEXT_SELECTION_MSG_ID", // = 112;
778 "SHOW_RECT_MSG_ID", // = 113;
779 "LONG_PRESS_CENTER", // = 114;
780 "PREVENT_TOUCH_ID", // = 115;
781 "WEBCORE_NEED_TOUCH_EVENTS", // = 116;
782 "INVAL_RECT_MSG_ID", // = 117;
783 "REQUEST_KEYBOARD", // = 118;
784 "DO_MOTION_UP", // = 119;
785 "SHOW_FULLSCREEN", // = 120;
786 "HIDE_FULLSCREEN", // = 121;
787 "DOM_FOCUS_CHANGED", // = 122;
Grace Kloba8abd50b2010-07-08 15:02:14 -0700788 "REPLACE_BASE_CONTENT", // = 123;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -0400789 "FORM_DID_BLUR", // = 124;
Grace Klobac2242f22010-03-05 14:00:26 -0800790 "RETURN_LABEL", // = 125;
Grace Klobae8300a12010-03-12 13:32:55 -0800791 "FIND_AGAIN", // = 126;
Leon Scrogginsb4157792010-03-18 12:42:33 -0400792 "CENTER_FIT_RECT", // = 127;
Grace Kloba50004bc2010-04-13 22:58:51 -0700793 "REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128;
Grace Kloba178db412010-05-18 22:22:23 -0700794 "SET_SCROLLBAR_MODES", // = 129;
795 "SELECTION_STRING_CHANGED", // = 130;
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -0700796 "SET_TOUCH_HIGHLIGHT_RECTS", // = 131;
Ben Murdoch62275a42010-09-07 11:27:28 +0100797 "SAVE_WEBARCHIVE_FINISHED", // = 132;
Ben Murdoch961d55f2010-12-02 13:58:24 +0000798 "SET_AUTOFILLABLE", // = 133;
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800799 "AUTOFILL_COMPLETE", // = 134;
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -0500800 "SELECT_AT", // = 135;
Nicolas Roard0e778a12011-03-11 14:29:05 -0800801 "SCREEN_ON", // = 136;
Mangesh Ghiware31f263d2011-11-21 16:54:20 -0800802 "ENTER_FULLSCREEN_VIDEO", // = 137;
803 "UPDATE_SELECTION", // = 138;
804 "UPDATE_ZOOM_DENSITY" // = 139;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 };
806
Grace Klobaa4fa1072009-11-09 12:01:50 -0800807 // If the site doesn't use the viewport meta tag to specify the viewport,
808 // use DEFAULT_VIEWPORT_WIDTH as the default viewport width
Shimeng (Simon) Wang14bcc0e2010-09-17 10:12:05 -0700809 static final int DEFAULT_VIEWPORT_WIDTH = 980;
Grace Klobaa4fa1072009-11-09 12:01:50 -0800810
811 // normally we try to fit the content to the minimum preferred width
812 // calculated by the Webkit. To avoid the bad behavior when some site's
813 // minimum preferred width keeps growing when changing the viewport width or
814 // the minimum preferred width is huge, an upper limit is needed.
815 static int sMaxViewportWidth = DEFAULT_VIEWPORT_WIDTH;
816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 // initial scale in percent. 0 means using default.
Grace Kloba16efce72009-11-10 15:49:03 -0800818 private int mInitialScaleInPercent = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819
Patrick Scottfa8be1c2011-02-02 14:09:34 -0500820 // Whether or not a scroll event should be sent to webkit. This is only set
821 // to false when restoring the scroll position.
822 private boolean mSendScrollEvent = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823
824 private int mSnapScrollMode = SNAP_NONE;
Cary Clarkac492e12009-10-14 14:53:37 -0400825 private static final int SNAP_NONE = 0;
826 private static final int SNAP_LOCK = 1; // not a separate state
827 private static final int SNAP_X = 2; // may be combined with SNAP_LOCK
828 private static final int SNAP_Y = 4; // may be combined with SNAP_LOCK
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 private boolean mSnapPositive;
Cary Clarkd6982c92009-05-29 11:02:22 -0400830
Cary Clark2ec30692010-02-23 10:50:38 -0500831 // keep these in sync with their counterparts in WebView.cpp
832 private static final int DRAW_EXTRAS_NONE = 0;
833 private static final int DRAW_EXTRAS_FIND = 1;
834 private static final int DRAW_EXTRAS_SELECTION = 2;
835 private static final int DRAW_EXTRAS_CURSOR_RING = 3;
836
Grace Kloba50004bc2010-04-13 22:58:51 -0700837 // keep this in sync with WebCore:ScrollbarMode in WebKit
838 private static final int SCROLLBAR_AUTO = 0;
839 private static final int SCROLLBAR_ALWAYSOFF = 1;
840 // as we auto fade scrollbar, this is ignored.
841 private static final int SCROLLBAR_ALWAYSON = 2;
842 private int mHorizontalScrollBarMode = SCROLLBAR_AUTO;
843 private int mVerticalScrollBarMode = SCROLLBAR_AUTO;
844
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700845 // constants for determining script injection strategy
846 private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1;
847 private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0;
848 private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1;
849
Svetoslav Ganovda355512010-05-12 22:04:44 -0700850 // the alias via which accessibility JavaScript interface is exposed
851 private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
852
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -0800853 // Template for JavaScript that injects a screen-reader.
854 private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
Svetoslav Ganovda355512010-05-12 22:04:44 -0700855 "javascript:(function() {" +
856 " var chooser = document.createElement('script');" +
857 " chooser.type = 'text/javascript';" +
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -0800858 " chooser.src = '%1s';" +
Svetoslav Ganovda355512010-05-12 22:04:44 -0700859 " document.getElementsByTagName('head')[0].appendChild(chooser);" +
860 " })();";
861
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700862 // Regular expression that matches the "axs" URL parameter.
863 // The value of 0 means the accessibility script is opted out
864 // The value of 1 means the accessibility script is already injected
865 private static final String PATTERN_MATCH_AXS_URL_PARAMETER = "(\\?axs=(0|1))|(&axs=(0|1))";
866
Svetoslav Ganov4acac232011-02-02 15:22:24 -0800867 // TextToSpeech instance exposed to JavaScript to the injected screenreader.
868 private TextToSpeech mTextToSpeech;
869
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700870 // variable to cache the above pattern in case accessibility is enabled.
871 private Pattern mMatchAxsUrlParameterPattern;
872
Adam Powell637d3372010-08-25 14:37:03 -0700873 /**
874 * Max distance to overscroll by in pixels.
875 * This how far content can be pulled beyond its normal bounds by the user.
876 */
877 private int mOverscrollDistance;
878
879 /**
880 * Max distance to overfling by in pixels.
881 * This is how far flinged content can move beyond the end of its normal bounds.
882 */
883 private int mOverflingDistance;
884
885 private OverScrollGlow mOverScrollGlow;
886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 // Used to match key downs and key ups
Leon Scroggins115626a2011-02-17 12:00:48 -0500888 private Vector<Integer> mKeysPressed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889
890 /* package */ static boolean mLogEvent = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891
892 // for event log
893 private long mLastTouchUpTime = 0;
894
Ben Murdochdb8d19c2010-10-29 11:44:17 +0100895 private WebViewCore.AutoFillData mAutoFillData;
Ben Murdoch62275a42010-09-07 11:27:28 +0100896
Kristian Monsencbb59db2011-05-09 16:04:34 +0100897 private static boolean sNotificationsEnabled = true;
898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 /**
900 * URI scheme for telephone number
901 */
902 public static final String SCHEME_TEL = "tel:";
903 /**
904 * URI scheme for email address
905 */
906 public static final String SCHEME_MAILTO = "mailto:";
907 /**
908 * URI scheme for map address
909 */
910 public static final String SCHEME_GEO = "geo:0,0?q=";
Cary Clarkd6982c92009-05-29 11:02:22 -0400911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 private int mBackgroundColor = Color.WHITE;
913
Cary Clark6f5dfc62010-11-11 13:09:20 -0500914 private static final long SELECT_SCROLL_INTERVAL = 1000 / 60; // 60 / second
915 private int mAutoScrollX = 0;
916 private int mAutoScrollY = 0;
Cary Clarkb9aaa772011-01-07 16:14:54 -0500917 private int mMinAutoScrollX = 0;
918 private int mMaxAutoScrollX = 0;
919 private int mMinAutoScrollY = 0;
920 private int mMaxAutoScrollY = 0;
921 private Rect mScrollingLayerBounds = new Rect();
Cary Clark6f5dfc62010-11-11 13:09:20 -0500922 private boolean mSentAutoScrollMessage = false;
923
Nicolas Roard2bc0b012011-11-16 19:26:25 -0800924 // Temporary hack to work around the context removal upon memory pressure
925 private static boolean mIncrementEGLContextHack = false;
926
Adam Powell4fb35d42011-03-03 17:54:55 -0800927 // used for serializing asynchronously handled touch events.
928 private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
929
Adam Powelle00e8a782011-09-11 17:48:42 -0700930 // Used to track whether picture updating was paused due to a window focus change.
931 private boolean mPictureUpdatePausedForFocusChange = false;
932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 // Used to notify listeners of a new picture.
934 private PictureListener mPictureListener;
935 /**
936 * Interface to listen for new pictures as they change.
Kristian Monsenfc771652011-05-10 16:44:05 +0100937 * @deprecated This interface is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 */
Kristian Monsenfc771652011-05-10 16:44:05 +0100939 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 public interface PictureListener {
941 /**
942 * Notify the listener that the picture has changed.
943 * @param view The WebView that owns the picture.
944 * @param picture The new picture.
Kristian Monsen4aad1022011-11-17 13:28:02 +0000945 * @deprecated Due to internal changes, the picture does not include
946 * composited layers such as fixed position elements or scrollable divs.
947 * While the PictureListener API can still be used to detect changes in
948 * the WebView content, you are advised against its usage until a replacement
949 * is provided in a future Android release
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 */
Kristian Monsenfc771652011-05-10 16:44:05 +0100951 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 public void onNewPicture(WebView view, Picture picture);
953 }
954
Leon Scroggins3246c222009-05-26 09:51:23 -0400955 // FIXME: Want to make this public, but need to change the API file.
956 public /*static*/ class HitTestResult {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 /**
958 * Default HitTestResult, where the target is unknown
959 */
960 public static final int UNKNOWN_TYPE = 0;
961 /**
Steve Block1854ddb2011-04-19 12:18:19 +0100962 * @deprecated This type is no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 */
Steve Block1854ddb2011-04-19 12:18:19 +0100964 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 public static final int ANCHOR_TYPE = 1;
966 /**
967 * HitTestResult for hitting a phone number
968 */
969 public static final int PHONE_TYPE = 2;
970 /**
971 * HitTestResult for hitting a map address
972 */
973 public static final int GEO_TYPE = 3;
974 /**
975 * HitTestResult for hitting an email address
976 */
977 public static final int EMAIL_TYPE = 4;
978 /**
979 * HitTestResult for hitting an HTML::img tag
980 */
981 public static final int IMAGE_TYPE = 5;
982 /**
Steve Block1854ddb2011-04-19 12:18:19 +0100983 * @deprecated This type is no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 */
Steve Block1854ddb2011-04-19 12:18:19 +0100985 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 public static final int IMAGE_ANCHOR_TYPE = 6;
987 /**
988 * HitTestResult for hitting a HTML::a tag with src=http
989 */
990 public static final int SRC_ANCHOR_TYPE = 7;
991 /**
992 * HitTestResult for hitting a HTML::a tag with src=http + HTML::img
993 */
994 public static final int SRC_IMAGE_ANCHOR_TYPE = 8;
995 /**
996 * HitTestResult for hitting an edit text area
997 */
998 public static final int EDIT_TEXT_TYPE = 9;
999
1000 private int mType;
1001 private String mExtra;
1002
1003 HitTestResult() {
1004 mType = UNKNOWN_TYPE;
1005 }
1006
1007 private void setType(int type) {
1008 mType = type;
1009 }
1010
1011 private void setExtra(String extra) {
1012 mExtra = extra;
1013 }
1014
1015 public int getType() {
1016 return mType;
1017 }
1018
1019 public String getExtra() {
1020 return mExtra;
1021 }
1022 }
1023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 /**
1025 * Construct a new WebView with a Context object.
1026 * @param context A Context object used to access application assets.
1027 */
1028 public WebView(Context context) {
1029 this(context, null);
1030 }
1031
1032 /**
1033 * Construct a new WebView with layout parameters.
1034 * @param context A Context object used to access application assets.
1035 * @param attrs An AttributeSet passed to our parent.
1036 */
1037 public WebView(Context context, AttributeSet attrs) {
1038 this(context, attrs, com.android.internal.R.attr.webViewStyle);
1039 }
1040
1041 /**
1042 * Construct a new WebView with layout parameters and a default style.
1043 * @param context A Context object used to access application assets.
1044 * @param attrs An AttributeSet passed to our parent.
1045 * @param defStyle The default style resource ID.
1046 */
1047 public WebView(Context context, AttributeSet attrs, int defStyle) {
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07001048 this(context, attrs, defStyle, false);
1049 }
1050
1051 /**
1052 * Construct a new WebView with layout parameters and a default style.
1053 * @param context A Context object used to access application assets.
1054 * @param attrs An AttributeSet passed to our parent.
1055 * @param defStyle The default style resource ID.
1056 */
1057 public WebView(Context context, AttributeSet attrs, int defStyle,
1058 boolean privateBrowsing) {
1059 this(context, attrs, defStyle, null, privateBrowsing);
Andrei Popescu4950b2b2009-09-03 13:56:07 +01001060 }
1061
1062 /**
1063 * Construct a new WebView with layout parameters, a default style and a set
1064 * of custom Javscript interfaces to be added to the WebView at initialization
Romain Guy01d0fbf2009-12-01 14:52:19 -08001065 * time. This guarantees that these interfaces will be available when the JS
Andrei Popescu4950b2b2009-09-03 13:56:07 +01001066 * context is initialized.
1067 * @param context A Context object used to access application assets.
1068 * @param attrs An AttributeSet passed to our parent.
1069 * @param defStyle The default style resource ID.
Steve Block81f19ff2010-11-01 13:23:24 +00001070 * @param javaScriptInterfaces is a Map of interface names, as keys, and
Andrei Popescu4950b2b2009-09-03 13:56:07 +01001071 * object implementing those interfaces, as values.
1072 * @hide pending API council approval.
1073 */
1074 protected WebView(Context context, AttributeSet attrs, int defStyle,
Steve Block81f19ff2010-11-01 13:23:24 +00001075 Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 super(context, attrs, defStyle);
Steve Block51b08912011-04-27 15:04:48 +01001077 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078
Kristian Monsen87af7312011-09-09 02:12:51 +01001079 if (context == null) {
1080 throw new IllegalArgumentException("Invalid context argument");
1081 }
1082
Kristian Monsend89a30a2010-11-16 18:11:59 +00001083 // Used by the chrome stack to find application paths
1084 JniUtil.setContext(context);
1085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 mCallbackProxy = new CallbackProxy(context, this);
Grace Kloba9a67c822009-12-20 11:33:58 -08001087 mViewManager = new ViewManager(this);
Ben Murdochd2e91d12011-02-25 17:11:02 +00001088 L10nUtils.setApplicationContext(context.getApplicationContext());
Steve Block81f19ff2010-11-01 13:23:24 +00001089 mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 mDatabase = WebViewDatabase.getInstance(context);
Adam Powell637d3372010-08-25 14:37:03 -07001091 mScroller = new OverScroller(context, null, 0, 0, false); //TODO Use OverScroller's flywheel
Derek Sollenberger03e48912010-05-18 17:03:42 -04001092 mZoomManager = new ZoomManager(this, mCallbackProxy);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001093
Derek Sollenberger90b6e482010-05-10 12:38:54 -04001094 /* The init method must follow the creation of certain member variables,
1095 * such as the mZoomManager.
1096 */
1097 init();
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001098 setupPackageListener(context);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001099 setupProxyListener(context);
Grace Kloba3a0def22010-01-23 21:11:54 -08001100 updateMultiTouchSupport(context);
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07001101
1102 if (privateBrowsing) {
1103 startPrivateBrowsing();
1104 }
Ben Murdochffcc49e2010-10-28 18:24:57 +01001105
Ben Murdoch01b04e12010-11-08 10:49:16 +00001106 mAutoFillData = new WebViewCore.AutoFillData();
Grace Kloba3a0def22010-01-23 21:11:54 -08001107 }
1108
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001109 private static class ProxyReceiver extends BroadcastReceiver {
1110 @Override
1111 public void onReceive(Context context, Intent intent) {
1112 if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) {
1113 handleProxyBroadcast(intent);
1114 }
1115 }
1116 }
1117
Kristian Monsen9437d912010-12-23 15:39:31 +00001118 /*
Kristian Monsencbb59db2011-05-09 16:04:34 +01001119 * Receiver for PROXY_CHANGE_ACTION, will be null when it is not added handling broadcasts.
Kristian Monsen9437d912010-12-23 15:39:31 +00001120 */
Kristian Monsencbb59db2011-05-09 16:04:34 +01001121 private static ProxyReceiver sProxyReceiver;
Kristian Monsen9437d912010-12-23 15:39:31 +00001122
Kristian Monsencbb59db2011-05-09 16:04:34 +01001123 /*
1124 * @param context This method expects this to be a valid context
1125 */
Kristian Monsen9437d912010-12-23 15:39:31 +00001126 private static synchronized void setupProxyListener(Context context) {
Kristian Monsencbb59db2011-05-09 16:04:34 +01001127 if (sProxyReceiver != null || sNotificationsEnabled == false) {
Kristian Monsen9437d912010-12-23 15:39:31 +00001128 return;
1129 }
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001130 IntentFilter filter = new IntentFilter();
1131 filter.addAction(Proxy.PROXY_CHANGE_ACTION);
Kristian Monsencbb59db2011-05-09 16:04:34 +01001132 sProxyReceiver = new ProxyReceiver();
Kristian Monsen9437d912010-12-23 15:39:31 +00001133 Intent currentProxy = context.getApplicationContext().registerReceiver(
Kristian Monsencbb59db2011-05-09 16:04:34 +01001134 sProxyReceiver, filter);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001135 if (currentProxy != null) {
1136 handleProxyBroadcast(currentProxy);
1137 }
1138 }
1139
Kristian Monsencbb59db2011-05-09 16:04:34 +01001140 /*
1141 * @param context This method expects this to be a valid context
1142 */
1143 private static synchronized void disableProxyListener(Context context) {
1144 if (sProxyReceiver == null)
1145 return;
1146
1147 context.getApplicationContext().unregisterReceiver(sProxyReceiver);
1148 sProxyReceiver = null;
1149 }
1150
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001151 private static void handleProxyBroadcast(Intent intent) {
1152 ProxyProperties proxyProperties = (ProxyProperties)intent.getExtra(Proxy.EXTRA_PROXY_INFO);
1153 if (proxyProperties == null || proxyProperties.getHost() == null) {
Kristian Monsen2032eee2011-05-23 14:25:27 +01001154 WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, null);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001155 return;
1156 }
Kristian Monsen2032eee2011-05-23 14:25:27 +01001157 WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, proxyProperties);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001158 }
1159
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001160 /*
Kristian Monsen4190aab2010-12-16 18:39:21 +00001161 * A variable to track if there is a receiver added for ACTION_PACKAGE_ADDED
1162 * or ACTION_PACKAGE_REMOVED.
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001163 */
Kristian Monsen4190aab2010-12-16 18:39:21 +00001164 private static boolean sPackageInstallationReceiverAdded = false;
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001165
1166 /*
1167 * A set of Google packages we monitor for the
1168 * navigator.isApplicationInstalled() API. Add additional packages as
1169 * needed.
1170 */
1171 private static Set<String> sGoogleApps;
1172 static {
1173 sGoogleApps = new HashSet<String>();
1174 sGoogleApps.add("com.google.android.youtube");
1175 }
1176
Kristian Monsen4190aab2010-12-16 18:39:21 +00001177 private static class PackageListener extends BroadcastReceiver {
1178 @Override
1179 public void onReceive(Context context, Intent intent) {
1180 final String action = intent.getAction();
1181 final String packageName = intent.getData().getSchemeSpecificPart();
1182 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1183 if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) {
1184 // if it is replacing, refreshPlugins() when adding
1185 return;
1186 }
1187
1188 if (sGoogleApps.contains(packageName)) {
1189 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
1190 WebViewCore.sendStaticMessage(EventHub.ADD_PACKAGE_NAME, packageName);
1191 } else {
1192 WebViewCore.sendStaticMessage(EventHub.REMOVE_PACKAGE_NAME, packageName);
1193 }
1194 }
1195
1196 PluginManager pm = PluginManager.getInstance(context);
1197 if (pm.containsPluginPermissionAndSignatures(packageName)) {
1198 pm.refreshPlugins(Intent.ACTION_PACKAGE_ADDED.equals(action));
1199 }
1200 }
1201 }
1202
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001203 private void setupPackageListener(Context context) {
1204
1205 /*
1206 * we must synchronize the instance check and the creation of the
1207 * receiver to ensure that only ONE receiver exists for all WebView
1208 * instances.
1209 */
1210 synchronized (WebView.class) {
1211
1212 // if the receiver already exists then we do not need to register it
1213 // again
Kristian Monsen4190aab2010-12-16 18:39:21 +00001214 if (sPackageInstallationReceiverAdded) {
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001215 return;
1216 }
1217
1218 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
1219 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1220 filter.addDataScheme("package");
Kristian Monsen4190aab2010-12-16 18:39:21 +00001221 BroadcastReceiver packageListener = new PackageListener();
1222 context.getApplicationContext().registerReceiver(packageListener, filter);
1223 sPackageInstallationReceiverAdded = true;
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001224 }
1225
1226 // check if any of the monitored apps are already installed
1227 AsyncTask<Void, Void, Set<String>> task = new AsyncTask<Void, Void, Set<String>>() {
1228
1229 @Override
1230 protected Set<String> doInBackground(Void... unused) {
1231 Set<String> installedPackages = new HashSet<String>();
1232 PackageManager pm = mContext.getPackageManager();
Kristian Monsen63a1b0c2011-03-09 13:54:54 +00001233 for (String name : sGoogleApps) {
1234 try {
1235 PackageInfo pInfo = pm.getPackageInfo(name,
1236 PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
1237 installedPackages.add(name);
Steve Block51b08912011-04-27 15:04:48 +01001238 } catch (PackageManager.NameNotFoundException e) {
Kristian Monsen63a1b0c2011-03-09 13:54:54 +00001239 // package not found
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001240 }
1241 }
1242 return installedPackages;
1243 }
1244
1245 // Executes on the UI thread
1246 @Override
1247 protected void onPostExecute(Set<String> installedPackages) {
Derek Sollenbergerc92de672010-09-01 08:55:22 -04001248 if (mWebViewCore != null) {
1249 mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, installedPackages);
1250 }
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001251 }
1252 };
1253 task.execute();
1254 }
1255
Grace Kloba3a0def22010-01-23 21:11:54 -08001256 void updateMultiTouchSupport(Context context) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04001257 mZoomManager.updateMultiTouchSupport(context);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001258 }
1259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 private void init() {
John Reck34a676b2011-09-07 13:41:17 -07001261 OnTrimMemoryListener.init(getContext());
1262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 setWillNotDraw(false);
1264 setFocusable(true);
1265 setFocusableInTouchMode(true);
1266 setClickable(true);
1267 setLongClickable(true);
1268
Romain Guy4296fc42009-07-06 11:48:52 -07001269 final ViewConfiguration configuration = ViewConfiguration.get(getContext());
Grace Kloba8b97e4b2009-07-28 13:11:38 -07001270 int slop = configuration.getScaledTouchSlop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 mTouchSlopSquare = slop * slop;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07001272 slop = configuration.getScaledDoubleTapSlop();
1273 mDoubleTapSlopSquare = slop * slop;
Grace Kloba25737912009-06-19 12:42:47 -07001274 final float density = getContext().getResources().getDisplayMetrics().density;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001275 // use one line height, 16 based on our current default font, for how
1276 // far we allow a touch be away from the edge of a link
Grace Kloba25737912009-06-19 12:42:47 -07001277 mNavSlop = (int) (16 * density);
Derek Sollenberger90b6e482010-05-10 12:38:54 -04001278 mZoomManager.init(density);
Romain Guy4296fc42009-07-06 11:48:52 -07001279 mMaximumFling = configuration.getScaledMaximumFlingVelocity();
Patrick Scotta3ebcc92010-07-16 11:52:22 -04001280
1281 // Compute the inverse of the density squared.
1282 DRAG_LAYER_INVERSE_DENSITY_SQUARED = 1 / (density * density);
Adam Powell637d3372010-08-25 14:37:03 -07001283
1284 mOverscrollDistance = configuration.getScaledOverscrollDistance();
1285 mOverflingDistance = configuration.getScaledOverflingDistance();
Teng-Hui Zhu15bfa532011-02-14 17:01:16 -08001286
1287 setScrollBarStyle(super.getScrollBarStyle());
Leon Scroggins115626a2011-02-17 12:00:48 -05001288 // Initially use a size of two, since the user is likely to only hold
1289 // down two keys at a time (shift + another key)
1290 mKeysPressed = new Vector<Integer>(2);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08001291 mHTML5VideoViewProxy = null ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 }
1293
Patrick Dubroye0a799a2011-05-04 16:19:22 -07001294 @Override
1295 public boolean shouldDelayChildPressedState() {
1296 return true;
1297 }
1298
Svetoslav Ganovda355512010-05-12 22:04:44 -07001299 /**
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001300 * Adds accessibility APIs to JavaScript.
Svetoslav Ganovda355512010-05-12 22:04:44 -07001301 *
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001302 * Note: This method is responsible to performing the necessary
1303 * check if the accessibility APIs should be exposed.
Svetoslav Ganovda355512010-05-12 22:04:44 -07001304 */
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001305 private void addAccessibilityApisToJavaScript() {
1306 if (AccessibilityManager.getInstance(mContext).isEnabled()
1307 && getSettings().getJavaScriptEnabled()) {
1308 // exposing the TTS for now ...
Narayan Kamath68e2af52011-11-28 17:10:04 +00001309 final Context ctx = getContext();
1310 if (ctx != null) {
1311 final String packageName = ctx.getPackageName();
1312 if (packageName != null) {
1313 mTextToSpeech = new TextToSpeech(getContext(), null, null,
1314 packageName + ".**webview**");
1315 addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
1316 }
1317 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001318 }
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001319 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001320
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001321 /**
1322 * Removes accessibility APIs from JavaScript.
1323 */
1324 private void removeAccessibilityApisFromJavaScript() {
1325 // exposing the TTS for now ...
1326 if (mTextToSpeech != null) {
1327 removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE);
1328 mTextToSpeech.shutdown();
1329 mTextToSpeech = null;
1330 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001331 }
1332
Adam Powell637d3372010-08-25 14:37:03 -07001333 @Override
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -07001334 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1335 super.onInitializeAccessibilityNodeInfo(info);
1336 info.setScrollable(isScrollableForAccessibility());
1337 }
1338
1339 @Override
1340 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1341 super.onInitializeAccessibilityEvent(event);
1342 event.setScrollable(isScrollableForAccessibility());
1343 event.setScrollX(mScrollX);
1344 event.setScrollY(mScrollY);
1345 final int convertedContentWidth = contentToViewX(getContentWidth());
1346 final int adjustedViewWidth = getWidth() - mPaddingLeft - mPaddingRight;
1347 event.setMaxScrollX(Math.max(convertedContentWidth - adjustedViewWidth, 0));
1348 final int convertedContentHeight = contentToViewY(getContentHeight());
1349 final int adjustedViewHeight = getHeight() - mPaddingTop - mPaddingBottom;
1350 event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
1351 }
1352
1353 private boolean isScrollableForAccessibility() {
1354 return (contentToViewX(getContentWidth()) > getWidth() - mPaddingLeft - mPaddingRight
1355 || contentToViewY(getContentHeight()) > getHeight() - mPaddingTop - mPaddingBottom);
1356 }
1357
1358 @Override
Adam Powell637d3372010-08-25 14:37:03 -07001359 public void setOverScrollMode(int mode) {
1360 super.setOverScrollMode(mode);
1361 if (mode != OVER_SCROLL_NEVER) {
1362 if (mOverScrollGlow == null) {
1363 mOverScrollGlow = new OverScrollGlow(this);
1364 }
1365 } else {
1366 mOverScrollGlow = null;
1367 }
1368 }
1369
Mangesh Ghiwaree832b632011-11-16 11:46:39 -08001370 /* package */ void adjustDefaultZoomDensity(int zoomDensity) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04001371 final float density = mContext.getResources().getDisplayMetrics().density
Grace Kloba0d8b77c2009-06-25 11:20:51 -07001372 * 100 / zoomDensity;
Mangesh Ghiwaree832b632011-11-16 11:46:39 -08001373 updateDefaultZoomDensity(density);
1374 }
1375
1376 /* package */ void updateDefaultZoomDensity(float density) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04001377 mNavSlop = (int) (16 * density);
1378 mZoomManager.updateDefaultZoomDensity(density);
Grace Kloba0d8b77c2009-06-25 11:20:51 -07001379 }
1380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 /* package */ boolean onSavePassword(String schemePlusHost, String username,
1382 String password, final Message resumeMsg) {
1383 boolean rVal = false;
1384 if (resumeMsg == null) {
1385 // null resumeMsg implies saving password silently
1386 mDatabase.setUsernamePassword(schemePlusHost, username, password);
1387 } else {
1388 final Message remember = mPrivateHandler.obtainMessage(
1389 REMEMBER_PASSWORD);
1390 remember.getData().putString("host", schemePlusHost);
1391 remember.getData().putString("username", username);
1392 remember.getData().putString("password", password);
1393 remember.obj = resumeMsg;
1394
1395 final Message neverRemember = mPrivateHandler.obtainMessage(
1396 NEVER_REMEMBER_PASSWORD);
1397 neverRemember.getData().putString("host", schemePlusHost);
1398 neverRemember.getData().putString("username", username);
1399 neverRemember.getData().putString("password", password);
1400 neverRemember.obj = resumeMsg;
1401
1402 new AlertDialog.Builder(getContext())
1403 .setTitle(com.android.internal.R.string.save_password_label)
1404 .setMessage(com.android.internal.R.string.save_password_message)
1405 .setPositiveButton(com.android.internal.R.string.save_password_notnow,
1406 new DialogInterface.OnClickListener() {
1407 public void onClick(DialogInterface dialog, int which) {
1408 resumeMsg.sendToTarget();
1409 }
1410 })
1411 .setNeutralButton(com.android.internal.R.string.save_password_remember,
1412 new DialogInterface.OnClickListener() {
1413 public void onClick(DialogInterface dialog, int which) {
1414 remember.sendToTarget();
1415 }
1416 })
1417 .setNegativeButton(com.android.internal.R.string.save_password_never,
1418 new DialogInterface.OnClickListener() {
1419 public void onClick(DialogInterface dialog, int which) {
1420 neverRemember.sendToTarget();
1421 }
1422 })
1423 .setOnCancelListener(new OnCancelListener() {
1424 public void onCancel(DialogInterface dialog) {
1425 resumeMsg.sendToTarget();
1426 }
1427 }).show();
1428 // Return true so that WebViewCore will pause while the dialog is
1429 // up.
1430 rVal = true;
1431 }
1432 return rVal;
1433 }
1434
1435 @Override
1436 public void setScrollBarStyle(int style) {
1437 if (style == View.SCROLLBARS_INSIDE_INSET
1438 || style == View.SCROLLBARS_OUTSIDE_INSET) {
1439 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
1440 } else {
1441 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
1442 }
1443 super.setScrollBarStyle(style);
1444 }
1445
1446 /**
1447 * Specify whether the horizontal scrollbar has overlay style.
1448 * @param overlay TRUE if horizontal scrollbar should have overlay style.
1449 */
1450 public void setHorizontalScrollbarOverlay(boolean overlay) {
Steve Block51b08912011-04-27 15:04:48 +01001451 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 mOverlayHorizontalScrollbar = overlay;
1453 }
1454
1455 /**
1456 * Specify whether the vertical scrollbar has overlay style.
1457 * @param overlay TRUE if vertical scrollbar should have overlay style.
1458 */
1459 public void setVerticalScrollbarOverlay(boolean overlay) {
Steve Block51b08912011-04-27 15:04:48 +01001460 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 mOverlayVerticalScrollbar = overlay;
1462 }
1463
1464 /**
1465 * Return whether horizontal scrollbar has overlay style
1466 * @return TRUE if horizontal scrollbar has overlay style.
1467 */
1468 public boolean overlayHorizontalScrollbar() {
Steve Block51b08912011-04-27 15:04:48 +01001469 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 return mOverlayHorizontalScrollbar;
1471 }
1472
1473 /**
1474 * Return whether vertical scrollbar has overlay style
1475 * @return TRUE if vertical scrollbar has overlay style.
1476 */
1477 public boolean overlayVerticalScrollbar() {
Steve Block51b08912011-04-27 15:04:48 +01001478 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 return mOverlayVerticalScrollbar;
1480 }
1481
1482 /*
1483 * Return the width of the view where the content of WebView should render
1484 * to.
Grace Kloba6ed525e2009-09-17 15:31:12 -07001485 * Note: this can be called from WebCoreThread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 */
Grace Kloba6ed525e2009-09-17 15:31:12 -07001487 /* package */ int getViewWidth() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) {
1489 return getWidth();
1490 } else {
Shimeng (Simon) Wang37127542010-12-03 16:34:00 -08001491 return Math.max(0, getWidth() - getVerticalScrollbarWidth());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 }
1493 }
1494
Michael Kolb601e7792011-02-23 17:43:16 -08001495 /**
Mike Reede8853fc2009-09-04 14:01:48 -04001496 * returns the height of the titlebarview (if any). Does not care about
1497 * scrolling
Michael Kolb75a03f92011-02-23 16:12:13 -08001498 * @hide
Mike Reede8853fc2009-09-04 14:01:48 -04001499 */
Michael Kolb75a03f92011-02-23 16:12:13 -08001500 protected int getTitleHeight() {
Mike Reede8853fc2009-09-04 14:01:48 -04001501 return mTitleBar != null ? mTitleBar.getHeight() : 0;
1502 }
1503
Michael Kolbe54f6652011-03-16 09:11:51 -07001504 /**
Mike Reede8853fc2009-09-04 14:01:48 -04001505 * Return the amount of the titlebarview (if any) that is visible
Michael Kolb73980a92010-08-05 16:32:51 -07001506 *
Michael Kolb24e53b02011-03-16 12:52:04 -07001507 * @deprecated This method is now obsolete.
Mike Reede8853fc2009-09-04 14:01:48 -04001508 */
Michael Kolb73980a92010-08-05 16:32:51 -07001509 public int getVisibleTitleHeight() {
Steve Block51b08912011-04-27 15:04:48 +01001510 checkThread();
Steve Block92c99162011-05-23 17:36:01 +01001511 return getVisibleTitleHeightImpl();
1512 }
1513
1514 private int getVisibleTitleHeightImpl() {
Adam Powell637d3372010-08-25 14:37:03 -07001515 // need to restrict mScrollY due to over scroll
John Reckfffce6f2011-10-06 20:37:01 -07001516 return Math.max(getTitleHeight() - Math.max(0, mScrollY),
John Reckd6ac7272011-11-08 15:00:17 -08001517 getOverlappingActionModeHeight());
1518 }
1519
1520 private int mCachedOverlappingActionModeHeight = -1;
1521
1522 private int getOverlappingActionModeHeight() {
1523 if (mFindCallback == null) {
1524 return 0;
1525 }
1526 if (mCachedOverlappingActionModeHeight < 0) {
1527 getGlobalVisibleRect(mGlobalVisibleRect, mGlobalVisibleOffset);
1528 mCachedOverlappingActionModeHeight = Math.max(0,
1529 mFindCallback.getActionModeGlobalBottom() - mGlobalVisibleRect.top);
1530 }
1531 return mCachedOverlappingActionModeHeight;
Mike Reede8853fc2009-09-04 14:01:48 -04001532 }
1533
1534 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 * Return the height of the view where the content of WebView should render
Leon Scroggins0236e672009-09-02 21:12:08 -04001536 * to. Note that this excludes mTitleBar, if there is one.
Grace Kloba6ed525e2009-09-17 15:31:12 -07001537 * Note: this can be called from WebCoreThread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 */
Grace Kloba6ed525e2009-09-17 15:31:12 -07001539 /* package */ int getViewHeight() {
Steve Block92c99162011-05-23 17:36:01 +01001540 return getViewHeightWithTitle() - getVisibleTitleHeightImpl();
Grace Kloba8eff73f2009-09-24 09:34:32 -07001541 }
1542
John Reck816c0de2011-06-02 16:04:53 -07001543 int getViewHeightWithTitle() {
Leon Scroggins0236e672009-09-02 21:12:08 -04001544 int height = getHeight();
Mike Reede8853fc2009-09-04 14:01:48 -04001545 if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) {
Leon Scroggins0236e672009-09-02 21:12:08 -04001546 height -= getHorizontalScrollbarHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 }
Grace Kloba8eff73f2009-09-24 09:34:32 -07001548 return height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 }
1550
1551 /**
1552 * @return The SSL certificate for the main top-level page or null if
1553 * there is no certificate (the site is not secure).
1554 */
1555 public SslCertificate getCertificate() {
Steve Block51b08912011-04-27 15:04:48 +01001556 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 return mCertificate;
1558 }
1559
1560 /**
1561 * Sets the SSL certificate for the main top-level page.
1562 */
1563 public void setCertificate(SslCertificate certificate) {
Steve Block51b08912011-04-27 15:04:48 +01001564 checkThread();
Brian Carlstromdba8cb72010-03-18 16:56:41 -07001565 if (DebugFlags.WEB_VIEW) {
1566 Log.v(LOGTAG, "setCertificate=" + certificate);
1567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 // here, the certificate can be null (if the site is not secure)
1569 mCertificate = certificate;
1570 }
1571
1572 //-------------------------------------------------------------------------
1573 // Methods called by activity
1574 //-------------------------------------------------------------------------
1575
1576 /**
1577 * Save the username and password for a particular host in the WebView's
1578 * internal database.
1579 * @param host The host that required the credentials.
1580 * @param username The username for the given host.
1581 * @param password The password for the given host.
1582 */
1583 public void savePassword(String host, String username, String password) {
Steve Block51b08912011-04-27 15:04:48 +01001584 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 mDatabase.setUsernamePassword(host, username, password);
1586 }
1587
1588 /**
1589 * Set the HTTP authentication credentials for a given host and realm.
1590 *
1591 * @param host The host for the credentials.
1592 * @param realm The realm for the credentials.
1593 * @param username The username for the password. If it is null, it means
1594 * password can't be saved.
1595 * @param password The password
1596 */
1597 public void setHttpAuthUsernamePassword(String host, String realm,
1598 String username, String password) {
Steve Block51b08912011-04-27 15:04:48 +01001599 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
1601 }
1602
1603 /**
1604 * Retrieve the HTTP authentication username and password for a given
1605 * host & realm pair
1606 *
1607 * @param host The host for which the credentials apply.
1608 * @param realm The realm for which the credentials apply.
1609 * @return String[] if found, String[0] is username, which can be null and
1610 * String[1] is password. Return null if it can't find anything.
1611 */
1612 public String[] getHttpAuthUsernamePassword(String host, String realm) {
Steve Block51b08912011-04-27 15:04:48 +01001613 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 return mDatabase.getHttpAuthUsernamePassword(host, realm);
1615 }
1616
1617 /**
Leon Scroggins05919f22010-09-14 17:22:36 -04001618 * Remove Find or Select ActionModes, if active.
1619 */
1620 private void clearActionModes() {
1621 if (mSelectCallback != null) {
1622 mSelectCallback.finish();
1623 }
1624 if (mFindCallback != null) {
1625 mFindCallback.finish();
1626 }
1627 }
1628
1629 /**
1630 * Called to clear state when moving from one page to another, or changing
1631 * in some other way that makes elements associated with the current page
1632 * (such as WebTextView or ActionModes) no longer relevant.
1633 */
1634 private void clearHelpers() {
1635 clearTextEntry();
1636 clearActionModes();
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04001637 dismissFullScreenMode();
Ben Murdoch2ffc9ec2011-11-28 15:41:31 +00001638 cancelSelectDialog();
1639 }
1640
1641 private void cancelSelectDialog() {
1642 if (mListBoxDialog != null) {
1643 mListBoxDialog.cancel();
1644 mListBoxDialog = null;
1645 }
Leon Scroggins05919f22010-09-14 17:22:36 -04001646 }
1647
1648 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649 * Destroy the internal state of the WebView. This method should be called
1650 * after the WebView has been removed from the view system. No other
1651 * methods may be called on a WebView after destroy.
1652 */
1653 public void destroy() {
Steve Block51b08912011-04-27 15:04:48 +01001654 checkThread();
1655 destroyImpl();
1656 }
1657
1658 private void destroyImpl() {
Leon Scroggins05919f22010-09-14 17:22:36 -04001659 clearHelpers();
Mattias Falk0ae2ec82010-09-16 16:24:46 +02001660 if (mListBoxDialog != null) {
1661 mListBoxDialog.dismiss();
1662 mListBoxDialog = null;
1663 }
George Mount1fa26cb2011-10-03 10:56:28 -07001664 // remove so that it doesn't cause events
1665 if (mWebTextView != null) {
1666 mWebTextView.remove();
1667 mWebTextView = null;
1668 }
Cary Clarkd9fd8572011-02-03 05:25:05 -05001669 if (mNativeClass != 0) nativeStopGL();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 if (mWebViewCore != null) {
1671 // Set the handlers to null before destroying WebViewCore so no
Cary Clarkd6982c92009-05-29 11:02:22 -04001672 // more messages will be posted.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 mCallbackProxy.setWebViewClient(null);
1674 mCallbackProxy.setWebChromeClient(null);
1675 // Tell WebViewCore to destroy itself
Andrei Popescu04098572010-03-09 12:23:19 +00001676 synchronized (this) {
1677 WebViewCore webViewCore = mWebViewCore;
1678 mWebViewCore = null; // prevent using partial webViewCore
1679 webViewCore.destroy();
1680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 // Remove any pending messages that might not be serviced yet.
1682 mPrivateHandler.removeCallbacksAndMessages(null);
1683 mCallbackProxy.removeCallbacksAndMessages(null);
1684 // Wake up the WebCore thread just in case it is waiting for a
Steve Block81f19ff2010-11-01 13:23:24 +00001685 // JavaScript dialog.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 synchronized (mCallbackProxy) {
1687 mCallbackProxy.notify();
1688 }
1689 }
1690 if (mNativeClass != 0) {
1691 nativeDestroy();
1692 mNativeClass = 0;
1693 }
1694 }
1695
1696 /**
1697 * Enables platform notifications of data state and proxy changes.
Kristian Monsencbb59db2011-05-09 16:04:34 +01001698 * Notifications are enabled by default.
Kristian Monsenfc771652011-05-10 16:44:05 +01001699 *
1700 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001702 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 public static void enablePlatformNotifications() {
Steve Block51b08912011-04-27 15:04:48 +01001704 checkThread();
Kristian Monsencbb59db2011-05-09 16:04:34 +01001705 synchronized (WebView.class) {
1706 Network.enablePlatformNotifications();
1707 sNotificationsEnabled = true;
1708 Context context = JniUtil.getContext();
1709 if (context != null)
1710 setupProxyListener(context);
1711 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
1713
1714 /**
Kristian Monsencbb59db2011-05-09 16:04:34 +01001715 * Disables platform notifications of data state and proxy changes.
1716 * Notifications are enabled by default.
Kristian Monsenfc771652011-05-10 16:44:05 +01001717 *
1718 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001720 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 public static void disablePlatformNotifications() {
Steve Block51b08912011-04-27 15:04:48 +01001722 checkThread();
Kristian Monsencbb59db2011-05-09 16:04:34 +01001723 synchronized (WebView.class) {
1724 Network.disablePlatformNotifications();
1725 sNotificationsEnabled = false;
1726 Context context = JniUtil.getContext();
1727 if (context != null)
1728 disableProxyListener(context);
1729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 }
Cary Clarkd6982c92009-05-29 11:02:22 -04001731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 /**
Feng Qianb3081372009-06-29 15:55:18 -07001733 * Sets JavaScript engine flags.
1734 *
1735 * @param flags JS engine flags in a String
1736 *
1737 * @hide pending API solidification
1738 */
1739 public void setJsFlags(String flags) {
Steve Block51b08912011-04-27 15:04:48 +01001740 checkThread();
Feng Qianb3081372009-06-29 15:55:18 -07001741 mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
1742 }
1743
1744 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 * Inform WebView of the network state. This is used to set
Steve Block81f19ff2010-11-01 13:23:24 +00001746 * the JavaScript property window.navigator.isOnline and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 * generates the online/offline event as specified in HTML5, sec. 5.7.7
1748 * @param networkUp boolean indicating if network is available
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 */
1750 public void setNetworkAvailable(boolean networkUp) {
Steve Block51b08912011-04-27 15:04:48 +01001751 checkThread();
Grace Klobaa72cc092009-04-02 08:50:17 -07001752 mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE,
1753 networkUp ? 1 : 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 }
1755
1756 /**
Andrei Popescuf5dba882010-01-12 22:42:41 +00001757 * Inform WebView about the current network type.
1758 * {@hide}
1759 */
1760 public void setNetworkType(String type, String subtype) {
Steve Block51b08912011-04-27 15:04:48 +01001761 checkThread();
Andrei Popescuf5dba882010-01-12 22:42:41 +00001762 Map<String, String> map = new HashMap<String, String>();
1763 map.put("type", type);
1764 map.put("subtype", subtype);
1765 mWebViewCore.sendMessage(EventHub.SET_NETWORK_TYPE, map);
1766 }
1767 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04001768 * Save the state of this WebView used in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 * {@link android.app.Activity#onSaveInstanceState}. Please note that this
1770 * method no longer stores the display data for this WebView. The previous
1771 * behavior could potentially leak files if {@link #restoreState} was never
1772 * called. See {@link #savePicture} and {@link #restorePicture} for saving
1773 * and restoring the display data.
1774 * @param outState The Bundle to store the WebView state.
1775 * @return The same copy of the back/forward list used to save the state. If
1776 * saveState fails, the returned list will be null.
1777 * @see #savePicture
1778 * @see #restorePicture
1779 */
1780 public WebBackForwardList saveState(Bundle outState) {
Steve Block51b08912011-04-27 15:04:48 +01001781 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 if (outState == null) {
1783 return null;
1784 }
1785 // We grab a copy of the back/forward list because a client of WebView
1786 // may have invalidated the history list by calling clearHistory.
1787 WebBackForwardList list = copyBackForwardList();
1788 final int currentIndex = list.getCurrentIndex();
1789 final int size = list.getSize();
1790 // We should fail saving the state if the list is empty or the index is
1791 // not in a valid range.
1792 if (currentIndex < 0 || currentIndex >= size || size == 0) {
1793 return null;
1794 }
1795 outState.putInt("index", currentIndex);
1796 // FIXME: This should just be a byte[][] instead of ArrayList but
1797 // Parcel.java does not have the code to handle multi-dimensional
1798 // arrays.
1799 ArrayList<byte[]> history = new ArrayList<byte[]>(size);
1800 for (int i = 0; i < size; i++) {
1801 WebHistoryItem item = list.getItemAtIndex(i);
Cary Clark4fbf81b2009-09-29 16:07:56 -04001802 if (null == item) {
1803 // FIXME: this shouldn't happen
1804 // need to determine how item got set to null
1805 Log.w(LOGTAG, "saveState: Unexpected null history item.");
1806 return null;
1807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 byte[] data = item.getFlattenedData();
1809 if (data == null) {
1810 // It would be very odd to not have any data for a given history
1811 // item. And we will fail to rebuild the history list without
1812 // flattened data.
1813 return null;
1814 }
1815 history.add(data);
1816 }
1817 outState.putSerializable("history", history);
1818 if (mCertificate != null) {
1819 outState.putBundle("certificate",
1820 SslCertificate.saveState(mCertificate));
1821 }
Elliott Slaughterd6284792010-08-18 18:17:52 -07001822 outState.putBoolean("privateBrowsingEnabled", isPrivateBrowsingEnabled());
Shimeng (Simon) Wang4ae1f6f2010-08-26 10:58:38 -07001823 mZoomManager.saveZoomState(outState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 return list;
1825 }
1826
1827 /**
1828 * Save the current display data to the Bundle given. Used in conjunction
1829 * with {@link #saveState}.
1830 * @param b A Bundle to store the display data.
1831 * @param dest The file to store the serialized picture data. Will be
1832 * overwritten with this WebView's picture data.
1833 * @return True if the picture was successfully saved.
Kristian Monsenfc771652011-05-10 16:44:05 +01001834 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001836 @Deprecated
Patrick Scottda9a22b2010-04-08 08:32:52 -04001837 public boolean savePicture(Bundle b, final File dest) {
Steve Block51b08912011-04-27 15:04:48 +01001838 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 if (dest == null || b == null) {
1840 return false;
1841 }
1842 final Picture p = capturePicture();
Patrick Scottda9a22b2010-04-08 08:32:52 -04001843 // Use a temporary file while writing to ensure the destination file
1844 // contains valid data.
1845 final File temp = new File(dest.getPath() + ".writing");
1846 new Thread(new Runnable() {
1847 public void run() {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001848 FileOutputStream out = null;
Patrick Scottda9a22b2010-04-08 08:32:52 -04001849 try {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001850 out = new FileOutputStream(temp);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001851 p.writeToStream(out);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001852 // Writing the picture succeeded, rename the temporary file
1853 // to the destination.
1854 temp.renameTo(dest);
1855 } catch (Exception e) {
1856 // too late to do anything about it.
1857 } finally {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001858 if (out != null) {
1859 try {
1860 out.close();
1861 } catch (Exception e) {
1862 // Can't do anything about that
1863 }
1864 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001865 temp.delete();
1866 }
1867 }
1868 }).start();
1869 // now update the bundle
1870 b.putInt("scrollX", mScrollX);
1871 b.putInt("scrollY", mScrollY);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001872 mZoomManager.saveZoomState(b);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001873 return true;
1874 }
1875
1876 private void restoreHistoryPictureFields(Picture p, Bundle b) {
1877 int sx = b.getInt("scrollX", 0);
1878 int sy = b.getInt("scrollY", 0);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001879
Patrick Scottda9a22b2010-04-08 08:32:52 -04001880 mDrawHistory = true;
1881 mHistoryPicture = p;
Huahui Wu88b869a2011-03-17 17:42:12 -07001882
Patrick Scottda9a22b2010-04-08 08:32:52 -04001883 mScrollX = sx;
1884 mScrollY = sy;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001885 mZoomManager.restoreZoomState(b);
1886 final float scale = mZoomManager.getScale();
Patrick Scottda9a22b2010-04-08 08:32:52 -04001887 mHistoryWidth = Math.round(p.getWidth() * scale);
1888 mHistoryHeight = Math.round(p.getHeight() * scale);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001889
Patrick Scottda9a22b2010-04-08 08:32:52 -04001890 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 }
1892
1893 /**
1894 * Restore the display data that was save in {@link #savePicture}. Used in
1895 * conjunction with {@link #restoreState}.
John Reck2df8f422011-09-22 19:50:41 -07001896 *
1897 * Note that this will not work if the WebView is hardware accelerated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 * @param b A Bundle containing the saved display data.
1899 * @param src The file where the picture data was stored.
1900 * @return True if the picture was successfully restored.
Kristian Monsenfc771652011-05-10 16:44:05 +01001901 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001903 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 public boolean restorePicture(Bundle b, File src) {
Steve Block51b08912011-04-27 15:04:48 +01001905 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 if (src == null || b == null) {
1907 return false;
1908 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001909 if (!src.exists()) {
1910 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001912 try {
1913 final FileInputStream in = new FileInputStream(src);
1914 final Bundle copy = new Bundle(b);
1915 new Thread(new Runnable() {
1916 public void run() {
Patrick Scottda9a22b2010-04-08 08:32:52 -04001917 try {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001918 final Picture p = Picture.createFromStream(in);
1919 if (p != null) {
1920 // Post a runnable on the main thread to update the
1921 // history picture fields.
1922 mPrivateHandler.post(new Runnable() {
1923 public void run() {
1924 restoreHistoryPictureFields(p, copy);
1925 }
1926 });
1927 }
1928 } finally {
1929 try {
1930 in.close();
1931 } catch (Exception e) {
1932 // Nothing we can do now.
1933 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001934 }
1935 }
1936 }).start();
1937 } catch (FileNotFoundException e){
1938 e.printStackTrace();
1939 }
1940 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 }
1942
1943 /**
John Reck816c0de2011-06-02 16:04:53 -07001944 * Saves the view data to the output stream. The output is highly
1945 * version specific, and may not be able to be loaded by newer versions
1946 * of WebView.
1947 * @param stream The {@link OutputStream} to save to
1948 * @return True if saved successfully
1949 * @hide
1950 */
1951 public boolean saveViewState(OutputStream stream) {
1952 try {
1953 return ViewStateSerializer.serializeViewState(stream, this);
1954 } catch (IOException e) {
1955 Log.w(LOGTAG, "Failed to saveViewState", e);
1956 }
1957 return false;
1958 }
1959
1960 /**
1961 * Loads the view data from the input stream. See
1962 * {@link #saveViewState(OutputStream)} for more information.
1963 * @param stream The {@link InputStream} to load from
1964 * @return True if loaded successfully
1965 * @hide
1966 */
1967 public boolean loadViewState(InputStream stream) {
1968 try {
John Reck60c84d62011-06-08 18:00:02 -07001969 mLoadedPicture = ViewStateSerializer.deserializeViewState(stream, this);
John Reck95b7d6f2011-06-03 15:23:43 -07001970 mBlockWebkitViewMessages = true;
John Reck60c84d62011-06-08 18:00:02 -07001971 setNewPicture(mLoadedPicture, true);
John Reck23a446c2011-10-17 17:06:09 -07001972 mLoadedPicture.mViewState = null;
John Reck816c0de2011-06-02 16:04:53 -07001973 return true;
1974 } catch (IOException e) {
1975 Log.w(LOGTAG, "Failed to loadViewState", e);
1976 }
1977 return false;
1978 }
1979
1980 /**
John Reck95b7d6f2011-06-03 15:23:43 -07001981 * Clears the view state set with {@link #loadViewState(InputStream)}.
1982 * This WebView will then switch to showing the content from webkit
1983 * @hide
1984 */
1985 public void clearViewState() {
1986 mBlockWebkitViewMessages = false;
John Reck60c84d62011-06-08 18:00:02 -07001987 mLoadedPicture = null;
John Reck95b7d6f2011-06-03 15:23:43 -07001988 invalidate();
1989 }
1990
1991 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 * Restore the state of this WebView from the given map used in
Cary Clarkd6982c92009-05-29 11:02:22 -04001993 * {@link android.app.Activity#onRestoreInstanceState}. This method should
1994 * be called to restore the state of the WebView before using the object. If
1995 * it is called after the WebView has had a chance to build state (load
1996 * pages, create a back/forward list, etc.) there may be undesirable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 * side-effects. Please note that this method no longer restores the
1998 * display data for this WebView. See {@link #savePicture} and {@link
1999 * #restorePicture} for saving and restoring the display data.
2000 * @param inState The incoming Bundle of state.
2001 * @return The restored back/forward list or null if restoreState failed.
2002 * @see #savePicture
2003 * @see #restorePicture
2004 */
2005 public WebBackForwardList restoreState(Bundle inState) {
Steve Block51b08912011-04-27 15:04:48 +01002006 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 WebBackForwardList returnList = null;
2008 if (inState == null) {
2009 return returnList;
2010 }
2011 if (inState.containsKey("index") && inState.containsKey("history")) {
2012 mCertificate = SslCertificate.restoreState(
2013 inState.getBundle("certificate"));
2014
2015 final WebBackForwardList list = mCallbackProxy.getBackForwardList();
2016 final int index = inState.getInt("index");
2017 // We can't use a clone of the list because we need to modify the
2018 // shared copy, so synchronize instead to prevent concurrent
2019 // modifications.
2020 synchronized (list) {
2021 final List<byte[]> history =
2022 (List<byte[]>) inState.getSerializable("history");
2023 final int size = history.size();
2024 // Check the index bounds so we don't crash in native code while
2025 // restoring the history index.
2026 if (index < 0 || index >= size) {
2027 return null;
2028 }
2029 for (int i = 0; i < size; i++) {
2030 byte[] data = history.remove(0);
2031 if (data == null) {
2032 // If we somehow have null data, we cannot reconstruct
2033 // the item and thus our history list cannot be rebuilt.
2034 return null;
2035 }
2036 WebHistoryItem item = new WebHistoryItem(data);
2037 list.addHistoryItem(item);
2038 }
2039 // Grab the most recent copy to return to the caller.
2040 returnList = copyBackForwardList();
2041 // Update the copy to have the correct index.
2042 returnList.setCurrentIndex(index);
2043 }
Elliott Slaughterd6284792010-08-18 18:17:52 -07002044 // Restore private browsing setting.
2045 if (inState.getBoolean("privateBrowsingEnabled")) {
2046 getSettings().setPrivateBrowsingEnabled(true);
2047 }
Shimeng (Simon) Wang4ae1f6f2010-08-26 10:58:38 -07002048 mZoomManager.restoreZoomState(inState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 // Remove all pending messages because we are restoring previous
2050 // state.
2051 mWebViewCore.removeMessages();
2052 // Send a restore state message.
2053 mWebViewCore.sendMessage(EventHub.RESTORE_STATE, index);
2054 }
2055 return returnList;
2056 }
2057
2058 /**
Steve Blockf71dea02011-08-01 12:29:14 +01002059 * Load the given URL with the specified additional HTTP headers.
2060 * @param url The URL of the resource to load.
2061 * @param additionalHttpHeaders The additional headers to be used in the
2062 * HTTP request for this URL, specified as a map from name to
2063 * value. Note that if this map contains any of the headers
2064 * that are set by default by the WebView, such as those
2065 * controlling caching, accept types or the User-Agent, their
2066 * values may be overriden by the WebView's defaults.
Grace Klobad0d9bc22010-01-26 18:08:28 -08002067 */
Steve Blockf71dea02011-08-01 12:29:14 +01002068 public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
Steve Block51b08912011-04-27 15:04:48 +01002069 checkThread();
Steve Blockf71dea02011-08-01 12:29:14 +01002070 loadUrlImpl(url, additionalHttpHeaders);
Steve Block51b08912011-04-27 15:04:48 +01002071 }
2072
2073 private void loadUrlImpl(String url, Map<String, String> extraHeaders) {
Grace Klobad0d9bc22010-01-26 18:08:28 -08002074 switchOutDrawHistory();
2075 WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
2076 arg.mUrl = url;
2077 arg.mExtraHeaders = extraHeaders;
2078 mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04002079 clearHelpers();
Grace Klobad0d9bc22010-01-26 18:08:28 -08002080 }
2081
2082 /**
Steve Blockf71dea02011-08-01 12:29:14 +01002083 * Load the given URL.
2084 * @param url The URL of the resource to load.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002085 */
2086 public void loadUrl(String url) {
Steve Block51b08912011-04-27 15:04:48 +01002087 checkThread();
2088 loadUrlImpl(url);
2089 }
2090
2091 private void loadUrlImpl(String url) {
Patrick Scott4c3ca702009-07-15 15:41:05 -04002092 if (url == null) {
2093 return;
2094 }
Steve Block51b08912011-04-27 15:04:48 +01002095 loadUrlImpl(url, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 }
2097
2098 /**
Grace Kloba57534302009-05-22 18:55:02 -07002099 * Load the url with postData using "POST" method into the WebView. If url
2100 * is not a network url, it will be loaded with {link
2101 * {@link #loadUrl(String)} instead.
Cary Clarkd6982c92009-05-29 11:02:22 -04002102 *
Grace Kloba57534302009-05-22 18:55:02 -07002103 * @param url The url of the resource to load.
2104 * @param postData The data will be passed to "POST" request.
Grace Kloba57534302009-05-22 18:55:02 -07002105 */
2106 public void postUrl(String url, byte[] postData) {
Steve Block51b08912011-04-27 15:04:48 +01002107 checkThread();
Grace Kloba57534302009-05-22 18:55:02 -07002108 if (URLUtil.isNetworkUrl(url)) {
2109 switchOutDrawHistory();
Cary Clarkded054c2009-06-15 10:26:08 -04002110 WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
2111 arg.mUrl = url;
2112 arg.mPostData = postData;
Grace Kloba57534302009-05-22 18:55:02 -07002113 mWebViewCore.sendMessage(EventHub.POST_URL, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04002114 clearHelpers();
Grace Kloba57534302009-05-22 18:55:02 -07002115 } else {
Steve Block51b08912011-04-27 15:04:48 +01002116 loadUrlImpl(url);
Grace Kloba57534302009-05-22 18:55:02 -07002117 }
2118 }
2119
2120 /**
Steve Blockb28b22a2011-07-04 13:01:25 +01002121 * Load the given data into the WebView using a 'data' scheme URL.
2122 * <p>
2123 * Note that JavaScript's same origin policy means that script running in a
2124 * page loaded using this method will be unable to access content loaded
2125 * using any scheme other than 'data', including 'http(s)'. To avoid this
2126 * restriction, use {@link
2127 * #loadDataWithBaseURL(String,String,String,String,String)
2128 * loadDataWithBaseURL()} with an appropriate base URL.
Steve Blockf95d4902011-06-09 11:53:26 +01002129 * <p>
2130 * If the value of the encoding parameter is 'base64', then the data must
2131 * be encoded as base64. Otherwise, the data must use ASCII encoding for
2132 * octets inside the range of safe URL characters and use the standard %xx
John Reckcca606d2011-10-07 12:31:26 -07002133 * hex encoding of URLs for octets outside that range. For example,
2134 * '#', '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively.
Steve Blockb19c7872011-10-10 14:09:44 +01002135 * <p>
2136 * The 'data' scheme URL formed by this method uses the default US-ASCII
2137 * charset. If you need need to set a different charset, you should form a
Steve Block33f962b2011-10-11 14:49:47 +01002138 * 'data' scheme URL which explicitly specifies a charset parameter in the
2139 * mediatype portion of the URL and call {@link #loadUrl(String)} instead.
2140 * Note that the charset obtained from the mediatype portion of a data URL
2141 * always overrides that specified in the HTML or XML document itself.
Steve Blockf95d4902011-06-09 11:53:26 +01002142 * @param data A String of data in the given encoding.
Steve Block33f962b2011-10-11 14:49:47 +01002143 * @param mimeType The MIME type of the data, e.g. 'text/html'.
Steve Blockf95d4902011-06-09 11:53:26 +01002144 * @param encoding The encoding of the data.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 */
2146 public void loadData(String data, String mimeType, String encoding) {
Steve Block51b08912011-04-27 15:04:48 +01002147 checkThread();
2148 loadDataImpl(data, mimeType, encoding);
2149 }
2150
2151 private void loadDataImpl(String data, String mimeType, String encoding) {
Steve Blockf95d4902011-06-09 11:53:26 +01002152 StringBuilder dataUrl = new StringBuilder("data:");
2153 dataUrl.append(mimeType);
2154 if ("base64".equals(encoding)) {
2155 dataUrl.append(";base64");
2156 }
2157 dataUrl.append(",");
2158 dataUrl.append(data);
2159 loadUrlImpl(dataUrl.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161
2162 /**
Steve Blockb28b22a2011-07-04 13:01:25 +01002163 * Load the given data into the WebView, using baseUrl as the base URL for
2164 * the content. The base URL is used both to resolve relative URLs and when
2165 * applying JavaScript's same origin policy. The historyUrl is used for the
2166 * history entry.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 * <p>
Steve Blockae328572011-06-08 18:58:51 +01002168 * Note that content specified in this way can access local device files
2169 * (via 'file' scheme URLs) only if baseUrl specifies a scheme other than
2170 * 'http', 'https', 'ftp', 'ftps', 'about' or 'javascript'.
Steve Blocke482d892011-07-01 13:57:32 +01002171 * <p>
2172 * If the base URL uses the data scheme, this method is equivalent to
2173 * calling {@link #loadData(String,String,String) loadData()} and the
2174 * historyUrl is ignored.
Steve Blockb28b22a2011-07-04 13:01:25 +01002175 * @param baseUrl URL to use as the page's base URL. If null defaults to
Steve Blocke482d892011-07-01 13:57:32 +01002176 * 'about:blank'
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002177 * @param data A String of data in the given encoding.
Steve Blocke482d892011-07-01 13:57:32 +01002178 * @param mimeType The MIMEType of the data, e.g. 'text/html'. If null,
2179 * defaults to 'text/html'.
2180 * @param encoding The encoding of the data.
2181 * @param historyUrl URL to use as the history entry, if null defaults to
2182 * 'about:blank'.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 */
2184 public void loadDataWithBaseURL(String baseUrl, String data,
Leon Scroggins1bb1a912010-03-23 15:39:46 -04002185 String mimeType, String encoding, String historyUrl) {
Steve Block51b08912011-04-27 15:04:48 +01002186 checkThread();
Cary Clarkd6982c92009-05-29 11:02:22 -04002187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
Steve Block51b08912011-04-27 15:04:48 +01002189 loadDataImpl(data, mimeType, encoding);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 return;
2191 }
2192 switchOutDrawHistory();
Cary Clarkded054c2009-06-15 10:26:08 -04002193 WebViewCore.BaseUrlData arg = new WebViewCore.BaseUrlData();
2194 arg.mBaseUrl = baseUrl;
2195 arg.mData = data;
2196 arg.mMimeType = mimeType;
2197 arg.mEncoding = encoding;
Leon Scroggins1bb1a912010-03-23 15:39:46 -04002198 arg.mHistoryUrl = historyUrl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04002200 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002201 }
2202
2203 /**
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07002204 * Saves the current view as a web archive.
2205 *
2206 * @param filename The filename where the archive should be placed.
2207 */
2208 public void saveWebArchive(String filename) {
Steve Block51b08912011-04-27 15:04:48 +01002209 checkThread();
2210 saveWebArchiveImpl(filename, false, null);
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07002211 }
2212
2213 /* package */ static class SaveWebArchiveMessage {
2214 SaveWebArchiveMessage (String basename, boolean autoname, ValueCallback<String> callback) {
2215 mBasename = basename;
2216 mAutoname = autoname;
2217 mCallback = callback;
2218 }
2219
2220 /* package */ final String mBasename;
2221 /* package */ final boolean mAutoname;
2222 /* package */ final ValueCallback<String> mCallback;
2223 /* package */ String mResultFile;
2224 }
2225
2226 /**
2227 * Saves the current view as a web archive.
2228 *
2229 * @param basename The filename where the archive should be placed.
2230 * @param autoname If false, takes basename to be a file. If true, basename
2231 * is assumed to be a directory in which a filename will be
2232 * chosen according to the url of the current page.
2233 * @param callback Called after the web archive has been saved. The
2234 * parameter for onReceiveValue will either be the filename
2235 * under which the file was saved, or null if saving the
2236 * file failed.
2237 */
2238 public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
Steve Block51b08912011-04-27 15:04:48 +01002239 checkThread();
2240 saveWebArchiveImpl(basename, autoname, callback);
2241 }
2242
2243 private void saveWebArchiveImpl(String basename, boolean autoname,
2244 ValueCallback<String> callback) {
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07002245 mWebViewCore.sendMessage(EventHub.SAVE_WEBARCHIVE,
2246 new SaveWebArchiveMessage(basename, autoname, callback));
2247 }
2248
2249 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 * Stop the current load.
2251 */
2252 public void stopLoading() {
Steve Block51b08912011-04-27 15:04:48 +01002253 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 // TODO: should we clear all the messages in the queue before sending
2255 // STOP_LOADING?
2256 switchOutDrawHistory();
2257 mWebViewCore.sendMessage(EventHub.STOP_LOADING);
2258 }
2259
2260 /**
2261 * Reload the current url.
2262 */
2263 public void reload() {
Steve Block51b08912011-04-27 15:04:48 +01002264 checkThread();
Leon Scroggins05919f22010-09-14 17:22:36 -04002265 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 switchOutDrawHistory();
2267 mWebViewCore.sendMessage(EventHub.RELOAD);
2268 }
2269
2270 /**
2271 * Return true if this WebView has a back history item.
2272 * @return True iff this WebView has a back history item.
2273 */
2274 public boolean canGoBack() {
Steve Block51b08912011-04-27 15:04:48 +01002275 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2277 synchronized (l) {
2278 if (l.getClearPending()) {
2279 return false;
2280 } else {
2281 return l.getCurrentIndex() > 0;
2282 }
2283 }
2284 }
2285
2286 /**
2287 * Go back in the history of this WebView.
2288 */
2289 public void goBack() {
Steve Block51b08912011-04-27 15:04:48 +01002290 checkThread();
2291 goBackOrForwardImpl(-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292 }
2293
2294 /**
2295 * Return true if this WebView has a forward history item.
2296 * @return True iff this Webview has a forward history item.
2297 */
2298 public boolean canGoForward() {
Steve Block51b08912011-04-27 15:04:48 +01002299 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2301 synchronized (l) {
2302 if (l.getClearPending()) {
2303 return false;
2304 } else {
2305 return l.getCurrentIndex() < l.getSize() - 1;
2306 }
2307 }
2308 }
2309
2310 /**
2311 * Go forward in the history of this WebView.
2312 */
2313 public void goForward() {
Steve Block51b08912011-04-27 15:04:48 +01002314 checkThread();
2315 goBackOrForwardImpl(1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002316 }
2317
2318 /**
2319 * Return true if the page can go back or forward the given
2320 * number of steps.
2321 * @param steps The negative or positive number of steps to move the
2322 * history.
2323 */
2324 public boolean canGoBackOrForward(int steps) {
Steve Block51b08912011-04-27 15:04:48 +01002325 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2327 synchronized (l) {
2328 if (l.getClearPending()) {
2329 return false;
2330 } else {
2331 int newIndex = l.getCurrentIndex() + steps;
2332 return newIndex >= 0 && newIndex < l.getSize();
2333 }
2334 }
2335 }
2336
2337 /**
2338 * Go to the history item that is the number of steps away from
2339 * the current item. Steps is negative if backward and positive
2340 * if forward.
2341 * @param steps The number of steps to take back or forward in the back
2342 * forward list.
2343 */
2344 public void goBackOrForward(int steps) {
Steve Block51b08912011-04-27 15:04:48 +01002345 checkThread();
2346 goBackOrForwardImpl(steps);
2347 }
2348
2349 private void goBackOrForwardImpl(int steps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002350 goBackOrForward(steps, false);
2351 }
2352
2353 private void goBackOrForward(int steps, boolean ignoreSnapshot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 if (steps != 0) {
Leon Scroggins05919f22010-09-14 17:22:36 -04002355 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356 mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps,
2357 ignoreSnapshot ? 1 : 0);
2358 }
2359 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002360
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002361 /**
2362 * Returns true if private browsing is enabled in this WebView.
2363 */
Elliott Slaughter7c2d1352010-08-20 15:57:18 -07002364 public boolean isPrivateBrowsingEnabled() {
Steve Block51b08912011-04-27 15:04:48 +01002365 checkThread();
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002366 return getSettings().isPrivateBrowsingEnabled();
2367 }
2368
Elliott Slaughter7c2d1352010-08-20 15:57:18 -07002369 private void startPrivateBrowsing() {
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002370 getSettings().setPrivateBrowsingEnabled(true);
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002371 }
2372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002373 private boolean extendScroll(int y) {
2374 int finalY = mScroller.getFinalY();
2375 int newY = pinLocY(finalY + y);
2376 if (newY == finalY) return false;
2377 mScroller.setFinalY(newY);
2378 mScroller.extendDuration(computeDuration(0, y));
2379 return true;
2380 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002382 /**
2383 * Scroll the contents of the view up by half the view size
2384 * @param top true to jump to the top of the page
2385 * @return true if the page was scrolled
2386 */
2387 public boolean pageUp(boolean top) {
Steve Block51b08912011-04-27 15:04:48 +01002388 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002389 if (mNativeClass == 0) {
2390 return false;
2391 }
Cary Clarke872f3a2009-06-11 09:51:11 -04002392 nativeClearCursor(); // start next trackball movement from page edge
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002393 if (top) {
2394 // go to the top of the document
2395 return pinScrollTo(mScrollX, 0, true, 0);
2396 }
2397 // Page up
2398 int h = getHeight();
2399 int y;
2400 if (h > 2 * PAGE_SCROLL_OVERLAP) {
2401 y = -h + PAGE_SCROLL_OVERLAP;
2402 } else {
2403 y = -h / 2;
2404 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002405 return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002406 : extendScroll(y);
2407 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002409 /**
2410 * Scroll the contents of the view down by half the page size
2411 * @param bottom true to jump to bottom of page
2412 * @return true if the page was scrolled
2413 */
2414 public boolean pageDown(boolean bottom) {
Steve Block51b08912011-04-27 15:04:48 +01002415 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002416 if (mNativeClass == 0) {
2417 return false;
2418 }
Cary Clarke872f3a2009-06-11 09:51:11 -04002419 nativeClearCursor(); // start next trackball movement from page edge
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002420 if (bottom) {
Adam Powell637d3372010-08-25 14:37:03 -07002421 return pinScrollTo(mScrollX, computeRealVerticalScrollRange(), true, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002422 }
2423 // Page down.
2424 int h = getHeight();
2425 int y;
2426 if (h > 2 * PAGE_SCROLL_OVERLAP) {
2427 y = h - PAGE_SCROLL_OVERLAP;
2428 } else {
2429 y = h / 2;
2430 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002431 return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002432 : extendScroll(y);
2433 }
2434
2435 /**
2436 * Clear the view so that onDraw() will draw nothing but white background,
2437 * and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY
2438 */
2439 public void clearView() {
Steve Block51b08912011-04-27 15:04:48 +01002440 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002441 mContentWidth = 0;
2442 mContentHeight = 0;
Chris Craik5cf78f72011-07-28 11:34:31 -07002443 setBaseLayer(0, null, false, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002444 mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
2445 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002446
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002447 /**
2448 * Return a new picture that captures the current display of the webview.
2449 * This is a copy of the display, and will be unaffected if the webview
2450 * later loads a different URL.
2451 *
2452 * @return a picture containing the current contents of the view. Note this
2453 * picture is of the entire document, and is not restricted to the
2454 * bounds of the view.
2455 */
2456 public Picture capturePicture() {
Steve Block51b08912011-04-27 15:04:48 +01002457 checkThread();
Cary Clark5ffbb812010-10-08 15:38:39 -04002458 if (mNativeClass == 0) return null;
Grace Kloba8abd50b2010-07-08 15:02:14 -07002459 Picture result = new Picture();
2460 nativeCopyBaseContentToPicture(result);
2461 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002462 }
2463
2464 /**
2465 * Return true if the browser is displaying a TextView for text input.
2466 */
2467 private boolean inEditingMode() {
Leon Scroggins63284ed2010-04-09 14:54:46 -04002468 return mWebTextView != null && mWebTextView.getParent() != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002469 }
2470
Leon Scroggins6088e832010-02-17 13:17:32 -05002471 /**
2472 * Remove the WebTextView.
Leon Scroggins6088e832010-02-17 13:17:32 -05002473 */
Leon Scroggins2aed7762010-08-13 17:11:42 -04002474 private void clearTextEntry() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 if (inEditingMode()) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04002476 mWebTextView.remove();
Leon Scroggins III6f992702010-08-12 14:24:00 -04002477 } else {
2478 // The keyboard may be open with the WebView as the served view
2479 hideSoftKeyboard();
2480 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002481 }
2482
Cary Clarkd6982c92009-05-29 11:02:22 -04002483 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002484 * Return the current scale of the WebView
2485 * @return The current scale.
2486 */
2487 public float getScale() {
Steve Block51b08912011-04-27 15:04:48 +01002488 checkThread();
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002489 return mZoomManager.getScale();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002490 }
2491
John Reck1cfe8dd2011-09-27 20:14:39 -07002492 // Called by JNI. Returns the scale to apply to the text selection handles
2493 /* package */ float getTextHandleScale() {
2494 float density = mContext.getResources().getDisplayMetrics().density;
2495 return density / getScale();
2496 }
2497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498 /**
Mangesh Ghiware66b2ff82011-12-08 13:43:55 -08002499 * Compute the reading level scale of the WebView
2500 * @param scale The current scale.
Mangesh Ghiwareb5f9fc32011-08-31 17:49:07 -07002501 * @return The reading level scale.
2502 */
Mangesh Ghiware66b2ff82011-12-08 13:43:55 -08002503 /*package*/ float computeReadingLevelScale(float scale) {
2504 return mZoomManager.computeReadingLevelScale(scale);
Mangesh Ghiwareb5f9fc32011-08-31 17:49:07 -07002505 }
2506
2507 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002508 * Set the initial scale for the WebView. 0 means default. If
2509 * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
2510 * way. Otherwise it starts with 100%. If initial scale is greater than 0,
Mangesh Ghiwaree832b632011-11-16 11:46:39 -08002511 * WebView starts with this value as initial scale.
2512 * Please note that unlike the scale properties in the viewport meta tag,
2513 * this method doesn't take the screen density into account.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002514 *
2515 * @param scaleInPercent The initial scale in percent.
2516 */
2517 public void setInitialScale(int scaleInPercent) {
Steve Block51b08912011-04-27 15:04:48 +01002518 checkThread();
Derek Sollenberger341e22f2010-06-02 12:34:34 -04002519 mZoomManager.setInitialScaleInPercent(scaleInPercent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002520 }
2521
2522 /**
2523 * Invoke the graphical zoom picker widget for this WebView. This will
2524 * result in the zoom widget appearing on the screen to control the zoom
2525 * level of this WebView.
2526 */
2527 public void invokeZoomPicker() {
Steve Block51b08912011-04-27 15:04:48 +01002528 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 if (!getSettings().supportZoom()) {
2530 Log.w(LOGTAG, "This WebView doesn't support zoom.");
2531 return;
2532 }
Leon Scroggins05919f22010-09-14 17:22:36 -04002533 clearHelpers();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04002534 mZoomManager.invokeZoomPicker();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 }
2536
2537 /**
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04002538 * Return a HitTestResult based on the current cursor node. If a HTML::a tag
Steve Block81f19ff2010-11-01 13:23:24 +00002539 * is found and the anchor has a non-JavaScript url, the HitTestResult type
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 * is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
Steve Block81f19ff2010-11-01 13:23:24 +00002541 * anchor does not have a url or if it is a JavaScript url, the type will
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 * be UNKNOWN_TYPE and the url has to be retrieved through
2543 * {@link #requestFocusNodeHref} asynchronously. If a HTML::img tag is
2544 * found, the HitTestResult type is set to IMAGE_TYPE and the url is set in
2545 * the "extra" field. A type of
2546 * SRC_IMAGE_ANCHOR_TYPE indicates an anchor with a url that has an image as
2547 * a child node. If a phone number is found, the HitTestResult type is set
2548 * to PHONE_TYPE and the phone number is set in the "extra" field of
2549 * HitTestResult. If a map address is found, the HitTestResult type is set
2550 * to GEO_TYPE and the address is set in the "extra" field of HitTestResult.
2551 * If an email address is found, the HitTestResult type is set to EMAIL_TYPE
2552 * and the email is set in the "extra" field of HitTestResult. Otherwise,
2553 * HitTestResult type is set to UNKNOWN_TYPE.
2554 */
2555 public HitTestResult getHitTestResult() {
Steve Block51b08912011-04-27 15:04:48 +01002556 checkThread();
Cary Clarkb8491342010-11-29 16:23:19 -05002557 return hitTestResult(mInitialHitTestResult);
2558 }
2559
2560 private HitTestResult hitTestResult(HitTestResult fallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 if (mNativeClass == 0) {
2562 return null;
2563 }
2564
2565 HitTestResult result = new HitTestResult();
Cary Clarkd6982c92009-05-29 11:02:22 -04002566 if (nativeHasCursorNode()) {
2567 if (nativeCursorIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002568 result.setType(HitTestResult.EDIT_TEXT_TYPE);
Cary Clarkd6982c92009-05-29 11:02:22 -04002569 } else {
2570 String text = nativeCursorText();
2571 if (text != null) {
2572 if (text.startsWith(SCHEME_TEL)) {
2573 result.setType(HitTestResult.PHONE_TYPE);
2574 result.setExtra(text.substring(SCHEME_TEL.length()));
2575 } else if (text.startsWith(SCHEME_MAILTO)) {
2576 result.setType(HitTestResult.EMAIL_TYPE);
2577 result.setExtra(text.substring(SCHEME_MAILTO.length()));
2578 } else if (text.startsWith(SCHEME_GEO)) {
2579 result.setType(HitTestResult.GEO_TYPE);
2580 result.setExtra(URLDecoder.decode(text
2581 .substring(SCHEME_GEO.length())));
2582 } else if (nativeCursorIsAnchor()) {
2583 result.setType(HitTestResult.SRC_ANCHOR_TYPE);
2584 result.setExtra(text);
2585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 }
2587 }
Cary Clarkb8491342010-11-29 16:23:19 -05002588 } else if (fallback != null) {
2589 /* If webkit causes a rebuild while the long press is in progress,
2590 * the cursor node may be reset, even if it is still around. This
2591 * uses the cursor node saved when the touch began. Since the
2592 * nativeImageURI below only changes the result if it is successful,
2593 * this uses the data beneath the touch if available or the original
2594 * tap data otherwise.
2595 */
2596 Log.v(LOGTAG, "hitTestResult use fallback");
2597 result = fallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002598 }
2599 int type = result.getType();
2600 if (type == HitTestResult.UNKNOWN_TYPE
2601 || type == HitTestResult.SRC_ANCHOR_TYPE) {
2602 // Now check to see if it is an image.
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002603 int contentX = viewToContentX(mLastTouchX + mScrollX);
2604 int contentY = viewToContentY(mLastTouchY + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002605 String text = nativeImageURI(contentX, contentY);
2606 if (text != null) {
Cary Clarkd6982c92009-05-29 11:02:22 -04002607 result.setType(type == HitTestResult.UNKNOWN_TYPE ?
2608 HitTestResult.IMAGE_TYPE :
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
2610 result.setExtra(text);
2611 }
2612 }
2613 return result;
2614 }
2615
Leon Scrogginse26efa32009-12-15 16:38:45 -05002616 // Called by JNI when the DOM has changed the focus. Clear the focus so
2617 // that new keys will go to the newly focused field
2618 private void domChangedFocus() {
2619 if (inEditingMode()) {
2620 mPrivateHandler.obtainMessage(DOM_FOCUS_CHANGED).sendToTarget();
2621 }
2622 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 /**
Cary Clark861368a2010-12-15 11:24:37 -05002624 * Request the anchor or image element URL at the last tapped point.
2625 * If hrefMsg is null, this method returns immediately and does not
2626 * dispatch hrefMsg to its target. If the tapped point hits an image,
2627 * an anchor, or an image in an anchor, the message associates
2628 * strings in named keys in its data. The value paired with the key
2629 * may be an empty string.
Cary Clarkd6982c92009-05-29 11:02:22 -04002630 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002631 * @param hrefMsg This message will be dispatched with the result of the
Cary Clark861368a2010-12-15 11:24:37 -05002632 * request. The message data contains three keys:
2633 * - "url" returns the anchor's href attribute.
2634 * - "title" returns the anchor's text.
2635 * - "src" returns the image's src attribute.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002636 */
2637 public void requestFocusNodeHref(Message hrefMsg) {
Steve Block51b08912011-04-27 15:04:48 +01002638 checkThread();
Cary Clarke41bb532010-11-30 15:59:59 -05002639 if (hrefMsg == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002640 return;
2641 }
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002642 int contentX = viewToContentX(mLastTouchX + mScrollX);
2643 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clark3ecd7db2011-02-24 14:58:23 -05002644 if (nativeHasCursorNode()) {
2645 Rect cursorBounds = nativeGetCursorRingBounds();
2646 if (!cursorBounds.contains(contentX, contentY)) {
2647 int slop = viewToContentDimension(mNavSlop);
2648 cursorBounds.inset(-slop, -slop);
2649 if (cursorBounds.contains(contentX, contentY)) {
2650 contentX = (int) cursorBounds.centerX();
2651 contentY = (int) cursorBounds.centerY();
2652 }
2653 }
2654 }
Cary Clarke41bb532010-11-30 15:59:59 -05002655 mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
2656 contentX, contentY, hrefMsg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 /**
2660 * Request the url of the image last touched by the user. msg will be sent
2661 * to its target with a String representing the url as its object.
Cary Clarkd6982c92009-05-29 11:02:22 -04002662 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 * @param msg This message will be dispatched with the result of the request
2664 * as the data member with "url" as key. The result can be null.
2665 */
2666 public void requestImageRef(Message msg) {
Steve Block51b08912011-04-27 15:04:48 +01002667 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04002668 if (0 == mNativeClass) return; // client isn't initialized
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002669 int contentX = viewToContentX(mLastTouchX + mScrollX);
2670 int contentY = viewToContentY(mLastTouchY + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 String ref = nativeImageURI(contentX, contentY);
2672 Bundle data = msg.getData();
2673 data.putString("url", ref);
2674 msg.setData(data);
2675 msg.sendToTarget();
2676 }
2677
Derek Sollenberger87b17be52010-06-01 11:49:31 -04002678 static int pinLoc(int x, int viewMax, int docMax) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax);
2680 if (docMax < viewMax) { // the doc has room on the sides for "blank"
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002681 // pin the short document to the top/left of the screen
2682 x = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683// Log.d(LOGTAG, "--- center " + x);
2684 } else if (x < 0) {
2685 x = 0;
2686// Log.d(LOGTAG, "--- zero");
2687 } else if (x + viewMax > docMax) {
2688 x = docMax - viewMax;
2689// Log.d(LOGTAG, "--- pin " + x);
2690 }
2691 return x;
2692 }
2693
2694 // Expects x in view coordinates
Derek Sollenberger03e48912010-05-18 17:03:42 -04002695 int pinLocX(int x) {
Adam Powell637d3372010-08-25 14:37:03 -07002696 if (mInOverScrollMode) return x;
2697 return pinLoc(x, getViewWidth(), computeRealHorizontalScrollRange());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698 }
2699
2700 // Expects y in view coordinates
Derek Sollenberger03e48912010-05-18 17:03:42 -04002701 int pinLocY(int y) {
Adam Powell637d3372010-08-25 14:37:03 -07002702 if (mInOverScrollMode) return y;
Mike Reede5e63f42010-03-19 14:38:23 -04002703 return pinLoc(y, getViewHeightWithTitle(),
Adam Powell637d3372010-08-25 14:37:03 -07002704 computeRealVerticalScrollRange() + getTitleHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 }
2706
Leon Scroggins0236e672009-09-02 21:12:08 -04002707 /**
2708 * A title bar which is embedded in this WebView, and scrolls along with it
2709 * vertically, but not horizontally.
2710 */
2711 private View mTitleBar;
2712
2713 /**
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002714 * the title bar rendering gravity
2715 */
2716 private int mTitleGravity;
2717
2718 /**
Leon Scroggins0236e672009-09-02 21:12:08 -04002719 * Add or remove a title bar to be embedded into the WebView, and scroll
2720 * along with it vertically, while remaining in view horizontally. Pass
2721 * null to remove the title bar from the WebView, and return to drawing
2722 * the WebView normally without translating to account for the title bar.
2723 * @hide
2724 */
Leon Scroggins078c52c2009-09-04 16:58:09 -04002725 public void setEmbeddedTitleBar(View v) {
2726 if (mTitleBar == v) return;
2727 if (mTitleBar != null) {
Leon Scroggins0236e672009-09-02 21:12:08 -04002728 removeView(mTitleBar);
Leon Scroggins078c52c2009-09-04 16:58:09 -04002729 }
2730 if (null != v) {
Leon Scroggins0236e672009-09-02 21:12:08 -04002731 addView(v, new AbsoluteLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08002732 ViewGroup.LayoutParams.MATCH_PARENT,
Leon Scroggins078c52c2009-09-04 16:58:09 -04002733 ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0));
Leon Scroggins0236e672009-09-02 21:12:08 -04002734 }
2735 mTitleBar = v;
2736 }
2737
2738 /**
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002739 * Set where to render the embedded title bar
2740 * NO_GRAVITY at the top of the page
2741 * TOP at the top of the screen
2742 * @hide
2743 */
2744 public void setTitleBarGravity(int gravity) {
2745 mTitleGravity = gravity;
Michael Kolb63052ac2011-04-06 16:32:38 -07002746 // force refresh
2747 invalidate();
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002748 }
2749
2750 /**
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002751 * Given a distance in view space, convert it to content space. Note: this
2752 * does not reflect translation, just scaling, so this should not be called
2753 * with coordinates, but should be called for dimensions like width or
2754 * height.
2755 */
2756 private int viewToContentDimension(int d) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002757 return Math.round(d * mZoomManager.getInvScale());
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002758 }
2759
2760 /**
Leon Scroggins0236e672009-09-02 21:12:08 -04002761 * Given an x coordinate in view space, convert it to content space. Also
2762 * may be used for absolute heights (such as for the WebTextView's
2763 * textSize, which is unaffected by the height of the title bar).
2764 */
2765 /*package*/ int viewToContentX(int x) {
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002766 return viewToContentDimension(x);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 }
2768
Leon Scroggins0236e672009-09-02 21:12:08 -04002769 /**
2770 * Given a y coordinate in view space, convert it to content space.
2771 * Takes into account the height of the title bar if there is one
2772 * embedded into the WebView.
2773 */
2774 /*package*/ int viewToContentY(int y) {
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002775 return viewToContentDimension(y - getTitleHeight());
Mike Reede8853fc2009-09-04 14:01:48 -04002776 }
2777
2778 /**
Nicolas Roard46318cf2010-05-10 15:15:51 -07002779 * Given a x coordinate in view space, convert it to content space.
2780 * Returns the result as a float.
2781 */
2782 private float viewToContentXf(int x) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002783 return x * mZoomManager.getInvScale();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002784 }
2785
2786 /**
2787 * Given a y coordinate in view space, convert it to content space.
2788 * Takes into account the height of the title bar if there is one
2789 * embedded into the WebView. Returns the result as a float.
2790 */
2791 private float viewToContentYf(int y) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002792 return (y - getTitleHeight()) * mZoomManager.getInvScale();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002793 }
2794
2795 /**
Mike Reede8853fc2009-09-04 14:01:48 -04002796 * Given a distance in content space, convert it to view space. Note: this
2797 * does not reflect translation, just scaling, so this should not be called
2798 * with coordinates, but should be called for dimensions like width or
2799 * height.
2800 */
2801 /*package*/ int contentToViewDimension(int d) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002802 return Math.round(d * mZoomManager.getScale());
Leon Scroggins0236e672009-09-02 21:12:08 -04002803 }
2804
2805 /**
2806 * Given an x coordinate in content space, convert it to view
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002807 * space.
Leon Scroggins0236e672009-09-02 21:12:08 -04002808 */
2809 /*package*/ int contentToViewX(int x) {
Mike Reede8853fc2009-09-04 14:01:48 -04002810 return contentToViewDimension(x);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002811 }
2812
Leon Scroggins0236e672009-09-02 21:12:08 -04002813 /**
2814 * Given a y coordinate in content space, convert it to view
2815 * space. Takes into account the height of the title bar.
2816 */
2817 /*package*/ int contentToViewY(int y) {
Mike Reede8853fc2009-09-04 14:01:48 -04002818 return contentToViewDimension(y) + getTitleHeight();
Leon Scroggins0236e672009-09-02 21:12:08 -04002819 }
2820
Mike Reede9e86b82009-09-15 11:26:53 -04002821 private Rect contentToViewRect(Rect x) {
2822 return new Rect(contentToViewX(x.left), contentToViewY(x.top),
2823 contentToViewX(x.right), contentToViewY(x.bottom));
2824 }
2825
2826 /* To invalidate a rectangle in content coordinates, we need to transform
2827 the rect into view coordinates, so we can then call invalidate(...).
2828
2829 Normally, we would just call contentToView[XY](...), which eventually
2830 calls Math.round(coordinate * mActualScale). However, for invalidates,
2831 we need to account for the slop that occurs with antialiasing. To
2832 address that, we are a little more liberal in the size of the rect that
2833 we invalidate.
2834
2835 This liberal calculation calls floor() for the top/left, and ceil() for
2836 the bottom/right coordinates. This catches the possible extra pixels of
2837 antialiasing that we might have missed with just round().
2838 */
2839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 // Called by JNI to invalidate the View, given rectangle coordinates in
2841 // content space
2842 private void viewInvalidate(int l, int t, int r, int b) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002843 final float scale = mZoomManager.getScale();
Mike Reede9e86b82009-09-15 11:26:53 -04002844 final int dy = getTitleHeight();
2845 invalidate((int)Math.floor(l * scale),
2846 (int)Math.floor(t * scale) + dy,
2847 (int)Math.ceil(r * scale),
2848 (int)Math.ceil(b * scale) + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 }
2850
2851 // Called by JNI to invalidate the View after a delay, given rectangle
2852 // coordinates in content space
2853 private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002854 final float scale = mZoomManager.getScale();
Mike Reede9e86b82009-09-15 11:26:53 -04002855 final int dy = getTitleHeight();
2856 postInvalidateDelayed(delay,
2857 (int)Math.floor(l * scale),
2858 (int)Math.floor(t * scale) + dy,
2859 (int)Math.ceil(r * scale),
2860 (int)Math.ceil(b * scale) + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 }
2862
Mike Reede9e86b82009-09-15 11:26:53 -04002863 private void invalidateContentRect(Rect r) {
2864 viewInvalidate(r.left, r.top, r.right, r.bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002865 }
2866
Cary Clark278ce052009-08-31 16:08:42 -04002867 // stop the scroll animation, and don't let a subsequent fling add
2868 // to the existing velocity
2869 private void abortAnimation() {
2870 mScroller.abortAnimation();
2871 mLastVelocity = 0;
2872 }
2873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 /* call from webcoreview.draw(), so we're still executing in the UI thread
2875 */
2876 private void recordNewContentSize(int w, int h, boolean updateLayout) {
2877
2878 // premature data from webkit, ignore
2879 if ((w | h) == 0) {
2880 return;
2881 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883 // don't abort a scroll animation if we didn't change anything
2884 if (mContentWidth != w || mContentHeight != h) {
2885 // record new dimensions
2886 mContentWidth = w;
2887 mContentHeight = h;
2888 // If history Picture is drawn, don't update scroll. They will be
2889 // updated when we get out of that mode.
2890 if (!mDrawHistory) {
2891 // repin our scroll, taking into account the new content size
Derek Sollenberger03e48912010-05-18 17:03:42 -04002892 updateScrollCoordinates(pinLocX(mScrollX), pinLocY(mScrollY));
Leon Scrogginsd84e7d52009-09-29 11:11:45 -04002893 if (!mScroller.isFinished()) {
2894 // We are in the middle of a scroll. Repin the final scroll
2895 // position.
2896 mScroller.setFinalX(pinLocX(mScroller.getFinalX()));
2897 mScroller.setFinalY(pinLocY(mScroller.getFinalY()));
2898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002899 }
2900 }
2901 contentSizeChanged(updateLayout);
2902 }
2903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002904 // Used to avoid sending many visible rect messages.
John Reck9f9fac02011-11-10 17:33:24 -08002905 private Rect mLastVisibleRectSent = new Rect();
2906 private Rect mLastGlobalRect = new Rect();
John Reckaefc28a2011-11-07 17:42:06 -08002907 private Rect mVisibleRect = new Rect();
2908 private Rect mGlobalVisibleRect = new Rect();
2909 private Point mScrollOffset = new Point();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002910
Derek Sollenberger03e48912010-05-18 17:03:42 -04002911 Rect sendOurVisibleRect() {
Derek Sollenberger293c3602010-06-04 10:44:48 -04002912 if (mZoomManager.isPreventingWebkitUpdates()) return mLastVisibleRectSent;
John Reckaefc28a2011-11-07 17:42:06 -08002913 calcOurContentVisibleRect(mVisibleRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002914 // Rect.equals() checks for null input.
John Reckaefc28a2011-11-07 17:42:06 -08002915 if (!mVisibleRect.equals(mLastVisibleRectSent)) {
John Reck95b7d6f2011-06-03 15:23:43 -07002916 if (!mBlockWebkitViewMessages) {
John Reckaefc28a2011-11-07 17:42:06 -08002917 mScrollOffset.set(mVisibleRect.left, mVisibleRect.top);
John Reck95b7d6f2011-06-03 15:23:43 -07002918 mWebViewCore.removeMessages(EventHub.SET_SCROLL_OFFSET);
2919 mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
John Reckaefc28a2011-11-07 17:42:06 -08002920 nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, mScrollOffset);
John Reck95b7d6f2011-06-03 15:23:43 -07002921 }
John Reck9f9fac02011-11-10 17:33:24 -08002922 mLastVisibleRectSent.set(mVisibleRect);
Cary Clark32820242010-12-03 10:27:20 -05002923 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002924 }
John Reckaefc28a2011-11-07 17:42:06 -08002925 if (getGlobalVisibleRect(mGlobalVisibleRect)
2926 && !mGlobalVisibleRect.equals(mLastGlobalRect)) {
Cary Clark3524be92009-06-22 13:09:11 -04002927 if (DebugFlags.WEB_VIEW) {
John Reckaefc28a2011-11-07 17:42:06 -08002928 Log.v(LOGTAG, "sendOurVisibleRect=(" + mGlobalVisibleRect.left + ","
2929 + mGlobalVisibleRect.top + ",r=" + mGlobalVisibleRect.right + ",b="
2930 + mGlobalVisibleRect.bottom);
Cary Clark3524be92009-06-22 13:09:11 -04002931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002932 // TODO: the global offset is only used by windowRect()
2933 // in ChromeClientAndroid ; other clients such as touch
2934 // and mouse events could return view + screen relative points.
John Reck95b7d6f2011-06-03 15:23:43 -07002935 if (!mBlockWebkitViewMessages) {
John Reckaefc28a2011-11-07 17:42:06 -08002936 mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, mGlobalVisibleRect);
John Reck95b7d6f2011-06-03 15:23:43 -07002937 }
John Reck9f9fac02011-11-10 17:33:24 -08002938 mLastGlobalRect.set(mGlobalVisibleRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939 }
John Reckaefc28a2011-11-07 17:42:06 -08002940 return mVisibleRect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002941 }
2942
John Reckaefc28a2011-11-07 17:42:06 -08002943 private Point mGlobalVisibleOffset = new Point();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002944 // Sets r to be the visible rectangle of our webview in view coordinates
2945 private void calcOurVisibleRect(Rect r) {
John Reckaefc28a2011-11-07 17:42:06 -08002946 getGlobalVisibleRect(r, mGlobalVisibleOffset);
2947 r.offset(-mGlobalVisibleOffset.x, -mGlobalVisibleOffset.y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 }
2949
2950 // Sets r to be our visible rectangle in content coordinates
2951 private void calcOurContentVisibleRect(Rect r) {
2952 calcOurVisibleRect(r);
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002953 r.left = viewToContentX(r.left);
Leon Scroggins37df6a82009-09-23 10:31:23 -04002954 // viewToContentY will remove the total height of the title bar. Add
2955 // the visible height back in to account for the fact that if the title
2956 // bar is partially visible, the part of the visible rect which is
2957 // displaying our content is displaced by that amount.
Steve Block92c99162011-05-23 17:36:01 +01002958 r.top = viewToContentY(r.top + getVisibleTitleHeightImpl());
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002959 r.right = viewToContentX(r.right);
2960 r.bottom = viewToContentY(r.bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002961 }
2962
John Reckaefc28a2011-11-07 17:42:06 -08002963 private Rect mContentVisibleRect = new Rect();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002964 // Sets r to be our visible rectangle in content coordinates. We use this
2965 // method on the native side to compute the position of the fixed layers.
2966 // Uses floating coordinates (necessary to correctly place elements when
2967 // the scale factor is not 1)
2968 private void calcOurContentVisibleRectF(RectF r) {
John Reckaefc28a2011-11-07 17:42:06 -08002969 calcOurVisibleRect(mContentVisibleRect);
2970 r.left = viewToContentXf(mContentVisibleRect.left);
Nicolas Roard46318cf2010-05-10 15:15:51 -07002971 // viewToContentY will remove the total height of the title bar. Add
2972 // the visible height back in to account for the fact that if the title
2973 // bar is partially visible, the part of the visible rect which is
2974 // displaying our content is displaced by that amount.
John Reckaefc28a2011-11-07 17:42:06 -08002975 r.top = viewToContentYf(mContentVisibleRect.top + getVisibleTitleHeightImpl());
2976 r.right = viewToContentXf(mContentVisibleRect.right);
2977 r.bottom = viewToContentYf(mContentVisibleRect.bottom);
Nicolas Roard46318cf2010-05-10 15:15:51 -07002978 }
2979
Grace Klobaef347ef2009-07-30 11:20:32 -07002980 static class ViewSizeData {
2981 int mWidth;
2982 int mHeight;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08002983 float mHeightWidthRatio;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08002984 int mActualViewHeight;
Grace Klobaef347ef2009-07-30 11:20:32 -07002985 int mTextWrapWidth;
Grace Kloba3a0def22010-01-23 21:11:54 -08002986 int mAnchorX;
2987 int mAnchorY;
Grace Klobaef347ef2009-07-30 11:20:32 -07002988 float mScale;
Cary Clark6d45acc2009-08-27 15:42:57 -04002989 boolean mIgnoreHeight;
Grace Klobaef347ef2009-07-30 11:20:32 -07002990 }
2991
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002992 /**
2993 * Compute unzoomed width and height, and if they differ from the last
Derek Sollenberger03e48912010-05-18 17:03:42 -04002994 * values we sent, send them to webkit (to be used as new viewport)
2995 *
2996 * @param force ensures that the message is sent to webkit even if the width
2997 * or height has not changed since the last message
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 *
2999 * @return true if new values were sent
3000 */
Derek Sollenberger03e48912010-05-18 17:03:42 -04003001 boolean sendViewSizeZoom(boolean force) {
John Reck95b7d6f2011-06-03 15:23:43 -07003002 if (mBlockWebkitViewMessages) return false;
Derek Sollenberger293c3602010-06-04 10:44:48 -04003003 if (mZoomManager.isPreventingWebkitUpdates()) return false;
Grace Kloba3a0def22010-01-23 21:11:54 -08003004
Grace Klobaef347ef2009-07-30 11:20:32 -07003005 int viewWidth = getViewWidth();
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003006 int newWidth = Math.round(viewWidth * mZoomManager.getInvScale());
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003007 // This height could be fixed and be different from actual visible height.
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08003008 int viewHeight = getViewHeightWithTitle() - getTitleHeight();
3009 int newHeight = Math.round(viewHeight * mZoomManager.getInvScale());
3010 // Make the ratio more accurate than (newHeight / newWidth), since the
3011 // latter both are calculated and rounded.
3012 float heightWidthRatio = (float) viewHeight / viewWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003013 /*
3014 * Because the native side may have already done a layout before the
3015 * View system was able to measure us, we have to send a height of 0 to
3016 * remove excess whitespace when we grow our width. This will trigger a
3017 * layout and a change in content size. This content size change will
3018 * mean that contentSizeChanged will either call this method directly or
3019 * indirectly from onSizeChanged.
3020 */
3021 if (newWidth > mLastWidthSent && mWrapContent) {
3022 newHeight = 0;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08003023 heightWidthRatio = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024 }
Shimeng (Simon) Wang6a0b5ca2011-02-08 09:49:35 -08003025 // Actual visible content height.
3026 int actualViewHeight = Math.round(getViewHeight() * mZoomManager.getInvScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003027 // Avoid sending another message if the dimensions have not changed.
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003028 if (newWidth != mLastWidthSent || newHeight != mLastHeightSent || force ||
3029 actualViewHeight != mLastActualHeightSent) {
Grace Klobaef347ef2009-07-30 11:20:32 -07003030 ViewSizeData data = new ViewSizeData();
3031 data.mWidth = newWidth;
3032 data.mHeight = newHeight;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08003033 data.mHeightWidthRatio = heightWidthRatio;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003034 data.mActualViewHeight = actualViewHeight;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003035 data.mTextWrapWidth = Math.round(viewWidth / mZoomManager.getTextWrapScale());
3036 data.mScale = mZoomManager.getScale();
Derek Sollenberger293c3602010-06-04 10:44:48 -04003037 data.mIgnoreHeight = mZoomManager.isFixedLengthAnimationInProgress()
3038 && !mHeightCanMeasure;
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04003039 data.mAnchorX = mZoomManager.getDocumentAnchorX();
3040 data.mAnchorY = mZoomManager.getDocumentAnchorY();
Grace Klobaef347ef2009-07-30 11:20:32 -07003041 mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003042 mLastWidthSent = newWidth;
3043 mLastHeightSent = newHeight;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003044 mLastActualHeightSent = actualViewHeight;
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04003045 mZoomManager.clearDocumentAnchor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003046 return true;
3047 }
3048 return false;
3049 }
3050
Mangesh Ghiwareedb528e2011-10-12 14:25:41 -07003051 /**
3052 * Update the double-tap zoom.
3053 */
Mangesh Ghiwarebb99e282011-10-21 10:53:29 -07003054 /* package */ void updateDoubleTapZoom(int doubleTapZoom) {
3055 mZoomManager.updateDoubleTapZoom(doubleTapZoom);
Mangesh Ghiwareedb528e2011-10-12 14:25:41 -07003056 }
3057
Adam Powell637d3372010-08-25 14:37:03 -07003058 private int computeRealHorizontalScrollRange() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 if (mDrawHistory) {
3060 return mHistoryWidth;
3061 } else {
Grace Klobae621d6f2009-09-11 13:20:39 -07003062 // to avoid rounding error caused unnecessary scrollbar, use floor
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003063 return (int) Math.floor(mContentWidth * mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003064 }
3065 }
3066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067 @Override
Adam Powell637d3372010-08-25 14:37:03 -07003068 protected int computeHorizontalScrollRange() {
3069 int range = computeRealHorizontalScrollRange();
3070
3071 // Adjust reported range if overscrolled to compress the scroll bars
3072 final int scrollX = mScrollX;
3073 final int overscrollRight = computeMaxScrollX();
3074 if (scrollX < 0) {
3075 range -= scrollX;
3076 } else if (scrollX > overscrollRight) {
3077 range += scrollX - overscrollRight;
3078 }
3079
3080 return range;
3081 }
3082
3083 @Override
3084 protected int computeHorizontalScrollOffset() {
3085 return Math.max(mScrollX, 0);
3086 }
3087
3088 private int computeRealVerticalScrollRange() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003089 if (mDrawHistory) {
3090 return mHistoryHeight;
3091 } else {
Grace Klobae621d6f2009-09-11 13:20:39 -07003092 // to avoid rounding error caused unnecessary scrollbar, use floor
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003093 return (int) Math.floor(mContentHeight * mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003094 }
3095 }
3096
Leon Scroggins0236e672009-09-02 21:12:08 -04003097 @Override
Adam Powell637d3372010-08-25 14:37:03 -07003098 protected int computeVerticalScrollRange() {
3099 int range = computeRealVerticalScrollRange();
3100
3101 // Adjust reported range if overscrolled to compress the scroll bars
3102 final int scrollY = mScrollY;
3103 final int overscrollBottom = computeMaxScrollY();
3104 if (scrollY < 0) {
3105 range -= scrollY;
3106 } else if (scrollY > overscrollBottom) {
3107 range += scrollY - overscrollBottom;
3108 }
3109
3110 return range;
3111 }
3112
3113 @Override
Leon Scroggins0236e672009-09-02 21:12:08 -04003114 protected int computeVerticalScrollOffset() {
Mike Reede8853fc2009-09-04 14:01:48 -04003115 return Math.max(mScrollY - getTitleHeight(), 0);
Leon Scroggins0236e672009-09-02 21:12:08 -04003116 }
3117
3118 @Override
3119 protected int computeVerticalScrollExtent() {
3120 return getViewHeight();
3121 }
3122
Mike Reede8853fc2009-09-04 14:01:48 -04003123 /** @hide */
3124 @Override
3125 protected void onDrawVerticalScrollBar(Canvas canvas,
3126 Drawable scrollBar,
3127 int l, int t, int r, int b) {
Adam Powell637d3372010-08-25 14:37:03 -07003128 if (mScrollY < 0) {
3129 t -= mScrollY;
3130 }
Steve Block92c99162011-05-23 17:36:01 +01003131 scrollBar.setBounds(l, t + getVisibleTitleHeightImpl(), r, b);
Mike Reede8853fc2009-09-04 14:01:48 -04003132 scrollBar.draw(canvas);
3133 }
3134
Adam Powell637d3372010-08-25 14:37:03 -07003135 @Override
3136 protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
3137 boolean clampedY) {
Patrick Scott62310912010-12-06 17:44:50 -05003138 // Special-case layer scrolling so that we do not trigger normal scroll
3139 // updating.
3140 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
John Reck83b9e1d2011-11-02 10:18:12 -07003141 scrollLayerTo(scrollX, scrollY);
Patrick Scott62310912010-12-06 17:44:50 -05003142 return;
3143 }
Adam Powell637d3372010-08-25 14:37:03 -07003144 mInOverScrollMode = false;
3145 int maxX = computeMaxScrollX();
3146 int maxY = computeMaxScrollY();
3147 if (maxX == 0) {
3148 // do not over scroll x if the page just fits the screen
3149 scrollX = pinLocX(scrollX);
3150 } else if (scrollX < 0 || scrollX > maxX) {
3151 mInOverScrollMode = true;
3152 }
3153 if (scrollY < 0 || scrollY > maxY) {
3154 mInOverScrollMode = true;
3155 }
3156
3157 int oldX = mScrollX;
3158 int oldY = mScrollY;
3159
3160 super.scrollTo(scrollX, scrollY);
3161
3162 if (mOverScrollGlow != null) {
3163 mOverScrollGlow.pullGlow(mScrollX, mScrollY, oldX, oldY, maxX, maxY);
3164 }
3165 }
3166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 /**
3168 * Get the url for the current page. This is not always the same as the url
3169 * passed to WebViewClient.onPageStarted because although the load for
3170 * that url has begun, the current page may not have changed.
3171 * @return The url for the current page.
3172 */
3173 public String getUrl() {
Steve Block51b08912011-04-27 15:04:48 +01003174 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003175 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3176 return h != null ? h.getUrl() : null;
3177 }
Cary Clarkd6982c92009-05-29 11:02:22 -04003178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04003180 * Get the original url for the current page. This is not always the same
3181 * as the url passed to WebViewClient.onPageStarted because although the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 * load for that url has begun, the current page may not have changed.
3183 * Also, there may have been redirects resulting in a different url to that
3184 * originally requested.
3185 * @return The url that was originally requested for the current page.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 */
3187 public String getOriginalUrl() {
Steve Block51b08912011-04-27 15:04:48 +01003188 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003189 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3190 return h != null ? h.getOriginalUrl() : null;
3191 }
3192
3193 /**
3194 * Get the title for the current page. This is the title of the current page
3195 * until WebViewClient.onReceivedTitle is called.
3196 * @return The title for the current page.
3197 */
3198 public String getTitle() {
Steve Block51b08912011-04-27 15:04:48 +01003199 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3201 return h != null ? h.getTitle() : null;
3202 }
3203
3204 /**
3205 * Get the favicon for the current page. This is the favicon of the current
3206 * page until WebViewClient.onReceivedIcon is called.
3207 * @return The favicon for the current page.
3208 */
3209 public Bitmap getFavicon() {
Steve Block51b08912011-04-27 15:04:48 +01003210 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3212 return h != null ? h.getFavicon() : null;
3213 }
3214
3215 /**
Ben Murdoch372dfc82010-07-01 15:56:01 +01003216 * Get the touch icon url for the apple-touch-icon <link> element, or
3217 * a URL on this site's server pointing to the standard location of a
3218 * touch icon.
Patrick Scott2ba12622009-08-04 13:20:05 -04003219 * @hide
3220 */
3221 public String getTouchIconUrl() {
3222 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3223 return h != null ? h.getTouchIconUrl() : null;
3224 }
3225
3226 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 * Get the progress for the current page.
3228 * @return The progress for the current page between 0 and 100.
3229 */
3230 public int getProgress() {
Steve Block51b08912011-04-27 15:04:48 +01003231 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 return mCallbackProxy.getProgress();
3233 }
Cary Clarkd6982c92009-05-29 11:02:22 -04003234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003235 /**
3236 * @return the height of the HTML content.
3237 */
3238 public int getContentHeight() {
Steve Block51b08912011-04-27 15:04:48 +01003239 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 return mContentHeight;
3241 }
3242
3243 /**
Leon Scrogginsea96d1e2009-09-23 13:41:01 -04003244 * @return the width of the HTML content.
3245 * @hide
3246 */
3247 public int getContentWidth() {
3248 return mContentWidth;
3249 }
3250
3251 /**
John Reck9b90d552011-06-14 15:19:17 -07003252 * @hide
3253 */
3254 public int getPageBackgroundColor() {
3255 return nativeGetBackgroundColor();
3256 }
3257
3258 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003259 * Pause all layout, parsing, and JavaScript timers for all webviews. This
Mike Reedd205d5b2009-05-27 11:02:29 -04003260 * is a global requests, not restricted to just this webview. This can be
3261 * useful if the application has been paused.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 */
3263 public void pauseTimers() {
Steve Block51b08912011-04-27 15:04:48 +01003264 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
3266 }
3267
3268 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003269 * Resume all layout, parsing, and JavaScript timers for all webviews.
Mike Reedd205d5b2009-05-27 11:02:29 -04003270 * This will resume dispatching all timers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271 */
3272 public void resumeTimers() {
Steve Block51b08912011-04-27 15:04:48 +01003273 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
3275 }
3276
3277 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003278 * Call this to pause any extra processing associated with this WebView and
3279 * its associated DOM, plugins, JavaScript etc. For example, if the WebView
3280 * is taken offscreen, this could be called to reduce unnecessary CPU or
3281 * network traffic. When the WebView is again "active", call onResume().
Mike Reedd205d5b2009-05-27 11:02:29 -04003282 *
Steve Block81f19ff2010-11-01 13:23:24 +00003283 * Note that this differs from pauseTimers(), which affects all WebViews.
Mike Reedd205d5b2009-05-27 11:02:29 -04003284 */
3285 public void onPause() {
Steve Block51b08912011-04-27 15:04:48 +01003286 checkThread();
Mike Reedd205d5b2009-05-27 11:02:29 -04003287 if (!mIsPaused) {
3288 mIsPaused = true;
3289 mWebViewCore.sendMessage(EventHub.ON_PAUSE);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08003290 // We want to pause the current playing video when switching out
3291 // from the current WebView/tab.
3292 if (mHTML5VideoViewProxy != null) {
3293 mHTML5VideoViewProxy.pauseAndDispatch();
3294 }
John Reck5f1c5492011-11-09 16:23:07 -08003295 if (mNativeClass != 0) {
3296 nativeSetPauseDrawing(mNativeClass, true);
3297 }
Ben Murdoch2ffc9ec2011-11-28 15:41:31 +00003298
3299 cancelSelectDialog();
John Reck5f1c5492011-11-09 16:23:07 -08003300 }
3301 }
3302
3303 @Override
3304 protected void onWindowVisibilityChanged(int visibility) {
3305 super.onWindowVisibilityChanged(visibility);
3306 updateDrawingState();
3307 }
3308
3309 void updateDrawingState() {
3310 if (mNativeClass == 0 || mIsPaused) return;
3311 if (getWindowVisibility() != VISIBLE) {
3312 nativeSetPauseDrawing(mNativeClass, true);
3313 } else if (getVisibility() != VISIBLE) {
3314 nativeSetPauseDrawing(mNativeClass, true);
3315 } else {
3316 nativeSetPauseDrawing(mNativeClass, false);
Mike Reedd205d5b2009-05-27 11:02:29 -04003317 }
3318 }
3319
3320 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003321 * Call this to resume a WebView after a previous call to onPause().
Mike Reedd205d5b2009-05-27 11:02:29 -04003322 */
3323 public void onResume() {
Steve Block51b08912011-04-27 15:04:48 +01003324 checkThread();
Mike Reedd205d5b2009-05-27 11:02:29 -04003325 if (mIsPaused) {
3326 mIsPaused = false;
3327 mWebViewCore.sendMessage(EventHub.ON_RESUME);
John Reck5f1c5492011-11-09 16:23:07 -08003328 if (mNativeClass != 0) {
3329 nativeSetPauseDrawing(mNativeClass, false);
3330 }
Mike Reedd205d5b2009-05-27 11:02:29 -04003331 }
3332 }
3333
3334 /**
3335 * Returns true if the view is paused, meaning onPause() was called. Calling
3336 * onResume() sets the paused state back to false.
3337 * @hide
3338 */
3339 public boolean isPaused() {
3340 return mIsPaused;
3341 }
3342
3343 /**
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003344 * Call this to inform the view that memory is low so that it can
3345 * free any available memory.
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003346 */
3347 public void freeMemory() {
Steve Block51b08912011-04-27 15:04:48 +01003348 checkThread();
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003349 mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
3350 }
3351
3352 /**
Mike Hearnadcd2ed2009-01-21 16:44:36 +01003353 * Clear the resource cache. Note that the cache is per-application, so
3354 * this will clear the cache for all WebViews used.
3355 *
3356 * @param includeDiskFiles If false, only the RAM cache is cleared.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003357 */
3358 public void clearCache(boolean includeDiskFiles) {
Steve Block51b08912011-04-27 15:04:48 +01003359 checkThread();
Mike Hearnadcd2ed2009-01-21 16:44:36 +01003360 // Note: this really needs to be a static method as it clears cache for all
3361 // WebView. But we need mWebViewCore to send message to WebCore thread, so
3362 // we can't make this static.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
3364 includeDiskFiles ? 1 : 0, 0);
3365 }
3366
3367 /**
3368 * Make sure that clearing the form data removes the adapter from the
3369 * currently focused textfield if there is one.
3370 */
3371 public void clearFormData() {
Steve Block51b08912011-04-27 15:04:48 +01003372 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003373 if (inEditingMode()) {
John Recka6070602011-10-05 18:26:57 -07003374 mWebTextView.setAdapterCustom(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 }
3376 }
3377
3378 /**
3379 * Tell the WebView to clear its internal back/forward list.
3380 */
3381 public void clearHistory() {
Steve Block51b08912011-04-27 15:04:48 +01003382 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003383 mCallbackProxy.getBackForwardList().setClearPending();
3384 mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
3385 }
3386
3387 /**
3388 * Clear the SSL preferences table stored in response to proceeding with SSL
3389 * certificate errors.
3390 */
3391 public void clearSslPreferences() {
Steve Block51b08912011-04-27 15:04:48 +01003392 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
3394 }
3395
3396 /**
3397 * Return the WebBackForwardList for this WebView. This contains the
3398 * back/forward list for use in querying each item in the history stack.
3399 * This is a copy of the private WebBackForwardList so it contains only a
3400 * snapshot of the current state. Multiple calls to this method may return
3401 * different objects. The object returned from this method will not be
3402 * updated to reflect any new state.
3403 */
3404 public WebBackForwardList copyBackForwardList() {
Steve Block51b08912011-04-27 15:04:48 +01003405 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 return mCallbackProxy.getBackForwardList().clone();
3407 }
3408
3409 /*
3410 * Highlight and scroll to the next occurance of String in findAll.
Cary Clarkd6982c92009-05-29 11:02:22 -04003411 * Wraps the page infinitely, and scrolls. Must be called after
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 * calling findAll.
3413 *
3414 * @param forward Direction to search.
3415 */
3416 public void findNext(boolean forward) {
Steve Block51b08912011-04-27 15:04:48 +01003417 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04003418 if (0 == mNativeClass) return; // client isn't initialized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003419 nativeFindNext(forward);
3420 }
3421
3422 /*
3423 * Find all instances of find on the page and highlight them.
3424 * @param find String to find.
3425 * @return int The number of occurances of the String "find"
3426 * that were found.
3427 */
3428 public int findAll(String find) {
Steve Block51b08912011-04-27 15:04:48 +01003429 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04003430 if (0 == mNativeClass) return 0; // client isn't initialized
Cary Clarkde023c12010-03-03 10:05:16 -05003431 int result = find != null ? nativeFindAll(find.toLowerCase(),
Leon Scroggins4f4a5672010-10-19 13:58:11 -04003432 find.toUpperCase(), find.equalsIgnoreCase(mLastFind)) : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 invalidate();
Leon Scroggins5de63892009-10-29 09:48:43 -04003434 mLastFind = find;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 return result;
3436 }
3437
Cary Clark3403eb32010-03-03 10:05:16 -05003438 /**
Leon Scroggins93553d72011-03-08 11:43:40 -05003439 * Start an ActionMode for finding text in this WebView. Only works if this
3440 * WebView is attached to the view system.
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003441 * @param text If non-null, will be the initial text to search for.
3442 * Otherwise, the last String searched for in this WebView will
3443 * be used to start.
Leon Scroggins571354f2011-01-04 10:12:41 -05003444 * @param showIme If true, show the IME, assuming the user will begin typing.
3445 * If false and text is non-null, perform a find all.
3446 * @return boolean True if the find dialog is shown, false otherwise.
Cary Clarkde023c12010-03-03 10:05:16 -05003447 */
Leon Scroggins571354f2011-01-04 10:12:41 -05003448 public boolean showFindDialog(String text, boolean showIme) {
Steve Block51b08912011-04-27 15:04:48 +01003449 checkThread();
Leon Scroggins19abf2d2011-01-10 14:50:04 -05003450 FindActionModeCallback callback = new FindActionModeCallback(mContext);
Leon Scroggins93553d72011-03-08 11:43:40 -05003451 if (getParent() == null || startActionMode(callback) == null) {
Leon Scroggins571354f2011-01-04 10:12:41 -05003452 // Could not start the action mode, so end Find on page
Leon Scroggins571354f2011-01-04 10:12:41 -05003453 return false;
3454 }
John Reckd6ac7272011-11-08 15:00:17 -08003455 mCachedOverlappingActionModeHeight = -1;
Leon Scroggins19abf2d2011-01-10 14:50:04 -05003456 mFindCallback = callback;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003457 setFindIsUp(true);
3458 mFindCallback.setWebView(this);
Leon Scroggins571354f2011-01-04 10:12:41 -05003459 if (showIme) {
3460 mFindCallback.showSoftInput();
3461 } else if (text != null) {
3462 mFindCallback.setText(text);
3463 mFindCallback.findAll();
3464 return true;
3465 }
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003466 if (text == null) {
3467 text = mLastFind;
3468 }
3469 if (text != null) {
3470 mFindCallback.setText(text);
3471 }
Leon Scroggins571354f2011-01-04 10:12:41 -05003472 return true;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003473 }
3474
3475 /**
3476 * Keep track of the find callback so that we can remove its titlebar if
3477 * necessary.
3478 */
3479 private FindActionModeCallback mFindCallback;
3480
3481 /**
3482 * Toggle whether the find dialog is showing, for both native and Java.
3483 */
3484 private void setFindIsUp(boolean isUp) {
Cary Clarkde023c12010-03-03 10:05:16 -05003485 mFindIsUp = isUp;
Cary Clarkde023c12010-03-03 10:05:16 -05003486 if (0 == mNativeClass) return; // client isn't initialized
3487 nativeSetFindIsUp(isUp);
3488 }
3489
Leon Scroggins III26723fc2010-04-19 13:21:42 -04003490 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003491 * Return the index of the currently highlighted match.
Leon Scroggins III26723fc2010-04-19 13:21:42 -04003492 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003493 int findIndex() {
Leon Scroggins6a367f52010-05-06 17:37:40 -04003494 if (0 == mNativeClass) return -1;
3495 return nativeFindIndex();
3496 }
3497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498 // Used to know whether the find dialog is open. Affects whether
3499 // or not we draw the highlights for matches.
3500 private boolean mFindIsUp;
Cary Clarkde023c12010-03-03 10:05:16 -05003501
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003502 // Keep track of the last string sent, so we can search again when find is
3503 // reopened.
Leon Scroggins5de63892009-10-29 09:48:43 -04003504 private String mLastFind;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04003507 * Return the first substring consisting of the address of a physical
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003508 * location. Currently, only addresses in the United States are detected,
3509 * and consist of:
3510 * - a house number
3511 * - a street name
3512 * - a street type (Road, Circle, etc), either spelled out or abbreviated
3513 * - a city name
3514 * - a state or territory, either spelled out or two-letter abbr.
3515 * - an optional 5 digit or 9 digit zip code.
3516 *
3517 * All names must be correctly capitalized, and the zip code, if present,
3518 * must be valid for the state. The street type must be a standard USPS
3519 * spelling or abbreviation. The state or territory must also be spelled
Cary Clarkd6982c92009-05-29 11:02:22 -04003520 * or abbreviated using USPS standards. The house number may not exceed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 * five digits.
3522 * @param addr The string to search for addresses.
3523 *
3524 * @return the address, or if no address is found, return null.
3525 */
3526 public static String findAddress(String addr) {
Steve Block51b08912011-04-27 15:04:48 +01003527 checkThread();
Cary Clark3e399de2009-06-17 10:00:57 -04003528 return findAddress(addr, false);
3529 }
3530
3531 /**
3532 * @hide
3533 * Return the first substring consisting of the address of a physical
3534 * location. Currently, only addresses in the United States are detected,
3535 * and consist of:
3536 * - a house number
3537 * - a street name
3538 * - a street type (Road, Circle, etc), either spelled out or abbreviated
3539 * - a city name
3540 * - a state or territory, either spelled out or two-letter abbr.
3541 * - an optional 5 digit or 9 digit zip code.
3542 *
3543 * Names are optionally capitalized, and the zip code, if present,
3544 * must be valid for the state. The street type must be a standard USPS
3545 * spelling or abbreviation. The state or territory must also be spelled
3546 * or abbreviated using USPS standards. The house number may not exceed
3547 * five digits.
3548 * @param addr The string to search for addresses.
3549 * @param caseInsensitive addr Set to true to make search ignore case.
3550 *
3551 * @return the address, or if no address is found, return null.
3552 */
3553 public static String findAddress(String addr, boolean caseInsensitive) {
3554 return WebViewCore.nativeFindAddress(addr, caseInsensitive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 }
3556
3557 /*
3558 * Clear the highlighting surrounding text matches created by findAll.
3559 */
3560 public void clearMatches() {
Steve Block51b08912011-04-27 15:04:48 +01003561 checkThread();
Cary Clark32847a92009-11-17 16:04:18 -05003562 if (mNativeClass == 0)
3563 return;
Cary Clarkde023c12010-03-03 10:05:16 -05003564 nativeSetFindIsEmpty();
3565 invalidate();
3566 }
3567
3568 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003569 * Called when the find ActionMode ends.
Cary Clarkde023c12010-03-03 10:05:16 -05003570 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003571 void notifyFindDialogDismissed() {
3572 mFindCallback = null;
John Reckd6ac7272011-11-08 15:00:17 -08003573 mCachedOverlappingActionModeHeight = -1;
Shimeng (Simon) Wang4d8ef422010-03-22 17:06:17 -07003574 if (mWebViewCore == null) {
3575 return;
3576 }
Cary Clarkde023c12010-03-03 10:05:16 -05003577 clearMatches();
3578 setFindIsUp(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003579 // Now that the dialog has been removed, ensure that we scroll to a
3580 // location that is not beyond the end of the page.
3581 pinScrollTo(mScrollX, mScrollY, false, 0);
3582 invalidate();
3583 }
3584
3585 /**
3586 * Query the document to see if it contains any image references. The
3587 * message object will be dispatched with arg1 being set to 1 if images
3588 * were found and 0 if the document does not reference any images.
3589 * @param response The message that will be dispatched with the result.
3590 */
3591 public void documentHasImages(Message response) {
Steve Block51b08912011-04-27 15:04:48 +01003592 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593 if (response == null) {
3594 return;
3595 }
3596 mWebViewCore.sendMessage(EventHub.DOC_HAS_IMAGES, response);
3597 }
3598
Michael Kolb73980a92010-08-05 16:32:51 -07003599 /**
3600 * Request the scroller to abort any ongoing animation
3601 *
3602 * @hide
3603 */
3604 public void stopScroll() {
3605 mScroller.forceFinished(true);
3606 mLastVelocity = 0;
3607 }
3608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003609 @Override
3610 public void computeScroll() {
3611 if (mScroller.computeScrollOffset()) {
3612 int oldX = mScrollX;
3613 int oldY = mScrollY;
Adam Powell637d3372010-08-25 14:37:03 -07003614 int x = mScroller.getCurrX();
3615 int y = mScroller.getCurrY();
3616 invalidate(); // So we draw again
3617
3618 if (!mScroller.isFinished()) {
Patrick Scott62310912010-12-06 17:44:50 -05003619 int rangeX = computeMaxScrollX();
3620 int rangeY = computeMaxScrollY();
3621 int overflingDistance = mOverflingDistance;
3622
3623 // Use the layer's scroll data if needed.
3624 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
3625 oldX = mScrollingLayerRect.left;
3626 oldY = mScrollingLayerRect.top;
3627 rangeX = mScrollingLayerRect.right;
3628 rangeY = mScrollingLayerRect.bottom;
3629 // No overscrolling for layers.
3630 overflingDistance = 0;
3631 }
3632
Adam Powell637d3372010-08-25 14:37:03 -07003633 overScrollBy(x - oldX, y - oldY, oldX, oldY,
3634 rangeX, rangeY,
Patrick Scott62310912010-12-06 17:44:50 -05003635 overflingDistance, overflingDistance, false);
Adam Powell637d3372010-08-25 14:37:03 -07003636
3637 if (mOverScrollGlow != null) {
3638 mOverScrollGlow.absorbGlow(x, y, oldX, oldY, rangeX, rangeY);
3639 }
3640 } else {
Patrick Scott62310912010-12-06 17:44:50 -05003641 if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
3642 mScrollX = x;
3643 mScrollY = y;
3644 } else {
3645 // Update the layer position instead of WebView.
John Reck83b9e1d2011-11-02 10:18:12 -07003646 scrollLayerTo(x, y);
Patrick Scott62310912010-12-06 17:44:50 -05003647 }
Adam Powell4c3ce842010-11-23 17:39:56 -08003648 abortAnimation();
Chris Craik58d94af2011-08-18 11:42:13 -07003649 nativeSetIsScrolling(false);
John Reck95b7d6f2011-06-03 15:23:43 -07003650 if (!mBlockWebkitViewMessages) {
3651 WebViewCore.resumePriority();
3652 if (!mSelectingText) {
3653 WebViewCore.resumeUpdatePicture(mWebViewCore);
3654 }
Cary Clark0df02692010-11-24 11:01:37 -05003655 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05003656 if (oldX != mScrollX || oldY != mScrollY) {
3657 sendOurVisibleRect();
3658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 }
3660 } else {
3661 super.computeScroll();
3662 }
3663 }
3664
John Reck83b9e1d2011-11-02 10:18:12 -07003665 private void scrollLayerTo(int x, int y) {
3666 if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
3667 return;
3668 }
Michael Kolb5da91bd2011-11-29 15:29:03 -08003669 nativeScrollLayer(mCurrentScrollingLayerId, x, y);
John Reck83b9e1d2011-11-02 10:18:12 -07003670 mScrollingLayerRect.left = x;
3671 mScrollingLayerRect.top = y;
3672 onScrollChanged(mScrollX, mScrollY, mScrollX, mScrollY);
3673 invalidate();
3674 }
3675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003676 private static int computeDuration(int dx, int dy) {
3677 int distance = Math.max(Math.abs(dx), Math.abs(dy));
3678 int duration = distance * 1000 / STD_SPEED;
3679 return Math.min(duration, MAX_DURATION);
3680 }
3681
3682 // helper to pin the scrollBy parameters (already in view coordinates)
3683 // returns true if the scroll was changed
3684 private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) {
3685 return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
3686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003687 // helper to pin the scrollTo parameters (already in view coordinates)
3688 // returns true if the scroll was changed
3689 private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) {
3690 x = pinLocX(x);
3691 y = pinLocY(y);
3692 int dx = x - mScrollX;
3693 int dy = y - mScrollY;
3694
3695 if ((dx | dy) == 0) {
3696 return false;
3697 }
Cary Clark21a97ef2010-11-16 09:59:40 -05003698 abortAnimation();
Leon Scrogginsd55de402009-09-17 14:19:49 -04003699 if (animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003700 // Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003701 mScroller.startScroll(mScrollX, mScrollY, dx, dy,
3702 animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
Mike Cleronf116bf82009-09-27 19:14:12 -07003703 awakenScrollBars(mScroller.getDuration());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003704 invalidate();
3705 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 scrollTo(x, y);
3707 }
3708 return true;
3709 }
3710
3711 // Scale from content to view coordinates, and pin.
3712 // Also called by jni webview.cpp
Leon Scroggins4c943042009-07-31 15:05:42 -04003713 private boolean setContentScrollBy(int cx, int cy, boolean animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003714 if (mDrawHistory) {
3715 // disallow WebView to change the scroll position as History Picture
3716 // is used in the view system.
3717 // TODO: as we switchOutDrawHistory when trackball or navigation
3718 // keys are hit, this should be safe. Right?
Leon Scroggins4c943042009-07-31 15:05:42 -04003719 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003720 }
Mike Reede8853fc2009-09-04 14:01:48 -04003721 cx = contentToViewDimension(cx);
3722 cy = contentToViewDimension(cy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 if (mHeightCanMeasure) {
3724 // move our visible rect according to scroll request
3725 if (cy != 0) {
3726 Rect tempRect = new Rect();
3727 calcOurVisibleRect(tempRect);
3728 tempRect.offset(cx, cy);
3729 requestRectangleOnScreen(tempRect);
3730 }
3731 // FIXME: We scroll horizontally no matter what because currently
3732 // ScrollView and ListView will not scroll horizontally.
3733 // FIXME: Why do we only scroll horizontally if there is no
3734 // vertical scroll?
3735// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
Leon Scroggins4c943042009-07-31 15:05:42 -04003736 return cy == 0 && cx != 0 && pinScrollBy(cx, 0, animate, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 } else {
Leon Scroggins4c943042009-07-31 15:05:42 -04003738 return pinScrollBy(cx, cy, animate, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 }
3740 }
3741
Leon Scroggins405d7852009-11-02 14:50:54 -08003742 /**
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003743 * Called by CallbackProxy when the page starts loading.
3744 * @param url The URL of the page which has started loading.
3745 */
3746 /* package */ void onPageStarted(String url) {
3747 // every time we start a new page, we want to reset the
3748 // WebView certificate: if the new site is secure, we
3749 // will reload it and get a new certificate set;
3750 // if the new site is not secure, the certificate must be
3751 // null, and that will be the case
3752 setCertificate(null);
3753
3754 // reset the flag since we set to true in if need after
3755 // loading is see onPageFinished(Url)
3756 mAccessibilityScriptInjected = false;
3757 }
3758
3759 /**
Leon Scroggins405d7852009-11-02 14:50:54 -08003760 * Called by CallbackProxy when the page finishes loading.
3761 * @param url The URL of the page which has finished loading.
3762 */
3763 /* package */ void onPageFinished(String url) {
3764 if (mPageThatNeedsToSlideTitleBarOffScreen != null) {
3765 // If the user is now on a different page, or has scrolled the page
3766 // past the point where the title bar is offscreen, ignore the
3767 // scroll request.
3768 if (mPageThatNeedsToSlideTitleBarOffScreen.equals(url)
3769 && mScrollX == 0 && mScrollY == 0) {
3770 pinScrollTo(0, mYDistanceToSlideTitleOffScreen, true,
3771 SLIDE_TITLE_DURATION);
3772 }
3773 mPageThatNeedsToSlideTitleBarOffScreen = null;
3774 }
Shimeng (Simon) Wangd75fd492011-02-16 14:52:13 -08003775 mZoomManager.onPageFinished(url);
Svetoslav Ganovda355512010-05-12 22:04:44 -07003776 injectAccessibilityForUrl(url);
3777 }
3778
3779 /**
3780 * This method injects accessibility in the loaded document if accessibility
3781 * is enabled. If JavaScript is enabled we try to inject a URL specific script.
3782 * If no URL specific script is found or JavaScript is disabled we fallback to
3783 * the default {@link AccessibilityInjector} implementation.
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003784 * </p>
3785 * If the URL has the "axs" paramter set to 1 it has already done the
3786 * script injection so we do nothing. If the parameter is set to 0
3787 * the URL opts out accessibility script injection so we fall back to
3788 * the default {@link AccessibilityInjector}.
3789 * </p>
3790 * Note: If the user has not opted-in the accessibility script injection no scripts
3791 * are injected rather the default {@link AccessibilityInjector} implementation
3792 * is used.
Svetoslav Ganovda355512010-05-12 22:04:44 -07003793 *
3794 * @param url The URL loaded by this {@link WebView}.
3795 */
3796 private void injectAccessibilityForUrl(String url) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08003797 if (mWebViewCore == null) {
3798 return;
3799 }
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003800 AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
3801
3802 if (!accessibilityManager.isEnabled()) {
Svetoslav Ganovda355512010-05-12 22:04:44 -07003803 // it is possible that accessibility was turned off between reloads
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003804 ensureAccessibilityScriptInjectorInstance(false);
3805 return;
3806 }
3807
3808 if (!getSettings().getJavaScriptEnabled()) {
3809 // no JS so we fallback to the basic buil-in support
3810 ensureAccessibilityScriptInjectorInstance(true);
3811 return;
3812 }
3813
3814 // check the URL "axs" parameter to choose appropriate action
3815 int axsParameterValue = getAxsUrlParameterValue(url);
3816 if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED) {
3817 boolean onDeviceScriptInjectionEnabled = (Settings.Secure.getInt(mContext
3818 .getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
3819 if (onDeviceScriptInjectionEnabled) {
3820 ensureAccessibilityScriptInjectorInstance(false);
3821 // neither script injected nor script injection opted out => we inject
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -08003822 loadUrl(getScreenReaderInjectingJs());
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003823 // TODO: Set this flag after successfull script injection. Maybe upon injection
3824 // the chooser should update the meta tag and we check it to declare success
3825 mAccessibilityScriptInjected = true;
3826 } else {
3827 // injection disabled so we fallback to the basic built-in support
3828 ensureAccessibilityScriptInjectorInstance(true);
3829 }
3830 } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) {
3831 // injection opted out so we fallback to the basic buil-in support
3832 ensureAccessibilityScriptInjectorInstance(true);
3833 } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
3834 ensureAccessibilityScriptInjectorInstance(false);
3835 // the URL provides accessibility but we still need to add our generic script
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -08003836 loadUrl(getScreenReaderInjectingJs());
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003837 } else {
3838 Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
3839 }
3840 }
3841
3842 /**
3843 * Ensures the instance of the {@link AccessibilityInjector} to be present ot not.
3844 *
3845 * @param present True to ensure an insance, false to ensure no instance.
3846 */
3847 private void ensureAccessibilityScriptInjectorInstance(boolean present) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08003848 if (present) {
3849 if (mAccessibilityInjector == null) {
3850 mAccessibilityInjector = new AccessibilityInjector(this);
3851 }
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003852 } else {
Svetoslav Ganovda355512010-05-12 22:04:44 -07003853 mAccessibilityInjector = null;
3854 }
Leon Scroggins405d7852009-11-02 14:50:54 -08003855 }
3856
3857 /**
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -08003858 * Gets JavaScript that injects a screen-reader.
3859 *
3860 * @return The JavaScript snippet.
3861 */
3862 private String getScreenReaderInjectingJs() {
3863 String screenReaderUrl = Settings.Secure.getString(mContext.getContentResolver(),
3864 Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
3865 return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
3866 }
3867
3868 /**
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003869 * Gets the "axs" URL parameter value.
3870 *
3871 * @param url A url to fetch the paramter from.
3872 * @return The parameter value if such, -1 otherwise.
3873 */
3874 private int getAxsUrlParameterValue(String url) {
3875 if (mMatchAxsUrlParameterPattern == null) {
3876 mMatchAxsUrlParameterPattern = Pattern.compile(PATTERN_MATCH_AXS_URL_PARAMETER);
3877 }
3878 Matcher matcher = mMatchAxsUrlParameterPattern.matcher(url);
3879 if (matcher.find()) {
3880 String keyValuePair = url.substring(matcher.start(), matcher.end());
3881 return Integer.parseInt(keyValuePair.split("=")[1]);
3882 }
3883 return -1;
3884 }
3885
3886 /**
Leon Scroggins405d7852009-11-02 14:50:54 -08003887 * The URL of a page that sent a message to scroll the title bar off screen.
3888 *
3889 * Many mobile sites tell the page to scroll to (0,1) in order to scroll the
3890 * title bar off the screen. Sometimes, the scroll position is set before
3891 * the page finishes loading. Rather than scrolling while the page is still
3892 * loading, keep track of the URL and new scroll position so we can perform
3893 * the scroll once the page finishes loading.
3894 */
3895 private String mPageThatNeedsToSlideTitleBarOffScreen;
3896
3897 /**
3898 * The destination Y scroll position to be used when the page finishes
3899 * loading. See mPageThatNeedsToSlideTitleBarOffScreen.
3900 */
3901 private int mYDistanceToSlideTitleOffScreen;
3902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 // scale from content to view coordinates, and pin
Leon Scroggins83d4ba82009-09-17 17:27:13 -04003904 // return true if pin caused the final x/y different than the request cx/cy,
3905 // and a future scroll may reach the request cx/cy after our size has
3906 // changed
3907 // return false if the view scroll to the exact position as it is requested,
3908 // where negative numbers are taken to mean 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003909 private boolean setContentScrollTo(int cx, int cy) {
3910 if (mDrawHistory) {
3911 // disallow WebView to change the scroll position as History Picture
3912 // is used in the view system.
3913 // One known case where this is called is that WebCore tries to
3914 // restore the scroll position. As history Picture already uses the
3915 // saved scroll position, it is ok to skip this.
3916 return false;
3917 }
Leon Scrogginsd7b95aa2009-09-21 13:27:02 -04003918 int vx;
3919 int vy;
3920 if ((cx | cy) == 0) {
3921 // If the page is being scrolled to (0,0), do not add in the title
3922 // bar's height, and simply scroll to (0,0). (The only other work
3923 // in contentToView_ is to multiply, so this would not change 0.)
3924 vx = 0;
3925 vy = 0;
3926 } else {
3927 vx = contentToViewX(cx);
3928 vy = contentToViewY(cy);
3929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
3931// vx + " " + vy + "]");
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003932 // Some mobile sites attempt to scroll the title bar off the page by
Leon Scrogginsd7b95aa2009-09-21 13:27:02 -04003933 // scrolling to (0,1). If we are at the top left corner of the
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003934 // page, assume this is an attempt to scroll off the title bar, and
3935 // animate the title bar off screen slowly enough that the user can see
3936 // it.
Leon Scroggins405d7852009-11-02 14:50:54 -08003937 if (cx == 0 && cy == 1 && mScrollX == 0 && mScrollY == 0
3938 && mTitleBar != null) {
3939 // FIXME: 100 should be defined somewhere as our max progress.
3940 if (getProgress() < 100) {
3941 // Wait to scroll the title bar off screen until the page has
3942 // finished loading. Keep track of the URL and the destination
3943 // Y position
3944 mPageThatNeedsToSlideTitleBarOffScreen = getUrl();
3945 mYDistanceToSlideTitleOffScreen = vy;
3946 } else {
3947 pinScrollTo(vx, vy, true, SLIDE_TITLE_DURATION);
3948 }
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003949 // Since we are animating, we have not yet reached the desired
3950 // scroll position. Do not return true to request another attempt
3951 return false;
3952 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953 pinScrollTo(vx, vy, false, 0);
Leon Scroggins83d4ba82009-09-17 17:27:13 -04003954 // If the request was to scroll to a negative coordinate, treat it as if
3955 // it was a request to scroll to 0
3956 if ((mScrollX != vx && cx >= 0) || (mScrollY != vy && cy >= 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003957 return true;
3958 } else {
3959 return false;
3960 }
3961 }
3962
3963 // scale from content to view coordinates, and pin
3964 private void spawnContentScrollTo(int cx, int cy) {
3965 if (mDrawHistory) {
3966 // disallow WebView to change the scroll position as History Picture
3967 // is used in the view system.
3968 return;
3969 }
Leon Scroggins0236e672009-09-02 21:12:08 -04003970 int vx = contentToViewX(cx);
3971 int vy = contentToViewY(cy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003972 pinScrollTo(vx, vy, true, 0);
3973 }
3974
3975 /**
3976 * These are from webkit, and are in content coordinate system (unzoomed)
3977 */
3978 private void contentSizeChanged(boolean updateLayout) {
3979 // suppress 0,0 since we usually see real dimensions soon after
3980 // this avoids drawing the prev content in a funny place. If we find a
3981 // way to consolidate these notifications, this check may become
3982 // obsolete
3983 if ((mContentWidth | mContentHeight) == 0) {
3984 return;
3985 }
3986
3987 if (mHeightCanMeasure) {
Mike Reede8853fc2009-09-04 14:01:48 -04003988 if (getMeasuredHeight() != contentToViewDimension(mContentHeight)
Grace Kloba3f9faf42009-10-13 14:13:54 -07003989 || updateLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003990 requestLayout();
3991 }
3992 } else if (mWidthCanMeasure) {
Mike Reede8853fc2009-09-04 14:01:48 -04003993 if (getMeasuredWidth() != contentToViewDimension(mContentWidth)
Grace Kloba3f9faf42009-10-13 14:13:54 -07003994 || updateLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003995 requestLayout();
3996 }
3997 } else {
3998 // If we don't request a layout, try to send our view size to the
3999 // native side to ensure that WebCore has the correct dimensions.
Derek Sollenberger03e48912010-05-18 17:03:42 -04004000 sendViewSizeZoom(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004001 }
4002 }
4003
4004 /**
4005 * Set the WebViewClient that will receive various notifications and
4006 * requests. This will replace the current handler.
4007 * @param client An implementation of WebViewClient.
4008 */
4009 public void setWebViewClient(WebViewClient client) {
Steve Block51b08912011-04-27 15:04:48 +01004010 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 mCallbackProxy.setWebViewClient(client);
4012 }
4013
4014 /**
Grace Kloba94ab3b62009-10-07 18:00:19 -07004015 * Gets the WebViewClient
4016 * @return the current WebViewClient instance.
4017 *
4018 *@hide pending API council approval.
4019 */
4020 public WebViewClient getWebViewClient() {
4021 return mCallbackProxy.getWebViewClient();
4022 }
4023
4024 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004025 * Register the interface to be used when content can not be handled by
4026 * the rendering engine, and should be downloaded instead. This will replace
4027 * the current handler.
4028 * @param listener An implementation of DownloadListener.
4029 */
4030 public void setDownloadListener(DownloadListener listener) {
Steve Block51b08912011-04-27 15:04:48 +01004031 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004032 mCallbackProxy.setDownloadListener(listener);
4033 }
4034
4035 /**
4036 * Set the chrome handler. This is an implementation of WebChromeClient for
Steve Block81f19ff2010-11-01 13:23:24 +00004037 * use in handling JavaScript dialogs, favicons, titles, and the progress.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004038 * This will replace the current handler.
4039 * @param client An implementation of WebChromeClient.
4040 */
4041 public void setWebChromeClient(WebChromeClient client) {
Steve Block51b08912011-04-27 15:04:48 +01004042 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 mCallbackProxy.setWebChromeClient(client);
4044 }
4045
4046 /**
Andrei Popescu6fa29582009-06-19 14:54:09 +01004047 * Gets the chrome handler.
4048 * @return the current WebChromeClient instance.
4049 *
4050 * @hide API council approval.
4051 */
4052 public WebChromeClient getWebChromeClient() {
4053 return mCallbackProxy.getWebChromeClient();
4054 }
4055
4056 /**
Patrick Scott0b2e84b2010-03-02 08:58:44 -05004057 * Set the back/forward list client. This is an implementation of
4058 * WebBackForwardListClient for handling new items and changes in the
4059 * history index.
4060 * @param client An implementation of WebBackForwardListClient.
4061 * {@hide}
4062 */
4063 public void setWebBackForwardListClient(WebBackForwardListClient client) {
4064 mCallbackProxy.setWebBackForwardListClient(client);
4065 }
4066
4067 /**
4068 * Gets the WebBackForwardListClient.
4069 * {@hide}
4070 */
4071 public WebBackForwardListClient getWebBackForwardListClient() {
4072 return mCallbackProxy.getWebBackForwardListClient();
4073 }
4074
4075 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004076 * Set the Picture listener. This is an interface used to receive
4077 * notifications of a new Picture.
4078 * @param listener An implementation of WebView.PictureListener.
Kristian Monsenfc771652011-05-10 16:44:05 +01004079 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004080 */
Kristian Monsenfc771652011-05-10 16:44:05 +01004081 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004082 public void setPictureListener(PictureListener listener) {
Steve Block51b08912011-04-27 15:04:48 +01004083 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004084 mPictureListener = listener;
4085 }
4086
4087 /**
4088 * {@hide}
4089 */
4090 /* FIXME: Debug only! Remove for SDK! */
4091 public void externalRepresentation(Message callback) {
4092 mWebViewCore.sendMessage(EventHub.REQUEST_EXT_REPRESENTATION, callback);
4093 }
4094
4095 /**
4096 * {@hide}
4097 */
4098 /* FIXME: Debug only! Remove for SDK! */
4099 public void documentAsText(Message callback) {
4100 mWebViewCore.sendMessage(EventHub.REQUEST_DOC_AS_TEXT, callback);
4101 }
4102
4103 /**
Steve Block4cd73c52011-11-09 13:06:52 +00004104 * This method injects the supplied Java object into the WebView. The
4105 * object is injected into the JavaScript context of the main frame, using
4106 * the supplied name. This allows the Java object to be accessed from
4107 * JavaScript. Note that that injected objects will not appear in
4108 * JavaScript until the page is next (re)loaded. For example:
4109 * <pre> webView.addJavascriptInterface(new Object(), "injectedObject");
4110 * webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
4111 * webView.loadUrl("javascript:alert(injectedObject.toString())");</pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004112 * <p><strong>IMPORTANT:</strong>
4113 * <ul>
Steve Block4cd73c52011-11-09 13:06:52 +00004114 * <li> addJavascriptInterface() can be used to allow JavaScript to control
4115 * the host application. This is a powerful feature, but also presents a
4116 * security risk. Use of this method in a WebView containing untrusted
4117 * content could allow an attacker to manipulate the host application in
4118 * unintended ways, executing Java code with the permissions of the host
4119 * application. Use extreme care when using this method in a WebView which
4120 * could contain untrusted content.
4121 * <li> JavaScript interacts with Java object on a private, background
4122 * thread of the WebView. Care is therefore required to maintain thread
4123 * safety.</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004124 * </ul></p>
Steve Block4cd73c52011-11-09 13:06:52 +00004125 * @param object The Java object to inject into the WebView's JavaScript
4126 * context. Null values are ignored.
4127 * @param name The name used to expose the instance in JavaScript.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004128 */
Steve Block4cd73c52011-11-09 13:06:52 +00004129 public void addJavascriptInterface(Object object, String name) {
Steve Block51b08912011-04-27 15:04:48 +01004130 checkThread();
Steve Block4cd73c52011-11-09 13:06:52 +00004131 if (object == null) {
Steve Block544295e2010-12-02 18:40:06 +00004132 return;
4133 }
Cary Clarkded054c2009-06-15 10:26:08 -04004134 WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
Steve Block4cd73c52011-11-09 13:06:52 +00004135 arg.mObject = object;
4136 arg.mInterfaceName = name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004137 mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
4138 }
4139
4140 /**
Steve Block689a3422010-12-07 18:18:26 +00004141 * Removes a previously added JavaScript interface with the given name.
4142 * @param interfaceName The name of the interface to remove.
4143 */
4144 public void removeJavascriptInterface(String interfaceName) {
Steve Block51b08912011-04-27 15:04:48 +01004145 checkThread();
Svetoslav Ganovfa443142011-03-02 14:54:03 -08004146 if (mWebViewCore != null) {
4147 WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
4148 arg.mInterfaceName = interfaceName;
4149 mWebViewCore.sendMessage(EventHub.REMOVE_JS_INTERFACE, arg);
4150 }
Steve Block689a3422010-12-07 18:18:26 +00004151 }
4152
4153 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004154 * Return the WebSettings object used to control the settings for this
4155 * WebView.
4156 * @return A WebSettings object that can be used to control this WebView's
4157 * settings.
4158 */
4159 public WebSettings getSettings() {
Steve Block51b08912011-04-27 15:04:48 +01004160 checkThread();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04004161 return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162 }
4163
4164 /**
4165 * Return the list of currently loaded plugins.
4166 * @return The list of currently loaded plugins.
Andrei Popescu385df692009-08-13 11:59:57 +01004167 *
Kristian Monsenf0d97312011-01-12 19:15:35 +00004168 * @hide
Andrei Popescu385df692009-08-13 11:59:57 +01004169 * @deprecated This was used for Gears, which has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004170 */
Andrei Popescu385df692009-08-13 11:59:57 +01004171 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004172 public static synchronized PluginList getPluginList() {
Steve Block51b08912011-04-27 15:04:48 +01004173 checkThread();
Grace Klobabb245ea2009-11-10 13:13:24 -08004174 return new PluginList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004175 }
4176
4177 /**
Kristian Monsenf0d97312011-01-12 19:15:35 +00004178 * @hide
Andrei Popescu385df692009-08-13 11:59:57 +01004179 * @deprecated This was used for Gears, which has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004180 */
Andrei Popescu385df692009-08-13 11:59:57 +01004181 @Deprecated
Steve Block51b08912011-04-27 15:04:48 +01004182 public void refreshPlugins(boolean reloadOpenPages) {
4183 checkThread();
4184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004185
4186 //-------------------------------------------------------------------------
4187 // Override View methods
4188 //-------------------------------------------------------------------------
4189
4190 @Override
4191 protected void finalize() throws Throwable {
Cary Clark9a4c0632009-08-10 16:40:08 -04004192 try {
John Reckb9376462011-09-13 14:34:52 -07004193 if (mNativeClass != 0) {
John Reck5540abc2011-09-15 11:08:00 -07004194 mPrivateHandler.post(new Runnable() {
John Reckb9376462011-09-13 14:34:52 -07004195 @Override
4196 public void run() {
4197 destroy();
4198 }
4199 });
4200 }
Cary Clark9a4c0632009-08-10 16:40:08 -04004201 } finally {
4202 super.finalize();
4203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004204 }
Cary Clarkd6982c92009-05-29 11:02:22 -04004205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004206 @Override
Leon Scroggins0236e672009-09-02 21:12:08 -04004207 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
4208 if (child == mTitleBar) {
4209 // When drawing the title bar, move it horizontally to always show
Adam Powell9d32d242010-03-29 16:02:07 -07004210 // at the top of the WebView.
Leon Scroggins0236e672009-09-02 21:12:08 -04004211 mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft());
Michael Kolbc4ca53f2011-02-05 13:53:14 -08004212 int newTop = 0;
4213 if (mTitleGravity == Gravity.NO_GRAVITY) {
4214 newTop = Math.min(0, mScrollY);
4215 } else if (mTitleGravity == Gravity.TOP) {
4216 newTop = mScrollY;
4217 }
Michael Kolb75a03f92011-02-23 16:12:13 -08004218 mTitleBar.setBottom(newTop + mTitleBar.getHeight());
Mindy Pereira3331f2b2010-12-03 09:58:37 -08004219 mTitleBar.setTop(newTop);
Leon Scroggins0236e672009-09-02 21:12:08 -04004220 }
4221 return super.drawChild(canvas, child, drawingTime);
4222 }
4223
John Reck335f4542011-08-25 18:25:09 -07004224 private void drawContent(Canvas canvas, boolean drawRings) {
John Reck335f4542011-08-25 18:25:09 -07004225 drawCoreAndCursorRing(canvas, mBackgroundColor,
4226 mDrawCursorRing && drawRings);
Mike Reed19f3f0e2009-11-12 12:50:20 -05004227 }
4228
Adam Powell637d3372010-08-25 14:37:03 -07004229 /**
4230 * Draw the background when beyond bounds
4231 * @param canvas Canvas to draw into
4232 */
4233 private void drawOverScrollBackground(Canvas canvas) {
4234 if (mOverScrollBackground == null) {
4235 mOverScrollBackground = new Paint();
4236 Bitmap bm = BitmapFactory.decodeResource(
4237 mContext.getResources(),
4238 com.android.internal.R.drawable.status_bar_background);
4239 mOverScrollBackground.setShader(new BitmapShader(bm,
4240 Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
4241 mOverScrollBorder = new Paint();
4242 mOverScrollBorder.setStyle(Paint.Style.STROKE);
4243 mOverScrollBorder.setStrokeWidth(0);
4244 mOverScrollBorder.setColor(0xffbbbbbb);
4245 }
4246
4247 int top = 0;
4248 int right = computeRealHorizontalScrollRange();
4249 int bottom = top + computeRealVerticalScrollRange();
4250 // first draw the background and anchor to the top of the view
4251 canvas.save();
4252 canvas.translate(mScrollX, mScrollY);
4253 canvas.clipRect(-mScrollX, top - mScrollY, right - mScrollX, bottom
4254 - mScrollY, Region.Op.DIFFERENCE);
4255 canvas.drawPaint(mOverScrollBackground);
4256 canvas.restore();
4257 // then draw the border
4258 canvas.drawRect(-1, top - 1, right, bottom, mOverScrollBorder);
4259 // next clip the region for the content
4260 canvas.clipRect(0, top, right, bottom);
4261 }
4262
Mike Reed19f3f0e2009-11-12 12:50:20 -05004263 @Override
4264 protected void onDraw(Canvas canvas) {
George Mount5d3f6e62011-12-05 15:19:00 -08004265 if (inFullScreenMode()) {
4266 return; // no need to draw anything if we aren't visible.
4267 }
John Reck086a5142011-08-31 16:59:10 -07004268 // if mNativeClass is 0, the WebView is either destroyed or not
4269 // initialized. In either case, just draw the background color and return
Mike Reed19f3f0e2009-11-12 12:50:20 -05004270 if (mNativeClass == 0) {
John Reck086a5142011-08-31 16:59:10 -07004271 canvas.drawColor(mBackgroundColor);
Mike Reed19f3f0e2009-11-12 12:50:20 -05004272 return;
4273 }
4274
Grace Klobae47ac472010-03-11 14:53:07 -08004275 // if both mContentWidth and mContentHeight are 0, it means there is no
4276 // valid Picture passed to WebView yet. This can happen when WebView
4277 // just starts. Draw the background and return.
4278 if ((mContentWidth | mContentHeight) == 0 && mHistoryPicture == null) {
4279 canvas.drawColor(mBackgroundColor);
4280 return;
4281 }
4282
Ben Murdoch811ba6c2011-01-26 10:19:39 +00004283 if (canvas.isHardwareAccelerated()) {
Nicolas Roard2bc0b012011-11-16 19:26:25 -08004284 if (mIncrementEGLContextHack == false) {
4285 mIncrementEGLContextHack = true;
4286 EGL10 egl = (EGL10) EGLContext.getEGL();
4287 EGLDisplay eglDisplay = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
4288 int[] version = new int[2];
4289 egl.eglInitialize(eglDisplay, version);
4290 }
Ben Murdoch811ba6c2011-01-26 10:19:39 +00004291 mZoomManager.setHardwareAccelerated();
4292 }
4293
Mike Reed19f3f0e2009-11-12 12:50:20 -05004294 int saveCount = canvas.save();
Adam Powell637d3372010-08-25 14:37:03 -07004295 if (mInOverScrollMode && !getSettings()
4296 .getUseWebViewBackgroundForOverscrollBackground()) {
4297 drawOverScrollBackground(canvas);
4298 }
Mike Reed19f3f0e2009-11-12 12:50:20 -05004299 if (mTitleBar != null) {
Michael Kolb75a03f92011-02-23 16:12:13 -08004300 canvas.translate(0, getTitleHeight());
Mike Reed19f3f0e2009-11-12 12:50:20 -05004301 }
John Reck335f4542011-08-25 18:25:09 -07004302 boolean drawJavaRings = !mTouchHighlightRegion.isEmpty()
4303 && (mTouchMode == TOUCH_INIT_MODE
4304 || mTouchMode == TOUCH_SHORTPRESS_START_MODE
John Reck0ba72ad2011-08-29 10:19:02 -07004305 || mTouchMode == TOUCH_SHORTPRESS_MODE
4306 || mTouchMode == TOUCH_DONE_MODE);
John Reck335f4542011-08-25 18:25:09 -07004307 boolean drawNativeRings = !drawJavaRings;
4308 if (USE_WEBKIT_RINGS) {
4309 drawNativeRings = !drawJavaRings && !isInTouchMode();
4310 }
4311 drawContent(canvas, drawNativeRings);
Leon Scroggins0236e672009-09-02 21:12:08 -04004312 canvas.restoreToCount(saveCount);
Cary Clarkd6982c92009-05-29 11:02:22 -04004313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004314 if (AUTO_REDRAW_HACK && mAutoRedraw) {
4315 invalidate();
4316 }
Nicolas Roard38863332010-01-04 19:30:55 +00004317 mWebViewCore.signalRepaintDone();
Grace Kloba178db412010-05-18 22:22:23 -07004318
Adam Powell637d3372010-08-25 14:37:03 -07004319 if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas)) {
4320 invalidate();
4321 }
4322
Grace Kloba178db412010-05-18 22:22:23 -07004323 // paint the highlight in the end
John Reck335f4542011-08-25 18:25:09 -07004324 if (drawJavaRings) {
4325 long delay = System.currentTimeMillis() - mTouchHighlightRequested;
4326 if (delay < ViewConfiguration.getTapTimeout()) {
4327 Rect r = mTouchHighlightRegion.getBounds();
4328 postInvalidateDelayed(delay, r.left, r.top, r.right, r.bottom);
4329 } else {
4330 if (mTouchHightlightPaint == null) {
4331 mTouchHightlightPaint = new Paint();
John Reck086a5142011-08-31 16:59:10 -07004332 mTouchHightlightPaint.setColor(HIGHLIGHT_COLOR);
John Reck335f4542011-08-25 18:25:09 -07004333 }
4334 RegionIterator iter = new RegionIterator(mTouchHighlightRegion);
4335 Rect r = new Rect();
4336 while (iter.next(r)) {
4337 canvas.drawRect(r, mTouchHightlightPaint);
4338 }
Grace Kloba178db412010-05-18 22:22:23 -07004339 }
Grace Kloba178db412010-05-18 22:22:23 -07004340 }
4341 if (DEBUG_TOUCH_HIGHLIGHT) {
4342 if (getSettings().getNavDump()) {
4343 if ((mTouchHighlightX | mTouchHighlightY) != 0) {
4344 if (mTouchCrossHairColor == null) {
4345 mTouchCrossHairColor = new Paint();
4346 mTouchCrossHairColor.setColor(Color.RED);
4347 }
4348 canvas.drawLine(mTouchHighlightX - mNavSlop,
4349 mTouchHighlightY - mNavSlop, mTouchHighlightX
4350 + mNavSlop + 1, mTouchHighlightY + mNavSlop
4351 + 1, mTouchCrossHairColor);
4352 canvas.drawLine(mTouchHighlightX + mNavSlop + 1,
4353 mTouchHighlightY - mNavSlop, mTouchHighlightX
4354 - mNavSlop,
4355 mTouchHighlightY + mNavSlop + 1,
4356 mTouchCrossHairColor);
4357 }
4358 }
4359 }
4360 }
4361
John Reck335f4542011-08-25 18:25:09 -07004362 private void removeTouchHighlight() {
4363 mWebViewCore.removeMessages(EventHub.GET_TOUCH_HIGHLIGHT_RECTS);
4364 mPrivateHandler.removeMessages(SET_TOUCH_HIGHLIGHT_RECTS);
4365 setTouchHighlightRects(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004366 }
4367
4368 @Override
4369 public void setLayoutParams(ViewGroup.LayoutParams params) {
4370 if (params.height == LayoutParams.WRAP_CONTENT) {
4371 mWrapContent = true;
4372 }
4373 super.setLayoutParams(params);
4374 }
4375
4376 @Override
4377 public boolean performLongClick() {
Grace Kloba98e6fcf2010-01-27 15:20:30 -08004378 // performLongClick() is the result of a delayed message. If we switch
4379 // to windows overview, the WebView will be temporarily removed from the
4380 // view system. In that case, do nothing.
4381 if (getParent() == null) return false;
Adam Powellbe366682010-09-12 12:47:04 -07004382
4383 // A multi-finger gesture can look like a long press; make sure we don't take
4384 // long press actions if we're scaling.
4385 final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
4386 if (detector != null && detector.isInProgress()) {
4387 return false;
4388 }
Michael Kolbc4ca53f2011-02-05 13:53:14 -08004389
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004390 if (mNativeClass != 0 && nativeCursorIsTextInput()) {
4391 // Send the click so that the textfield is in focus
Leon Scroggins1d96ca02009-10-23 11:49:03 -04004392 centerKeyPressOnTextField();
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004393 rebuildWebTextView();
Leon Scroggins2c8e0512010-05-11 15:50:27 -04004394 } else {
Leon Scroggins2aed7762010-08-13 17:11:42 -04004395 clearTextEntry();
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004397 if (inEditingMode()) {
Leon Scrogginsfcf57762010-12-14 18:09:23 -05004398 // Since we just called rebuildWebTextView, the layout is not set
4399 // properly. Update it so it can correctly find the word to select.
4400 mWebTextView.ensureLayout();
4401 // Provide a touch down event to WebTextView, which will allow it
4402 // to store the location to use in performLongClick.
4403 AbsoluteLayout.LayoutParams params
4404 = (AbsoluteLayout.LayoutParams) mWebTextView.getLayoutParams();
4405 MotionEvent fake = MotionEvent.obtain(mLastTouchTime,
4406 mLastTouchTime, MotionEvent.ACTION_DOWN,
4407 mLastTouchX - params.x + mScrollX,
4408 mLastTouchY - params.y + mScrollY, 0);
4409 mWebTextView.dispatchTouchEvent(fake);
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004410 return mWebTextView.performLongClick();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004411 }
Cary Clark1e8e10d2010-11-17 13:49:25 -05004412 if (mSelectingText) return false; // long click does nothing on selection
Cary Clark924af702010-06-04 16:37:43 -04004413 /* if long click brings up a context menu, the super function
4414 * returns true and we're done. Otherwise, nothing happened when
4415 * the user clicked. */
4416 if (super.performLongClick()) {
4417 return true;
4418 }
4419 /* In the case where the application hasn't already handled the long
4420 * click action, look for a word under the click. If one is found,
4421 * animate the text selection into view.
4422 * FIXME: no animation code yet */
Adam Powellad804e32011-09-14 19:11:08 -07004423 final boolean isSelecting = selectText();
4424 if (isSelecting) {
4425 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
4426 }
4427 return isSelecting;
Cary Clarkfc8bf742010-11-22 11:02:29 -05004428 }
4429
4430 /**
4431 * Select the word at the last click point.
4432 *
4433 * @hide pending API council approval
4434 */
4435 public boolean selectText() {
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08004436 int x = viewToContentX(mLastTouchX + mScrollX);
4437 int y = viewToContentY(mLastTouchY + mScrollY);
Cary Clark2cdee232010-12-29 14:59:24 -05004438 return selectText(x, y);
4439 }
4440
4441 /**
4442 * Select the word at the indicated content coordinates.
4443 */
4444 boolean selectText(int x, int y) {
Cary Clark03f00222011-02-10 19:37:15 -05004445 if (!setUpSelect(true, x, y)) {
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05004446 return false;
4447 }
Cary Clark03f00222011-02-10 19:37:15 -05004448 nativeSetExtendSelection();
4449 mDrawSelectionPointer = false;
Cary Clark03f00222011-02-10 19:37:15 -05004450 mTouchMode = TOUCH_DRAG_MODE;
4451 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004452 }
4453
Cary Clarkc5cd5e92010-11-22 15:20:02 -05004454 private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
4455
4456 @Override
4457 protected void onConfigurationChanged(Configuration newConfig) {
John Reckd6ac7272011-11-08 15:00:17 -08004458 mCachedOverlappingActionModeHeight = -1;
Cary Clarkc5cd5e92010-11-22 15:20:02 -05004459 if (mSelectingText && mOrientation != newConfig.orientation) {
4460 selectionDone();
4461 }
4462 mOrientation = newConfig.orientation;
John Reck23a446c2011-10-17 17:06:09 -07004463 if (mWebViewCore != null && !mBlockWebkitViewMessages) {
4464 mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
4465 }
Cary Clarkc5cd5e92010-11-22 15:20:02 -05004466 }
4467
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04004468 /**
4469 * Keep track of the Callback so we can end its ActionMode or remove its
4470 * titlebar.
4471 */
4472 private SelectActionModeCallback mSelectCallback;
4473
Leon Scroggins63356742010-12-15 17:37:08 -05004474 // These values are possible options for didUpdateWebTextViewDimensions.
4475 private static final int FULLY_ON_SCREEN = 0;
4476 private static final int INTERSECTS_SCREEN = 1;
4477 private static final int ANYWHERE = 2;
4478
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004479 /**
4480 * Check to see if the focused textfield/textarea is still on screen. If it
4481 * is, update the the dimensions and location of WebTextView. Otherwise,
4482 * remove the WebTextView. Should be called when the zoom level changes.
Leon Scroggins63356742010-12-15 17:37:08 -05004483 * @param intersection How to determine whether the textfield/textarea is
4484 * still on screen.
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004485 * @return boolean True if the textfield/textarea is still on screen and the
4486 * dimensions/location of WebTextView have been updated.
4487 */
Leon Scroggins63356742010-12-15 17:37:08 -05004488 private boolean didUpdateWebTextViewDimensions(int intersection) {
Cary Clark5da9aeb2009-10-06 17:40:53 -04004489 Rect contentBounds = nativeFocusCandidateNodeBounds();
4490 Rect vBox = contentToViewRect(contentBounds);
4491 Rect visibleRect = new Rect();
4492 calcOurVisibleRect(visibleRect);
Michael Kolb5da91bd2011-11-29 15:29:03 -08004493 offsetByLayerScrollPosition(vBox);
Leon Scrogginsbcbf5642010-02-17 17:56:51 -05004494 // If the textfield is on screen, place the WebTextView in
4495 // its new place, accounting for our new scroll/zoom values,
4496 // and adjust its textsize.
Leon Scroggins63356742010-12-15 17:37:08 -05004497 boolean onScreen;
4498 switch (intersection) {
4499 case FULLY_ON_SCREEN:
4500 onScreen = visibleRect.contains(vBox);
4501 break;
4502 case INTERSECTS_SCREEN:
4503 onScreen = Rect.intersects(visibleRect, vBox);
4504 break;
4505 case ANYWHERE:
4506 onScreen = true;
4507 break;
4508 default:
4509 throw new AssertionError(
4510 "invalid parameter passed to didUpdateWebTextViewDimensions");
4511 }
4512 if (onScreen) {
Cary Clark5da9aeb2009-10-06 17:40:53 -04004513 mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
4514 vBox.height());
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004515 mWebTextView.updateTextSize();
4516 updateWebTextViewPadding();
Cary Clark5da9aeb2009-10-06 17:40:53 -04004517 return true;
4518 } else {
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004519 // The textfield is now off screen. The user probably
4520 // was not zooming to see the textfield better. Remove
4521 // the WebTextView. If the user types a key, and the
4522 // textfield is still in focus, we will reconstruct
4523 // the WebTextView and scroll it back on screen.
4524 mWebTextView.remove();
Cary Clark5da9aeb2009-10-06 17:40:53 -04004525 return false;
4526 }
4527 }
4528
Michael Kolb5da91bd2011-11-29 15:29:03 -08004529 private void offsetByLayerScrollPosition(Rect box) {
4530 if ((mCurrentScrollingLayerId != 0)
4531 && (mCurrentScrollingLayerId == nativeFocusCandidateLayerId())) {
4532 box.offsetTo(box.left - mScrollingLayerRect.left,
4533 box.top - mScrollingLayerRect.top);
4534 }
4535 }
4536
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07004537 void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator,
Chris Craik5cf78f72011-07-28 11:34:31 -07004538 boolean isPictureAfterFirstLayout, boolean registerPageSwapCallback) {
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004539 if (mNativeClass == 0)
4540 return;
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07004541 nativeSetBaseLayer(layer, invalRegion, showVisualIndicator,
Chris Craik5cf78f72011-07-28 11:34:31 -07004542 isPictureAfterFirstLayout, registerPageSwapCallback);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08004543 if (mHTML5VideoViewProxy != null) {
4544 mHTML5VideoViewProxy.setBaseLayer(layer);
4545 }
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004546 }
4547
John Reck816c0de2011-06-02 16:04:53 -07004548 int getBaseLayer() {
John Reck90afe212011-09-01 11:39:37 -07004549 if (mNativeClass == 0) {
4550 return 0;
4551 }
John Reck816c0de2011-06-02 16:04:53 -07004552 return nativeGetBaseLayer();
4553 }
4554
Derek Sollenberger293c3602010-06-04 10:44:48 -04004555 private void onZoomAnimationStart() {
4556 // If it is in password mode, turn it off so it does not draw misplaced.
Chris Craike3e7a882011-07-25 14:35:22 -07004557 if (inEditingMode()) {
4558 mWebTextView.setVisibility(INVISIBLE);
Derek Sollenberger293c3602010-06-04 10:44:48 -04004559 }
4560 }
4561
4562 private void onZoomAnimationEnd() {
4563 // adjust the edit text view if needed
Chris Craike3e7a882011-07-25 14:35:22 -07004564 if (inEditingMode()
4565 && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04004566 // If it is a password field, start drawing the WebTextView once
4567 // again.
Chris Craike3e7a882011-07-25 14:35:22 -07004568 mWebTextView.setVisibility(VISIBLE);
Derek Sollenberger293c3602010-06-04 10:44:48 -04004569 }
4570 }
4571
4572 void onFixedLengthZoomAnimationStart() {
4573 WebViewCore.pauseUpdatePicture(getWebViewCore());
4574 onZoomAnimationStart();
4575 }
4576
4577 void onFixedLengthZoomAnimationEnd() {
John Reck95b7d6f2011-06-03 15:23:43 -07004578 if (!mBlockWebkitViewMessages && !mSelectingText) {
Cary Clark0df02692010-11-24 11:01:37 -05004579 WebViewCore.resumeUpdatePicture(mWebViewCore);
4580 }
Derek Sollenberger293c3602010-06-04 10:44:48 -04004581 onZoomAnimationEnd();
4582 }
4583
Grace Kloba8abd50b2010-07-08 15:02:14 -07004584 private static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG |
4585 Paint.DITHER_FLAG |
4586 Paint.SUBPIXEL_TEXT_FLAG;
4587 private static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG |
4588 Paint.DITHER_FLAG;
4589
4590 private final DrawFilter mZoomFilter =
4591 new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
4592 // If we need to trade better quality for speed, set mScrollFilter to null
4593 private final DrawFilter mScrollFilter =
4594 new PaintFlagsDrawFilter(SCROLL_BITS, 0);
4595
Cary Clarkd6982c92009-05-29 11:02:22 -04004596 private void drawCoreAndCursorRing(Canvas canvas, int color,
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004597 boolean drawCursorRing) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598 if (mDrawHistory) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04004599 canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 canvas.drawPicture(mHistoryPicture);
4601 return;
4602 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004603 if (mNativeClass == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604
Derek Sollenberger293c3602010-06-04 10:44:48 -04004605 boolean animateZoom = mZoomManager.isFixedLengthAnimationInProgress();
Grace Klobac2242f22010-03-05 14:00:26 -08004606 boolean animateScroll = ((!mScroller.isFinished()
Cary Clark25415e22009-10-12 13:41:28 -04004607 || mVelocityTracker != null)
4608 && (mTouchMode != TOUCH_DRAG_MODE ||
Grace Klobac2242f22010-03-05 14:00:26 -08004609 mHeldMotionless != MOTIONLESS_TRUE))
4610 || mDeferTouchMode == TOUCH_DRAG_MODE;
Cary Clark25415e22009-10-12 13:41:28 -04004611 if (mTouchMode == TOUCH_DRAG_MODE) {
4612 if (mHeldMotionless == MOTIONLESS_PENDING) {
4613 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
4614 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
4615 mHeldMotionless = MOTIONLESS_FALSE;
4616 }
4617 if (mHeldMotionless == MOTIONLESS_FALSE) {
4618 mPrivateHandler.sendMessageDelayed(mPrivateHandler
4619 .obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
Ben Murdochfd8d3de2011-10-13 13:23:29 +01004620 mPrivateHandler.sendMessageDelayed(mPrivateHandler
4621 .obtainMessage(AWAKEN_SCROLL_BARS),
4622 ViewConfiguration.getScrollDefaultDelay());
Cary Clark25415e22009-10-12 13:41:28 -04004623 mHeldMotionless = MOTIONLESS_PENDING;
4624 }
4625 }
John Reck57efcff2011-09-15 13:51:52 -07004626 int saveCount = canvas.save();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004627 if (animateZoom) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04004628 mZoomManager.animateZoom(canvas);
Romain Guyd6cf4772011-03-04 17:10:54 -08004629 } else if (!canvas.isHardwareAccelerated()) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04004630 canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004631 }
4632
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004633 boolean UIAnimationsRunning = false;
4634 // Currently for each draw we compute the animation values;
4635 // We may in the future decide to do that independently.
Chris Craikd0051c02011-11-29 10:26:10 -08004636 if (mNativeClass != 0 && !canvas.isHardwareAccelerated()
4637 && nativeEvaluateLayersAnimations(mNativeClass)) {
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004638 UIAnimationsRunning = true;
4639 // If we have unfinished (or unstarted) animations,
Nicolas Roardf2674c12011-03-16 16:04:57 -07004640 // we ask for a repaint. We only need to do this in software
4641 // rendering (with hardware rendering we already have a different
4642 // method of requesting a repaint)
Chris Craikd0051c02011-11-29 10:26:10 -08004643 mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
4644 invalidate();
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004645 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004646
Cary Clark2ec30692010-02-23 10:50:38 -05004647 // decide which adornments to draw
4648 int extras = DRAW_EXTRAS_NONE;
4649 if (mFindIsUp) {
Cary Clark924af702010-06-04 16:37:43 -04004650 extras = DRAW_EXTRAS_FIND;
John Reckeffabe82011-10-27 09:09:36 -07004651 } else if (mSelectingText && (!USE_JAVA_TEXT_SELECTION || DEBUG_TEXT_HANDLES)) {
Cary Clark924af702010-06-04 16:37:43 -04004652 extras = DRAW_EXTRAS_SELECTION;
John Reckb61bfed2011-10-13 19:07:50 -07004653 nativeSetSelectionPointer(mNativeClass,
4654 mDrawSelectionPointer,
4655 mZoomManager.getInvScale(), mSelectX, mSelectY - getTitleHeight());
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004656 } else if (drawCursorRing) {
Cary Clark2ec30692010-02-23 10:50:38 -05004657 extras = DRAW_EXTRAS_CURSOR_RING;
4658 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05004659 if (DebugFlags.WEB_VIEW) {
4660 Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp
4661 + " mSelectingText=" + mSelectingText
4662 + " nativePageShouldHandleShiftAndArrows()="
4663 + nativePageShouldHandleShiftAndArrows()
4664 + " animateZoom=" + animateZoom
4665 + " extras=" + extras);
4666 }
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004667
George Mount82ed95f2011-11-15 11:27:47 -08004668 calcOurContentVisibleRectF(mVisibleContentRect);
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004669 if (canvas.isHardwareAccelerated()) {
George Mount82ed95f2011-11-15 11:27:47 -08004670 Rect glRectViewport = mGLViewportEmpty ? null : mGLRectViewport;
4671 Rect viewRectViewport = mGLViewportEmpty ? null : mViewRectViewport;
Derek Sollenberger1d335f32011-07-08 11:28:23 -04004672
George Mount82ed95f2011-11-15 11:27:47 -08004673 int functor = nativeGetDrawGLFunction(mNativeClass, glRectViewport,
4674 viewRectViewport, mVisibleContentRect, getScale(), extras);
4675 ((HardwareCanvas) canvas).callDrawGLFunction(functor);
Derek Sollenberger1d335f32011-07-08 11:28:23 -04004676 if (mHardwareAccelSkia != getSettings().getHardwareAccelSkiaEnabled()) {
4677 mHardwareAccelSkia = getSettings().getHardwareAccelSkiaEnabled();
4678 nativeUseHardwareAccelSkia(mHardwareAccelSkia);
4679 }
4680
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004681 } else {
4682 DrawFilter df = null;
4683 if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) {
4684 df = mZoomFilter;
4685 } else if (animateScroll) {
4686 df = mScrollFilter;
4687 }
4688 canvas.setDrawFilter(df);
Patrick Scott85b69e02011-01-25 15:19:45 -05004689 // XXX: Revisit splitting content. Right now it causes a
4690 // synchronization problem with layers.
George Mount82ed95f2011-11-15 11:27:47 -08004691 int content = nativeDraw(canvas, mVisibleContentRect, color,
4692 extras, false);
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004693 canvas.setDrawFilter(null);
John Reck95b7d6f2011-06-03 15:23:43 -07004694 if (!mBlockWebkitViewMessages && content != 0) {
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004695 mWebViewCore.sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0);
4696 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004697 }
Cary Clark2ec30692010-02-23 10:50:38 -05004698
John Reck57efcff2011-09-15 13:51:52 -07004699 canvas.restoreToCount(saveCount);
4700 if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
4701 drawTextSelectionHandles(canvas);
4702 }
4703
Cary Clark2ec30692010-02-23 10:50:38 -05004704 if (extras == DRAW_EXTRAS_CURSOR_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004705 if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
4706 mTouchMode = TOUCH_SHORTPRESS_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004708 }
Cary Clark5da9aeb2009-10-06 17:40:53 -04004709 if (mFocusSizeChanged) {
4710 mFocusSizeChanged = false;
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004711 // If we are zooming, this will get handled above, when the zoom
4712 // finishes. We also do not need to do this unless the WebTextView
Chris Craik5cf78f72011-07-28 11:34:31 -07004713 // is showing. With hardware acceleration, the pageSwapCallback()
4714 // updates the WebTextView position in sync with page swapping
4715 if (!canvas.isHardwareAccelerated() && !animateZoom && inEditingMode()) {
Leon Scroggins63356742010-12-15 17:37:08 -05004716 didUpdateWebTextViewDimensions(ANYWHERE);
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004717 }
Cary Clark5da9aeb2009-10-06 17:40:53 -04004718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004719 }
4720
John Reck086a5142011-08-31 16:59:10 -07004721 private void drawTextSelectionHandles(Canvas canvas) {
4722 if (mTextSelectionPaint == null) {
4723 mTextSelectionPaint = new Paint();
4724 mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
4725 }
4726 mTextSelectionRegion.setEmpty();
John Reckeffabe82011-10-27 09:09:36 -07004727 nativeGetTextSelectionRegion(mNativeClass, mTextSelectionRegion);
John Reck086a5142011-08-31 16:59:10 -07004728 Rect r = new Rect();
4729 RegionIterator iter = new RegionIterator(mTextSelectionRegion);
John Reckeffabe82011-10-27 09:09:36 -07004730 Rect clip = canvas.getClipBounds();
John Reck086a5142011-08-31 16:59:10 -07004731 while (iter.next(r)) {
John Reckeffabe82011-10-27 09:09:36 -07004732 r.set(contentToViewDimension(r.left),
John Reck086a5142011-08-31 16:59:10 -07004733 contentToViewDimension(r.top),
4734 contentToViewDimension(r.right),
4735 contentToViewDimension(r.bottom));
John Reckeffabe82011-10-27 09:09:36 -07004736 if (r.intersect(clip)) {
4737 canvas.drawRect(r, mTextSelectionPaint);
John Reck086a5142011-08-31 16:59:10 -07004738 }
John Reck086a5142011-08-31 16:59:10 -07004739 }
4740 if (mSelectHandleLeft == null) {
4741 mSelectHandleLeft = mContext.getResources().getDrawable(
4742 com.android.internal.R.drawable.text_select_handle_left);
4743 }
John Reckeffabe82011-10-27 09:09:36 -07004744 int[] handles = new int[4];
4745 nativeGetSelectionHandles(mNativeClass, handles);
4746 int start_x = contentToViewDimension(handles[0]);
4747 int start_y = contentToViewDimension(handles[1]);
4748 int end_x = contentToViewDimension(handles[2]);
4749 int end_y = contentToViewDimension(handles[3]);
John Reck086a5142011-08-31 16:59:10 -07004750 // Magic formula copied from TextView
4751 start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4;
4752 mSelectHandleLeft.setBounds(start_x, start_y,
4753 start_x + mSelectHandleLeft.getIntrinsicWidth(),
4754 start_y + mSelectHandleLeft.getIntrinsicHeight());
4755 if (mSelectHandleRight == null) {
4756 mSelectHandleRight = mContext.getResources().getDrawable(
4757 com.android.internal.R.drawable.text_select_handle_right);
4758 }
4759 end_x -= mSelectHandleRight.getIntrinsicWidth() / 4;
4760 mSelectHandleRight.setBounds(end_x, end_y,
4761 end_x + mSelectHandleRight.getIntrinsicWidth(),
4762 end_y + mSelectHandleRight.getIntrinsicHeight());
John Reckeffabe82011-10-27 09:09:36 -07004763 if (DEBUG_TEXT_HANDLES) {
4764 mSelectHandleLeft.setAlpha(125);
4765 mSelectHandleRight.setAlpha(125);
4766 }
John Reck086a5142011-08-31 16:59:10 -07004767 mSelectHandleLeft.draw(canvas);
4768 mSelectHandleRight.draw(canvas);
4769 }
4770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004771 // draw history
4772 private boolean mDrawHistory = false;
4773 private Picture mHistoryPicture = null;
4774 private int mHistoryWidth = 0;
4775 private int mHistoryHeight = 0;
4776
4777 // Only check the flag, can be called from WebCore thread
4778 boolean drawHistory() {
4779 return mDrawHistory;
4780 }
4781
Derek Sollenberger341e22f2010-06-02 12:34:34 -04004782 int getHistoryPictureWidth() {
4783 return (mHistoryPicture != null) ? mHistoryPicture.getWidth() : 0;
4784 }
4785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 // Should only be called in UI thread
4787 void switchOutDrawHistory() {
4788 if (null == mWebViewCore) return; // CallbackProxy may trigger this
Grace Kloba8abd50b2010-07-08 15:02:14 -07004789 if (mDrawHistory && (getProgress() == 100 || nativeHasContent())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004790 mDrawHistory = false;
Patrick Scottda9a22b2010-04-08 08:32:52 -04004791 mHistoryPicture = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004792 invalidate();
4793 int oldScrollX = mScrollX;
4794 int oldScrollY = mScrollY;
4795 mScrollX = pinLocX(mScrollX);
4796 mScrollY = pinLocY(mScrollY);
4797 if (oldScrollX != mScrollX || oldScrollY != mScrollY) {
Grace Kloba327dce92010-04-02 15:38:55 -07004798 onScrollChanged(mScrollX, mScrollY, oldScrollX, oldScrollY);
4799 } else {
4800 sendOurVisibleRect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004802 }
4803 }
4804
Cary Clarkd6982c92009-05-29 11:02:22 -04004805 WebViewCore.CursorData cursorData() {
Svetoslav Ganov7882a782011-05-11 17:53:01 -07004806 WebViewCore.CursorData result = cursorDataNoPosition();
Cary Clarked56eda2009-06-18 09:48:47 -04004807 Point position = nativeCursorPosition();
4808 result.mX = position.x;
4809 result.mY = position.y;
Cary Clarkd6982c92009-05-29 11:02:22 -04004810 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004811 }
Cary Clarkd6982c92009-05-29 11:02:22 -04004812
Svetoslav Ganov7882a782011-05-11 17:53:01 -07004813 WebViewCore.CursorData cursorDataNoPosition() {
4814 WebViewCore.CursorData result = new WebViewCore.CursorData();
4815 result.mMoveGeneration = nativeMoveGeneration();
4816 result.mFrame = nativeCursorFramePointer();
4817 return result;
4818 }
4819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004820 /**
4821 * Delete text from start to end in the focused textfield. If there is no
Cary Clarkd6982c92009-05-29 11:02:22 -04004822 * focus, or if start == end, silently fail. If start and end are out of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004823 * order, swap them.
4824 * @param start Beginning of selection to delete.
4825 * @param end End of selection to delete.
4826 */
4827 /* package */ void deleteSelection(int start, int end) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004828 mTextGeneration++;
Leon Scroggins6679f2f2009-08-12 18:48:10 -04004829 WebViewCore.TextSelectionData data
4830 = new WebViewCore.TextSelectionData(start, end);
4831 mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
4832 data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004833 }
4834
4835 /**
4836 * Set the selection to (start, end) in the focused textfield. If start and
4837 * end are out of order, swap them.
4838 * @param start Beginning of selection.
4839 * @param end End of selection.
4840 */
4841 /* package */ void setSelection(int start, int end) {
Leon Scrogginsacea08d2010-05-27 15:09:32 -04004842 if (mWebViewCore != null) {
4843 mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end);
4844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004845 }
4846
Derek Sollenberger7cabb032010-01-21 10:37:38 -05004847 @Override
4848 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
4849 InputConnection connection = super.onCreateInputConnection(outAttrs);
4850 outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_FULLSCREEN;
4851 return connection;
4852 }
4853
Leon Scroggins04e0a102010-01-08 16:19:27 -05004854 /**
4855 * Called in response to a message from webkit telling us that the soft
4856 * keyboard should be launched.
4857 */
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004858 private void displaySoftKeyboard(boolean isTextView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004859 InputMethodManager imm = (InputMethodManager)
4860 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004861
Shimeng (Simon) Wang7924a4a2010-09-14 13:20:46 -07004862 // bring it back to the default level scale so that user can enter text
Shimeng (Simon) Wang6c09ef02010-09-09 13:56:34 -07004863 boolean zoom = mZoomManager.getScale() < mZoomManager.getDefaultScale();
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004864 if (zoom) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04004865 mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
Shimeng (Simon) Wang6c09ef02010-09-09 13:56:34 -07004866 mZoomManager.setZoomScale(mZoomManager.getDefaultScale(), false);
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004867 }
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004868 if (isTextView) {
Leon Scroggins04e0a102010-01-08 16:19:27 -05004869 rebuildWebTextView();
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004870 if (inEditingMode()) {
Leon Scrogginsd69b7012011-03-09 16:18:28 -05004871 imm.showSoftInput(mWebTextView, 0, mWebTextView.getResultReceiver());
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004872 if (zoom) {
Leon Scroggins63356742010-12-15 17:37:08 -05004873 didUpdateWebTextViewDimensions(INTERSECTS_SCREEN);
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004874 }
4875 return;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07004876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004877 }
Leon Scroggins200c13d2010-05-14 15:35:42 -04004878 // Used by plugins and contentEditable.
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004879 // Also used if the navigation cache is out of date, and
4880 // does not recognize that a textfield is in focus. In that
4881 // case, use WebView as the targeted view.
4882 // see http://b/issue?id=2457459
4883 imm.showSoftInput(this, 0);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004884 }
4885
4886 // Called by WebKit to instruct the UI to hide the keyboard
4887 private void hideSoftKeyboard() {
Leon Scrogginsf2e17a82010-09-24 15:58:50 -04004888 InputMethodManager imm = InputMethodManager.peekInstance();
4889 if (imm != null && (imm.isActive(this)
4890 || (inEditingMode() && imm.isActive(mWebTextView)))) {
Leon Scroggins III71d17e42010-09-02 12:53:08 -04004891 imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
4892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004893 }
4894
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004895 /*
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004896 * This method checks the current focus and cursor and potentially rebuilds
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004897 * mWebTextView to have the appropriate properties, such as password,
4898 * multiline, and what text it contains. It also removes it if necessary.
4899 */
Leon Scroggins01058282009-07-30 16:33:56 -04004900 /* package */ void rebuildWebTextView() {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004901 // If the WebView does not have focus, do nothing until it gains focus.
Grace Kloba04b28682009-09-14 14:38:37 -07004902 if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004903 return;
4904 }
4905 boolean alreadyThere = inEditingMode();
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004906 // inEditingMode can only return true if mWebTextView is non-null,
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004907 // so we can safely call remove() if (alreadyThere)
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004908 if (0 == mNativeClass || !nativeFocusCandidateIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004909 if (alreadyThere) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004910 mWebTextView.remove();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004911 }
4912 return;
4913 }
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004914 // At this point, we know we have found an input field, so go ahead
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004915 // and create the WebTextView if necessary.
4916 if (mWebTextView == null) {
Ben Murdochdb8d19c2010-10-29 11:44:17 +01004917 mWebTextView = new WebTextView(mContext, WebView.this, mAutoFillData.getQueryId());
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004918 // Initialize our generation number.
4919 mTextGeneration = 0;
4920 }
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004921 mWebTextView.updateTextSize();
John Reckc0e9fb92011-10-21 12:39:43 -07004922 updateWebTextViewPosition();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004923 String text = nativeFocusCandidateText();
4924 int nodePointer = nativeFocusCandidatePointer();
Chris Craike3e7a882011-07-25 14:35:22 -07004925 // This needs to be called before setType, which may call
4926 // requestFormData, and it needs to have the correct nodePointer.
4927 mWebTextView.setNodePointer(nodePointer);
4928 mWebTextView.setType(nativeFocusCandidateType());
Russell Brennerb76b3b12011-09-28 18:00:02 -07004929 // Gravity needs to be set after setType
4930 mWebTextView.setGravityForRtl(nativeFocusCandidateIsRtlText());
Chris Craike3e7a882011-07-25 14:35:22 -07004931 if (null == text) {
4932 if (DebugFlags.WEB_VIEW) {
4933 Log.v(LOGTAG, "rebuildWebTextView null == text");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004934 }
Chris Craike3e7a882011-07-25 14:35:22 -07004935 text = "";
4936 }
4937 mWebTextView.setTextAndKeepSelection(text);
4938 InputMethodManager imm = InputMethodManager.peekInstance();
4939 if (imm != null && imm.isActive(mWebTextView)) {
4940 imm.restartInput(mWebTextView);
John Reckc0e9fb92011-10-21 12:39:43 -07004941 mWebTextView.clearComposingText();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004942 }
Leon Scrogginsf8ca2d72010-10-21 17:14:42 -04004943 if (isFocused()) {
4944 mWebTextView.requestFocus();
4945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004946 }
4947
John Reckc0e9fb92011-10-21 12:39:43 -07004948 private void updateWebTextViewPosition() {
4949 Rect visibleRect = new Rect();
4950 calcOurContentVisibleRect(visibleRect);
4951 // Note that sendOurVisibleRect calls viewToContent, so the coordinates
4952 // should be in content coordinates.
4953 Rect bounds = nativeFocusCandidateNodeBounds();
4954 Rect vBox = contentToViewRect(bounds);
Michael Kolb5da91bd2011-11-29 15:29:03 -08004955 offsetByLayerScrollPosition(vBox);
John Reckc0e9fb92011-10-21 12:39:43 -07004956 mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
4957 if (!Rect.intersects(bounds, visibleRect)) {
4958 revealSelection();
4959 }
4960 updateWebTextViewPadding();
4961 }
4962
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004963 /**
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004964 * Update the padding of mWebTextView based on the native textfield/textarea
4965 */
4966 void updateWebTextViewPadding() {
4967 Rect paddingRect = nativeFocusCandidatePaddingRect();
4968 if (paddingRect != null) {
4969 // Use contentToViewDimension since these are the dimensions of
4970 // the padding.
4971 mWebTextView.setPadding(
4972 contentToViewDimension(paddingRect.left),
4973 contentToViewDimension(paddingRect.top),
4974 contentToViewDimension(paddingRect.right),
4975 contentToViewDimension(paddingRect.bottom));
4976 }
4977 }
4978
4979 /**
Leon Scroggins200c13d2010-05-14 15:35:42 -04004980 * Tell webkit to put the cursor on screen.
4981 */
4982 /* package */ void revealSelection() {
4983 if (mWebViewCore != null) {
4984 mWebViewCore.sendMessage(EventHub.REVEAL_SELECTION);
4985 }
4986 }
4987
4988 /**
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004989 * Called by WebTextView to find saved form data associated with the
4990 * textfield
4991 * @param name Name of the textfield.
4992 * @param nodePointer Pointer to the node of the textfield, so it can be
4993 * compared to the currently focused textfield when the data is
4994 * retrieved.
Ben Murdoch62275a42010-09-07 11:27:28 +01004995 * @param autoFillable true if WebKit has determined this field is part of
4996 * a form that can be auto filled.
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004997 * @param autoComplete true if the attribute "autocomplete" is set to true
4998 * on the textfield.
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004999 */
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005000 /* package */ void requestFormData(String name, int nodePointer,
5001 boolean autoFillable, boolean autoComplete) {
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05005002 if (mWebViewCore.getSettings().getSaveFormData()) {
5003 Message update = mPrivateHandler.obtainMessage(REQUEST_FORM_DATA);
5004 update.arg1 = nodePointer;
5005 RequestFormData updater = new RequestFormData(name, getUrl(),
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005006 update, autoFillable, autoComplete);
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05005007 Thread t = new Thread(updater);
5008 t.start();
5009 }
5010 }
5011
Leon Scroggins3a503392010-01-06 17:04:38 -05005012 /**
5013 * Pass a message to find out the <label> associated with the <input>
5014 * identified by nodePointer
5015 * @param framePointer Pointer to the frame containing the <input> node
5016 * @param nodePointer Pointer to the node for which a <label> is desired.
5017 */
5018 /* package */ void requestLabel(int framePointer, int nodePointer) {
5019 mWebViewCore.sendMessage(EventHub.REQUEST_LABEL, framePointer,
5020 nodePointer);
5021 }
5022
Leon Scrogginsd3465f62009-06-02 10:57:54 -04005023 /*
5024 * This class requests an Adapter for the WebTextView which shows past
5025 * entries stored in the database. It is a Runnable so that it can be done
5026 * in its own thread, without slowing down the UI.
5027 */
5028 private class RequestFormData implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005029 private String mName;
5030 private String mUrl;
5031 private Message mUpdateMessage;
Ben Murdoch62275a42010-09-07 11:27:28 +01005032 private boolean mAutoFillable;
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005033 private boolean mAutoComplete;
Ben Murdoch50799a92011-07-25 11:35:45 +01005034 private WebSettings mWebSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005035
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005036 public RequestFormData(String name, String url, Message msg,
5037 boolean autoFillable, boolean autoComplete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005038 mName = name;
Ben Murdoch2376f822011-09-09 16:49:44 +01005039 mUrl = WebTextView.urlForAutoCompleteData(url);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005040 mUpdateMessage = msg;
Ben Murdoch62275a42010-09-07 11:27:28 +01005041 mAutoFillable = autoFillable;
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005042 mAutoComplete = autoComplete;
Ben Murdoch50799a92011-07-25 11:35:45 +01005043 mWebSettings = getSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005044 }
5045
5046 public void run() {
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005047 ArrayList<String> pastEntries = new ArrayList<String>();
Ben Murdoch62275a42010-09-07 11:27:28 +01005048
5049 if (mAutoFillable) {
5050 // Note that code inside the adapter click handler in WebTextView depends
5051 // on the AutoFill item being at the top of the drop down list. If you change
5052 // the order, make sure to do it there too!
Ben Murdoch50799a92011-07-25 11:35:45 +01005053 if (mWebSettings != null && mWebSettings.getAutoFillProfile() != null) {
Ben Murdoch57914382010-11-16 11:50:39 +00005054 pastEntries.add(getResources().getText(
5055 com.android.internal.R.string.autofill_this_form).toString() +
5056 " " +
5057 mAutoFillData.getPreviewString());
5058 mWebTextView.setAutoFillProfileIsSet(true);
5059 } else {
5060 // There is no autofill profile set up yet, so add an option that
5061 // will invite the user to set their profile up.
5062 pastEntries.add(getResources().getText(
5063 com.android.internal.R.string.setup_autofill).toString());
5064 mWebTextView.setAutoFillProfileIsSet(false);
5065 }
Ben Murdoch62275a42010-09-07 11:27:28 +01005066 }
5067
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005068 if (mAutoComplete) {
5069 pastEntries.addAll(mDatabase.getFormData(mUrl, mName));
5070 }
Ben Murdoch62275a42010-09-07 11:27:28 +01005071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005072 if (pastEntries.size() > 0) {
5073 AutoCompleteAdapter adapter = new
5074 AutoCompleteAdapter(mContext, pastEntries);
Cary Clarkded054c2009-06-15 10:26:08 -04005075 mUpdateMessage.obj = adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005076 mUpdateMessage.sendToTarget();
5077 }
5078 }
5079 }
5080
Grace Kloba8ae1b412009-11-23 10:35:34 -08005081 /**
5082 * Dump the display tree to "/sdcard/displayTree.txt"
5083 *
5084 * @hide debug only
5085 */
5086 public void dumpDisplayTree() {
5087 nativeDumpDisplayTree(getUrl());
5088 }
5089
5090 /**
5091 * Dump the dom tree to adb shell if "toFile" is False, otherwise dump it to
5092 * "/sdcard/domTree.txt"
5093 *
5094 * @hide debug only
5095 */
5096 public void dumpDomTree(boolean toFile) {
5097 mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE, toFile ? 1 : 0, 0);
5098 }
5099
5100 /**
5101 * Dump the render tree to adb shell if "toFile" is False, otherwise dump it
5102 * to "/sdcard/renderTree.txt"
5103 *
5104 * @hide debug only
5105 */
5106 public void dumpRenderTree(boolean toFile) {
5107 mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE, toFile ? 1 : 0, 0);
5108 }
5109
Andrei Popescu5e7bb0a2010-02-01 22:32:16 +00005110 /**
Steve Block68dede32010-08-04 10:28:46 +01005111 * Called by DRT on UI thread, need to proxy to WebCore thread.
5112 *
5113 * @hide debug only
5114 */
5115 public void useMockDeviceOrientation() {
5116 mWebViewCore.sendMessage(EventHub.USE_MOCK_DEVICE_ORIENTATION);
5117 }
5118
5119 /**
5120 * Called by DRT on WebCore thread.
5121 *
5122 * @hide debug only
5123 */
5124 public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
5125 boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
Steve Blockf4a705f2010-08-11 13:08:24 +01005126 mWebViewCore.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta,
5127 canProvideGamma, gamma);
Steve Block68dede32010-08-04 10:28:46 +01005128 }
5129
Leon Scrogginse3225672009-06-03 15:53:13 -04005130 // This is used to determine long press with the center key. Does not
5131 // affect long press with the trackball/touch.
5132 private boolean mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005133
5134 @Override
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04005135 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
John Reck95b7d6f2011-06-03 15:23:43 -07005136 if (mBlockWebkitViewMessages) {
5137 return false;
5138 }
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04005139 // send complex characters to webkit for use by JS and plugins
5140 if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getCharacters() != null) {
5141 // pass the key to DOM
5142 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
5143 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
5144 // return true as DOM handles the key
5145 return true;
5146 }
5147 return false;
5148 }
5149
Cary Clarkaa86ac82010-12-28 11:30:18 -05005150 private boolean isEnterActionKey(int keyCode) {
5151 return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
5152 || keyCode == KeyEvent.KEYCODE_ENTER
5153 || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
5154 }
5155
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04005156 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005157 public boolean onKeyDown(int keyCode, KeyEvent event) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005158 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005159 Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
Cary Clarkaa86ac82010-12-28 11:30:18 -05005160 + "keyCode=" + keyCode
Cary Clark215b72c2009-06-26 14:38:43 -04005161 + ", " + event + ", unicode=" + event.getUnicodeChar());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005162 }
John Reck95b7d6f2011-06-03 15:23:43 -07005163 if (mBlockWebkitViewMessages) {
5164 return false;
5165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005166
Cary Clark122da932010-12-28 15:58:08 -05005167 // don't implement accelerator keys here; defer to host application
5168 if (event.isCtrlPressed()) {
5169 return false;
5170 }
5171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005172 if (mNativeClass == 0) {
5173 return false;
5174 }
5175
5176 // do this hack up front, so it always works, regardless of touch-mode
5177 if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) {
5178 mAutoRedraw = !mAutoRedraw;
5179 if (mAutoRedraw) {
5180 invalidate();
5181 }
5182 return true;
5183 }
5184
5185 // Bubble up the key event if
5186 // 1. it is a system key; or
Grace Kloba04b28682009-09-14 14:38:37 -07005187 // 2. the host application wants to handle it;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005188 if (event.isSystem()
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005189 || mCallbackProxy.uiOverrideKeyEvent(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005190 return false;
5191 }
5192
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005193 // accessibility support
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005194 if (accessibilityScriptInjected()) {
Svetoslav Ganovb01c3d22011-01-11 14:19:17 -08005195 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5196 // if an accessibility script is injected we delegate to it the key handling.
5197 // this script is a screen reader which is a fully fledged solution for blind
5198 // users to navigate in and interact with web pages.
5199 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
5200 return true;
5201 } else {
5202 // Clean up if accessibility was disabled after loading the current URL.
5203 mAccessibilityScriptInjected = false;
5204 }
5205 } else if (mAccessibilityInjector != null) {
5206 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5207 if (mAccessibilityInjector.onKeyEvent(event)) {
5208 // if an accessibility injector is present (no JavaScript enabled or the site
5209 // opts out injecting our JavaScript screen reader) we let it decide whether
5210 // to act on and consume the event.
5211 return true;
5212 }
5213 } else {
5214 // Clean up if accessibility was disabled after loading the current URL.
5215 mAccessibilityInjector = null;
5216 }
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005217 }
5218
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08005219 if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
Cary Clarka3ee56f2011-01-10 11:20:56 -05005220 if (event.hasNoModifiers()) {
5221 pageUp(false);
5222 return true;
5223 } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
5224 pageUp(true);
5225 return true;
5226 }
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08005227 }
5228
5229 if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
Cary Clarka3ee56f2011-01-10 11:20:56 -05005230 if (event.hasNoModifiers()) {
5231 pageDown(false);
5232 return true;
5233 } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
5234 pageDown(true);
5235 return true;
5236 }
5237 }
5238
5239 if (keyCode == KeyEvent.KEYCODE_MOVE_HOME && event.hasNoModifiers()) {
5240 pageUp(true);
5241 return true;
5242 }
5243
5244 if (keyCode == KeyEvent.KEYCODE_MOVE_END && event.hasNoModifiers()) {
5245 pageDown(true);
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08005246 return true;
5247 }
5248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005249 if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
5250 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005251 switchOutDrawHistory();
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005252 if (nativePageShouldHandleShiftAndArrows()) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07005253 letPageHandleNavKey(keyCode, event.getEventTime(), true, event.getMetaState());
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05005254 return true;
5255 }
Cary Clarka3ee56f2011-01-10 11:20:56 -05005256 if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
5257 switch (keyCode) {
5258 case KeyEvent.KEYCODE_DPAD_UP:
5259 pageUp(true);
5260 return true;
5261 case KeyEvent.KEYCODE_DPAD_DOWN:
5262 pageDown(true);
5263 return true;
5264 case KeyEvent.KEYCODE_DPAD_LEFT:
5265 nativeClearCursor(); // start next trackball movement from page edge
5266 return pinScrollTo(0, mScrollY, true, 0);
5267 case KeyEvent.KEYCODE_DPAD_RIGHT:
5268 nativeClearCursor(); // start next trackball movement from page edge
5269 return pinScrollTo(mContentWidth, mScrollY, true, 0);
5270 }
5271 }
Cary Clark924af702010-06-04 16:37:43 -04005272 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04005273 int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
5274 ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
5275 int yRate = keyCode == KeyEvent.KEYCODE_DPAD_UP ?
5276 -1 : keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : 0;
5277 int multiplier = event.getRepeatCount() + 1;
5278 moveSelection(xRate * multiplier, yRate * multiplier);
5279 return true;
5280 }
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05005281 if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005282 playSoundEffect(keyCodeToSoundsEffect(keyCode));
5283 return true;
5284 }
5285 // Bubble up the key event as WebView doesn't handle it
5286 return false;
5287 }
5288
Cary Clark1477b8f2011-02-09 19:33:00 -05005289 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005290 switchOutDrawHistory();
Cary Clarkddbda002011-01-06 13:40:15 -05005291 boolean wantsKeyEvents = nativeCursorNodePointer() == 0
5292 || nativeCursorWantsKeyEvents();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005293 if (event.getRepeatCount() == 0) {
Cary Clark924af702010-06-04 16:37:43 -04005294 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04005295 return true; // discard press if copy in progress
5296 }
Leon Scrogginse3225672009-06-03 15:53:13 -04005297 mGotCenterDown = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005298 mPrivateHandler.sendMessageDelayed(mPrivateHandler
Leon Scrogginse3225672009-06-03 15:53:13 -04005299 .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT);
Cary Clarkddbda002011-01-06 13:40:15 -05005300 if (!wantsKeyEvents) return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005301 }
5302 // Bubble up the key event as WebView doesn't handle it
Cary Clarkddbda002011-01-06 13:40:15 -05005303 if (!wantsKeyEvents) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005304 }
5305
5306 if (getSettings().getNavDump()) {
5307 switch (keyCode) {
5308 case KeyEvent.KEYCODE_4:
Grace Kloba8ae1b412009-11-23 10:35:34 -08005309 dumpDisplayTree();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 break;
5311 case KeyEvent.KEYCODE_5:
5312 case KeyEvent.KEYCODE_6:
Grace Kloba8ae1b412009-11-23 10:35:34 -08005313 dumpDomTree(keyCode == KeyEvent.KEYCODE_5);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005314 break;
5315 case KeyEvent.KEYCODE_7:
5316 case KeyEvent.KEYCODE_8:
Grace Kloba8ae1b412009-11-23 10:35:34 -08005317 dumpRenderTree(keyCode == KeyEvent.KEYCODE_7);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005318 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005319 }
5320 }
5321
Derek Sollenberger718d69f2009-10-19 15:56:43 -04005322 if (nativeCursorIsTextInput()) {
Leon Scroggins1cc24202009-06-16 10:10:28 -04005323 // This message will put the node in focus, for the DOM's notion
Leon Scrogginsb45a2632011-01-12 14:11:24 -05005324 // of focus.
5325 mWebViewCore.sendMessage(EventHub.FAKE_CLICK, nativeCursorFramePointer(),
Leon Scroggins01058282009-07-30 16:33:56 -04005326 nativeCursorNodePointer());
Leon Scroggins0658e8f2009-06-26 14:09:09 -04005327 // This will bring up the WebTextView and put it in focus, for
5328 // our view system's notion of focus
5329 rebuildWebTextView();
5330 // Now we need to pass the event to it
Leon Scrogginsc66f68a2009-10-02 15:12:30 -04005331 if (inEditingMode()) {
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005332 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005333 return mWebTextView.dispatchKeyEvent(event);
Leon Scrogginsc66f68a2009-10-02 15:12:30 -04005334 }
Leon Scroggins40981262009-07-01 10:57:47 -04005335 } else if (nativeHasFocusNode()) {
5336 // In this case, the cursor is not on a text input, but the focus
5337 // might be. Check it, and if so, hand over to the WebTextView.
5338 rebuildWebTextView();
5339 if (inEditingMode()) {
Leon Scroggins0aa341f2010-02-24 16:49:35 -05005340 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005341 return mWebTextView.dispatchKeyEvent(event);
Leon Scroggins40981262009-07-01 10:57:47 -04005342 }
Cary Clark19436562009-06-04 16:25:07 -04005343 }
5344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005345 // TODO: should we pass all the keys to DOM or check the meta tag
Cary Clark2f1d60c2009-06-03 08:05:53 -04005346 if (nativeCursorWantsKeyEvents() || true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005347 // pass the key to DOM
5348 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
5349 // return true as DOM handles the key
5350 return true;
5351 }
5352
5353 // Bubble up the key event as WebView doesn't handle it
5354 return false;
5355 }
5356
5357 @Override
5358 public boolean onKeyUp(int keyCode, KeyEvent event) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005359 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005360 Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
Cary Clark215b72c2009-06-26 14:38:43 -04005361 + ", " + event + ", unicode=" + event.getUnicodeChar());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005362 }
John Reck95b7d6f2011-06-03 15:23:43 -07005363 if (mBlockWebkitViewMessages) {
5364 return false;
5365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005366
5367 if (mNativeClass == 0) {
5368 return false;
5369 }
5370
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04005371 // special CALL handling when cursor node's href is "tel:XXX"
Cary Clarkd6982c92009-05-29 11:02:22 -04005372 if (keyCode == KeyEvent.KEYCODE_CALL && nativeHasCursorNode()) {
5373 String text = nativeCursorText();
5374 if (!nativeCursorIsTextInput() && text != null
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005375 && text.startsWith(SCHEME_TEL)) {
5376 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
5377 getContext().startActivity(intent);
5378 return true;
5379 }
5380 }
5381
5382 // Bubble up the key event if
5383 // 1. it is a system key; or
5384 // 2. the host application wants to handle it;
Svetoslav Ganovda355512010-05-12 22:04:44 -07005385 if (event.isSystem()
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005386 || mCallbackProxy.uiOverrideKeyEvent(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005387 return false;
5388 }
5389
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005390 // accessibility support
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005391 if (accessibilityScriptInjected()) {
Svetoslav Ganovb01c3d22011-01-11 14:19:17 -08005392 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5393 // if an accessibility script is injected we delegate to it the key handling.
5394 // this script is a screen reader which is a fully fledged solution for blind
5395 // users to navigate in and interact with web pages.
5396 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
5397 return true;
5398 } else {
5399 // Clean up if accessibility was disabled after loading the current URL.
5400 mAccessibilityScriptInjected = false;
5401 }
5402 } else if (mAccessibilityInjector != null) {
5403 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5404 if (mAccessibilityInjector.onKeyEvent(event)) {
5405 // if an accessibility injector is present (no JavaScript enabled or the site
5406 // opts out injecting our JavaScript screen reader) we let it decide whether to
5407 // act on and consume the event.
5408 return true;
5409 }
5410 } else {
5411 // Clean up if accessibility was disabled after loading the current URL.
5412 mAccessibilityInjector = null;
5413 }
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005414 }
5415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005416 if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
5417 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005418 if (nativePageShouldHandleShiftAndArrows()) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07005419 letPageHandleNavKey(keyCode, event.getEventTime(), false, event.getMetaState());
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05005420 return true;
5421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005422 // always handle the navigation keys in the UI thread
5423 // Bubble up the key event as WebView doesn't handle it
5424 return false;
5425 }
5426
Cary Clarkaa86ac82010-12-28 11:30:18 -05005427 if (isEnterActionKey(keyCode)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005428 // remove the long press message first
Leon Scrogginse3225672009-06-03 15:53:13 -04005429 mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
5430 mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005431
Cary Clark924af702010-06-04 16:37:43 -04005432 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04005433 if (mExtendSelection) {
Cary Clark924af702010-06-04 16:37:43 -04005434 copySelection();
5435 selectionDone();
Cary Clarkc05af372009-10-16 10:52:27 -04005436 } else {
5437 mExtendSelection = true;
Cary Clark924af702010-06-04 16:37:43 -04005438 nativeSetExtendSelection();
Cary Clark09e383c2009-10-26 16:43:58 -04005439 invalidate(); // draw the i-beam instead of the arrow
Cary Clarkc05af372009-10-16 10:52:27 -04005440 }
5441 return true; // discard press if copy in progress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005442 }
Grace Klobadd817492009-09-14 10:17:06 -07005443
5444 // perform the single click
5445 Rect visibleRect = sendOurVisibleRect();
5446 // Note that sendOurVisibleRect calls viewToContent, so the
5447 // coordinates should be in content coordinates.
5448 if (!nativeCursorIntersects(visibleRect)) {
5449 return false;
5450 }
Grace Klobadd817492009-09-14 10:17:06 -07005451 WebViewCore.CursorData data = cursorData();
5452 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
5453 playSoundEffect(SoundEffectConstants.CLICK);
Leon Scroggins1d60c5c2009-10-23 10:16:51 -04005454 if (nativeCursorIsTextInput()) {
5455 rebuildWebTextView();
Leon Scroggins1d96ca02009-10-23 11:49:03 -04005456 centerKeyPressOnTextField();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005457 if (inEditingMode()) {
5458 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005459 }
Leon Scroggins1d60c5c2009-10-23 10:16:51 -04005460 return true;
5461 }
Leon Scroggins2aed7762010-08-13 17:11:42 -04005462 clearTextEntry();
Cary Clarke60cb7f2010-08-25 14:56:00 -04005463 nativeShowCursorTimed();
Cary Clarkddbda002011-01-06 13:40:15 -05005464 if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
5465 return true;
5466 }
5467 if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) {
Grace Klobadd817492009-09-14 10:17:06 -07005468 mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
5469 nativeCursorNodePointer());
Cary Clarkddbda002011-01-06 13:40:15 -05005470 return true;
Grace Klobadd817492009-09-14 10:17:06 -07005471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005472 }
5473
5474 // TODO: should we pass all the keys to DOM or check the meta tag
Cary Clark2f1d60c2009-06-03 08:05:53 -04005475 if (nativeCursorWantsKeyEvents() || true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005476 // pass the key to DOM
5477 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
5478 // return true as DOM handles the key
5479 return true;
5480 }
5481
5482 // Bubble up the key event as WebView doesn't handle it
5483 return false;
5484 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005485
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005486 /*
Cary Clark03f00222011-02-10 19:37:15 -05005487 * Enter selecting text mode, and see if CAB should be shown.
5488 * Returns true if the WebView is now in
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005489 * selecting text mode (including if it was already in that mode, and this
5490 * method did nothing).
5491 */
Cary Clark03f00222011-02-10 19:37:15 -05005492 private boolean setUpSelect(boolean selectWord, int x, int y) {
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005493 if (0 == mNativeClass) return false; // client isn't initialized
5494 if (inFullScreenMode()) return false;
5495 if (mSelectingText) return true;
Cary Clark03f00222011-02-10 19:37:15 -05005496 nativeResetSelection();
5497 if (selectWord && !nativeWordSelection(x, y)) {
5498 selectionDone();
5499 return false;
5500 }
5501 mSelectCallback = new SelectActionModeCallback();
5502 mSelectCallback.setWebView(this);
5503 if (startActionMode(mSelectCallback) == null) {
5504 // There is no ActionMode, so do not allow the user to modify a
5505 // selection.
5506 selectionDone();
5507 return false;
5508 }
Cary Clark09e383c2009-10-26 16:43:58 -04005509 mExtendSelection = false;
Cary Clark924af702010-06-04 16:37:43 -04005510 mSelectingText = mDrawSelectionPointer = true;
John Reckeffabe82011-10-27 09:09:36 -07005511 if (DEBUG_TEXT_HANDLES) {
5512 // Debugging text handles requires running in software mode
5513 setLayerType(LAYER_TYPE_SOFTWARE, null);
5514 }
Cary Clark924af702010-06-04 16:37:43 -04005515 // don't let the picture change during text selection
5516 WebViewCore.pauseUpdatePicture(mWebViewCore);
Cary Clark09e383c2009-10-26 16:43:58 -04005517 if (nativeHasCursorNode()) {
5518 Rect rect = nativeCursorNodeBounds();
5519 mSelectX = contentToViewX(rect.left);
5520 mSelectY = contentToViewY(rect.top);
Steve Block92c99162011-05-23 17:36:01 +01005521 } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08005522 mSelectX = mScrollX + mLastTouchX;
5523 mSelectY = mScrollY + mLastTouchY;
Cary Clark09e383c2009-10-26 16:43:58 -04005524 } else {
5525 mSelectX = mScrollX + getViewWidth() / 2;
5526 mSelectY = mScrollY + getViewHeightWithTitle() / 2;
5527 }
5528 nativeHideCursor();
Cary Clarkb9aaa772011-01-07 16:14:54 -05005529 mMinAutoScrollX = 0;
5530 mMaxAutoScrollX = getViewWidth();
5531 mMinAutoScrollY = 0;
5532 mMaxAutoScrollY = getViewHeightWithTitle();
Michael Kolb5da91bd2011-11-29 15:29:03 -08005533 mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX),
Cary Clarkb9aaa772011-01-07 16:14:54 -05005534 viewToContentY(mSelectY), mScrollingLayerRect,
5535 mScrollingLayerBounds);
Michael Kolb5da91bd2011-11-29 15:29:03 -08005536 if (mCurrentScrollingLayerId != 0) {
Cary Clarkb9aaa772011-01-07 16:14:54 -05005537 if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
5538 mMinAutoScrollX = Math.max(mMinAutoScrollX,
5539 contentToViewX(mScrollingLayerBounds.left));
5540 mMaxAutoScrollX = Math.min(mMaxAutoScrollX,
5541 contentToViewX(mScrollingLayerBounds.right));
5542 }
5543 if (mScrollingLayerRect.top != mScrollingLayerRect.bottom) {
5544 mMinAutoScrollY = Math.max(mMinAutoScrollY,
5545 contentToViewY(mScrollingLayerBounds.top));
5546 mMaxAutoScrollY = Math.min(mMaxAutoScrollY,
5547 contentToViewY(mScrollingLayerBounds.bottom));
5548 }
5549 }
5550 mMinAutoScrollX += SELECT_SCROLL;
5551 mMaxAutoScrollX -= SELECT_SCROLL;
5552 mMinAutoScrollY += SELECT_SCROLL;
5553 mMaxAutoScrollY -= SELECT_SCROLL;
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005554 return true;
Cary Clark09e383c2009-10-26 16:43:58 -04005555 }
5556
Cary Clark966641a2010-03-04 08:41:56 -05005557 /**
5558 * Use this method to put the WebView into text selection mode.
5559 * Do not rely on this functionality; it will be deprecated in the future.
Kristian Monsenfc771652011-05-10 16:44:05 +01005560 * @deprecated This method is now obsolete.
Cary Clark966641a2010-03-04 08:41:56 -05005561 */
Kristian Monsenfc771652011-05-10 16:44:05 +01005562 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005563 public void emulateShiftHeld() {
Steve Block51b08912011-04-27 15:04:48 +01005564 checkThread();
Cary Clark03f00222011-02-10 19:37:15 -05005565 setUpSelect(false, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005566 }
5567
Cary Clark924af702010-06-04 16:37:43 -04005568 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005569 * Select all of the text in this WebView.
Cary Clark2cdee232010-12-29 14:59:24 -05005570 *
5571 * @hide pending API council approval.
Cary Clark924af702010-06-04 16:37:43 -04005572 */
Cary Clark2cdee232010-12-29 14:59:24 -05005573 public void selectAll() {
Cary Clark924af702010-06-04 16:37:43 -04005574 if (0 == mNativeClass) return; // client isn't initialized
5575 if (inFullScreenMode()) return;
Cary Clark2cdee232010-12-29 14:59:24 -05005576 if (!mSelectingText) {
5577 // retrieve a point somewhere within the text
5578 Point select = nativeSelectableText();
5579 if (!selectText(select.x, select.y)) return;
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005580 }
Cary Clark924af702010-06-04 16:37:43 -04005581 nativeSelectAll();
5582 mDrawSelectionPointer = false;
5583 mExtendSelection = true;
5584 invalidate();
5585 }
5586
5587 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005588 * Called when the selection has been removed.
Cary Clark924af702010-06-04 16:37:43 -04005589 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005590 void selectionDone() {
Cary Clark924af702010-06-04 16:37:43 -04005591 if (mSelectingText) {
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005592 mSelectingText = false;
John Reckeffabe82011-10-27 09:09:36 -07005593 if (DEBUG_TEXT_HANDLES) {
5594 // Debugging text handles required running in software mode, set
5595 // back to default now
5596 setLayerType(LAYER_TYPE_NONE, null);
5597 }
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005598 // finish is idempotent, so this is fine even if selectionDone was
5599 // called by mSelectCallback.onDestroyActionMode
5600 mSelectCallback.finish();
5601 mSelectCallback = null;
Cary Clark0df02692010-11-24 11:01:37 -05005602 WebViewCore.resumePriority();
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005603 WebViewCore.resumeUpdatePicture(mWebViewCore);
Cary Clark924af702010-06-04 16:37:43 -04005604 invalidate(); // redraw without selection
Cary Clark6f5dfc62010-11-11 13:09:20 -05005605 mAutoScrollX = 0;
5606 mAutoScrollY = 0;
5607 mSentAutoScrollMessage = false;
Cary Clark924af702010-06-04 16:37:43 -04005608 }
5609 }
5610
5611 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005612 * Copy the selection to the clipboard
Cary Clark2cdee232010-12-29 14:59:24 -05005613 *
5614 * @hide pending API council approval.
Cary Clark924af702010-06-04 16:37:43 -04005615 */
Cary Clark2cdee232010-12-29 14:59:24 -05005616 public boolean copySelection() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005617 boolean copiedSomething = false;
Cary Clark924af702010-06-04 16:37:43 -04005618 String selection = getSelection();
Cary Clark7170bb62011-01-12 10:12:15 -05005619 if (selection != null && selection != "") {
Cary Clark924af702010-06-04 16:37:43 -04005620 if (DebugFlags.WEB_VIEW) {
5621 Log.v(LOGTAG, "copySelection \"" + selection + "\"");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005622 }
Cary Clark924af702010-06-04 16:37:43 -04005623 Toast.makeText(mContext
5624 , com.android.internal.R.string.text_copied
5625 , Toast.LENGTH_SHORT).show();
5626 copiedSomething = true;
Dianne Hackborn90d5e8c2010-08-05 13:47:55 -07005627 ClipboardManager cm = (ClipboardManager)getContext()
5628 .getSystemService(Context.CLIPBOARD_SERVICE);
5629 cm.setText(selection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005630 }
Cary Clark09e383c2009-10-26 16:43:58 -04005631 invalidate(); // remove selection region and pointer
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005632 return copiedSomething;
5633 }
5634
Cary Clark924af702010-06-04 16:37:43 -04005635 /**
Narayan Kamath9497c5f2011-02-22 12:05:34 +00005636 * @hide pending API Council approval.
5637 */
5638 public SearchBox getSearchBox() {
Michael Kolbb7481862011-03-03 17:09:19 -08005639 if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
5640 return null;
5641 }
Narayan Kamath9497c5f2011-02-22 12:05:34 +00005642 return mWebViewCore.getBrowserFrame().getSearchBox();
5643 }
5644
5645 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005646 * Returns the currently highlighted text as a string.
Cary Clark924af702010-06-04 16:37:43 -04005647 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005648 String getSelection() {
Cary Clark924af702010-06-04 16:37:43 -04005649 if (mNativeClass == 0) return "";
5650 return nativeGetSelection();
5651 }
5652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005653 @Override
5654 protected void onAttachedToWindow() {
5655 super.onAttachedToWindow();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005656 if (hasWindowFocus()) setActive(true);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005657 final ViewTreeObserver treeObserver = getViewTreeObserver();
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005658 if (mGlobalLayoutListener == null) {
5659 mGlobalLayoutListener = new InnerGlobalLayoutListener();
5660 treeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener);
5661 }
5662 if (mScrollChangedListener == null) {
5663 mScrollChangedListener = new InnerScrollChangedListener();
5664 treeObserver.addOnScrollChangedListener(mScrollChangedListener);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005665 }
Svetoslav Ganov4acac232011-02-02 15:22:24 -08005666
5667 addAccessibilityApisToJavaScript();
Adam Powell4fb35d42011-03-03 17:54:55 -08005668
5669 mTouchEventQueue.reset();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005670 }
5671
5672 @Override
5673 protected void onDetachedFromWindow() {
Leon Scroggins05919f22010-09-14 17:22:36 -04005674 clearHelpers();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005675 mZoomManager.dismissZoomPicker();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005676 if (hasWindowFocus()) setActive(false);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005677
5678 final ViewTreeObserver treeObserver = getViewTreeObserver();
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005679 if (mGlobalLayoutListener != null) {
5680 treeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
5681 mGlobalLayoutListener = null;
5682 }
5683 if (mScrollChangedListener != null) {
5684 treeObserver.removeOnScrollChangedListener(mScrollChangedListener);
5685 mScrollChangedListener = null;
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005686 }
5687
Svetoslav Ganov4acac232011-02-02 15:22:24 -08005688 removeAccessibilityApisFromJavaScript();
5689
Grace Kloba378f0282010-03-26 15:01:30 -07005690 super.onDetachedFromWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005692
Steve Howard16bd9372010-04-12 14:46:09 -07005693 @Override
5694 protected void onVisibilityChanged(View changedView, int visibility) {
5695 super.onVisibilityChanged(changedView, visibility);
Derek Sollenbergerf39d2662010-06-24 16:41:04 -04005696 // The zoomManager may be null if the webview is created from XML that
5697 // specifies the view's visibility param as not visible (see http://b/2794841)
5698 if (visibility != View.VISIBLE && mZoomManager != null) {
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005699 mZoomManager.dismissZoomPicker();
Steve Howard16bd9372010-04-12 14:46:09 -07005700 }
John Reck5f1c5492011-11-09 16:23:07 -08005701 updateDrawingState();
Steve Howard16bd9372010-04-12 14:46:09 -07005702 }
5703
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005704 /**
5705 * @deprecated WebView no longer needs to implement
5706 * ViewGroup.OnHierarchyChangeListener. This method does nothing now.
5707 */
5708 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005709 public void onChildViewAdded(View parent, View child) {}
Cary Clarkd6982c92009-05-29 11:02:22 -04005710
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005711 /**
5712 * @deprecated WebView no longer needs to implement
5713 * ViewGroup.OnHierarchyChangeListener. This method does nothing now.
5714 */
5715 @Deprecated
5716 public void onChildViewRemoved(View p, View child) {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005717
5718 /**
5719 * @deprecated WebView should not have implemented
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005720 * ViewTreeObserver.OnGlobalFocusChangeListener. This method does nothing now.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005721 */
5722 @Deprecated
5723 public void onGlobalFocusChanged(View oldFocus, View newFocus) {
5724 }
5725
Leon Scroggins40777232011-01-18 16:49:20 -05005726 void setActive(boolean active) {
Grace Kloba9b95ab12010-04-01 16:07:30 -07005727 if (active) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005728 if (hasFocus()) {
5729 // If our window regained focus, and we have focus, then begin
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005730 // drawing the cursor ring
Michael Kolbedb39ce2011-11-17 10:17:28 -08005731 mDrawCursorRing = !inEditingMode();
Leon Scroggins2aed7762010-08-13 17:11:42 -04005732 setFocusControllerActive(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005733 } else {
Michael Kolbedb39ce2011-11-17 10:17:28 -08005734 mDrawCursorRing = false;
Leon Scroggins2aed7762010-08-13 17:11:42 -04005735 if (!inEditingMode()) {
5736 // If our window gained focus, but we do not have it, do not
5737 // draw the cursor ring.
Leon Scroggins2aed7762010-08-13 17:11:42 -04005738 setFocusControllerActive(false);
5739 }
John Reckbdfb3c52011-09-21 18:20:30 -07005740 // We do not call recordButtons here because we assume
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005741 // that when we lost focus, or window focus, it got called with
5742 // false for the first parameter
5743 }
5744 } else {
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005745 if (!mZoomManager.isZoomPickerVisible()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005746 /*
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005747 * The external zoom controls come in their own window, so our
5748 * window loses focus. Our policy is to not draw the cursor ring
5749 * if our window is not focused, but this is an exception since
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005750 * the user can still navigate the web page with the zoom
5751 * controls showing.
5752 */
Cary Clarkd6982c92009-05-29 11:02:22 -04005753 mDrawCursorRing = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005754 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005755 mKeysPressed.clear();
Grace Kloba378f0282010-03-26 15:01:30 -07005756 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
5757 mTouchMode = TOUCH_DONE_MODE;
Leon Scroggins2aed7762010-08-13 17:11:42 -04005758 setFocusControllerActive(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005759 }
5760 invalidate();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005761 }
5762
5763 // To avoid drawing the cursor ring, and remove the TextView when our window
5764 // loses focus.
5765 @Override
5766 public void onWindowFocusChanged(boolean hasWindowFocus) {
5767 setActive(hasWindowFocus);
5768 if (hasWindowFocus) {
Patrick Scott8a5d3352010-08-18 11:00:42 -04005769 JWebCoreJavaBridge.setActiveWebView(this);
Adam Powellf4f520a2011-09-13 20:16:32 -07005770 if (mPictureUpdatePausedForFocusChange) {
Adam Powelle00e8a782011-09-11 17:48:42 -07005771 WebViewCore.resumeUpdatePicture(mWebViewCore);
Adam Powelle00e8a782011-09-11 17:48:42 -07005772 mPictureUpdatePausedForFocusChange = false;
5773 }
Grace Kloba9b95ab12010-04-01 16:07:30 -07005774 } else {
Patrick Scott8a5d3352010-08-18 11:00:42 -04005775 JWebCoreJavaBridge.removeActiveWebView(this);
Adam Powelle00e8a782011-09-11 17:48:42 -07005776 final WebSettings settings = getSettings();
Adam Powellf4f520a2011-09-13 20:16:32 -07005777 if (settings != null && settings.enableSmoothTransition() &&
Adam Powelle00e8a782011-09-11 17:48:42 -07005778 mWebViewCore != null && !WebViewCore.isUpdatePicturePaused(mWebViewCore)) {
5779 WebViewCore.pauseUpdatePicture(mWebViewCore);
Adam Powelle00e8a782011-09-11 17:48:42 -07005780 mPictureUpdatePausedForFocusChange = true;
5781 }
Grace Kloba9b95ab12010-04-01 16:07:30 -07005782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005783 super.onWindowFocusChanged(hasWindowFocus);
5784 }
5785
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005786 /*
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005787 * Pass a message to WebCore Thread, telling the WebCore::Page's
5788 * FocusController to be "inactive" so that it will
5789 * not draw the blinking cursor. It gets set to "active" to draw the cursor
5790 * in WebViewCore.cpp, when the WebCore thread receives key events/clicks.
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005791 */
Leon Scroggins2aed7762010-08-13 17:11:42 -04005792 /* package */ void setFocusControllerActive(boolean active) {
5793 if (mWebViewCore == null) return;
5794 mWebViewCore.sendMessage(EventHub.SET_ACTIVE, active ? 1 : 0, 0);
Leon Scroggins244d2d42010-12-06 16:29:38 -05005795 // Need to send this message after the document regains focus.
5796 if (active && mListBoxMessage != null) {
5797 mWebViewCore.sendMessage(mListBoxMessage);
5798 mListBoxMessage = null;
5799 }
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005800 }
5801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005802 @Override
5803 protected void onFocusChanged(boolean focused, int direction,
5804 Rect previouslyFocusedRect) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005805 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005806 Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction);
5807 }
5808 if (focused) {
5809 // When we regain focus, if we have window focus, resume drawing
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005810 // the cursor ring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005811 if (hasWindowFocus()) {
Michael Kolbedb39ce2011-11-17 10:17:28 -08005812 mDrawCursorRing = !inEditingMode();
Leon Scroggins2aed7762010-08-13 17:11:42 -04005813 setFocusControllerActive(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005814 //} else {
5815 // The WebView has gained focus while we do not have
5816 // windowfocus. When our window lost focus, we should have
John Reckbdfb3c52011-09-21 18:20:30 -07005817 // called recordButtons(false...)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005818 }
5819 } else {
5820 // When we lost focus, unless focus went to the TextView (which is
Cary Clarkd6982c92009-05-29 11:02:22 -04005821 // true if we are in editing mode), stop drawing the cursor ring.
Michael Kolbedb39ce2011-11-17 10:17:28 -08005822 mDrawCursorRing = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005823 if (!inEditingMode()) {
Leon Scrogginsb4ffd112011-01-24 17:43:47 -05005824 setFocusControllerActive(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005825 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005826 mKeysPressed.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005827 }
5828
5829 super.onFocusChanged(focused, direction, previouslyFocusedRect);
5830 }
5831
Nicolas Roard12c18e62010-10-13 20:14:31 -07005832 void setGLRectViewport() {
Teng-Hui Zhue6fb0f12010-11-23 16:37:45 -08005833 // Use the getGlobalVisibleRect() to get the intersection among the parents
Chet Haase91fc3cf2011-01-28 00:20:04 -08005834 // visible == false means we're clipped - send a null rect down to indicate that
5835 // we should not draw
5836 boolean visible = getGlobalVisibleRect(mGLRectViewport);
5837 if (visible) {
5838 // Then need to invert the Y axis, just for GL
5839 View rootView = getRootView();
5840 int rootViewHeight = rootView.getHeight();
Romain Guycabfcc12011-03-07 18:06:46 -08005841 mViewRectViewport.set(mGLRectViewport);
Chet Haase91fc3cf2011-01-28 00:20:04 -08005842 int savedWebViewBottom = mGLRectViewport.bottom;
Steve Block92c99162011-05-23 17:36:01 +01005843 mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeightImpl();
Chet Haase91fc3cf2011-01-28 00:20:04 -08005844 mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
5845 mGLViewportEmpty = false;
5846 } else {
5847 mGLViewportEmpty = true;
5848 }
George Mount82ed95f2011-11-15 11:27:47 -08005849 calcOurContentVisibleRectF(mVisibleContentRect);
Romain Guycabfcc12011-03-07 18:06:46 -08005850 nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
George Mount5d3f6e62011-12-05 15:19:00 -08005851 mGLViewportEmpty ? null : mViewRectViewport,
5852 mVisibleContentRect);
Nicolas Roard12c18e62010-10-13 20:14:31 -07005853 }
5854
Grace Kloba3f9faf42009-10-13 14:13:54 -07005855 /**
5856 * @hide
5857 */
5858 @Override
5859 protected boolean setFrame(int left, int top, int right, int bottom) {
5860 boolean changed = super.setFrame(left, top, right, bottom);
5861 if (!changed && mHeightCanMeasure) {
5862 // When mHeightCanMeasure is true, we will set mLastHeightSent to 0
5863 // in WebViewCore after we get the first layout. We do call
5864 // requestLayout() when we get contentSizeChanged(). But the View
5865 // system won't call onSizeChanged if the dimension is not changed.
5866 // In this case, we need to call sendViewSizeZoom() explicitly to
5867 // notify the WebKit about the new dimensions.
Derek Sollenberger03e48912010-05-18 17:03:42 -04005868 sendViewSizeZoom(false);
Grace Kloba3f9faf42009-10-13 14:13:54 -07005869 }
Nicolas Roard12c18e62010-10-13 20:14:31 -07005870 setGLRectViewport();
Grace Kloba3f9faf42009-10-13 14:13:54 -07005871 return changed;
5872 }
5873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005874 @Override
5875 protected void onSizeChanged(int w, int h, int ow, int oh) {
5876 super.onSizeChanged(w, h, ow, oh);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005877
Grace Klobaa4fa1072009-11-09 12:01:50 -08005878 // adjust the max viewport width depending on the view dimensions. This
5879 // is to ensure the scaling is not going insane. So do not shrink it if
5880 // the view size is temporarily smaller, e.g. when soft keyboard is up.
Derek Sollenberger4aef6972010-06-24 15:03:43 -04005881 int newMaxViewportWidth = (int) (Math.max(w, h) / mZoomManager.getDefaultMinZoomScale());
Grace Klobaa4fa1072009-11-09 12:01:50 -08005882 if (newMaxViewportWidth > sMaxViewportWidth) {
5883 sMaxViewportWidth = newMaxViewportWidth;
5884 }
5885
Derek Sollenberger341e22f2010-06-02 12:34:34 -04005886 mZoomManager.onSizeChanged(w, h, ow, oh);
John Reck60c84d62011-06-08 18:00:02 -07005887
5888 if (mLoadedPicture != null && mDelaySetPicture == null) {
5889 // Size changes normally result in a new picture
5890 // Re-set the loaded picture to simulate that
5891 // However, do not update the base layer as that hasn't changed
5892 setNewPicture(mLoadedPicture, false);
5893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005894 }
5895
5896 @Override
5897 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
5898 super.onScrollChanged(l, t, oldl, oldt);
Adam Powell637d3372010-08-25 14:37:03 -07005899 if (!mInOverScrollMode) {
5900 sendOurVisibleRect();
5901 // update WebKit if visible title bar height changed. The logic is same
Steve Block92c99162011-05-23 17:36:01 +01005902 // as getVisibleTitleHeightImpl.
Adam Powell637d3372010-08-25 14:37:03 -07005903 int titleHeight = getTitleHeight();
5904 if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
5905 sendViewSizeZoom(false);
5906 }
Mike Reedb64f6f82010-03-23 10:29:37 -04005907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005908 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005910 @Override
5911 public boolean dispatchKeyEvent(KeyEvent event) {
Leon Scroggins115626a2011-02-17 12:00:48 -05005912 switch (event.getAction()) {
5913 case KeyEvent.ACTION_DOWN:
5914 mKeysPressed.add(Integer.valueOf(event.getKeyCode()));
5915 break;
5916 case KeyEvent.ACTION_MULTIPLE:
5917 // Always accept the action.
5918 break;
5919 case KeyEvent.ACTION_UP:
5920 int location = mKeysPressed.indexOf(Integer.valueOf(event.getKeyCode()));
5921 if (location == -1) {
5922 // We did not receive the key down for this key, so do not
5923 // handle the key up.
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005924 return false;
Leon Scroggins115626a2011-02-17 12:00:48 -05005925 } else {
5926 // We did receive the key down. Handle the key up, and
5927 // remove it from our pressed keys.
5928 mKeysPressed.remove(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005929 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005930 break;
5931 default:
5932 // Accept the action. This should not happen, unless a new
5933 // action is added to KeyEvent.
5934 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005935 }
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005936 if (inEditingMode() && mWebTextView.isFocused()) {
5937 // Ensure that the WebTextView gets the event, even if it does
5938 // not currently have a bounds.
5939 return mWebTextView.dispatchKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005940 } else {
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005941 return super.dispatchKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005942 }
5943 }
5944
John Reck75738722011-06-10 11:28:53 -07005945 /*
5946 * Here is the snap align logic:
5947 * 1. If it starts nearly horizontally or vertically, snap align;
5948 * 2. If there is a dramitic direction change, let it go;
5949 *
5950 * Adjustable parameters. Angle is the radians on a unit circle, limited
5951 * to quadrant 1. Values range from 0f (horizontal) to PI/2 (vertical)
5952 */
John Reck2664d852011-06-13 10:37:15 -07005953 private static final float HSLOPE_TO_START_SNAP = .25f;
5954 private static final float HSLOPE_TO_BREAK_SNAP = .4f;
John Reck75738722011-06-10 11:28:53 -07005955 private static final float VSLOPE_TO_START_SNAP = 1.25f;
5956 private static final float VSLOPE_TO_BREAK_SNAP = .95f;
5957 /*
5958 * These values are used to influence the average angle when entering
5959 * snap mode. If is is the first movement entering snap, we set the average
5960 * to the appropriate ideal. If the user is entering into snap after the
5961 * first movement, then we average the average angle with these values.
5962 */
5963 private static final float ANGLE_VERT = 2f;
5964 private static final float ANGLE_HORIZ = 0f;
John Reck2664d852011-06-13 10:37:15 -07005965 /*
5966 * The modified moving average weight.
5967 * Formula: MAV[t]=MAV[t-1] + (P[t]-MAV[t-1])/n
5968 */
5969 private static final float MMA_WEIGHT_N = 5;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005970
Grace Klobac2242f22010-03-05 14:00:26 -08005971 private boolean hitFocusedPlugin(int contentX, int contentY) {
Cary Clarke84a0db2010-03-17 15:58:20 -04005972 if (DebugFlags.WEB_VIEW) {
5973 Log.v(LOGTAG, "nativeFocusIsPlugin()=" + nativeFocusIsPlugin());
5974 Rect r = nativeFocusNodeBounds();
5975 Log.v(LOGTAG, "nativeFocusNodeBounds()=(" + r.left + ", " + r.top
5976 + ", " + r.right + ", " + r.bottom + ")");
5977 }
Grace Klobac2242f22010-03-05 14:00:26 -08005978 return nativeFocusIsPlugin()
Cary Clarke84a0db2010-03-17 15:58:20 -04005979 && nativeFocusNodeBounds().contains(contentX, contentY);
Grace Klobac2242f22010-03-05 14:00:26 -08005980 }
5981
5982 private boolean shouldForwardTouchEvent() {
John Reck95b7d6f2011-06-03 15:23:43 -07005983 if (mFullScreenHolder != null) return true;
5984 if (mBlockWebkitViewMessages) return false;
5985 return mForwardTouchEvents
Cary Clark924af702010-06-04 16:37:43 -04005986 && !mSelectingText
Adam Powella0def722011-03-14 17:54:10 -07005987 && mPreventDefault != PREVENT_DEFAULT_IGNORE
John Reck95b7d6f2011-06-03 15:23:43 -07005988 && mPreventDefault != PREVENT_DEFAULT_NO;
Grace Klobac2242f22010-03-05 14:00:26 -08005989 }
5990
5991 private boolean inFullScreenMode() {
5992 return mFullScreenHolder != null;
5993 }
5994
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04005995 private void dismissFullScreenMode() {
5996 if (inFullScreenMode()) {
Derek Sollenberger7ab3d672011-06-01 14:45:05 -04005997 mFullScreenHolder.hide();
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04005998 mFullScreenHolder = null;
George Mount5d3f6e62011-12-05 15:19:00 -08005999 invalidate();
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04006000 }
6001 }
6002
Derek Sollenberger293c3602010-06-04 10:44:48 -04006003 void onPinchToZoomAnimationStart() {
6004 // cancel the single touch handling
6005 cancelTouch();
6006 onZoomAnimationStart();
6007 }
6008
6009 void onPinchToZoomAnimationEnd(ScaleGestureDetector detector) {
6010 onZoomAnimationEnd();
6011 // start a drag, TOUCH_PINCH_DRAG, can't use TOUCH_INIT_MODE as
6012 // it may trigger the unwanted click, can't use TOUCH_DRAG_MODE
6013 // as it may trigger the unwanted fling.
6014 mTouchMode = TOUCH_PINCH_DRAG;
6015 mConfirmMove = true;
6016 startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime);
6017 }
6018
Patrick Scott62310912010-12-06 17:44:50 -05006019 // See if there is a layer at x, y and switch to TOUCH_DRAG_LAYER_MODE if a
6020 // layer is found.
Patrick Scott4b903782010-11-30 08:14:05 -05006021 private void startScrollingLayer(float x, float y) {
Patrick Scott62310912010-12-06 17:44:50 -05006022 int contentX = viewToContentX((int) x + mScrollX);
6023 int contentY = viewToContentY((int) y + mScrollY);
Michael Kolb5da91bd2011-11-29 15:29:03 -08006024 mCurrentScrollingLayerId = nativeScrollableLayer(contentX, contentY,
Cary Clarkb9aaa772011-01-07 16:14:54 -05006025 mScrollingLayerRect, mScrollingLayerBounds);
Michael Kolb5da91bd2011-11-29 15:29:03 -08006026 if (mCurrentScrollingLayerId != 0) {
Patrick Scott62310912010-12-06 17:44:50 -05006027 mTouchMode = TOUCH_DRAG_LAYER_MODE;
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006028 }
6029 }
6030
6031 // 1/(density * density) used to compute the distance between points.
6032 // Computed in init().
6033 private float DRAG_LAYER_INVERSE_DENSITY_SQUARED;
6034
6035 // The distance between two points reported in onTouchEvent scaled by the
6036 // density of the screen.
6037 private static final int DRAG_LAYER_FINGER_DISTANCE = 20000;
6038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006039 @Override
Svetoslav Ganov7882a782011-05-11 17:53:01 -07006040 public boolean onHoverEvent(MotionEvent event) {
6041 if (mNativeClass == 0) {
6042 return false;
6043 }
6044 WebViewCore.CursorData data = cursorDataNoPosition();
Svetoslav Ganovfbb15602011-06-21 17:51:36 -07006045 data.mX = viewToContentX((int) event.getX() + mScrollX);
6046 data.mY = viewToContentY((int) event.getY() + mScrollY);
Svetoslav Ganov7882a782011-05-11 17:53:01 -07006047 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
6048 return true;
6049 }
6050
6051 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006052 public boolean onTouchEvent(MotionEvent ev) {
Andy Stadlerb34fd1ff2010-09-27 15:51:09 -07006053 if (mNativeClass == 0 || (!isClickable() && !isLongClickable())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006054 return false;
6055 }
6056
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006057 if (DebugFlags.WEB_VIEW) {
Huahui Wu41865f42010-09-02 13:41:41 -07006058 Log.v(LOGTAG, ev + " at " + ev.getEventTime()
6059 + " mTouchMode=" + mTouchMode
6060 + " numPointers=" + ev.getPointerCount());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006061 }
6062
Adam Powell4fb35d42011-03-03 17:54:55 -08006063 // If WebKit wasn't interested in this multitouch gesture, enqueue
6064 // the event for handling directly rather than making the round trip
6065 // to WebKit and back.
6066 if (ev.getPointerCount() > 1 && mPreventDefault != PREVENT_DEFAULT_NO) {
6067 passMultiTouchToWebKit(ev, mTouchEventQueue.nextTouchSequence());
Adam Powelle33cef82011-02-23 16:51:20 -08006068 } else {
Adam Powell4fb35d42011-03-03 17:54:55 -08006069 mTouchEventQueue.enqueueTouchEvent(ev);
Huahui Wu41865f42010-09-02 13:41:41 -07006070 }
6071
Adam Powell4fb35d42011-03-03 17:54:55 -08006072 // Since all events are handled asynchronously, we always want the gesture stream.
6073 return true;
Huahui Wu0904c0d2011-01-07 17:30:53 -08006074 }
Patrick Scott4b903782010-11-30 08:14:05 -05006075
John Reck75738722011-06-10 11:28:53 -07006076 private float calculateDragAngle(int dx, int dy) {
6077 dx = Math.abs(dx);
6078 dy = Math.abs(dy);
6079 return (float) Math.atan2(dy, dx);
6080 }
6081
Huahui Wuf147d452011-01-12 14:02:36 -08006082 /*
6083 * Common code for single touch and multi-touch.
6084 * (x, y) denotes current focus point, which is the touch point for single touch
6085 * and the middle point for multi-touch.
6086 */
Huahui Wu1f301252011-01-19 17:32:32 -08006087 private boolean handleTouchEventCommon(MotionEvent ev, int action, int x, int y) {
Huahui Wu0904c0d2011-01-07 17:30:53 -08006088 long eventTime = ev.getEventTime();
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006090 // Due to the touch screen edge effect, a touch closer to the edge
6091 // always snapped to the edge. As getViewWidth() can be different from
6092 // getWidth() due to the scrollbar, adjusting the point to match
6093 // getViewWidth(). Same applied to the height.
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006094 x = Math.min(x, getViewWidth() - 1);
6095 y = Math.min(y, getViewHeightWithTitle() - 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006096
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006097 int deltaX = mLastTouchX - x;
6098 int deltaY = mLastTouchY - y;
6099 int contentX = viewToContentX(x + mScrollX);
6100 int contentY = viewToContentY(y + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006101
6102 switch (action) {
6103 case MotionEvent.ACTION_DOWN: {
Grace Klobac2242f22010-03-05 14:00:26 -08006104 mPreventDefault = PREVENT_DEFAULT_NO;
6105 mConfirmMove = false;
Cary Clarkb8491342010-11-29 16:23:19 -05006106 mInitialHitTestResult = null;
Grace Kloba04b28682009-09-14 14:38:37 -07006107 if (!mScroller.isFinished()) {
Cary Clark278ce052009-08-31 16:08:42 -04006108 // stop the current scroll animation, but if this is
6109 // the start of a fling, allow it to add to the current
6110 // fling's velocity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006111 mScroller.abortAnimation();
6112 mTouchMode = TOUCH_DRAG_START_MODE;
Grace Klobac2242f22010-03-05 14:00:26 -08006113 mConfirmMove = true;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006114 nativeSetIsScrolling(false);
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006115 } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
6116 mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
John Reck335f4542011-08-25 18:25:09 -07006117 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
6118 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07006119 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006120 if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
6121 mTouchMode = TOUCH_DOUBLE_TAP_MODE;
6122 } else {
6123 // commit the short press action for the previous tap
6124 doShortPress();
Grace Klobac2242f22010-03-05 14:00:26 -08006125 mTouchMode = TOUCH_INIT_MODE;
John Reck95b7d6f2011-06-03 15:23:43 -07006126 mDeferTouchProcess = !mBlockWebkitViewMessages
6127 && (!inFullScreenMode() && mForwardTouchEvents)
6128 ? hitFocusedPlugin(contentX, contentY)
6129 : false;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006130 }
Grace Klobac2242f22010-03-05 14:00:26 -08006131 } else { // the normal case
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006132 mTouchMode = TOUCH_INIT_MODE;
John Reck95b7d6f2011-06-03 15:23:43 -07006133 mDeferTouchProcess = !mBlockWebkitViewMessages
6134 && (!inFullScreenMode() && mForwardTouchEvents)
6135 ? hitFocusedPlugin(contentX, contentY)
6136 : false;
6137 if (!mBlockWebkitViewMessages) {
6138 mWebViewCore.sendMessage(
6139 EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
6140 }
John Reck335f4542011-08-25 18:25:09 -07006141 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
Grace Kloba178db412010-05-18 22:22:23 -07006142 TouchHighlightData data = new TouchHighlightData();
6143 data.mX = contentX;
6144 data.mY = contentY;
John Reck335f4542011-08-25 18:25:09 -07006145 data.mNativeLayerRect = new Rect();
6146 data.mNativeLayer = nativeScrollableLayer(
6147 contentX, contentY, data.mNativeLayerRect, null);
Grace Kloba178db412010-05-18 22:22:23 -07006148 data.mSlop = viewToContentDimension(mNavSlop);
John Reck335f4542011-08-25 18:25:09 -07006149 mTouchHighlightRegion.setEmpty();
John Reck95b7d6f2011-06-03 15:23:43 -07006150 if (!mBlockWebkitViewMessages) {
John Reck335f4542011-08-25 18:25:09 -07006151 mTouchHighlightRequested = System.currentTimeMillis();
6152 mWebViewCore.sendMessageAtFrontOfQueue(
6153 EventHub.GET_TOUCH_HIGHLIGHT_RECTS, data);
John Reck95b7d6f2011-06-03 15:23:43 -07006154 }
Grace Kloba178db412010-05-18 22:22:23 -07006155 if (DEBUG_TOUCH_HIGHLIGHT) {
6156 if (getSettings().getNavDump()) {
6157 mTouchHighlightX = (int) x + mScrollX;
6158 mTouchHighlightY = (int) y + mScrollY;
6159 mPrivateHandler.postDelayed(new Runnable() {
6160 public void run() {
6161 mTouchHighlightX = mTouchHighlightY = 0;
6162 invalidate();
6163 }
6164 }, TOUCH_HIGHLIGHT_ELAPSE_TIME);
6165 }
6166 }
6167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006168 if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
Dan Egnor18e93962010-02-10 19:27:58 -08006169 EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006170 (eventTime - mLastTouchUpTime), eventTime);
6171 }
Cary Clark924af702010-06-04 16:37:43 -04006172 if (mSelectingText) {
6173 mDrawSelectionPointer = false;
6174 mSelectionStarted = nativeStartSelection(contentX, contentY);
6175 if (DebugFlags.WEB_VIEW) {
6176 Log.v(LOGTAG, "select=" + contentX + "," + contentY);
6177 }
6178 invalidate();
6179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006180 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07006181 // Trigger the link
Cary Clark43f608f2011-02-18 11:30:12 -05006182 if (!mSelectingText && (mTouchMode == TOUCH_INIT_MODE
6183 || mTouchMode == TOUCH_DOUBLE_TAP_MODE)) {
Grace Klobac2242f22010-03-05 14:00:26 -08006184 mPrivateHandler.sendEmptyMessageDelayed(
6185 SWITCH_TO_SHORTPRESS, TAP_TIMEOUT);
6186 mPrivateHandler.sendEmptyMessageDelayed(
6187 SWITCH_TO_LONGPRESS, LONG_PRESS_TIMEOUT);
6188 if (inFullScreenMode() || mDeferTouchProcess) {
6189 mPreventDefault = PREVENT_DEFAULT_YES;
John Reck95b7d6f2011-06-03 15:23:43 -07006190 } else if (!mBlockWebkitViewMessages && mForwardTouchEvents) {
Grace Klobac2242f22010-03-05 14:00:26 -08006191 mPreventDefault = PREVENT_DEFAULT_MAYBE_YES;
6192 } else {
6193 mPreventDefault = PREVENT_DEFAULT_NO;
6194 }
6195 // pass the touch events from UI thread to WebCore thread
6196 if (shouldForwardTouchEvent()) {
Huahui Wu98933f32011-07-07 14:27:44 -07006197 TouchEventData ted = new TouchEventData();
Grace Klobac2242f22010-03-05 14:00:26 -08006198 ted.mAction = action;
Huahui Wu98933f32011-07-07 14:27:44 -07006199 ted.mIds = new int[1];
6200 ted.mIds[0] = ev.getPointerId(0);
6201 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006202 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006203 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006204 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006205 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006206 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006207 ted.mNativeLayer = nativeScrollableLayer(
6208 contentX, contentY, ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08006209 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006210 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006211 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6212 if (mDeferTouchProcess) {
6213 // still needs to set them for compute deltaX/Y
6214 mLastTouchX = x;
6215 mLastTouchY = y;
6216 break;
6217 }
6218 if (!inFullScreenMode()) {
Ben Murdocha3f055e2010-05-26 18:46:56 +01006219 mPrivateHandler.removeMessages(PREVENT_DEFAULT_TIMEOUT);
Grace Klobac2242f22010-03-05 14:00:26 -08006220 mPrivateHandler.sendMessageDelayed(mPrivateHandler
6221 .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
6222 action, 0), TAP_TIMEOUT);
6223 }
6224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006225 }
Grace Kloba3a0def22010-01-23 21:11:54 -08006226 startTouch(x, y, eventTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006227 break;
6228 }
6229 case MotionEvent.ACTION_MOVE: {
Grace Klobac2242f22010-03-05 14:00:26 -08006230 boolean firstMove = false;
6231 if (!mConfirmMove && (deltaX * deltaX + deltaY * deltaY)
6232 >= mTouchSlopSquare) {
6233 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
6234 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6235 mConfirmMove = true;
6236 firstMove = true;
6237 if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
6238 mTouchMode = TOUCH_INIT_MODE;
6239 }
John Reck335f4542011-08-25 18:25:09 -07006240 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
6241 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07006242 }
Grace Klobac2242f22010-03-05 14:00:26 -08006243 }
6244 // pass the touch events from UI thread to WebCore thread
6245 if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
6246 || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
Huahui Wu98933f32011-07-07 14:27:44 -07006247 TouchEventData ted = new TouchEventData();
Grace Klobac2242f22010-03-05 14:00:26 -08006248 ted.mAction = action;
Huahui Wu98933f32011-07-07 14:27:44 -07006249 ted.mIds = new int[1];
6250 ted.mIds[0] = ev.getPointerId(0);
6251 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006252 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006253 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006254 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006255 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006256 ted.mReprocess = mDeferTouchProcess;
Michael Kolb5da91bd2011-11-29 15:29:03 -08006257 ted.mNativeLayer = mCurrentScrollingLayerId;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006258 ted.mNativeLayerRect.set(mScrollingLayerRect);
Adam Powellae9d2642011-03-08 16:00:30 -08006259 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006260 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006261 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6262 mLastSentTouchTime = eventTime;
6263 if (mDeferTouchProcess) {
6264 break;
6265 }
6266 if (firstMove && !inFullScreenMode()) {
6267 mPrivateHandler.sendMessageDelayed(mPrivateHandler
6268 .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
6269 action, 0), TAP_TIMEOUT);
6270 }
6271 }
6272 if (mTouchMode == TOUCH_DONE_MODE
6273 || mPreventDefault == PREVENT_DEFAULT_YES) {
6274 // no dragging during scroll zoom animation, or when prevent
6275 // default is yes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006276 break;
6277 }
Grace Klobac2242f22010-03-05 14:00:26 -08006278 if (mVelocityTracker == null) {
6279 Log.e(LOGTAG, "Got null mVelocityTracker when "
6280 + "mPreventDefault = " + mPreventDefault
6281 + " mDeferTouchProcess = " + mDeferTouchProcess
6282 + " mTouchMode = " + mTouchMode);
Huahui Wu8465cc92011-01-12 10:17:19 -08006283 } else {
6284 mVelocityTracker.addMovement(ev);
Grace Klobac2242f22010-03-05 14:00:26 -08006285 }
Cary Clark924af702010-06-04 16:37:43 -04006286 if (mSelectingText && mSelectionStarted) {
6287 if (DebugFlags.WEB_VIEW) {
6288 Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006289 }
Leon Scroggins7f7bd522010-11-05 11:23:31 -04006290 ViewParent parent = getParent();
6291 if (parent != null) {
6292 parent.requestDisallowInterceptTouchEvent(true);
6293 }
Cary Clarkb9aaa772011-01-07 16:14:54 -05006294 mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL
6295 : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
6296 mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL
6297 : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
6298 if ((mAutoScrollX != 0 || mAutoScrollY != 0)
6299 && !mSentAutoScrollMessage) {
6300 mSentAutoScrollMessage = true;
6301 mPrivateHandler.sendEmptyMessageDelayed(
6302 SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
Cary Clark6f5dfc62010-11-11 13:09:20 -05006303 }
Cary Clarkaa86ac82010-12-28 11:30:18 -05006304 if (deltaX != 0 || deltaY != 0) {
6305 nativeExtendSelection(contentX, contentY);
6306 invalidate();
6307 }
Cary Clark924af702010-06-04 16:37:43 -04006308 break;
6309 }
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006310
6311 if (mTouchMode != TOUCH_DRAG_MODE &&
6312 mTouchMode != TOUCH_DRAG_LAYER_MODE) {
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07006313
Grace Klobac2242f22010-03-05 14:00:26 -08006314 if (!mConfirmMove) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006315 break;
6316 }
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07006317
Grace Klobac2242f22010-03-05 14:00:26 -08006318 if (mPreventDefault == PREVENT_DEFAULT_MAYBE_YES
6319 || mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
Grace Klobaf58af622009-09-24 17:41:23 -07006320 // track mLastTouchTime as we may need to do fling at
6321 // ACTION_UP
6322 mLastTouchTime = eventTime;
6323 break;
6324 }
Adam Powell048a3a52010-09-08 23:59:37 -07006325
Huahui Wuc0109242011-01-14 12:51:12 -08006326 // Only lock dragging to one axis if we don't have a scale in progress.
6327 // Scaling implies free-roaming movement. Note this is only ever a question
6328 // if mZoomManager.supportsPanDuringZoom() is true.
6329 final ScaleGestureDetector detector =
6330 mZoomManager.getMultiTouchGestureDetector();
John Reck75738722011-06-10 11:28:53 -07006331 mAverageAngle = calculateDragAngle(deltaX, deltaY);
Huahui Wuc0109242011-01-14 12:51:12 -08006332 if (detector == null || !detector.isInProgress()) {
6333 // if it starts nearly horizontal or vertical, enforce it
John Reck75738722011-06-10 11:28:53 -07006334 if (mAverageAngle < HSLOPE_TO_START_SNAP) {
Huahui Wuc0109242011-01-14 12:51:12 -08006335 mSnapScrollMode = SNAP_X;
6336 mSnapPositive = deltaX > 0;
John Reck75738722011-06-10 11:28:53 -07006337 mAverageAngle = ANGLE_HORIZ;
6338 } else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
Huahui Wuc0109242011-01-14 12:51:12 -08006339 mSnapScrollMode = SNAP_Y;
6340 mSnapPositive = deltaY > 0;
John Reck75738722011-06-10 11:28:53 -07006341 mAverageAngle = ANGLE_VERT;
Huahui Wuc0109242011-01-14 12:51:12 -08006342 }
6343 }
6344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006345 mTouchMode = TOUCH_DRAG_MODE;
Romain Guyf7b4acc2009-12-01 16:24:45 -08006346 mLastTouchX = x;
6347 mLastTouchY = y;
Romain Guyf7b4acc2009-12-01 16:24:45 -08006348 deltaX = 0;
6349 deltaY = 0;
6350
Patrick Scott62310912010-12-06 17:44:50 -05006351 startScrollingLayer(x, y);
Grace Klobac2242f22010-03-05 14:00:26 -08006352 startDrag();
6353 }
6354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006355 // do pan
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006356 boolean done = false;
Cary Clark25415e22009-10-12 13:41:28 -04006357 boolean keepScrollBarsVisible = false;
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006358 if (deltaX == 0 && deltaY == 0) {
Cary Clark25415e22009-10-12 13:41:28 -04006359 keepScrollBarsVisible = done = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006360 } else {
John Reck2664d852011-06-13 10:37:15 -07006361 mAverageAngle +=
6362 (calculateDragAngle(deltaX, deltaY) - mAverageAngle)
6363 / MMA_WEIGHT_N;
John Reck75738722011-06-10 11:28:53 -07006364 if (mSnapScrollMode != SNAP_NONE) {
6365 if (mSnapScrollMode == SNAP_Y) {
6366 // radical change means getting out of snap mode
6367 if (mAverageAngle < VSLOPE_TO_BREAK_SNAP) {
6368 mSnapScrollMode = SNAP_NONE;
6369 }
6370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006371 if (mSnapScrollMode == SNAP_X) {
6372 // radical change means getting out of snap mode
John Reck75738722011-06-10 11:28:53 -07006373 if (mAverageAngle > HSLOPE_TO_BREAK_SNAP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006374 mSnapScrollMode = SNAP_NONE;
6375 }
John Reck75738722011-06-10 11:28:53 -07006376 }
6377 } else {
6378 if (mAverageAngle < HSLOPE_TO_START_SNAP) {
6379 mSnapScrollMode = SNAP_X;
6380 mSnapPositive = deltaX > 0;
6381 mAverageAngle = (mAverageAngle + ANGLE_HORIZ) / 2;
6382 } else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
6383 mSnapScrollMode = SNAP_Y;
6384 mSnapPositive = deltaY > 0;
6385 mAverageAngle = (mAverageAngle + ANGLE_VERT) / 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006386 }
6387 }
Cary Clarkac492e12009-10-14 14:53:37 -04006388 if (mSnapScrollMode != SNAP_NONE) {
6389 if ((mSnapScrollMode & SNAP_X) == SNAP_X) {
6390 deltaY = 0;
Grace Kloba5b2c0562009-09-30 10:17:13 -07006391 } else {
Cary Clarkac492e12009-10-14 14:53:37 -04006392 deltaX = 0;
Grace Kloba5b2c0562009-09-30 10:17:13 -07006393 }
Cary Clarkac492e12009-10-14 14:53:37 -04006394 }
John Reck75738722011-06-10 11:28:53 -07006395 mLastTouchX = x;
6396 mLastTouchY = y;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006397
6398 if (deltaX * deltaX + deltaY * deltaY > mTouchSlopSquare) {
Cary Clarkac492e12009-10-14 14:53:37 -04006399 mHeldMotionless = MOTIONLESS_FALSE;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006400 nativeSetIsScrolling(true);
6401 } else {
6402 mHeldMotionless = MOTIONLESS_TRUE;
6403 nativeSetIsScrolling(false);
6404 keepScrollBarsVisible = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006405 }
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006407 mLastTouchTime = eventTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006408 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006409
Grace Klobac2242f22010-03-05 14:00:26 -08006410 doDrag(deltaX, deltaY);
Mike Reed19f3f0e2009-11-12 12:50:20 -05006411
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006412 // Turn off scrollbars when dragging a layer.
6413 if (keepScrollBarsVisible &&
6414 mTouchMode != TOUCH_DRAG_LAYER_MODE) {
Cary Clark25415e22009-10-12 13:41:28 -04006415 if (mHeldMotionless != MOTIONLESS_TRUE) {
6416 mHeldMotionless = MOTIONLESS_TRUE;
6417 invalidate();
6418 }
Grace Kloba5b2c0562009-09-30 10:17:13 -07006419 // keep the scrollbar on the screen even there is no scroll
6420 awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
6421 false);
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006422 // Post a message so that we'll keep them alive while we're not scrolling.
6423 mPrivateHandler.sendMessageDelayed(mPrivateHandler
6424 .obtainMessage(AWAKEN_SCROLL_BARS),
6425 ViewConfiguration.getScrollDefaultDelay());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006426 // return false to indicate that we can't pan out of the
6427 // view space
Cary Clark25415e22009-10-12 13:41:28 -04006428 return !done;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006429 } else {
6430 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006431 }
6432 break;
6433 }
6434 case MotionEvent.ACTION_UP: {
Leon Scroggins IIIae9f8e42010-04-14 16:06:06 -04006435 if (!isFocused()) requestFocus();
Grace Klobac2242f22010-03-05 14:00:26 -08006436 // pass the touch events from UI thread to WebCore thread
6437 if (shouldForwardTouchEvent()) {
Huahui Wu98933f32011-07-07 14:27:44 -07006438 TouchEventData ted = new TouchEventData();
6439 ted.mIds = new int[1];
6440 ted.mIds[0] = ev.getPointerId(0);
Grace Klobac2242f22010-03-05 14:00:26 -08006441 ted.mAction = action;
Huahui Wu98933f32011-07-07 14:27:44 -07006442 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006443 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006444 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006445 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006446 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006447 ted.mReprocess = mDeferTouchProcess;
Michael Kolb5da91bd2011-11-29 15:29:03 -08006448 ted.mNativeLayer = mCurrentScrollingLayerId;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006449 ted.mNativeLayerRect.set(mScrollingLayerRect);
Adam Powellae9d2642011-03-08 16:00:30 -08006450 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006451 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006452 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Mike Reed19f3f0e2009-11-12 12:50:20 -05006453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006454 mLastTouchUpTime = eventTime;
Cary Clarkb9aaa772011-01-07 16:14:54 -05006455 if (mSentAutoScrollMessage) {
6456 mAutoScrollX = mAutoScrollY = 0;
6457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006458 switch (mTouchMode) {
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006459 case TOUCH_DOUBLE_TAP_MODE: // double tap
6460 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
Grace Klobac2242f22010-03-05 14:00:26 -08006461 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6462 if (inFullScreenMode() || mDeferTouchProcess) {
Huahui Wu98933f32011-07-07 14:27:44 -07006463 TouchEventData ted = new TouchEventData();
6464 ted.mIds = new int[1];
6465 ted.mIds[0] = ev.getPointerId(0);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08006466 ted.mAction = WebViewCore.ACTION_DOUBLETAP;
Huahui Wu98933f32011-07-07 14:27:44 -07006467 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006468 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006469 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006470 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006471 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006472 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006473 ted.mNativeLayer = nativeScrollableLayer(
6474 contentX, contentY,
6475 ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08006476 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006477 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08006478 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006479 } else if (mPreventDefault != PREVENT_DEFAULT_YES){
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04006480 mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
Grace Klobac2242f22010-03-05 14:00:26 -08006481 mTouchMode = TOUCH_DONE_MODE;
Grace Kloba5f68d6f2009-12-08 18:42:54 -08006482 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006483 break;
Grace Klobaf58af622009-09-24 17:41:23 -07006484 case TOUCH_INIT_MODE: // tap
Grace Klobad66d84f2009-09-27 14:48:07 -07006485 case TOUCH_SHORTPRESS_START_MODE:
6486 case TOUCH_SHORTPRESS_MODE:
Grace Klobaf58af622009-09-24 17:41:23 -07006487 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
Grace Klobad66d84f2009-09-27 14:48:07 -07006488 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
Grace Klobac2242f22010-03-05 14:00:26 -08006489 if (mConfirmMove) {
Grace Klobaf58af622009-09-24 17:41:23 -07006490 Log.w(LOGTAG, "Miss a drag as we are waiting for" +
6491 " WebCore's response for touch down.");
Grace Klobac2242f22010-03-05 14:00:26 -08006492 if (mPreventDefault != PREVENT_DEFAULT_YES
Grace Klobad7625dd2010-03-04 11:46:12 -08006493 && (computeMaxScrollX() > 0
6494 || computeMaxScrollY() > 0)) {
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07006495 // If the user has performed a very quick touch
6496 // sequence it is possible that we may get here
6497 // before WebCore has had a chance to process the events.
6498 // In this case, any call to preventDefault in the
6499 // JS touch handler will not have been executed yet.
6500 // Hence we will see both the UI (now) and WebCore
6501 // (when context switches) handling the event,
6502 // regardless of whether the web developer actually
6503 // doeses preventDefault in their touch handler. This
6504 // is the nature of our asynchronous touch model.
6505
Grace Klobaf58af622009-09-24 17:41:23 -07006506 // we will not rewrite drag code here, but we
6507 // will try fling if it applies.
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006508 WebViewCore.reducePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006509 // to get better performance, pause updating the
6510 // picture
6511 WebViewCore.pauseUpdatePicture(mWebViewCore);
Grace Klobaf58af622009-09-24 17:41:23 -07006512 // fall through to TOUCH_DRAG_MODE
6513 } else {
Grace Klobac36862d52010-04-19 10:16:42 -07006514 // WebKit may consume the touch event and modify
6515 // DOM. drawContentPicture() will be called with
6516 // animateSroll as true for better performance.
6517 // Force redraw in high-quality.
6518 invalidate();
Grace Klobaf58af622009-09-24 17:41:23 -07006519 break;
6520 }
6521 } else {
Cary Clark924af702010-06-04 16:37:43 -04006522 if (mSelectingText) {
6523 // tapping on selection or controls does nothing
6524 if (!nativeHitSelection(contentX, contentY)) {
6525 selectionDone();
6526 }
6527 break;
6528 }
Grace Klobaec9a1042010-06-01 19:00:23 -07006529 // only trigger double tap if the WebView is
6530 // scalable
6531 if (mTouchMode == TOUCH_INIT_MODE
6532 && (canZoomIn() || canZoomOut())) {
Grace Klobac2242f22010-03-05 14:00:26 -08006533 mPrivateHandler.sendEmptyMessageDelayed(
6534 RELEASE_SINGLE_TAP, ViewConfiguration
6535 .getDoubleTapTimeout());
6536 } else {
6537 doShortPress();
Grace Klobaf58af622009-09-24 17:41:23 -07006538 }
6539 break;
6540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006541 case TOUCH_DRAG_MODE:
Patrick Scott2f492272010-12-03 09:52:35 -05006542 case TOUCH_DRAG_LAYER_MODE:
Cary Clark25415e22009-10-12 13:41:28 -04006543 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
6544 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006545 // if the user waits a while w/o moving before the
6546 // up, we don't want to do a fling
6547 if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
Grace Klobac2242f22010-03-05 14:00:26 -08006548 if (mVelocityTracker == null) {
6549 Log.e(LOGTAG, "Got null mVelocityTracker when "
6550 + "mPreventDefault = "
6551 + mPreventDefault
6552 + " mDeferTouchProcess = "
6553 + mDeferTouchProcess);
Huahui Wu8465cc92011-01-12 10:17:19 -08006554 } else {
6555 mVelocityTracker.addMovement(ev);
Grace Klobac2242f22010-03-05 14:00:26 -08006556 }
Grace Kloba9b657802010-04-08 13:46:23 -07006557 // set to MOTIONLESS_IGNORE so that it won't keep
6558 // removing and sending message in
6559 // drawCoreAndCursorRing()
6560 mHeldMotionless = MOTIONLESS_IGNORE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006561 doFling();
6562 break;
Adam Powell637d3372010-08-25 14:37:03 -07006563 } else {
6564 if (mScroller.springBack(mScrollX, mScrollY, 0,
6565 computeMaxScrollX(), 0,
6566 computeMaxScrollY())) {
6567 invalidate();
6568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006569 }
Grace Kloba9b657802010-04-08 13:46:23 -07006570 // redraw in high-quality, as we're done dragging
6571 mHeldMotionless = MOTIONLESS_TRUE;
6572 invalidate();
Grace Kloba524aab572010-04-07 11:12:52 -07006573 // fall through
6574 case TOUCH_DRAG_START_MODE:
6575 // TOUCH_DRAG_START_MODE should not happen for the real
6576 // device as we almost certain will get a MOVE. But this
6577 // is possible on emulator.
Cary Clark278ce052009-08-31 16:08:42 -04006578 mLastVelocity = 0;
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006579 WebViewCore.resumePriority();
Cary Clark0df02692010-11-24 11:01:37 -05006580 if (!mSelectingText) {
6581 WebViewCore.resumeUpdatePicture(mWebViewCore);
6582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006583 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006584 }
Grace Klobac2242f22010-03-05 14:00:26 -08006585 stopTouch();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006586 break;
6587 }
6588 case MotionEvent.ACTION_CANCEL: {
Grace Klobad7625dd2010-03-04 11:46:12 -08006589 if (mTouchMode == TOUCH_DRAG_MODE) {
Adam Powell637d3372010-08-25 14:37:03 -07006590 mScroller.springBack(mScrollX, mScrollY, 0,
6591 computeMaxScrollX(), 0, computeMaxScrollY());
Grace Klobac2242f22010-03-05 14:00:26 -08006592 invalidate();
Grace Klobad7625dd2010-03-04 11:46:12 -08006593 }
Grace Klobac2242f22010-03-05 14:00:26 -08006594 cancelWebCoreTouchEvent(contentX, contentY, false);
6595 cancelTouch();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006596 break;
6597 }
6598 }
6599 return true;
6600 }
Cary Clarkd6982c92009-05-29 11:02:22 -04006601
Adam Powell4fb35d42011-03-03 17:54:55 -08006602 private void passMultiTouchToWebKit(MotionEvent ev, long sequence) {
Huahui Wu98933f32011-07-07 14:27:44 -07006603 TouchEventData ted = new TouchEventData();
6604 ted.mAction = ev.getActionMasked();
6605 final int count = ev.getPointerCount();
6606 ted.mIds = new int[count];
6607 ted.mPoints = new Point[count];
6608 ted.mPointsInView = new Point[count];
6609 for (int c = 0; c < count; c++) {
Huahui Wue838a422011-01-13 16:03:43 -08006610 ted.mIds[c] = ev.getPointerId(c);
Huahui Wu41865f42010-09-02 13:41:41 -07006611 int x = viewToContentX((int) ev.getX(c) + mScrollX);
6612 int y = viewToContentY((int) ev.getY(c) + mScrollY);
6613 ted.mPoints[c] = new Point(x, y);
Huahui Wu88b869a2011-03-17 17:42:12 -07006614 ted.mPointsInView[c] = new Point((int) ev.getX(c), (int) ev.getY(c));
Huahui Wu41865f42010-09-02 13:41:41 -07006615 }
Huahui Wu98933f32011-07-07 14:27:44 -07006616 if (ted.mAction == MotionEvent.ACTION_POINTER_DOWN
6617 || ted.mAction == MotionEvent.ACTION_POINTER_UP) {
6618 ted.mActionIndex = ev.getActionIndex();
6619 }
6620 ted.mMetaState = ev.getMetaState();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006621 ted.mReprocess = true;
6622 ted.mMotionEvent = MotionEvent.obtain(ev);
Adam Powell4fb35d42011-03-03 17:54:55 -08006623 ted.mSequence = sequence;
Adam Powell3c534772011-04-04 14:27:12 -07006624 mTouchEventQueue.preQueueTouchEventData(ted);
Huahui Wu41865f42010-09-02 13:41:41 -07006625 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6626 cancelLongPress();
6627 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
Huahui Wu41865f42010-09-02 13:41:41 -07006628 }
6629
Adam Powell8f626a12011-03-10 19:27:15 -08006630 void handleMultiTouchInWebView(MotionEvent ev) {
Huahui Wu0904c0d2011-01-07 17:30:53 -08006631 if (DebugFlags.WEB_VIEW) {
6632 Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime()
6633 + " mTouchMode=" + mTouchMode
6634 + " numPointers=" + ev.getPointerCount()
6635 + " scrolloffset=(" + mScrollX + "," + mScrollY + ")");
6636 }
6637
6638 final ScaleGestureDetector detector =
6639 mZoomManager.getMultiTouchGestureDetector();
Huahui Wu8465cc92011-01-12 10:17:19 -08006640
6641 // A few apps use WebView but don't instantiate gesture detector.
6642 // We don't need to support multi touch for them.
Huahui Wu1f301252011-01-19 17:32:32 -08006643 if (detector == null) return;
Huahui Wu8465cc92011-01-12 10:17:19 -08006644
Huahui Wu0904c0d2011-01-07 17:30:53 -08006645 float x = ev.getX();
6646 float y = ev.getY();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006647
Adam Powell8f626a12011-03-10 19:27:15 -08006648 if (mPreventDefault != PREVENT_DEFAULT_YES) {
6649 detector.onTouchEvent(ev);
Huahui Wu0904c0d2011-01-07 17:30:53 -08006650
Adam Powell8f626a12011-03-10 19:27:15 -08006651 if (detector.isInProgress()) {
6652 if (DebugFlags.WEB_VIEW) {
6653 Log.v(LOGTAG, "detector is in progress");
6654 }
6655 mLastTouchTime = ev.getEventTime();
6656 x = detector.getFocusX();
6657 y = detector.getFocusY();
Huahui Wuf147d452011-01-12 14:02:36 -08006658
Adam Powell8f626a12011-03-10 19:27:15 -08006659 cancelLongPress();
6660 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6661 if (!mZoomManager.supportsPanDuringZoom()) {
6662 return;
6663 }
6664 mTouchMode = TOUCH_DRAG_MODE;
6665 if (mVelocityTracker == null) {
6666 mVelocityTracker = VelocityTracker.obtain();
6667 }
Huahui Wu0904c0d2011-01-07 17:30:53 -08006668 }
6669 }
6670
Huahui Wuf147d452011-01-12 14:02:36 -08006671 int action = ev.getActionMasked();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006672 if (action == MotionEvent.ACTION_POINTER_DOWN) {
6673 cancelTouch();
6674 action = MotionEvent.ACTION_DOWN;
Huahui Wu5f4835a2011-07-20 16:50:19 -07006675 } else if (action == MotionEvent.ACTION_POINTER_UP && ev.getPointerCount() >= 2) {
6676 // set mLastTouchX/Y to the remaining points for multi-touch.
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006677 mLastTouchX = Math.round(x);
6678 mLastTouchY = Math.round(y);
Huahui Wu0904c0d2011-01-07 17:30:53 -08006679 } else if (action == MotionEvent.ACTION_MOVE) {
6680 // negative x or y indicate it is on the edge, skip it.
6681 if (x < 0 || y < 0) {
Huahui Wu1f301252011-01-19 17:32:32 -08006682 return;
Huahui Wu0904c0d2011-01-07 17:30:53 -08006683 }
6684 }
6685
Huahui Wu1f301252011-01-19 17:32:32 -08006686 handleTouchEventCommon(ev, action, Math.round(x), Math.round(y));
Huahui Wu0904c0d2011-01-07 17:30:53 -08006687 }
6688
Grace Klobac2242f22010-03-05 14:00:26 -08006689 private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
6690 if (shouldForwardTouchEvent()) {
6691 if (removeEvents) {
6692 mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
6693 }
6694 TouchEventData ted = new TouchEventData();
Huahui Wue838a422011-01-13 16:03:43 -08006695 ted.mIds = new int[1];
6696 ted.mIds[0] = 0;
Huahui Wu41865f42010-09-02 13:41:41 -07006697 ted.mPoints = new Point[1];
6698 ted.mPoints[0] = new Point(x, y);
Huahui Wu88b869a2011-03-17 17:42:12 -07006699 ted.mPointsInView = new Point[1];
6700 int viewX = contentToViewX(x) - mScrollX;
6701 int viewY = contentToViewY(y) - mScrollY;
6702 ted.mPointsInView[0] = new Point(viewX, viewY);
Huahui Wu98933f32011-07-07 14:27:44 -07006703 ted.mAction = MotionEvent.ACTION_CANCEL;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006704 ted.mNativeLayer = nativeScrollableLayer(
6705 x, y, ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08006706 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Grace Klobac2242f22010-03-05 14:00:26 -08006707 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6708 mPreventDefault = PREVENT_DEFAULT_IGNORE;
Adam Powellbaa33802011-03-25 13:58:19 -07006709
6710 if (removeEvents) {
6711 // Mark this after sending the message above; we should
6712 // be willing to ignore the cancel event that we just sent.
6713 mTouchEventQueue.ignoreCurrentlyMissingEvents();
6714 }
Grace Klobac2242f22010-03-05 14:00:26 -08006715 }
6716 }
6717
Grace Kloba3a0def22010-01-23 21:11:54 -08006718 private void startTouch(float x, float y, long eventTime) {
6719 // Remember where the motion event started
John Reck75738722011-06-10 11:28:53 -07006720 mStartTouchX = mLastTouchX = Math.round(x);
6721 mStartTouchY = mLastTouchY = Math.round(y);
Grace Kloba3a0def22010-01-23 21:11:54 -08006722 mLastTouchTime = eventTime;
6723 mVelocityTracker = VelocityTracker.obtain();
6724 mSnapScrollMode = SNAP_NONE;
John Reck0966dd22011-09-18 11:03:00 -07006725 mPrivateHandler.sendEmptyMessageDelayed(UPDATE_SELECTION,
6726 ViewConfiguration.getTapTimeout());
Grace Kloba3a0def22010-01-23 21:11:54 -08006727 }
6728
Grace Klobac2242f22010-03-05 14:00:26 -08006729 private void startDrag() {
6730 WebViewCore.reducePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006731 // to get better performance, pause updating the picture
6732 WebViewCore.pauseUpdatePicture(mWebViewCore);
Chris Craik58d94af2011-08-18 11:42:13 -07006733 nativeSetIsScrolling(true);
6734
Grace Klobac2242f22010-03-05 14:00:26 -08006735 if (!mDragFromTextInput) {
6736 nativeHideCursor();
6737 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006738
6739 if (mHorizontalScrollBarMode != SCROLLBAR_ALWAYSOFF
6740 || mVerticalScrollBarMode != SCROLLBAR_ALWAYSOFF) {
6741 mZoomManager.invokeZoomPicker();
Grace Klobac2242f22010-03-05 14:00:26 -08006742 }
6743 }
6744
6745 private void doDrag(int deltaX, int deltaY) {
6746 if ((deltaX | deltaY) != 0) {
Patrick Scott62310912010-12-06 17:44:50 -05006747 int oldX = mScrollX;
6748 int oldY = mScrollY;
6749 int rangeX = computeMaxScrollX();
6750 int rangeY = computeMaxScrollY();
6751 int overscrollDistance = mOverscrollDistance;
Adam Powell637d3372010-08-25 14:37:03 -07006752
Patrick Scott62310912010-12-06 17:44:50 -05006753 // Check for the original scrolling layer in case we change
6754 // directions. mTouchMode might be TOUCH_DRAG_MODE if we have
6755 // reached the edge of a layer but mScrollingLayer will be non-zero
6756 // if we initiated the drag on a layer.
Michael Kolb5da91bd2011-11-29 15:29:03 -08006757 if (mCurrentScrollingLayerId != 0) {
Patrick Scott62310912010-12-06 17:44:50 -05006758 final int contentX = viewToContentDimension(deltaX);
6759 final int contentY = viewToContentDimension(deltaY);
6760
6761 // Check the scrolling bounds to see if we will actually do any
6762 // scrolling. The rectangle is in document coordinates.
6763 final int maxX = mScrollingLayerRect.right;
6764 final int maxY = mScrollingLayerRect.bottom;
6765 final int resultX = Math.max(0,
6766 Math.min(mScrollingLayerRect.left + contentX, maxX));
6767 final int resultY = Math.max(0,
6768 Math.min(mScrollingLayerRect.top + contentY, maxY));
6769
6770 if (resultX != mScrollingLayerRect.left ||
6771 resultY != mScrollingLayerRect.top) {
6772 // In case we switched to dragging the page.
6773 mTouchMode = TOUCH_DRAG_LAYER_MODE;
6774 deltaX = contentX;
6775 deltaY = contentY;
6776 oldX = mScrollingLayerRect.left;
6777 oldY = mScrollingLayerRect.top;
6778 rangeX = maxX;
6779 rangeY = maxY;
6780 } else {
6781 // Scroll the main page if we are not going to scroll the
6782 // layer. This does not reset mScrollingLayer in case the
6783 // user changes directions and the layer can scroll the
6784 // other way.
6785 mTouchMode = TOUCH_DRAG_MODE;
6786 }
6787 }
Adam Powell637d3372010-08-25 14:37:03 -07006788
6789 if (mOverScrollGlow != null) {
6790 mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
6791 }
6792
6793 overScrollBy(deltaX, deltaY, oldX, oldY,
6794 rangeX, rangeY,
6795 mOverscrollDistance, mOverscrollDistance, true);
6796 if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
6797 invalidate();
6798 }
Grace Klobac2242f22010-03-05 14:00:26 -08006799 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006800 mZoomManager.keepZoomPickerVisible();
Grace Klobac2242f22010-03-05 14:00:26 -08006801 }
6802
6803 private void stopTouch() {
Chris Craike2f3aee2011-09-02 18:30:12 -07006804 if (mScroller.isFinished() && !mSelectingText
6805 && (mTouchMode == TOUCH_DRAG_MODE || mTouchMode == TOUCH_DRAG_LAYER_MODE)) {
6806 WebViewCore.resumePriority();
6807 WebViewCore.resumeUpdatePicture(mWebViewCore);
6808 nativeSetIsScrolling(false);
6809 }
6810
Grace Klobac2242f22010-03-05 14:00:26 -08006811 // we also use mVelocityTracker == null to tell us that we are
6812 // not "moving around", so we can take the slower/prettier
6813 // mode in the drawing code
6814 if (mVelocityTracker != null) {
6815 mVelocityTracker.recycle();
6816 mVelocityTracker = null;
6817 }
Adam Powell637d3372010-08-25 14:37:03 -07006818
6819 // Release any pulled glows
6820 if (mOverScrollGlow != null) {
6821 mOverScrollGlow.releaseAll();
6822 }
Grace Klobac2242f22010-03-05 14:00:26 -08006823 }
6824
Grace Kloba3a0def22010-01-23 21:11:54 -08006825 private void cancelTouch() {
Grace Kloba3a0def22010-01-23 21:11:54 -08006826 // we also use mVelocityTracker == null to tell us that we are
6827 // not "moving around", so we can take the slower/prettier
6828 // mode in the drawing code
6829 if (mVelocityTracker != null) {
6830 mVelocityTracker.recycle();
6831 mVelocityTracker = null;
6832 }
Adam Powell637d3372010-08-25 14:37:03 -07006833
Cary Clark0df02692010-11-24 11:01:37 -05006834 if ((mTouchMode == TOUCH_DRAG_MODE
6835 || mTouchMode == TOUCH_DRAG_LAYER_MODE) && !mSelectingText) {
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006836 WebViewCore.resumePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006837 WebViewCore.resumeUpdatePicture(mWebViewCore);
Chris Craik58d94af2011-08-18 11:42:13 -07006838 nativeSetIsScrolling(false);
Grace Kloba3a0def22010-01-23 21:11:54 -08006839 }
6840 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
6841 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6842 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
6843 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
John Reck335f4542011-08-25 18:25:09 -07006844 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
6845 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07006846 }
Grace Kloba3a0def22010-01-23 21:11:54 -08006847 mHeldMotionless = MOTIONLESS_TRUE;
6848 mTouchMode = TOUCH_DONE_MODE;
6849 nativeHideCursor();
6850 }
6851
Jeff Brown33bbfd22011-02-24 20:55:35 -08006852 @Override
6853 public boolean onGenericMotionEvent(MotionEvent event) {
6854 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
6855 switch (event.getAction()) {
6856 case MotionEvent.ACTION_SCROLL: {
6857 final float vscroll;
6858 final float hscroll;
6859 if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
6860 vscroll = 0;
6861 hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
6862 } else {
6863 vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
6864 hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
6865 }
6866 if (hscroll != 0 || vscroll != 0) {
6867 final int vdelta = (int) (vscroll * getVerticalScrollFactor());
6868 final int hdelta = (int) (hscroll * getHorizontalScrollFactor());
Jeff Brown7f5b9962011-06-06 18:59:41 -07006869 if (pinScrollBy(hdelta, vdelta, false, 0)) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08006870 return true;
6871 }
6872 }
6873 }
6874 }
6875 }
6876 return super.onGenericMotionEvent(event);
6877 }
6878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006879 private long mTrackballFirstTime = 0;
6880 private long mTrackballLastTime = 0;
6881 private float mTrackballRemainsX = 0.0f;
6882 private float mTrackballRemainsY = 0.0f;
6883 private int mTrackballXMove = 0;
6884 private int mTrackballYMove = 0;
Cary Clark924af702010-06-04 16:37:43 -04006885 private boolean mSelectingText = false;
6886 private boolean mSelectionStarted = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006887 private boolean mExtendSelection = false;
Cary Clark924af702010-06-04 16:37:43 -04006888 private boolean mDrawSelectionPointer = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006889 private static final int TRACKBALL_KEY_TIMEOUT = 1000;
6890 private static final int TRACKBALL_TIMEOUT = 200;
6891 private static final int TRACKBALL_WAIT = 100;
6892 private static final int TRACKBALL_SCALE = 400;
6893 private static final int TRACKBALL_SCROLL_COUNT = 5;
6894 private static final int TRACKBALL_MOVE_COUNT = 10;
6895 private static final int TRACKBALL_MULTIPLIER = 3;
6896 private static final int SELECT_CURSOR_OFFSET = 16;
Cary Clark6f5dfc62010-11-11 13:09:20 -05006897 private static final int SELECT_SCROLL = 5;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006898 private int mSelectX = 0;
6899 private int mSelectY = 0;
Cary Clark5da9aeb2009-10-06 17:40:53 -04006900 private boolean mFocusSizeChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006901 private boolean mTrackballDown = false;
6902 private long mTrackballUpTime = 0;
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006903 private long mLastCursorTime = 0;
6904 private Rect mLastCursorBounds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006905
6906 // Set by default; BrowserActivity clears to interpret trackball data
Cary Clarkd6982c92009-05-29 11:02:22 -04006907 // directly for movement. Currently, the framework only passes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006908 // arrow key events, not trackball events, from one child to the next
6909 private boolean mMapTrackballToArrowKeys = true;
Cary Clarkd6982c92009-05-29 11:02:22 -04006910
John Reck83e59292011-06-04 00:46:45 -07006911 private DrawData mDelaySetPicture;
John Reck60c84d62011-06-08 18:00:02 -07006912 private DrawData mLoadedPicture;
John Reck83e59292011-06-04 00:46:45 -07006913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006914 public void setMapTrackballToArrowKeys(boolean setMap) {
Steve Block51b08912011-04-27 15:04:48 +01006915 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006916 mMapTrackballToArrowKeys = setMap;
6917 }
6918
6919 void resetTrackballTime() {
6920 mTrackballLastTime = 0;
6921 }
6922
6923 @Override
6924 public boolean onTrackballEvent(MotionEvent ev) {
6925 long time = ev.getEventTime();
6926 if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
6927 if (ev.getY() > 0) pageDown(true);
6928 if (ev.getY() < 0) pageUp(true);
6929 return true;
6930 }
6931 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Cary Clark924af702010-06-04 16:37:43 -04006932 if (mSelectingText) {
Cary Clarkbadd8392009-10-15 13:32:08 -04006933 return true; // discard press if copy in progress
6934 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006935 mTrackballDown = true;
Leon Scroggins3ccd3652009-06-26 17:22:50 -04006936 if (mNativeClass == 0) {
6937 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006938 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006939 if (time - mLastCursorTime <= TRACKBALL_TIMEOUT
6940 && !mLastCursorBounds.equals(nativeGetCursorRingBounds())) {
6941 nativeSelectBestAt(mLastCursorBounds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006942 }
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006943 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006944 Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
Cary Clarkd6982c92009-05-29 11:02:22 -04006945 + " time=" + time
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006946 + " mLastCursorTime=" + mLastCursorTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006947 }
6948 if (isInTouchMode()) requestFocusFromTouch();
6949 return false; // let common code in onKeyDown at it
Cary Clarkd6982c92009-05-29 11:02:22 -04006950 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006951 if (ev.getAction() == MotionEvent.ACTION_UP) {
Leon Scrogginse3225672009-06-03 15:53:13 -04006952 // LONG_PRESS_CENTER is set in common onKeyDown
6953 mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006954 mTrackballDown = false;
6955 mTrackballUpTime = time;
Cary Clark924af702010-06-04 16:37:43 -04006956 if (mSelectingText) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006957 if (mExtendSelection) {
Cary Clark924af702010-06-04 16:37:43 -04006958 copySelection();
6959 selectionDone();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006960 } else {
6961 mExtendSelection = true;
Cary Clark924af702010-06-04 16:37:43 -04006962 nativeSetExtendSelection();
Cary Clark09e383c2009-10-26 16:43:58 -04006963 invalidate(); // draw the i-beam instead of the arrow
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006964 }
Cary Clarkbadd8392009-10-15 13:32:08 -04006965 return true; // discard press if copy in progress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006966 }
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006967 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006968 Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
Cary Clarkd6982c92009-05-29 11:02:22 -04006969 + " time=" + time
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006970 );
6971 }
6972 return false; // let common code in onKeyUp at it
6973 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07006974 if ((mMapTrackballToArrowKeys && (ev.getMetaState() & KeyEvent.META_SHIFT_ON) == 0) ||
Svetoslav Ganov12bed782011-01-03 14:14:50 -08006975 AccessibilityManager.getInstance(mContext).isEnabled()) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006976 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006977 return false;
6978 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006979 if (mTrackballDown) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006980 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006981 return true; // discard move if trackball is down
6982 }
6983 if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006984 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006985 return true;
6986 }
6987 // TODO: alternatively we can do panning as touch does
6988 switchOutDrawHistory();
6989 if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006990 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04006991 Log.v(LOGTAG, "onTrackballEvent time="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006992 + time + " last=" + mTrackballLastTime);
6993 }
6994 mTrackballFirstTime = time;
6995 mTrackballXMove = mTrackballYMove = 0;
6996 }
6997 mTrackballLastTime = time;
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006998 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006999 Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time);
7000 }
7001 mTrackballRemainsX += ev.getX();
7002 mTrackballRemainsY += ev.getY();
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007003 doTrackball(time, ev.getMetaState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007004 return true;
7005 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007006
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007007 void moveSelection(float xRate, float yRate) {
7008 if (mNativeClass == 0)
7009 return;
7010 int width = getViewWidth();
7011 int height = getViewHeight();
Cary Clarkc05af372009-10-16 10:52:27 -04007012 mSelectX += xRate;
7013 mSelectY += yRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007014 int maxX = width + mScrollX;
7015 int maxY = height + mScrollY;
7016 mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
7017 , mSelectX));
7018 mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
7019 , mSelectY));
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007020 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04007021 Log.v(LOGTAG, "moveSelection"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007022 + " mSelectX=" + mSelectX
7023 + " mSelectY=" + mSelectY
7024 + " mScrollX=" + mScrollX
7025 + " mScrollY=" + mScrollY
7026 + " xRate=" + xRate
7027 + " yRate=" + yRate
7028 );
7029 }
Cary Clark924af702010-06-04 16:37:43 -04007030 nativeMoveSelection(viewToContentX(mSelectX), viewToContentY(mSelectY));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007031 int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
Cary Clarkd6982c92009-05-29 11:02:22 -04007032 : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007033 : 0;
7034 int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
Cary Clarkd6982c92009-05-29 11:02:22 -04007035 : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007036 : 0;
7037 pinScrollBy(scrollX, scrollY, true, 0);
7038 Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
7039 requestRectangleOnScreen(select);
7040 invalidate();
7041 }
7042
7043 private int scaleTrackballX(float xRate, int width) {
7044 int xMove = (int) (xRate / TRACKBALL_SCALE * width);
7045 int nextXMove = xMove;
7046 if (xMove > 0) {
7047 if (xMove > mTrackballXMove) {
7048 xMove -= mTrackballXMove;
7049 }
7050 } else if (xMove < mTrackballXMove) {
7051 xMove -= mTrackballXMove;
7052 }
7053 mTrackballXMove = nextXMove;
7054 return xMove;
7055 }
7056
7057 private int scaleTrackballY(float yRate, int height) {
7058 int yMove = (int) (yRate / TRACKBALL_SCALE * height);
7059 int nextYMove = yMove;
7060 if (yMove > 0) {
7061 if (yMove > mTrackballYMove) {
7062 yMove -= mTrackballYMove;
7063 }
7064 } else if (yMove < mTrackballYMove) {
7065 yMove -= mTrackballYMove;
7066 }
7067 mTrackballYMove = nextYMove;
7068 return yMove;
7069 }
7070
7071 private int keyCodeToSoundsEffect(int keyCode) {
7072 switch(keyCode) {
7073 case KeyEvent.KEYCODE_DPAD_UP:
7074 return SoundEffectConstants.NAVIGATION_UP;
7075 case KeyEvent.KEYCODE_DPAD_RIGHT:
7076 return SoundEffectConstants.NAVIGATION_RIGHT;
7077 case KeyEvent.KEYCODE_DPAD_DOWN:
7078 return SoundEffectConstants.NAVIGATION_DOWN;
7079 case KeyEvent.KEYCODE_DPAD_LEFT:
7080 return SoundEffectConstants.NAVIGATION_LEFT;
7081 }
7082 throw new IllegalArgumentException("keyCode must be one of " +
7083 "{KEYCODE_DPAD_UP, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_DOWN, " +
7084 "KEYCODE_DPAD_LEFT}.");
7085 }
7086
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007087 private void doTrackball(long time, int metaState) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007088 int elapsed = (int) (mTrackballLastTime - mTrackballFirstTime);
7089 if (elapsed == 0) {
7090 elapsed = TRACKBALL_TIMEOUT;
7091 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007092 float xRate = mTrackballRemainsX * 1000 / elapsed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007093 float yRate = mTrackballRemainsY * 1000 / elapsed;
Cary Clarkc05af372009-10-16 10:52:27 -04007094 int viewWidth = getViewWidth();
7095 int viewHeight = getViewHeight();
Cary Clark924af702010-06-04 16:37:43 -04007096 if (mSelectingText) {
7097 if (!mDrawSelectionPointer) {
7098 // The last selection was made by touch, disabling drawing the
7099 // selection pointer. Allow the trackball to adjust the
7100 // position of the touch control.
7101 mSelectX = contentToViewX(nativeSelectionX());
7102 mSelectY = contentToViewY(nativeSelectionY());
7103 mDrawSelectionPointer = mExtendSelection = true;
7104 nativeSetExtendSelection();
7105 }
Cary Clarkc05af372009-10-16 10:52:27 -04007106 moveSelection(scaleTrackballX(xRate, viewWidth),
7107 scaleTrackballY(yRate, viewHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007108 mTrackballRemainsX = mTrackballRemainsY = 0;
7109 return;
7110 }
7111 float ax = Math.abs(xRate);
7112 float ay = Math.abs(yRate);
7113 float maxA = Math.max(ax, ay);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007114 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007115 Log.v(LOGTAG, "doTrackball elapsed=" + elapsed
7116 + " xRate=" + xRate
7117 + " yRate=" + yRate
7118 + " mTrackballRemainsX=" + mTrackballRemainsX
7119 + " mTrackballRemainsY=" + mTrackballRemainsY);
7120 }
Cary Clarkc05af372009-10-16 10:52:27 -04007121 int width = mContentWidth - viewWidth;
7122 int height = mContentHeight - viewHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007123 if (width < 0) width = 0;
7124 if (height < 0) height = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007125 ax = Math.abs(mTrackballRemainsX * TRACKBALL_MULTIPLIER);
7126 ay = Math.abs(mTrackballRemainsY * TRACKBALL_MULTIPLIER);
7127 maxA = Math.max(ax, ay);
7128 int count = Math.max(0, (int) maxA);
7129 int oldScrollX = mScrollX;
7130 int oldScrollY = mScrollY;
7131 if (count > 0) {
Cary Clarkd6982c92009-05-29 11:02:22 -04007132 int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
7133 KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007134 mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
7135 KeyEvent.KEYCODE_DPAD_RIGHT;
7136 count = Math.min(count, TRACKBALL_MOVE_COUNT);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007137 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04007138 Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007139 + " count=" + count
7140 + " mTrackballRemainsX=" + mTrackballRemainsX
7141 + " mTrackballRemainsY=" + mTrackballRemainsY);
7142 }
Leon Scroggins9ab32b62010-05-03 14:19:50 +01007143 if (mNativeClass != 0 && nativePageShouldHandleShiftAndArrows()) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007144 for (int i = 0; i < count; i++) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007145 letPageHandleNavKey(selectKeyCode, time, true, metaState);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007146 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007147 letPageHandleNavKey(selectKeyCode, time, false, metaState);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007148 } else if (navHandledKey(selectKeyCode, count, false, time)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007149 playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
7150 }
7151 mTrackballRemainsX = mTrackballRemainsY = 0;
7152 }
7153 if (count >= TRACKBALL_SCROLL_COUNT) {
7154 int xMove = scaleTrackballX(xRate, width);
7155 int yMove = scaleTrackballY(yRate, height);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007156 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007157 Log.v(LOGTAG, "doTrackball pinScrollBy"
7158 + " count=" + count
7159 + " xMove=" + xMove + " yMove=" + yMove
Cary Clarkd6982c92009-05-29 11:02:22 -04007160 + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
7161 + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007162 );
7163 }
7164 if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
7165 xMove = 0;
7166 }
7167 if (Math.abs(mScrollY - oldScrollY) > Math.abs(yMove)) {
7168 yMove = 0;
7169 }
7170 if (xMove != 0 || yMove != 0) {
7171 pinScrollBy(xMove, yMove, true, 0);
7172 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007174 }
7175
Adam Powell637d3372010-08-25 14:37:03 -07007176 /**
7177 * Compute the maximum horizontal scroll position. Used by {@link OverScrollGlow}.
7178 * @return Maximum horizontal scroll position within real content
7179 */
7180 int computeMaxScrollX() {
7181 return Math.max(computeRealHorizontalScrollRange() - getViewWidth(), 0);
Grace Klobad7625dd2010-03-04 11:46:12 -08007182 }
7183
Adam Powell637d3372010-08-25 14:37:03 -07007184 /**
7185 * Compute the maximum vertical scroll position. Used by {@link OverScrollGlow}.
7186 * @return Maximum vertical scroll position within real content
7187 */
7188 int computeMaxScrollY() {
7189 return Math.max(computeRealVerticalScrollRange() + getTitleHeight()
Mike Reede5e63f42010-03-19 14:38:23 -04007190 - getViewHeightWithTitle(), 0);
Mike Reede8853fc2009-09-04 14:01:48 -04007191 }
7192
Derek Sollenberger03e48912010-05-18 17:03:42 -04007193 boolean updateScrollCoordinates(int x, int y) {
7194 int oldX = mScrollX;
7195 int oldY = mScrollY;
7196 mScrollX = x;
7197 mScrollY = y;
7198 if (oldX != mScrollX || oldY != mScrollY) {
7199 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
7200 return true;
7201 } else {
7202 return false;
7203 }
7204 }
7205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007206 public void flingScroll(int vx, int vy) {
Steve Block51b08912011-04-27 15:04:48 +01007207 checkThread();
Grace Klobad7625dd2010-03-04 11:46:12 -08007208 mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
Adam Powell637d3372010-08-25 14:37:03 -07007209 computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007210 invalidate();
7211 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007213 private void doFling() {
7214 if (mVelocityTracker == null) {
7215 return;
7216 }
Grace Klobad7625dd2010-03-04 11:46:12 -08007217 int maxX = computeMaxScrollX();
Mike Reede8853fc2009-09-04 14:01:48 -04007218 int maxY = computeMaxScrollY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007219
Romain Guy4296fc42009-07-06 11:48:52 -07007220 mVelocityTracker.computeCurrentVelocity(1000, mMaximumFling);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007221 int vx = (int) mVelocityTracker.getXVelocity();
7222 int vy = (int) mVelocityTracker.getYVelocity();
7223
Patrick Scott62310912010-12-06 17:44:50 -05007224 int scrollX = mScrollX;
7225 int scrollY = mScrollY;
7226 int overscrollDistance = mOverscrollDistance;
7227 int overflingDistance = mOverflingDistance;
7228
7229 // Use the layer's scroll data if applicable.
7230 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
7231 scrollX = mScrollingLayerRect.left;
7232 scrollY = mScrollingLayerRect.top;
7233 maxX = mScrollingLayerRect.right;
7234 maxY = mScrollingLayerRect.bottom;
7235 // No overscrolling for layers.
7236 overscrollDistance = overflingDistance = 0;
7237 }
7238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007239 if (mSnapScrollMode != SNAP_NONE) {
Cary Clarkac492e12009-10-14 14:53:37 -04007240 if ((mSnapScrollMode & SNAP_X) == SNAP_X) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007241 vy = 0;
7242 } else {
7243 vx = 0;
7244 }
7245 }
Cary Clarkaa7caa62009-09-08 14:15:07 -04007246 if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) {
Grace Klobaa7bc87c2010-01-29 14:56:25 -08007247 WebViewCore.resumePriority();
Cary Clark0df02692010-11-24 11:01:37 -05007248 if (!mSelectingText) {
7249 WebViewCore.resumeUpdatePicture(mWebViewCore);
7250 }
Patrick Scott62310912010-12-06 17:44:50 -05007251 if (mScroller.springBack(scrollX, scrollY, 0, maxX, 0, maxY)) {
Adam Powell637d3372010-08-25 14:37:03 -07007252 invalidate();
7253 }
Cary Clarkaa7caa62009-09-08 14:15:07 -04007254 return;
7255 }
Cary Clark278ce052009-08-31 16:08:42 -04007256 float currentVelocity = mScroller.getCurrVelocity();
Grace Kloba3c19d992010-05-17 19:19:06 -07007257 float velocity = (float) Math.hypot(vx, vy);
7258 if (mLastVelocity > 0 && currentVelocity > 0 && velocity
7259 > mLastVelocity * MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION) {
Cary Clark278ce052009-08-31 16:08:42 -04007260 float deltaR = (float) (Math.abs(Math.atan2(mLastVelY, mLastVelX)
7261 - Math.atan2(vy, vx)));
7262 final float circle = (float) (Math.PI) * 2.0f;
7263 if (deltaR > circle * 0.9f || deltaR < circle * 0.1f) {
7264 vx += currentVelocity * mLastVelX / mLastVelocity;
7265 vy += currentVelocity * mLastVelY / mLastVelocity;
Grace Kloba3c19d992010-05-17 19:19:06 -07007266 velocity = (float) Math.hypot(vx, vy);
Cary Clark278ce052009-08-31 16:08:42 -04007267 if (DebugFlags.WEB_VIEW) {
7268 Log.v(LOGTAG, "doFling vx= " + vx + " vy=" + vy);
7269 }
7270 } else if (DebugFlags.WEB_VIEW) {
7271 Log.v(LOGTAG, "doFling missed " + deltaR / circle);
7272 }
7273 } else if (DebugFlags.WEB_VIEW) {
7274 Log.v(LOGTAG, "doFling start last=" + mLastVelocity
Cary Clarkaa7caa62009-09-08 14:15:07 -04007275 + " current=" + currentVelocity
7276 + " vx=" + vx + " vy=" + vy
7277 + " maxX=" + maxX + " maxY=" + maxY
Patrick Scott62310912010-12-06 17:44:50 -05007278 + " scrollX=" + scrollX + " scrollY=" + scrollY
Michael Kolb5da91bd2011-11-29 15:29:03 -08007279 + " layer=" + mCurrentScrollingLayerId);
Cary Clark278ce052009-08-31 16:08:42 -04007280 }
Adam Powell637d3372010-08-25 14:37:03 -07007281
7282 // Allow sloppy flings without overscrolling at the edges.
Patrick Scott62310912010-12-06 17:44:50 -05007283 if ((scrollX == 0 || scrollX == maxX) && Math.abs(vx) < Math.abs(vy)) {
Adam Powell637d3372010-08-25 14:37:03 -07007284 vx = 0;
7285 }
Patrick Scott62310912010-12-06 17:44:50 -05007286 if ((scrollY == 0 || scrollY == maxY) && Math.abs(vy) < Math.abs(vx)) {
Adam Powell637d3372010-08-25 14:37:03 -07007287 vy = 0;
7288 }
7289
Patrick Scott62310912010-12-06 17:44:50 -05007290 if (overscrollDistance < overflingDistance) {
7291 if ((vx > 0 && scrollX == -overscrollDistance) ||
7292 (vx < 0 && scrollX == maxX + overscrollDistance)) {
Adam Powell637d3372010-08-25 14:37:03 -07007293 vx = 0;
7294 }
Patrick Scott62310912010-12-06 17:44:50 -05007295 if ((vy > 0 && scrollY == -overscrollDistance) ||
7296 (vy < 0 && scrollY == maxY + overscrollDistance)) {
Adam Powell637d3372010-08-25 14:37:03 -07007297 vy = 0;
7298 }
7299 }
7300
Cary Clark278ce052009-08-31 16:08:42 -04007301 mLastVelX = vx;
7302 mLastVelY = vy;
Grace Kloba3c19d992010-05-17 19:19:06 -07007303 mLastVelocity = velocity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007304
Adam Powell637d3372010-08-25 14:37:03 -07007305 // no horizontal overscroll if the content just fits
Patrick Scott62310912010-12-06 17:44:50 -05007306 mScroller.fling(scrollX, scrollY, -vx, -vy, 0, maxX, 0, maxY,
7307 maxX == 0 ? 0 : overflingDistance, overflingDistance);
Adam Powell637d3372010-08-25 14:37:03 -07007308 // Duration is calculated based on velocity. With range boundaries and overscroll
7309 // we may not know how long the final animation will take. (Hence the deprecation
7310 // warning on the call below.) It's not a big deal for scroll bars but if webcore
7311 // resumes during this effect we will take a performance hit. See computeScroll;
7312 // we resume webcore there when the animation is finished.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007313 final int time = mScroller.getDuration();
Patrick Scott5b87e292010-12-13 09:20:32 -05007314
7315 // Suppress scrollbars for layer scrolling.
7316 if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
7317 awakenScrollBars(time);
7318 }
7319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007320 invalidate();
7321 }
7322
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007323 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007324 * Returns a view containing zoom controls i.e. +/- buttons. The caller is
7325 * in charge of installing this view to the view hierarchy. This view will
7326 * become visible when the user starts scrolling via touch and fade away if
7327 * the user does not interact with it.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007328 * <p/>
The Android Open Source Project10592532009-03-18 17:39:46 -07007329 * API version 3 introduces a built-in zoom mechanism that is shown
7330 * automatically by the MapView. This is the preferred approach for
7331 * showing the zoom UI.
7332 *
7333 * @deprecated The built-in zoom mechanism is preferred, see
7334 * {@link WebSettings#setBuiltInZoomControls(boolean)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007335 */
The Android Open Source Project10592532009-03-18 17:39:46 -07007336 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007337 public View getZoomControls() {
Steve Block51b08912011-04-27 15:04:48 +01007338 checkThread();
The Android Open Source Project10592532009-03-18 17:39:46 -07007339 if (!getSettings().supportZoom()) {
7340 Log.w(LOGTAG, "This WebView doesn't support zoom.");
7341 return null;
7342 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04007343 return mZoomManager.getExternalZoomPicker();
The Android Open Source Project10592532009-03-18 17:39:46 -07007344 }
7345
Derek Sollenberger90b6e482010-05-10 12:38:54 -04007346 void dismissZoomControl() {
7347 mZoomManager.dismissZoomPicker();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007348 }
7349
Derek Sollenberger03e48912010-05-18 17:03:42 -04007350 float getDefaultZoomScale() {
Derek Sollenberger341e22f2010-06-02 12:34:34 -04007351 return mZoomManager.getDefaultScale();
Derek Sollenberger03e48912010-05-18 17:03:42 -04007352 }
7353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007354 /**
Mangesh Ghiwarefaab93d2011-09-21 13:58:47 -07007355 * Return the overview scale of the WebView
7356 * @return The overview scale.
7357 */
7358 float getZoomOverviewScale() {
7359 return mZoomManager.getZoomOverviewScale();
7360 }
7361
7362 /**
Grace Kloba6164ef12010-06-01 15:59:13 -07007363 * @return TRUE if the WebView can be zoomed in.
7364 */
7365 public boolean canZoomIn() {
Steve Block51b08912011-04-27 15:04:48 +01007366 checkThread();
Grace Kloba6164ef12010-06-01 15:59:13 -07007367 return mZoomManager.canZoomIn();
7368 }
7369
7370 /**
7371 * @return TRUE if the WebView can be zoomed out.
7372 */
7373 public boolean canZoomOut() {
Steve Block51b08912011-04-27 15:04:48 +01007374 checkThread();
Grace Kloba6164ef12010-06-01 15:59:13 -07007375 return mZoomManager.canZoomOut();
7376 }
7377
7378 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007379 * Perform zoom in in the webview
7380 * @return TRUE if zoom in succeeds. FALSE if no zoom changes.
7381 */
7382 public boolean zoomIn() {
Steve Block51b08912011-04-27 15:04:48 +01007383 checkThread();
Derek Sollenberger03e48912010-05-18 17:03:42 -04007384 return mZoomManager.zoomIn();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007385 }
7386
7387 /**
7388 * Perform zoom out in the webview
7389 * @return TRUE if zoom out succeeds. FALSE if no zoom changes.
7390 */
7391 public boolean zoomOut() {
Steve Block51b08912011-04-27 15:04:48 +01007392 checkThread();
Derek Sollenberger03e48912010-05-18 17:03:42 -04007393 return mZoomManager.zoomOut();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007394 }
7395
John Reck0966dd22011-09-18 11:03:00 -07007396 /**
7397 * This selects the best clickable target at mLastTouchX and mLastTouchY
7398 * and calls showCursorTimed on the native side
7399 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007400 private void updateSelection() {
7401 if (mNativeClass == 0) {
7402 return;
7403 }
John Reck0966dd22011-09-18 11:03:00 -07007404 mPrivateHandler.removeMessages(UPDATE_SELECTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007405 // mLastTouchX and mLastTouchY are the point in the current viewport
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007406 int contentX = viewToContentX(mLastTouchX + mScrollX);
7407 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clarke9290822011-02-22 13:20:56 -05007408 int slop = viewToContentDimension(mNavSlop);
7409 Rect rect = new Rect(contentX - slop, contentY - slop,
7410 contentX + slop, contentY + slop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007411 nativeSelectBestAt(rect);
Cary Clarkb8491342010-11-29 16:23:19 -05007412 mInitialHitTestResult = hitTestResult(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007413 }
7414
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007415 /**
Leon Scrogginsd5188652011-01-19 17:01:55 -05007416 * Scroll the focused text field to match the WebTextView
Cary Clarkeaa18de2009-09-28 12:50:42 -04007417 * @param xPercent New x position of the WebTextView from 0 to 1.
Leon Scroggins72543e12009-07-23 15:29:45 -04007418 */
Leon Scrogginsd5188652011-01-19 17:01:55 -05007419 /*package*/ void scrollFocusedTextInputX(float xPercent) {
Leon Scroggins72543e12009-07-23 15:29:45 -04007420 if (!inEditingMode() || mWebViewCore == null) {
7421 return;
7422 }
Leon Scrogginsd5188652011-01-19 17:01:55 -05007423 mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0,
Cary Clarkeaa18de2009-09-28 12:50:42 -04007424 new Float(xPercent));
Leon Scroggins72543e12009-07-23 15:29:45 -04007425 }
7426
7427 /**
Leon Scrogginsd5188652011-01-19 17:01:55 -05007428 * Scroll the focused textarea vertically to match the WebTextView
7429 * @param y New y position of the WebTextView in view coordinates
7430 */
7431 /* package */ void scrollFocusedTextInputY(int y) {
Leon Scroggins22e883d2011-01-31 10:54:19 -05007432 if (!inEditingMode() || mWebViewCore == null) {
Leon Scrogginsd5188652011-01-19 17:01:55 -05007433 return;
7434 }
Leon Scroggins22e883d2011-01-31 10:54:19 -05007435 mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0, viewToContentDimension(y));
Leon Scrogginsd5188652011-01-19 17:01:55 -05007436 }
7437
7438 /**
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007439 * Set our starting point and time for a drag from the WebTextView.
7440 */
7441 /*package*/ void initiateTextFieldDrag(float x, float y, long eventTime) {
7442 if (!inEditingMode()) {
7443 return;
7444 }
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007445 mLastTouchX = Math.round(x + mWebTextView.getLeft() - mScrollX);
7446 mLastTouchY = Math.round(y + mWebTextView.getTop() - mScrollY);
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007447 mLastTouchTime = eventTime;
7448 if (!mScroller.isFinished()) {
Cary Clark278ce052009-08-31 16:08:42 -04007449 abortAnimation();
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007450 }
7451 mSnapScrollMode = SNAP_NONE;
7452 mVelocityTracker = VelocityTracker.obtain();
7453 mTouchMode = TOUCH_DRAG_START_MODE;
7454 }
7455
7456 /**
7457 * Given a motion event from the WebTextView, set its location to our
7458 * coordinates, and handle the event.
7459 */
7460 /*package*/ boolean textFieldDrag(MotionEvent event) {
7461 if (!inEditingMode()) {
7462 return false;
7463 }
Leon Scroggins72543e12009-07-23 15:29:45 -04007464 mDragFromTextInput = true;
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007465 event.offsetLocation((float) (mWebTextView.getLeft() - mScrollX),
7466 (float) (mWebTextView.getTop() - mScrollY));
Leon Scroggins72543e12009-07-23 15:29:45 -04007467 boolean result = onTouchEvent(event);
7468 mDragFromTextInput = false;
7469 return result;
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007470 }
7471
Leon Scroggins6679f2f2009-08-12 18:48:10 -04007472 /**
Leon Scrogginsf90b1262009-11-24 14:49:21 -05007473 * Due a touch up from a WebTextView. This will be handled by webkit to
Leon Scroggins6679f2f2009-08-12 18:48:10 -04007474 * change the selection.
7475 * @param event MotionEvent in the WebTextView's coordinates.
7476 */
7477 /*package*/ void touchUpOnTextField(MotionEvent event) {
7478 if (!inEditingMode()) {
7479 return;
7480 }
Leon Scroggins0236e672009-09-02 21:12:08 -04007481 int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
7482 int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
Cary Clarke9290822011-02-22 13:20:56 -05007483 int slop = viewToContentDimension(mNavSlop);
7484 nativeMotionUp(x, y, slop);
Leon Scroggins6679f2f2009-08-12 18:48:10 -04007485 }
7486
Leon Scroggins1d96ca02009-10-23 11:49:03 -04007487 /**
7488 * Called when pressing the center key or trackball on a textfield.
7489 */
7490 /*package*/ void centerKeyPressOnTextField() {
7491 mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
7492 nativeCursorNodePointer());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007493 }
7494
7495 private void doShortPress() {
7496 if (mNativeClass == 0) {
7497 return;
7498 }
Grace Klobac2242f22010-03-05 14:00:26 -08007499 if (mPreventDefault == PREVENT_DEFAULT_YES) {
7500 return;
7501 }
7502 mTouchMode = TOUCH_DONE_MODE;
John Reck0966dd22011-09-18 11:03:00 -07007503 updateSelection();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007504 switchOutDrawHistory();
7505 // mLastTouchX and mLastTouchY are the point in the current viewport
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007506 int contentX = viewToContentX(mLastTouchX + mScrollX);
7507 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clarke9290822011-02-22 13:20:56 -05007508 int slop = viewToContentDimension(mNavSlop);
John Reck335f4542011-08-25 18:25:09 -07007509 if (USE_WEBKIT_RINGS && !mTouchHighlightRegion.isEmpty()) {
7510 // set mTouchHighlightRequested to 0 to cause an immediate
7511 // drawing of the touch rings
7512 mTouchHighlightRequested = 0;
7513 invalidate(mTouchHighlightRegion.getBounds());
7514 mPrivateHandler.postDelayed(new Runnable() {
7515 @Override
7516 public void run() {
7517 removeTouchHighlight();
7518 }
7519 }, ViewConfiguration.getPressedStateDuration());
7520 }
Grace Kloba178db412010-05-18 22:22:23 -07007521 if (getSettings().supportTouchOnly()) {
John Reck335f4542011-08-25 18:25:09 -07007522 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07007523 WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
7524 // use "0" as generation id to inform WebKit to use the same x/y as
7525 // it used when processing GET_TOUCH_HIGHLIGHT_RECTS
7526 touchUpData.mMoveGeneration = 0;
7527 mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
Cary Clarke9290822011-02-22 13:20:56 -05007528 } else if (nativePointInNavCache(contentX, contentY, slop)) {
Cary Clark1cb97ee2009-12-11 12:10:36 -05007529 WebViewCore.MotionUpData motionUpData = new WebViewCore
7530 .MotionUpData();
7531 motionUpData.mFrame = nativeCacheHitFramePointer();
7532 motionUpData.mNode = nativeCacheHitNodePointer();
7533 motionUpData.mBounds = nativeCacheHitNodeBounds();
7534 motionUpData.mX = contentX;
7535 motionUpData.mY = contentY;
7536 mWebViewCore.sendMessageAtFrontOfQueue(EventHub.VALID_NODE_BOUNDS,
7537 motionUpData);
7538 } else {
Cary Clarkbad0c542010-01-11 14:58:21 -05007539 doMotionUp(contentX, contentY);
Cary Clark1cb97ee2009-12-11 12:10:36 -05007540 }
7541 }
7542
Cary Clarkbad0c542010-01-11 14:58:21 -05007543 private void doMotionUp(int contentX, int contentY) {
Cary Clarke9290822011-02-22 13:20:56 -05007544 int slop = viewToContentDimension(mNavSlop);
7545 if (nativeMotionUp(contentX, contentY, slop) && mLogEvent) {
Dan Egnor18e93962010-02-10 19:27:58 -08007546 EventLog.writeEvent(EventLogTags.BROWSER_SNAP_CENTER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007547 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007548 if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007549 playSoundEffect(SoundEffectConstants.CLICK);
7550 }
7551 }
7552
Derek Sollenberger281432c2011-08-22 14:05:49 -04007553 void sendPluginDrawMsg() {
7554 mWebViewCore.sendMessage(EventHub.PLUGIN_SURFACE_READY);
7555 }
7556
Cary Clarkb2601352011-01-11 11:32:01 -05007557 /**
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007558 * Returns plugin bounds if x/y in content coordinates corresponds to a
7559 * plugin. Otherwise a NULL rectangle is returned.
Cary Clarkb2601352011-01-11 11:32:01 -05007560 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007561 Rect getPluginBounds(int x, int y) {
Cary Clarke9290822011-02-22 13:20:56 -05007562 int slop = viewToContentDimension(mNavSlop);
7563 if (nativePointInNavCache(x, y, slop) && nativeCacheHitIsPlugin()) {
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007564 return nativeCacheHitNodeBounds();
7565 } else {
7566 return null;
7567 }
Cary Clarkb2601352011-01-11 11:32:01 -05007568 }
7569
Grace Klobac6f95fe2010-03-10 13:25:34 -08007570 /*
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007571 * Return true if the rect (e.g. plugin) is fully visible and maximized
7572 * inside the WebView.
Grace Klobac6f95fe2010-03-10 13:25:34 -08007573 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007574 boolean isRectFitOnScreen(Rect rect) {
7575 final int rectWidth = rect.width();
7576 final int rectHeight = rect.height();
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04007577 final int viewWidth = getViewWidth();
7578 final int viewHeight = getViewHeightWithTitle();
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007579 float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight / rectHeight);
Derek Sollenberger369aca22010-06-09 14:11:59 -04007580 scale = mZoomManager.computeScaleWithLimits(scale);
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04007581 return !mZoomManager.willScaleTriggerZoom(scale)
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007582 && contentToViewX(rect.left) >= mScrollX
7583 && contentToViewX(rect.right) <= mScrollX + viewWidth
7584 && contentToViewY(rect.top) >= mScrollY
7585 && contentToViewY(rect.bottom) <= mScrollY + viewHeight;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007586 }
7587
7588 /*
Grace Klobae8300a12010-03-12 13:32:55 -08007589 * Maximize and center the rectangle, specified in the document coordinate
7590 * space, inside the WebView. If the zoom doesn't need to be changed, do an
7591 * animated scroll to center it. If the zoom needs to be changed, find the
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007592 * zoom center and do a smooth zoom transition. The rect is in document
7593 * coordinates
Grace Klobac6f95fe2010-03-10 13:25:34 -08007594 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007595 void centerFitRect(Rect rect) {
7596 final int rectWidth = rect.width();
7597 final int rectHeight = rect.height();
7598 final int viewWidth = getViewWidth();
7599 final int viewHeight = getViewHeightWithTitle();
7600 float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight
7601 / rectHeight);
Derek Sollenberger369aca22010-06-09 14:11:59 -04007602 scale = mZoomManager.computeScaleWithLimits(scale);
Derek Sollenberger03e48912010-05-18 17:03:42 -04007603 if (!mZoomManager.willScaleTriggerZoom(scale)) {
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007604 pinScrollTo(contentToViewX(rect.left + rectWidth / 2) - viewWidth / 2,
7605 contentToViewY(rect.top + rectHeight / 2) - viewHeight / 2,
Grace Klobac6f95fe2010-03-10 13:25:34 -08007606 true, 0);
7607 } else {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04007608 float actualScale = mZoomManager.getScale();
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007609 float oldScreenX = rect.left * actualScale - mScrollX;
7610 float rectViewX = rect.left * scale;
7611 float rectViewWidth = rectWidth * scale;
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007612 float newMaxWidth = mContentWidth * scale;
7613 float newScreenX = (viewWidth - rectViewWidth) / 2;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007614 // pin the newX to the WebView
Grace Klobae8300a12010-03-12 13:32:55 -08007615 if (newScreenX > rectViewX) {
7616 newScreenX = rectViewX;
7617 } else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) {
7618 newScreenX = viewWidth - (newMaxWidth - rectViewX);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007619 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007620 float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale)
7621 / (scale - actualScale);
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007622 float oldScreenY = rect.top * actualScale + getTitleHeight()
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007623 - mScrollY;
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007624 float rectViewY = rect.top * scale + getTitleHeight();
7625 float rectViewHeight = rectHeight * scale;
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007626 float newMaxHeight = mContentHeight * scale + getTitleHeight();
7627 float newScreenY = (viewHeight - rectViewHeight) / 2;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007628 // pin the newY to the WebView
Grace Klobae8300a12010-03-12 13:32:55 -08007629 if (newScreenY > rectViewY) {
7630 newScreenY = rectViewY;
7631 } else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) {
7632 newScreenY = viewHeight - (newMaxHeight - rectViewY);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007633 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007634 float zoomCenterY = (oldScreenY * scale - newScreenY * actualScale)
7635 / (scale - actualScale);
7636 mZoomManager.setZoomCenter(zoomCenterX, zoomCenterY);
Derek Sollenberger87b17be52010-06-01 11:49:31 -04007637 mZoomManager.startZoomAnimation(scale, false);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007638 }
7639 }
7640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007641 // Called by JNI to handle a touch on a node representing an email address,
7642 // address, or phone number
7643 private void overrideLoading(String url) {
7644 mCallbackProxy.uiOverrideUrlLoading(url);
7645 }
7646
7647 @Override
7648 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
Leon Scroggins III26723fc2010-04-19 13:21:42 -04007649 // FIXME: If a subwindow is showing find, and the user touches the
7650 // background window, it can steal focus.
7651 if (mFindIsUp) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007652 boolean result = false;
7653 if (inEditingMode()) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04007654 result = mWebTextView.requestFocus(direction,
7655 previouslyFocusedRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007656 } else {
7657 result = super.requestFocus(direction, previouslyFocusedRect);
Leon Scroggins572ba782011-01-28 11:25:53 -05007658 if (mWebViewCore.getSettings().getNeedInitialFocus() && !isInTouchMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007659 // For cases such as GMail, where we gain focus from a direction,
7660 // we want to move to the first available link.
7661 // FIXME: If there are no visible links, we may not want to
7662 int fakeKeyDirection = 0;
7663 switch(direction) {
7664 case View.FOCUS_UP:
7665 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_UP;
7666 break;
7667 case View.FOCUS_DOWN:
7668 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_DOWN;
7669 break;
7670 case View.FOCUS_LEFT:
7671 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_LEFT;
7672 break;
7673 case View.FOCUS_RIGHT:
7674 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_RIGHT;
7675 break;
7676 default:
7677 return result;
7678 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007679 if (mNativeClass != 0 && !nativeHasCursorNode()) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007680 navHandledKey(fakeKeyDirection, 1, true, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007681 }
7682 }
7683 }
7684 return result;
7685 }
7686
7687 @Override
7688 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
7689 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
7690
7691 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
7692 int heightSize = MeasureSpec.getSize(heightMeasureSpec);
7693 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
7694 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
7695
7696 int measuredHeight = heightSize;
7697 int measuredWidth = widthSize;
7698
7699 // Grab the content size from WebViewCore.
Grace Klobae621d6f2009-09-11 13:20:39 -07007700 int contentHeight = contentToViewDimension(mContentHeight);
7701 int contentWidth = contentToViewDimension(mContentWidth);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007702
7703// Log.d(LOGTAG, "------- measure " + heightMode);
7704
7705 if (heightMode != MeasureSpec.EXACTLY) {
7706 mHeightCanMeasure = true;
7707 measuredHeight = contentHeight;
7708 if (heightMode == MeasureSpec.AT_MOST) {
7709 // If we are larger than the AT_MOST height, then our height can
7710 // no longer be measured and we should scroll internally.
7711 if (measuredHeight > heightSize) {
7712 measuredHeight = heightSize;
7713 mHeightCanMeasure = false;
Dianne Hackborn189ee182010-12-02 21:48:53 -08007714 measuredHeight |= MEASURED_STATE_TOO_SMALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007715 }
7716 }
7717 } else {
7718 mHeightCanMeasure = false;
7719 }
7720 if (mNativeClass != 0) {
7721 nativeSetHeightCanMeasure(mHeightCanMeasure);
7722 }
7723 // For the width, always use the given size unless unspecified.
7724 if (widthMode == MeasureSpec.UNSPECIFIED) {
7725 mWidthCanMeasure = true;
7726 measuredWidth = contentWidth;
7727 } else {
Dianne Hackborn189ee182010-12-02 21:48:53 -08007728 if (measuredWidth < contentWidth) {
7729 measuredWidth |= MEASURED_STATE_TOO_SMALL;
7730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007731 mWidthCanMeasure = false;
7732 }
7733
7734 synchronized (this) {
7735 setMeasuredDimension(measuredWidth, measuredHeight);
7736 }
7737 }
7738
7739 @Override
7740 public boolean requestChildRectangleOnScreen(View child,
7741 Rect rect,
7742 boolean immediate) {
Cary Clarkdc09b5a2010-12-07 08:48:10 -05007743 if (mNativeClass == 0) {
7744 return false;
7745 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007746 // don't scroll while in zoom animation. When it is done, we will adjust
7747 // the necessary components (e.g., WebTextView if it is in editing mode)
Derek Sollenberger293c3602010-06-04 10:44:48 -04007748 if (mZoomManager.isFixedLengthAnimationInProgress()) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04007749 return false;
7750 }
7751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007752 rect.offset(child.getLeft() - child.getScrollX(),
7753 child.getTop() - child.getScrollY());
7754
Cary Clark31b83672010-03-09 09:20:34 -05007755 Rect content = new Rect(viewToContentX(mScrollX),
7756 viewToContentY(mScrollY),
7757 viewToContentX(mScrollX + getWidth()
7758 - getVerticalScrollbarWidth()),
7759 viewToContentY(mScrollY + getViewHeightWithTitle()));
7760 content = nativeSubtractLayers(content);
7761 int screenTop = contentToViewY(content.top);
7762 int screenBottom = contentToViewY(content.bottom);
7763 int height = screenBottom - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007764 int scrollYDelta = 0;
7765
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007766 if (rect.bottom > screenBottom) {
7767 int oneThirdOfScreenHeight = height / 3;
7768 if (rect.height() > 2 * oneThirdOfScreenHeight) {
7769 // If the rectangle is too tall to fit in the bottom two thirds
7770 // of the screen, place it at the top.
7771 scrollYDelta = rect.top - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007772 } else {
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007773 // If the rectangle will still fit on screen, we want its
7774 // top to be in the top third of the screen.
7775 scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007776 }
7777 } else if (rect.top < screenTop) {
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007778 scrollYDelta = rect.top - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007779 }
7780
Cary Clark31b83672010-03-09 09:20:34 -05007781 int screenLeft = contentToViewX(content.left);
7782 int screenRight = contentToViewX(content.right);
7783 int width = screenRight - screenLeft;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007784 int scrollXDelta = 0;
7785
7786 if (rect.right > screenRight && rect.left > screenLeft) {
7787 if (rect.width() > width) {
7788 scrollXDelta += (rect.left - screenLeft);
7789 } else {
7790 scrollXDelta += (rect.right - screenRight);
7791 }
7792 } else if (rect.left < screenLeft) {
7793 scrollXDelta -= (screenLeft - rect.left);
7794 }
7795
7796 if ((scrollYDelta | scrollXDelta) != 0) {
7797 return pinScrollBy(scrollXDelta, scrollYDelta, !immediate, 0);
7798 }
7799
7800 return false;
7801 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007803 /* package */ void replaceTextfieldText(int oldStart, int oldEnd,
7804 String replace, int newStart, int newEnd) {
Cary Clarkded054c2009-06-15 10:26:08 -04007805 WebViewCore.ReplaceTextData arg = new WebViewCore.ReplaceTextData();
7806 arg.mReplace = replace;
7807 arg.mNewStart = newStart;
7808 arg.mNewEnd = newEnd;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07007809 mTextGeneration++;
Leon Scroggins43488fc2009-07-06 14:32:49 -04007810 arg.mTextGeneration = mTextGeneration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007811 mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
7812 }
7813
7814 /* package */ void passToJavaScript(String currentText, KeyEvent event) {
George Mount1fa26cb2011-10-03 10:56:28 -07007815 // check if mWebViewCore has been destroyed
7816 if (mWebViewCore == null) {
7817 return;
7818 }
Cary Clarkded054c2009-06-15 10:26:08 -04007819 WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
7820 arg.mEvent = event;
7821 arg.mCurrentText = currentText;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007822 // Increase our text generation number, and pass it to webcore thread
7823 mTextGeneration++;
7824 mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
7825 // WebKit's document state is not saved until about to leave the page.
Cary Clarkd6982c92009-05-29 11:02:22 -04007826 // To make sure the host application, like Browser, has the up to date
7827 // document state when it goes to background, we force to save the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007828 // document state.
7829 mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
7830 mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
Cary Clarkd6982c92009-05-29 11:02:22 -04007831 cursorData(), 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007832 }
7833
Dounia Berrada940a1982011-04-27 13:53:13 -07007834 /**
7835 * @hide
7836 */
7837 public synchronized WebViewCore getWebViewCore() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007838 return mWebViewCore;
7839 }
7840
Adam Powell4fb35d42011-03-03 17:54:55 -08007841 /**
7842 * Used only by TouchEventQueue to store pending touch events.
7843 */
7844 private static class QueuedTouch {
7845 long mSequence;
7846 MotionEvent mEvent; // Optional
7847 TouchEventData mTed; // Optional
7848
7849 QueuedTouch mNext;
7850
7851 public QueuedTouch set(TouchEventData ted) {
7852 mSequence = ted.mSequence;
7853 mTed = ted;
7854 mEvent = null;
7855 mNext = null;
7856 return this;
7857 }
7858
7859 public QueuedTouch set(MotionEvent ev, long sequence) {
7860 mEvent = MotionEvent.obtain(ev);
7861 mSequence = sequence;
7862 mTed = null;
7863 mNext = null;
7864 return this;
7865 }
7866
7867 public QueuedTouch add(QueuedTouch other) {
7868 if (other.mSequence < mSequence) {
7869 other.mNext = this;
7870 return other;
7871 }
7872
7873 QueuedTouch insertAt = this;
7874 while (insertAt.mNext != null && insertAt.mNext.mSequence < other.mSequence) {
7875 insertAt = insertAt.mNext;
7876 }
7877 other.mNext = insertAt.mNext;
7878 insertAt.mNext = other;
7879 return this;
7880 }
7881 }
7882
7883 /**
7884 * WebView handles touch events asynchronously since some events must be passed to WebKit
7885 * for potentially slower processing. TouchEventQueue serializes touch events regardless
7886 * of which path they take to ensure that no events are ever processed out of order
7887 * by WebView.
7888 */
7889 private class TouchEventQueue {
7890 private long mNextTouchSequence = Long.MIN_VALUE + 1;
7891 private long mLastHandledTouchSequence = Long.MIN_VALUE;
Adam Powelld0197f32011-03-17 00:09:03 -07007892 private long mIgnoreUntilSequence = Long.MIN_VALUE + 1;
Adam Powell3c534772011-04-04 14:27:12 -07007893
7894 // Events waiting to be processed.
Adam Powell4fb35d42011-03-03 17:54:55 -08007895 private QueuedTouch mTouchEventQueue;
Adam Powell3c534772011-04-04 14:27:12 -07007896
7897 // Known events that are waiting on a response before being enqueued.
7898 private QueuedTouch mPreQueue;
7899
7900 // Pool of QueuedTouch objects saved for later use.
Adam Powell4fb35d42011-03-03 17:54:55 -08007901 private QueuedTouch mQueuedTouchRecycleBin;
7902 private int mQueuedTouchRecycleCount;
Adam Powell3c534772011-04-04 14:27:12 -07007903
Adam Powelld0197f32011-03-17 00:09:03 -07007904 private long mLastEventTime = Long.MAX_VALUE;
Adam Powell4fb35d42011-03-03 17:54:55 -08007905 private static final int MAX_RECYCLED_QUEUED_TOUCH = 15;
7906
Adam Powell80615b02011-03-10 15:53:24 -08007907 // milliseconds until we abandon hope of getting all of a previous gesture
Adam Powelld0197f32011-03-17 00:09:03 -07007908 private static final int QUEUED_GESTURE_TIMEOUT = 1000;
Adam Powell80615b02011-03-10 15:53:24 -08007909
Adam Powell4fb35d42011-03-03 17:54:55 -08007910 private QueuedTouch obtainQueuedTouch() {
7911 if (mQueuedTouchRecycleBin != null) {
7912 QueuedTouch result = mQueuedTouchRecycleBin;
7913 mQueuedTouchRecycleBin = result.mNext;
7914 mQueuedTouchRecycleCount--;
7915 return result;
7916 }
7917 return new QueuedTouch();
7918 }
7919
Adam Powell80615b02011-03-10 15:53:24 -08007920 /**
7921 * Allow events with any currently missing sequence numbers to be skipped in processing.
7922 */
7923 public void ignoreCurrentlyMissingEvents() {
7924 mIgnoreUntilSequence = mNextTouchSequence;
Adam Powell3c534772011-04-04 14:27:12 -07007925
7926 // Run any events we have available and complete, pre-queued or otherwise.
7927 runQueuedAndPreQueuedEvents();
7928 }
7929
7930 private void runQueuedAndPreQueuedEvents() {
7931 QueuedTouch qd = mPreQueue;
7932 boolean fromPreQueue = true;
7933 while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
7934 handleQueuedTouch(qd);
7935 QueuedTouch recycleMe = qd;
7936 if (fromPreQueue) {
7937 mPreQueue = qd.mNext;
7938 } else {
7939 mTouchEventQueue = qd.mNext;
7940 }
7941 recycleQueuedTouch(recycleMe);
7942 mLastHandledTouchSequence++;
7943
7944 long nextPre = mPreQueue != null ? mPreQueue.mSequence : Long.MAX_VALUE;
7945 long nextQueued = mTouchEventQueue != null ?
7946 mTouchEventQueue.mSequence : Long.MAX_VALUE;
7947 fromPreQueue = nextPre < nextQueued;
7948 qd = fromPreQueue ? mPreQueue : mTouchEventQueue;
7949 }
7950 }
7951
7952 /**
7953 * Add a TouchEventData to the pre-queue.
7954 *
7955 * An event in the pre-queue is an event that we know about that
7956 * has been sent to webkit, but that we haven't received back and
7957 * enqueued into the normal touch queue yet. If webkit ever times
7958 * out and we need to ignore currently missing events, we'll run
7959 * events from the pre-queue to patch the holes.
7960 *
7961 * @param ted TouchEventData to pre-queue
7962 */
7963 public void preQueueTouchEventData(TouchEventData ted) {
7964 QueuedTouch newTouch = obtainQueuedTouch().set(ted);
7965 if (mPreQueue == null) {
7966 mPreQueue = newTouch;
7967 } else {
7968 QueuedTouch insertionPoint = mPreQueue;
7969 while (insertionPoint.mNext != null &&
7970 insertionPoint.mNext.mSequence < newTouch.mSequence) {
7971 insertionPoint = insertionPoint.mNext;
7972 }
7973 newTouch.mNext = insertionPoint.mNext;
7974 insertionPoint.mNext = newTouch;
7975 }
Adam Powell80615b02011-03-10 15:53:24 -08007976 }
7977
Adam Powell4fb35d42011-03-03 17:54:55 -08007978 private void recycleQueuedTouch(QueuedTouch qd) {
7979 if (mQueuedTouchRecycleCount < MAX_RECYCLED_QUEUED_TOUCH) {
7980 qd.mNext = mQueuedTouchRecycleBin;
7981 mQueuedTouchRecycleBin = qd;
7982 mQueuedTouchRecycleCount++;
7983 }
7984 }
7985
7986 /**
7987 * Reset the touch event queue. This will dump any pending events
7988 * and reset the sequence numbering.
7989 */
7990 public void reset() {
7991 mNextTouchSequence = Long.MIN_VALUE + 1;
7992 mLastHandledTouchSequence = Long.MIN_VALUE;
Adam Powelld0197f32011-03-17 00:09:03 -07007993 mIgnoreUntilSequence = Long.MIN_VALUE + 1;
Adam Powell4fb35d42011-03-03 17:54:55 -08007994 while (mTouchEventQueue != null) {
7995 QueuedTouch recycleMe = mTouchEventQueue;
7996 mTouchEventQueue = mTouchEventQueue.mNext;
7997 recycleQueuedTouch(recycleMe);
7998 }
Adam Powell3c534772011-04-04 14:27:12 -07007999 while (mPreQueue != null) {
8000 QueuedTouch recycleMe = mPreQueue;
8001 mPreQueue = mPreQueue.mNext;
8002 recycleQueuedTouch(recycleMe);
8003 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008004 }
8005
8006 /**
8007 * Return the next valid sequence number for tagging incoming touch events.
8008 * @return The next touch event sequence number
8009 */
8010 public long nextTouchSequence() {
8011 return mNextTouchSequence++;
8012 }
8013
8014 /**
8015 * Enqueue a touch event in the form of TouchEventData.
8016 * The sequence number will be read from the mSequence field of the argument.
8017 *
8018 * If the touch event's sequence number is the next in line to be processed, it will
8019 * be handled before this method returns. Any subsequent events that have already
8020 * been queued will also be processed in their proper order.
8021 *
8022 * @param ted Touch data to be processed in order.
Adam Powellbaa33802011-03-25 13:58:19 -07008023 * @return true if the event was processed before returning, false if it was just enqueued.
Adam Powell4fb35d42011-03-03 17:54:55 -08008024 */
Adam Powellbaa33802011-03-25 13:58:19 -07008025 public boolean enqueueTouchEvent(TouchEventData ted) {
Adam Powell3c534772011-04-04 14:27:12 -07008026 // Remove from the pre-queue if present
8027 QueuedTouch preQueue = mPreQueue;
8028 if (preQueue != null) {
8029 // On exiting this block, preQueue is set to the pre-queued QueuedTouch object
8030 // if it was present in the pre-queue, and removed from the pre-queue itself.
8031 if (preQueue.mSequence == ted.mSequence) {
8032 mPreQueue = preQueue.mNext;
8033 } else {
8034 QueuedTouch prev = preQueue;
8035 preQueue = null;
8036 while (prev.mNext != null) {
8037 if (prev.mNext.mSequence == ted.mSequence) {
8038 preQueue = prev.mNext;
8039 prev.mNext = preQueue.mNext;
8040 break;
8041 } else {
8042 prev = prev.mNext;
8043 }
8044 }
8045 }
8046 }
8047
Adam Powell80615b02011-03-10 15:53:24 -08008048 if (ted.mSequence < mLastHandledTouchSequence) {
8049 // Stale event and we already moved on; drop it. (Should not be common.)
8050 Log.w(LOGTAG, "Stale touch event " + MotionEvent.actionToString(ted.mAction) +
8051 " received from webcore; ignoring");
Adam Powellbaa33802011-03-25 13:58:19 -07008052 return false;
Adam Powell80615b02011-03-10 15:53:24 -08008053 }
8054
Adam Powelld0197f32011-03-17 00:09:03 -07008055 if (dropStaleGestures(ted.mMotionEvent, ted.mSequence)) {
Adam Powellbaa33802011-03-25 13:58:19 -07008056 return false;
Adam Powelld0197f32011-03-17 00:09:03 -07008057 }
Adam Powell80615b02011-03-10 15:53:24 -08008058
Adam Powell3c534772011-04-04 14:27:12 -07008059 // dropStaleGestures above might have fast-forwarded us to
8060 // an event we have already.
8061 runNextQueuedEvents();
8062
Adam Powell4fb35d42011-03-03 17:54:55 -08008063 if (mLastHandledTouchSequence + 1 == ted.mSequence) {
Adam Powell3c534772011-04-04 14:27:12 -07008064 if (preQueue != null) {
8065 recycleQueuedTouch(preQueue);
8066 preQueue = null;
8067 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008068 handleQueuedTouchEventData(ted);
8069
8070 mLastHandledTouchSequence++;
8071
8072 // Do we have any more? Run them if so.
Adam Powell3c534772011-04-04 14:27:12 -07008073 runNextQueuedEvents();
Adam Powell4fb35d42011-03-03 17:54:55 -08008074 } else {
Adam Powell3c534772011-04-04 14:27:12 -07008075 // Reuse the pre-queued object if we had it.
8076 QueuedTouch qd = preQueue != null ? preQueue : obtainQueuedTouch().set(ted);
Adam Powell4fb35d42011-03-03 17:54:55 -08008077 mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
8078 }
Adam Powellbaa33802011-03-25 13:58:19 -07008079 return true;
Adam Powell4fb35d42011-03-03 17:54:55 -08008080 }
8081
8082 /**
8083 * Enqueue a touch event in the form of a MotionEvent from the framework.
8084 *
8085 * If the touch event's sequence number is the next in line to be processed, it will
8086 * be handled before this method returns. Any subsequent events that have already
8087 * been queued will also be processed in their proper order.
8088 *
8089 * @param ev MotionEvent to be processed in order
8090 */
8091 public void enqueueTouchEvent(MotionEvent ev) {
8092 final long sequence = nextTouchSequence();
Adam Powell80615b02011-03-10 15:53:24 -08008093
Adam Powelld0197f32011-03-17 00:09:03 -07008094 if (dropStaleGestures(ev, sequence)) {
8095 return;
8096 }
Adam Powell80615b02011-03-10 15:53:24 -08008097
Adam Powell3c534772011-04-04 14:27:12 -07008098 // dropStaleGestures above might have fast-forwarded us to
8099 // an event we have already.
8100 runNextQueuedEvents();
8101
Adam Powell4fb35d42011-03-03 17:54:55 -08008102 if (mLastHandledTouchSequence + 1 == sequence) {
8103 handleQueuedMotionEvent(ev);
8104
8105 mLastHandledTouchSequence++;
8106
8107 // Do we have any more? Run them if so.
Adam Powell3c534772011-04-04 14:27:12 -07008108 runNextQueuedEvents();
Adam Powell4fb35d42011-03-03 17:54:55 -08008109 } else {
8110 QueuedTouch qd = obtainQueuedTouch().set(ev, sequence);
8111 mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
8112 }
8113 }
8114
Adam Powell3c534772011-04-04 14:27:12 -07008115 private void runNextQueuedEvents() {
8116 QueuedTouch qd = mTouchEventQueue;
8117 while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
8118 handleQueuedTouch(qd);
8119 QueuedTouch recycleMe = qd;
8120 qd = qd.mNext;
8121 recycleQueuedTouch(recycleMe);
8122 mLastHandledTouchSequence++;
8123 }
8124 mTouchEventQueue = qd;
8125 }
8126
Adam Powelld0197f32011-03-17 00:09:03 -07008127 private boolean dropStaleGestures(MotionEvent ev, long sequence) {
8128 if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && !mConfirmMove) {
8129 // This is to make sure that we don't attempt to process a tap
8130 // or long press when webkit takes too long to get back to us.
8131 // The movement will be properly confirmed when we process the
8132 // enqueued event later.
8133 final int dx = Math.round(ev.getX()) - mLastTouchX;
8134 final int dy = Math.round(ev.getY()) - mLastTouchY;
8135 if (dx * dx + dy * dy > mTouchSlopSquare) {
8136 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
8137 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
8138 }
8139 }
Adam Powell8f626a12011-03-10 19:27:15 -08008140
Adam Powelld0197f32011-03-17 00:09:03 -07008141 if (mTouchEventQueue == null) {
8142 return sequence <= mLastHandledTouchSequence;
8143 }
Adam Powell8f626a12011-03-10 19:27:15 -08008144
Adam Powelld0197f32011-03-17 00:09:03 -07008145 // If we have a new down event and it's been a while since the last event
Adam Powell3c534772011-04-04 14:27:12 -07008146 // we saw, catch up as best we can and keep going.
Adam Powelld0197f32011-03-17 00:09:03 -07008147 if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) {
Adam Powell80615b02011-03-10 15:53:24 -08008148 long eventTime = ev.getEventTime();
Adam Powelld0197f32011-03-17 00:09:03 -07008149 long lastHandledEventTime = mLastEventTime;
8150 if (eventTime > lastHandledEventTime + QUEUED_GESTURE_TIMEOUT) {
Adam Powell80615b02011-03-10 15:53:24 -08008151 Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " +
Adam Powell3c534772011-04-04 14:27:12 -07008152 "Catching up.");
8153 runQueuedAndPreQueuedEvents();
8154
8155 // Drop leftovers that we truly don't have.
Adam Powell80615b02011-03-10 15:53:24 -08008156 QueuedTouch qd = mTouchEventQueue;
8157 while (qd != null && qd.mSequence < sequence) {
8158 QueuedTouch recycleMe = qd;
8159 qd = qd.mNext;
8160 recycleQueuedTouch(recycleMe);
8161 }
8162 mTouchEventQueue = qd;
8163 mLastHandledTouchSequence = sequence - 1;
8164 }
8165 }
8166
Adam Powelld0197f32011-03-17 00:09:03 -07008167 if (mIgnoreUntilSequence - 1 > mLastHandledTouchSequence) {
Adam Powell80615b02011-03-10 15:53:24 -08008168 QueuedTouch qd = mTouchEventQueue;
Adam Powelld0197f32011-03-17 00:09:03 -07008169 while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
Adam Powell80615b02011-03-10 15:53:24 -08008170 QueuedTouch recycleMe = qd;
8171 qd = qd.mNext;
8172 recycleQueuedTouch(recycleMe);
8173 }
8174 mTouchEventQueue = qd;
Adam Powelld0197f32011-03-17 00:09:03 -07008175 mLastHandledTouchSequence = mIgnoreUntilSequence - 1;
Adam Powell80615b02011-03-10 15:53:24 -08008176 }
Adam Powelld0197f32011-03-17 00:09:03 -07008177
Adam Powell3c534772011-04-04 14:27:12 -07008178 if (mPreQueue != null) {
8179 // Drop stale prequeued events
8180 QueuedTouch qd = mPreQueue;
8181 while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
8182 QueuedTouch recycleMe = qd;
8183 qd = qd.mNext;
8184 recycleQueuedTouch(recycleMe);
8185 }
8186 mPreQueue = qd;
8187 }
8188
Adam Powelld0197f32011-03-17 00:09:03 -07008189 return sequence <= mLastHandledTouchSequence;
Adam Powell80615b02011-03-10 15:53:24 -08008190 }
8191
Adam Powell4fb35d42011-03-03 17:54:55 -08008192 private void handleQueuedTouch(QueuedTouch qt) {
8193 if (qt.mTed != null) {
8194 handleQueuedTouchEventData(qt.mTed);
8195 } else {
8196 handleQueuedMotionEvent(qt.mEvent);
8197 qt.mEvent.recycle();
8198 }
8199 }
8200
8201 private void handleQueuedMotionEvent(MotionEvent ev) {
Adam Powelld0197f32011-03-17 00:09:03 -07008202 mLastEventTime = ev.getEventTime();
Adam Powell4fb35d42011-03-03 17:54:55 -08008203 int action = ev.getActionMasked();
8204 if (ev.getPointerCount() > 1) { // Multi-touch
Adam Powell4fb35d42011-03-03 17:54:55 -08008205 handleMultiTouchInWebView(ev);
8206 } else {
8207 final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
Adam Powell8f626a12011-03-10 19:27:15 -08008208 if (detector != null && mPreventDefault != PREVENT_DEFAULT_YES) {
Adam Powell4fb35d42011-03-03 17:54:55 -08008209 // ScaleGestureDetector needs a consistent event stream to operate properly.
8210 // It won't take any action with fewer than two pointers, but it needs to
8211 // update internal bookkeeping state.
8212 detector.onTouchEvent(ev);
8213 }
8214
8215 handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY()));
8216 }
8217 }
8218
8219 private void handleQueuedTouchEventData(TouchEventData ted) {
Adam Powelld0197f32011-03-17 00:09:03 -07008220 if (ted.mMotionEvent != null) {
8221 mLastEventTime = ted.mMotionEvent.getEventTime();
8222 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008223 if (!ted.mReprocess) {
8224 if (ted.mAction == MotionEvent.ACTION_DOWN
8225 && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {
8226 // if prevent default is called from WebCore, UI
8227 // will not handle the rest of the touch events any
8228 // more.
8229 mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
8230 : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN;
8231 } else if (ted.mAction == MotionEvent.ACTION_MOVE
8232 && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
8233 // the return for the first ACTION_MOVE will decide
8234 // whether UI will handle touch or not. Currently no
8235 // support for alternating prevent default
8236 mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
8237 : PREVENT_DEFAULT_NO;
8238 }
8239 if (mPreventDefault == PREVENT_DEFAULT_YES) {
8240 mTouchHighlightRegion.setEmpty();
8241 }
8242 } else {
8243 if (ted.mPoints.length > 1) { // multi-touch
Adam Powell8f626a12011-03-10 19:27:15 -08008244 if (!ted.mNativeResult && mPreventDefault != PREVENT_DEFAULT_YES) {
Adam Powell4fb35d42011-03-03 17:54:55 -08008245 mPreventDefault = PREVENT_DEFAULT_NO;
8246 handleMultiTouchInWebView(ted.mMotionEvent);
8247 } else {
8248 mPreventDefault = PREVENT_DEFAULT_YES;
8249 }
8250 return;
8251 }
8252
8253 // prevent default is not called in WebCore, so the
8254 // message needs to be reprocessed in UI
8255 if (!ted.mNativeResult) {
8256 // Following is for single touch.
8257 switch (ted.mAction) {
8258 case MotionEvent.ACTION_DOWN:
Huahui Wu88b869a2011-03-17 17:42:12 -07008259 mLastDeferTouchX = ted.mPointsInView[0].x;
8260 mLastDeferTouchY = ted.mPointsInView[0].y;
Adam Powell4fb35d42011-03-03 17:54:55 -08008261 mDeferTouchMode = TOUCH_INIT_MODE;
8262 break;
8263 case MotionEvent.ACTION_MOVE: {
8264 // no snapping in defer process
Huahui Wu88b869a2011-03-17 17:42:12 -07008265 int x = ted.mPointsInView[0].x;
8266 int y = ted.mPointsInView[0].y;
8267
Adam Powell4fb35d42011-03-03 17:54:55 -08008268 if (mDeferTouchMode != TOUCH_DRAG_MODE) {
8269 mDeferTouchMode = TOUCH_DRAG_MODE;
8270 mLastDeferTouchX = x;
8271 mLastDeferTouchY = y;
8272 startScrollingLayer(x, y);
8273 startDrag();
8274 }
8275 int deltaX = pinLocX((int) (mScrollX
8276 + mLastDeferTouchX - x))
8277 - mScrollX;
8278 int deltaY = pinLocY((int) (mScrollY
8279 + mLastDeferTouchY - y))
8280 - mScrollY;
8281 doDrag(deltaX, deltaY);
8282 if (deltaX != 0) mLastDeferTouchX = x;
8283 if (deltaY != 0) mLastDeferTouchY = y;
8284 break;
8285 }
8286 case MotionEvent.ACTION_UP:
8287 case MotionEvent.ACTION_CANCEL:
8288 if (mDeferTouchMode == TOUCH_DRAG_MODE) {
8289 // no fling in defer process
8290 mScroller.springBack(mScrollX, mScrollY, 0,
8291 computeMaxScrollX(), 0,
8292 computeMaxScrollY());
8293 invalidate();
8294 WebViewCore.resumePriority();
8295 WebViewCore.resumeUpdatePicture(mWebViewCore);
8296 }
8297 mDeferTouchMode = TOUCH_DONE_MODE;
8298 break;
8299 case WebViewCore.ACTION_DOUBLETAP:
8300 // doDoubleTap() needs mLastTouchX/Y as anchor
Huahui Wu88b869a2011-03-17 17:42:12 -07008301 mLastDeferTouchX = ted.mPointsInView[0].x;
8302 mLastDeferTouchY = ted.mPointsInView[0].y;
Adam Powell4fb35d42011-03-03 17:54:55 -08008303 mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
8304 mDeferTouchMode = TOUCH_DONE_MODE;
8305 break;
8306 case WebViewCore.ACTION_LONGPRESS:
8307 HitTestResult hitTest = getHitTestResult();
8308 if (hitTest != null && hitTest.mType
8309 != HitTestResult.UNKNOWN_TYPE) {
8310 performLongClick();
8311 }
8312 mDeferTouchMode = TOUCH_DONE_MODE;
8313 break;
8314 }
8315 }
8316 }
8317 }
8318 }
8319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008320 //-------------------------------------------------------------------------
8321 // Methods can be called from a separate thread, like WebViewCore
8322 // If it needs to call the View system, it has to send message.
8323 //-------------------------------------------------------------------------
8324
8325 /**
8326 * General handler to receive message coming from webkit thread
8327 */
8328 class PrivateHandler extends Handler {
8329 @Override
8330 public void handleMessage(Message msg) {
Cary Clark3e88ddc2009-10-08 14:59:46 -04008331 // exclude INVAL_RECT_MSG_ID since it is frequently output
8332 if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) {
Grace Klobac2242f22010-03-05 14:00:26 -08008333 if (msg.what >= FIRST_PRIVATE_MSG_ID
8334 && msg.what <= LAST_PRIVATE_MSG_ID) {
8335 Log.v(LOGTAG, HandlerPrivateDebugString[msg.what
8336 - FIRST_PRIVATE_MSG_ID]);
8337 } else if (msg.what >= FIRST_PACKAGE_MSG_ID
8338 && msg.what <= LAST_PACKAGE_MSG_ID) {
8339 Log.v(LOGTAG, HandlerPackageDebugString[msg.what
8340 - FIRST_PACKAGE_MSG_ID]);
8341 } else {
8342 Log.v(LOGTAG, Integer.toString(msg.what));
8343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008344 }
Grace Kloba207308a2009-09-27 11:44:14 -07008345 if (mWebViewCore == null) {
8346 // after WebView's destroy() is called, skip handling messages.
8347 return;
8348 }
John Reck83e59292011-06-04 00:46:45 -07008349 if (mBlockWebkitViewMessages
8350 && msg.what != WEBCORE_INITIALIZED_MSG_ID) {
John Reck95b7d6f2011-06-03 15:23:43 -07008351 // Blocking messages from webkit
8352 return;
8353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008354 switch (msg.what) {
8355 case REMEMBER_PASSWORD: {
8356 mDatabase.setUsernamePassword(
8357 msg.getData().getString("host"),
8358 msg.getData().getString("username"),
8359 msg.getData().getString("password"));
8360 ((Message) msg.obj).sendToTarget();
8361 break;
8362 }
8363 case NEVER_REMEMBER_PASSWORD: {
8364 mDatabase.setUsernamePassword(
8365 msg.getData().getString("host"), null, null);
8366 ((Message) msg.obj).sendToTarget();
8367 break;
8368 }
Grace Klobac2242f22010-03-05 14:00:26 -08008369 case PREVENT_DEFAULT_TIMEOUT: {
8370 // if timeout happens, cancel it so that it won't block UI
8371 // to continue handling touch events
8372 if ((msg.arg1 == MotionEvent.ACTION_DOWN
8373 && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES)
8374 || (msg.arg1 == MotionEvent.ACTION_MOVE
8375 && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN)) {
8376 cancelWebCoreTouchEvent(
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08008377 viewToContentX(mLastTouchX + mScrollX),
8378 viewToContentY(mLastTouchY + mScrollY),
Grace Klobac2242f22010-03-05 14:00:26 -08008379 true);
Grace Klobaf58af622009-09-24 17:41:23 -07008380 }
Grace Klobac2242f22010-03-05 14:00:26 -08008381 break;
8382 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05008383 case SCROLL_SELECT_TEXT: {
8384 if (mAutoScrollX == 0 && mAutoScrollY == 0) {
8385 mSentAutoScrollMessage = false;
8386 break;
8387 }
Michael Kolb5da91bd2011-11-29 15:29:03 -08008388 if (mCurrentScrollingLayerId == 0) {
Cary Clarkb9aaa772011-01-07 16:14:54 -05008389 pinScrollBy(mAutoScrollX, mAutoScrollY, true, 0);
8390 } else {
John Reck83b9e1d2011-11-02 10:18:12 -07008391 scrollLayerTo(mScrollingLayerRect.left + mAutoScrollX,
8392 mScrollingLayerRect.top + mAutoScrollY);
Cary Clarkb9aaa772011-01-07 16:14:54 -05008393 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05008394 sendEmptyMessageDelayed(
8395 SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
8396 break;
8397 }
John Reck0966dd22011-09-18 11:03:00 -07008398 case UPDATE_SELECTION: {
8399 if (mTouchMode == TOUCH_INIT_MODE
8400 || mTouchMode == TOUCH_SHORTPRESS_MODE
8401 || mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
8402 updateSelection();
8403 }
8404 break;
8405 }
Grace Klobac2242f22010-03-05 14:00:26 -08008406 case SWITCH_TO_SHORTPRESS: {
Cary Clarkb8491342010-11-29 16:23:19 -05008407 mInitialHitTestResult = null; // set by updateSelection()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008408 if (mTouchMode == TOUCH_INIT_MODE) {
Grace Kloba178db412010-05-18 22:22:23 -07008409 if (!getSettings().supportTouchOnly()
8410 && mPreventDefault != PREVENT_DEFAULT_YES) {
Grace Klobac2242f22010-03-05 14:00:26 -08008411 mTouchMode = TOUCH_SHORTPRESS_START_MODE;
8412 updateSelection();
8413 } else {
8414 // set to TOUCH_SHORTPRESS_MODE so that it won't
8415 // trigger double tap any more
8416 mTouchMode = TOUCH_SHORTPRESS_MODE;
8417 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07008418 } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
8419 mTouchMode = TOUCH_DONE_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008420 }
8421 break;
8422 }
8423 case SWITCH_TO_LONGPRESS: {
John Reck335f4542011-08-25 18:25:09 -07008424 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
8425 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07008426 }
Grace Klobac2242f22010-03-05 14:00:26 -08008427 if (inFullScreenMode() || mDeferTouchProcess) {
8428 TouchEventData ted = new TouchEventData();
Grace Kloba5f68d6f2009-12-08 18:42:54 -08008429 ted.mAction = WebViewCore.ACTION_LONGPRESS;
Huahui Wue838a422011-01-13 16:03:43 -08008430 ted.mIds = new int[1];
8431 ted.mIds[0] = 0;
Huahui Wu41865f42010-09-02 13:41:41 -07008432 ted.mPoints = new Point[1];
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08008433 ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX),
8434 viewToContentY(mLastTouchY + mScrollY));
Huahui Wu88b869a2011-03-17 17:42:12 -07008435 ted.mPointsInView = new Point[1];
8436 ted.mPointsInView[0] = new Point(mLastTouchX, mLastTouchY);
Grace Klobac2242f22010-03-05 14:00:26 -08008437 // metaState for long press is tricky. Should it be the
8438 // state when the press started or when the press was
8439 // released? Or some intermediary key state? For
8440 // simplicity for now, we don't set it.
Ben Murdoch8a032a32010-02-02 18:20:11 +00008441 ted.mMetaState = 0;
Grace Klobac2242f22010-03-05 14:00:26 -08008442 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05008443 ted.mNativeLayer = nativeScrollableLayer(
8444 ted.mPoints[0].x, ted.mPoints[0].y,
8445 ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08008446 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07008447 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08008448 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Grace Klobac2242f22010-03-05 14:00:26 -08008449 } else if (mPreventDefault != PREVENT_DEFAULT_YES) {
Grace Kloba6c451b72009-06-25 12:25:30 -07008450 mTouchMode = TOUCH_DONE_MODE;
Grace Klobac2242f22010-03-05 14:00:26 -08008451 performLongClick();
Grace Kloba6c451b72009-06-25 12:25:30 -07008452 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008453 break;
8454 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07008455 case RELEASE_SINGLE_TAP: {
Grace Klobac2242f22010-03-05 14:00:26 -08008456 doShortPress();
Grace Kloba8b97e4b2009-07-28 13:11:38 -07008457 break;
8458 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05008459 case SCROLL_TO_MSG_ID: {
8460 // arg1 = animate, arg2 = onlyIfImeIsShowing
8461 // obj = Point(x, y)
8462 if (msg.arg2 == 1) {
Leon Scrogginsfe77eb62011-02-01 11:05:22 -05008463 // This scroll is intended to bring the textfield into
8464 // view, but is only necessary if the IME is showing
8465 InputMethodManager imm = InputMethodManager.peekInstance();
8466 if (imm == null || !imm.isAcceptingText()
8467 || (!imm.isActive(WebView.this) && (!inEditingMode()
8468 || !imm.isActive(mWebTextView)))) {
8469 break;
8470 }
8471 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05008472 final Point p = (Point) msg.obj;
8473 if (msg.arg1 == 1) {
8474 spawnContentScrollTo(p.x, p.y);
8475 } else {
8476 setContentScrollTo(p.x, p.y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008477 }
8478 break;
Patrick Scottfa8be1c2011-02-02 14:09:34 -05008479 }
Grace Kloba769ed212010-01-27 10:52:47 -08008480 case UPDATE_ZOOM_RANGE: {
Derek Sollenbergerb983c892010-06-28 08:38:28 -04008481 WebViewCore.ViewState viewState = (WebViewCore.ViewState) msg.obj;
Grace Kloba188bf8d2010-04-07 11:30:19 -07008482 // mScrollX contains the new minPrefWidth
Derek Sollenbergerb983c892010-06-28 08:38:28 -04008483 mZoomManager.updateZoomRange(viewState, getViewWidth(), viewState.mScrollX);
Grace Kloba769ed212010-01-27 10:52:47 -08008484 break;
8485 }
Mangesh Ghiware31f263d2011-11-21 16:54:20 -08008486 case UPDATE_ZOOM_DENSITY: {
8487 final float density = (Float) msg.obj;
8488 mZoomManager.updateDefaultZoomDensity(density);
8489 break;
8490 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07008491 case REPLACE_BASE_CONTENT: {
8492 nativeReplaceBaseContent(msg.arg1);
8493 break;
8494 }
Grace Klobae397a882009-08-06 12:04:14 -07008495 case NEW_PICTURE_MSG_ID: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008496 // called for new content
Derek Sollenberger341e22f2010-06-02 12:34:34 -04008497 final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
John Reck60c84d62011-06-08 18:00:02 -07008498 setNewPicture(draw, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008499 break;
Grace Klobae397a882009-08-06 12:04:14 -07008500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008501 case WEBCORE_INITIALIZED_MSG_ID:
8502 // nativeCreate sets mNativeClass to a non-zero value
Leon Scrogginscdaff15bd2011-03-04 12:30:03 -05008503 String drawableDir = BrowserFrame.getRawResFilename(
8504 BrowserFrame.DRAWABLEDIR, mContext);
John Reck0507ac42011-11-21 13:30:32 -08008505 WindowManager windowManager =
8506 (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
8507 Display display = windowManager.getDefaultDisplay();
8508 nativeCreate(msg.arg1, drawableDir,
8509 ActivityManager.isHighEndGfx(display));
John Reck83e59292011-06-04 00:46:45 -07008510 if (mDelaySetPicture != null) {
John Reck60c84d62011-06-08 18:00:02 -07008511 setNewPicture(mDelaySetPicture, true);
John Reck83e59292011-06-04 00:46:45 -07008512 mDelaySetPicture = null;
8513 }
John Reck5f1c5492011-11-09 16:23:07 -08008514 if (mIsPaused) {
8515 nativeSetPauseDrawing(mNativeClass, true);
8516 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008517 break;
8518 case UPDATE_TEXTFIELD_TEXT_MSG_ID:
8519 // Make sure that the textfield is currently focused
Cary Clarkd6982c92009-05-29 11:02:22 -04008520 // and representing the same node as the pointer.
8521 if (inEditingMode() &&
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008522 mWebTextView.isSameTextField(msg.arg1)) {
Chris Craike3e7a882011-07-25 14:35:22 -07008523 if (msg.arg2 == mTextGeneration) {
Leon Scrogginsef7af282010-11-11 14:20:06 -05008524 String text = (String) msg.obj;
8525 if (null == text) {
8526 text = "";
8527 }
8528 mWebTextView.setTextAndKeepSelection(text);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008529 }
8530 }
8531 break;
Leon Scrogginsb4157792010-03-18 12:42:33 -04008532 case REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID:
8533 displaySoftKeyboard(true);
Leon Scroggins III901a7c22010-04-20 15:14:02 -04008534 // fall through to UPDATE_TEXT_SELECTION_MSG_ID
Leon Scroggins6679f2f2009-08-12 18:48:10 -04008535 case UPDATE_TEXT_SELECTION_MSG_ID:
Leon Scrogginsb4157792010-03-18 12:42:33 -04008536 updateTextSelectionFromMessage(msg.arg1, msg.arg2,
8537 (WebViewCore.TextSelectionData) msg.obj);
Leon Scroggins6679f2f2009-08-12 18:48:10 -04008538 break;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -04008539 case FORM_DID_BLUR:
8540 if (inEditingMode()
8541 && mWebTextView.isSameTextField(msg.arg1)) {
8542 hideSoftKeyboard();
8543 }
8544 break;
Leon Scroggins3a503392010-01-06 17:04:38 -05008545 case RETURN_LABEL:
8546 if (inEditingMode()
8547 && mWebTextView.isSameTextField(msg.arg1)) {
8548 mWebTextView.setHint((String) msg.obj);
8549 InputMethodManager imm
8550 = InputMethodManager.peekInstance();
8551 // The hint is propagated to the IME in
8552 // onCreateInputConnection. If the IME is already
8553 // active, restart it so that its hint text is updated.
8554 if (imm != null && imm.isActive(mWebTextView)) {
8555 imm.restartInput(mWebTextView);
8556 }
8557 }
8558 break;
Leon Scroggins9ab32b62010-05-03 14:19:50 +01008559 case UNHANDLED_NAV_KEY:
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008560 navHandledKey(msg.arg1, 1, false, 0);
Cary Clark215b72c2009-06-26 14:38:43 -04008561 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008562 case UPDATE_TEXT_ENTRY_MSG_ID:
Cary Clarkd6982c92009-05-29 11:02:22 -04008563 // this is sent after finishing resize in WebViewCore. Make
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008564 // sure the text edit box is still on the screen.
Cary Clarkd6982c92009-05-29 11:02:22 -04008565 if (inEditingMode() && nativeCursorIsTextInput()) {
John Reckc0e9fb92011-10-21 12:39:43 -07008566 updateWebTextViewPosition();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008568 break;
Cary Clark243ea062009-06-25 10:49:32 -04008569 case CLEAR_TEXT_ENTRY:
Leon Scroggins2aed7762010-08-13 17:11:42 -04008570 clearTextEntry();
Cary Clark243ea062009-06-25 10:49:32 -04008571 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008572 case INVAL_RECT_MSG_ID: {
8573 Rect r = (Rect)msg.obj;
8574 if (r == null) {
8575 invalidate();
8576 } else {
8577 // we need to scale r from content into view coords,
8578 // which viewInvalidate() does for us
8579 viewInvalidate(r.left, r.top, r.right, r.bottom);
8580 }
8581 break;
8582 }
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008583 case REQUEST_FORM_DATA:
Cary Clarkded054c2009-06-15 10:26:08 -04008584 AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj;
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008585 if (mWebTextView.isSameTextField(msg.arg1)) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008586 mWebTextView.setAdapterCustom(adapter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008587 }
8588 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008589
Leon Scrogginse3225672009-06-03 15:53:13 -04008590 case LONG_PRESS_CENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008591 // as this is shared by keydown and trackballdown, reset all
8592 // the states
Leon Scrogginse3225672009-06-03 15:53:13 -04008593 mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008594 mTrackballDown = false;
Grace Kloba98e6fcf2010-01-27 15:20:30 -08008595 performLongClick();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008596 break;
8597
8598 case WEBCORE_NEED_TOUCH_EVENTS:
8599 mForwardTouchEvents = (msg.arg1 != 0);
8600 break;
8601
8602 case PREVENT_TOUCH_ID:
Grace Klobac2242f22010-03-05 14:00:26 -08008603 if (inFullScreenMode()) {
8604 break;
8605 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008606 TouchEventData ted = (TouchEventData) msg.obj;
Adam Powellae9d2642011-03-08 16:00:30 -08008607
Adam Powellbaa33802011-03-25 13:58:19 -07008608 if (mTouchEventQueue.enqueueTouchEvent(ted)) {
8609 // WebCore is responding to us; remove pending timeout.
8610 // It will be re-posted when needed.
8611 removeMessages(PREVENT_DEFAULT_TIMEOUT);
8612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008613 break;
8614
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04008615 case REQUEST_KEYBOARD:
8616 if (msg.arg1 == 0) {
8617 hideSoftKeyboard();
8618 } else {
Leon Scrogginsb4157792010-03-18 12:42:33 -04008619 displaySoftKeyboard(false);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04008620 }
8621 break;
8622
Leon Scroggins5de63892009-10-29 09:48:43 -04008623 case FIND_AGAIN:
8624 // Ignore if find has been dismissed.
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04008625 if (mFindIsUp && mFindCallback != null) {
8626 mFindCallback.findAll();
Leon Scroggins5de63892009-10-29 09:48:43 -04008627 }
8628 break;
8629
Cary Clark25415e22009-10-12 13:41:28 -04008630 case DRAG_HELD_MOTIONLESS:
8631 mHeldMotionless = MOTIONLESS_TRUE;
8632 invalidate();
8633 // fall through to keep scrollbars awake
8634
8635 case AWAKEN_SCROLL_BARS:
8636 if (mTouchMode == TOUCH_DRAG_MODE
8637 && mHeldMotionless == MOTIONLESS_TRUE) {
8638 awakenScrollBars(ViewConfiguration
8639 .getScrollDefaultDelay(), false);
8640 mPrivateHandler.sendMessageDelayed(mPrivateHandler
8641 .obtainMessage(AWAKEN_SCROLL_BARS),
8642 ViewConfiguration.getScrollDefaultDelay());
8643 }
8644 break;
Cary Clark1cb97ee2009-12-11 12:10:36 -05008645
8646 case DO_MOTION_UP:
Cary Clarkbad0c542010-01-11 14:58:21 -05008647 doMotionUp(msg.arg1, msg.arg2);
Cary Clark1cb97ee2009-12-11 12:10:36 -05008648 break;
8649
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -05008650 case SCREEN_ON:
8651 setKeepScreenOn(msg.arg1 == 1);
8652 break;
8653
Nicolas Roard0e778a12011-03-11 14:29:05 -08008654 case ENTER_FULLSCREEN_VIDEO:
8655 int layerId = msg.arg1;
Teng-Hui Zhu10ab6542011-03-16 16:42:32 -07008656
8657 String url = (String) msg.obj;
8658 if (mHTML5VideoViewProxy != null) {
8659 mHTML5VideoViewProxy.enterFullScreenVideo(layerId, url);
8660 }
Nicolas Roard0e778a12011-03-11 14:29:05 -08008661 break;
8662
Grace Kloba3a0def22010-01-23 21:11:54 -08008663 case SHOW_FULLSCREEN: {
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008664 View view = (View) msg.obj;
Derek Sollenberger7ab3d672011-06-01 14:45:05 -04008665 int orientation = msg.arg1;
8666 int npp = msg.arg2;
Grace Kloba11438c32009-12-16 11:39:12 -08008667
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008668 if (inFullScreenMode()) {
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008669 Log.w(LOGTAG, "Should not have another full screen.");
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008670 dismissFullScreenMode();
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008671 }
Derek Sollenberger7ab3d672011-06-01 14:45:05 -04008672 mFullScreenHolder = new PluginFullScreenHolder(WebView.this, orientation, npp);
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008673 mFullScreenHolder.setContentView(view);
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008674 mFullScreenHolder.show();
George Mount5d3f6e62011-12-05 15:19:00 -08008675 invalidate();
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008676
8677 break;
8678 }
Grace Kloba11438c32009-12-16 11:39:12 -08008679 case HIDE_FULLSCREEN:
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008680 dismissFullScreenMode();
Grace Kloba11438c32009-12-16 11:39:12 -08008681 break;
8682
Leon Scrogginse26efa32009-12-15 16:38:45 -05008683 case DOM_FOCUS_CHANGED:
8684 if (inEditingMode()) {
8685 nativeClearCursor();
8686 rebuildWebTextView();
8687 }
8688 break;
8689
Grace Kloba3a0def22010-01-23 21:11:54 -08008690 case SHOW_RECT_MSG_ID: {
8691 WebViewCore.ShowRectData data = (WebViewCore.ShowRectData) msg.obj;
8692 int x = mScrollX;
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008693 int left = contentToViewX(data.mLeft);
Grace Kloba3a0def22010-01-23 21:11:54 -08008694 int width = contentToViewDimension(data.mWidth);
8695 int maxWidth = contentToViewDimension(data.mContentWidth);
8696 int viewWidth = getViewWidth();
8697 if (width < viewWidth) {
8698 // center align
8699 x += left + width / 2 - mScrollX - viewWidth / 2;
8700 } else {
8701 x += (int) (left + data.mXPercentInDoc * width
8702 - mScrollX - data.mXPercentInView * viewWidth);
8703 }
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008704 if (DebugFlags.WEB_VIEW) {
8705 Log.v(LOGTAG, "showRectMsg=(left=" + left + ",width=" +
8706 width + ",maxWidth=" + maxWidth +
8707 ",viewWidth=" + viewWidth + ",x="
8708 + x + ",xPercentInDoc=" + data.mXPercentInDoc +
8709 ",xPercentInView=" + data.mXPercentInView+ ")");
8710 }
Grace Kloba3a0def22010-01-23 21:11:54 -08008711 // use the passing content width to cap x as the current
8712 // mContentWidth may not be updated yet
8713 x = Math.max(0,
8714 (Math.min(maxWidth, x + viewWidth)) - viewWidth);
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008715 int top = contentToViewY(data.mTop);
Grace Kloba3a0def22010-01-23 21:11:54 -08008716 int height = contentToViewDimension(data.mHeight);
8717 int maxHeight = contentToViewDimension(data.mContentHeight);
8718 int viewHeight = getViewHeight();
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008719 int y = (int) (top + data.mYPercentInDoc * height -
8720 data.mYPercentInView * viewHeight);
8721 if (DebugFlags.WEB_VIEW) {
8722 Log.v(LOGTAG, "showRectMsg=(top=" + top + ",height=" +
8723 height + ",maxHeight=" + maxHeight +
8724 ",viewHeight=" + viewHeight + ",y="
8725 + y + ",yPercentInDoc=" + data.mYPercentInDoc +
8726 ",yPercentInView=" + data.mYPercentInView+ ")");
Grace Kloba3a0def22010-01-23 21:11:54 -08008727 }
8728 // use the passing content height to cap y as the current
8729 // mContentHeight may not be updated yet
8730 y = Math.max(0,
8731 (Math.min(maxHeight, y + viewHeight) - viewHeight));
Shimeng (Simon) Wangb7f17d42010-02-08 15:17:21 -08008732 // We need to take into account the visible title height
8733 // when scrolling since y is an absolute view position.
Steve Block92c99162011-05-23 17:36:01 +01008734 y = Math.max(0, y - getVisibleTitleHeightImpl());
Grace Kloba3a0def22010-01-23 21:11:54 -08008735 scrollTo(x, y);
8736 }
8737 break;
8738
Grace Klobae8300a12010-03-12 13:32:55 -08008739 case CENTER_FIT_RECT:
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05008740 centerFitRect((Rect)msg.obj);
Grace Klobae8300a12010-03-12 13:32:55 -08008741 break;
8742
Grace Kloba50004bc2010-04-13 22:58:51 -07008743 case SET_SCROLLBAR_MODES:
8744 mHorizontalScrollBarMode = msg.arg1;
8745 mVerticalScrollBarMode = msg.arg2;
8746 break;
8747
Svetoslav Ganovda355512010-05-12 22:04:44 -07008748 case SELECTION_STRING_CHANGED:
8749 if (mAccessibilityInjector != null) {
8750 String selectionString = (String) msg.obj;
8751 mAccessibilityInjector.onSelectionStringChange(selectionString);
8752 }
8753 break;
8754
Grace Kloba178db412010-05-18 22:22:23 -07008755 case SET_TOUCH_HIGHLIGHT_RECTS:
John Reck335f4542011-08-25 18:25:09 -07008756 @SuppressWarnings("unchecked")
8757 ArrayList<Rect> rects = (ArrayList<Rect>) msg.obj;
8758 setTouchHighlightRects(rects);
Grace Kloba178db412010-05-18 22:22:23 -07008759 break;
8760
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07008761 case SAVE_WEBARCHIVE_FINISHED:
8762 SaveWebArchiveMessage saveMessage = (SaveWebArchiveMessage)msg.obj;
8763 if (saveMessage.mCallback != null) {
8764 saveMessage.mCallback.onReceiveValue(saveMessage.mResultFile);
8765 }
8766 break;
8767
Ben Murdoch62275a42010-09-07 11:27:28 +01008768 case SET_AUTOFILLABLE:
Ben Murdochdb8d19c2010-10-29 11:44:17 +01008769 mAutoFillData = (WebViewCore.AutoFillData) msg.obj;
Ben Murdoch62275a42010-09-07 11:27:28 +01008770 if (mWebTextView != null) {
Ben Murdochdb8d19c2010-10-29 11:44:17 +01008771 mWebTextView.setAutoFillable(mAutoFillData.getQueryId());
Ben Murdoch62275a42010-09-07 11:27:28 +01008772 rebuildWebTextView();
8773 }
8774 break;
8775
Ben Murdoch961d55f2010-12-02 13:58:24 +00008776 case AUTOFILL_COMPLETE:
8777 if (mWebTextView != null) {
8778 // Clear the WebTextView adapter when AutoFill finishes
8779 // so that the drop down gets cleared.
8780 mWebTextView.setAdapterCustom(null);
8781 }
8782 break;
8783
Svetoslav Ganov9504f572011-01-14 11:38:17 -08008784 case SELECT_AT:
8785 nativeSelectAt(msg.arg1, msg.arg2);
8786 break;
8787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008788 default:
8789 super.handleMessage(msg);
8790 break;
8791 }
8792 }
8793 }
8794
John Reck335f4542011-08-25 18:25:09 -07008795 private void setTouchHighlightRects(ArrayList<Rect> rects) {
8796 invalidate(mTouchHighlightRegion.getBounds());
8797 mTouchHighlightRegion.setEmpty();
8798 if (rects != null) {
8799 for (Rect rect : rects) {
8800 Rect viewRect = contentToViewRect(rect);
8801 // some sites, like stories in nytimes.com, set
8802 // mouse event handler in the top div. It is not
8803 // user friendly to highlight the div if it covers
8804 // more than half of the screen.
8805 if (viewRect.width() < getWidth() >> 1
8806 || viewRect.height() < getHeight() >> 1) {
8807 mTouchHighlightRegion.union(viewRect);
8808 } else {
8809 Log.w(LOGTAG, "Skip the huge selection rect:"
8810 + viewRect);
8811 }
8812 }
8813 invalidate(mTouchHighlightRegion.getBounds());
8814 }
8815 }
8816
Chris Craik555c55e2011-07-28 15:39:43 -07008817 /** @hide Called by JNI when pages are swapped (only occurs with hardware
8818 * acceleration) */
Chris Craikd0051c02011-11-29 10:26:10 -08008819 protected void pageSwapCallback(boolean notifyAnimationStarted) {
Chris Craik5cf78f72011-07-28 11:34:31 -07008820 if (inEditingMode()) {
8821 didUpdateWebTextViewDimensions(ANYWHERE);
8822 }
Chris Craikd0051c02011-11-29 10:26:10 -08008823 if (notifyAnimationStarted) {
8824 mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
8825 }
Chris Craik5cf78f72011-07-28 11:34:31 -07008826 }
8827
John Reck60c84d62011-06-08 18:00:02 -07008828 void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) {
John Reck83e59292011-06-04 00:46:45 -07008829 if (mNativeClass == 0) {
8830 if (mDelaySetPicture != null) {
John Reck60c84d62011-06-08 18:00:02 -07008831 throw new IllegalStateException("Tried to setNewPicture with"
8832 + " a delay picture already set! (memory leak)");
John Reck83e59292011-06-04 00:46:45 -07008833 }
8834 // Not initialized yet, delay set
8835 mDelaySetPicture = draw;
8836 return;
8837 }
John Reck816c0de2011-06-02 16:04:53 -07008838 WebViewCore.ViewState viewState = draw.mViewState;
8839 boolean isPictureAfterFirstLayout = viewState != null;
Chris Craik5cf78f72011-07-28 11:34:31 -07008840
John Reck60c84d62011-06-08 18:00:02 -07008841 if (updateBaseLayer) {
Chris Craik555c55e2011-07-28 15:39:43 -07008842 // Request a callback on pageSwap (to reposition the webtextview)
8843 boolean registerPageSwapCallback =
8844 !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
8845
John Reck60c84d62011-06-08 18:00:02 -07008846 setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
8847 getSettings().getShowVisualIndicator(),
Chris Craik5cf78f72011-07-28 11:34:31 -07008848 isPictureAfterFirstLayout, registerPageSwapCallback);
John Reck60c84d62011-06-08 18:00:02 -07008849 }
John Reck816c0de2011-06-02 16:04:53 -07008850 final Point viewSize = draw.mViewSize;
John Reck816c0de2011-06-02 16:04:53 -07008851 // We update the layout (i.e. request a layout from the
8852 // view system) if the last view size that we sent to
8853 // WebCore matches the view size of the picture we just
8854 // received in the fixed dimension.
8855 final boolean updateLayout = viewSize.x == mLastWidthSent
8856 && viewSize.y == mLastHeightSent;
8857 // Don't send scroll event for picture coming from webkit,
8858 // since the new picture may cause a scroll event to override
8859 // the saved history scroll position.
8860 mSendScrollEvent = false;
8861 recordNewContentSize(draw.mContentSize.x,
8862 draw.mContentSize.y, updateLayout);
George Mounte263bc12011-10-31 13:49:03 -07008863 if (isPictureAfterFirstLayout) {
8864 // Reset the last sent data here since dealing with new page.
8865 mLastWidthSent = 0;
8866 mZoomManager.onFirstLayout(draw);
8867 int scrollX = viewState.mShouldStartScrolledRight
8868 ? getContentWidth() : viewState.mScrollX;
8869 int scrollY = viewState.mScrollY;
8870 setContentScrollTo(scrollX, scrollY);
8871 if (!mDrawHistory) {
8872 // As we are on a new page, remove the WebTextView. This
8873 // is necessary for page loads driven by webkit, and in
8874 // particular when the user was on a password field, so
8875 // the WebTextView was visible.
8876 clearTextEntry();
8877 }
8878 }
John Reck816c0de2011-06-02 16:04:53 -07008879 mSendScrollEvent = true;
George Mounte263bc12011-10-31 13:49:03 -07008880
John Reck816c0de2011-06-02 16:04:53 -07008881 if (DebugFlags.WEB_VIEW) {
8882 Rect b = draw.mInvalRegion.getBounds();
8883 Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
8884 b.left+","+b.top+","+b.right+","+b.bottom+"}");
8885 }
8886 invalidateContentRect(draw.mInvalRegion.getBounds());
8887
8888 if (mPictureListener != null) {
8889 mPictureListener.onNewPicture(WebView.this, capturePicture());
8890 }
8891
8892 // update the zoom information based on the new picture
8893 mZoomManager.onNewPicture(draw);
8894
8895 if (draw.mFocusSizeChanged && inEditingMode()) {
8896 mFocusSizeChanged = true;
8897 }
8898 if (isPictureAfterFirstLayout) {
8899 mViewManager.postReadyToDrawAll();
8900 }
8901 }
8902
Leon Scrogginsb4157792010-03-18 12:42:33 -04008903 /**
8904 * Used when receiving messages for REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID
8905 * and UPDATE_TEXT_SELECTION_MSG_ID. Update the selection of WebTextView.
8906 */
8907 private void updateTextSelectionFromMessage(int nodePointer,
8908 int textGeneration, WebViewCore.TextSelectionData data) {
8909 if (inEditingMode()
8910 && mWebTextView.isSameTextField(nodePointer)
8911 && textGeneration == mTextGeneration) {
8912 mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd);
8913 }
8914 }
8915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008916 // Class used to use a dropdown for a <select> element
8917 private class InvokeListBox implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008918 // Whether the listbox allows multiple selection.
8919 private boolean mMultiple;
8920 // Passed in to a list with multiple selection to tell
8921 // which items are selected.
8922 private int[] mSelectedArray;
Cary Clarkd6982c92009-05-29 11:02:22 -04008923 // Passed in to a list with single selection to tell
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008924 // where the initial selection is.
8925 private int mSelection;
8926
8927 private Container[] mContainers;
8928
8929 // Need these to provide stable ids to my ArrayAdapter,
8930 // which normally does not have stable ids. (Bug 1250098)
8931 private class Container extends Object {
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008932 /**
8933 * Possible values for mEnabled. Keep in sync with OptionStatus in
8934 * WebViewCore.cpp
8935 */
8936 final static int OPTGROUP = -1;
8937 final static int OPTION_DISABLED = 0;
8938 final static int OPTION_ENABLED = 1;
8939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008940 String mString;
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008941 int mEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008942 int mId;
8943
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08008944 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008945 public String toString() {
8946 return mString;
8947 }
8948 }
8949
8950 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04008951 * Subclass ArrayAdapter so we can disable OptionGroupLabels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008952 * and allow filtering.
8953 */
8954 private class MyArrayListAdapter extends ArrayAdapter<Container> {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008955 public MyArrayListAdapter() {
8956 super(mContext,
8957 mMultiple ? com.android.internal.R.layout.select_dialog_multichoice :
8958 com.android.internal.R.layout.webview_select_singlechoice,
8959 mContainers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008960 }
8961
8962 @Override
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008963 public View getView(int position, View convertView,
8964 ViewGroup parent) {
8965 // Always pass in null so that we will get a new CheckedTextView
8966 // Otherwise, an item which was previously used as an <optgroup>
8967 // element (i.e. has no check), could get used as an <option>
8968 // element, which needs a checkbox/radio, but it would not have
8969 // one.
8970 convertView = super.getView(position, null, parent);
8971 Container c = item(position);
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -04008972 if (c != null && Container.OPTION_ENABLED != c.mEnabled) {
8973 // ListView does not draw dividers between disabled and
8974 // enabled elements. Use a LinearLayout to provide dividers
8975 LinearLayout layout = new LinearLayout(mContext);
8976 layout.setOrientation(LinearLayout.VERTICAL);
8977 if (position > 0) {
8978 View dividerTop = new View(mContext);
8979 dividerTop.setBackgroundResource(
8980 android.R.drawable.divider_horizontal_bright);
8981 layout.addView(dividerTop);
8982 }
8983
8984 if (Container.OPTGROUP == c.mEnabled) {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008985 // Currently select_dialog_multichoice uses CheckedTextViews.
8986 // If that changes, the class cast will no longer be valid.
8987 if (mMultiple) {
8988 Assert.assertTrue(convertView instanceof CheckedTextView);
8989 ((CheckedTextView) convertView).setCheckMarkDrawable(null);
8990 }
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -04008991 } else {
8992 // c.mEnabled == Container.OPTION_DISABLED
8993 // Draw the disabled element in a disabled state.
8994 convertView.setEnabled(false);
8995 }
8996
8997 layout.addView(convertView);
8998 if (position < getCount() - 1) {
8999 View dividerBottom = new View(mContext);
9000 dividerBottom.setBackgroundResource(
9001 android.R.drawable.divider_horizontal_bright);
9002 layout.addView(dividerBottom);
9003 }
9004 return layout;
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009005 }
9006 return convertView;
9007 }
9008
9009 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009010 public boolean hasStableIds() {
Leon Scroggins3667ce42009-05-13 15:58:03 -04009011 // AdapterView's onChanged method uses this to determine whether
9012 // to restore the old state. Return false so that the old (out
9013 // of date) state does not replace the new, valid state.
9014 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009015 }
9016
9017 private Container item(int position) {
9018 if (position < 0 || position >= getCount()) {
9019 return null;
9020 }
9021 return (Container) getItem(position);
9022 }
9023
9024 @Override
9025 public long getItemId(int position) {
9026 Container item = item(position);
9027 if (item == null) {
9028 return -1;
9029 }
9030 return item.mId;
9031 }
9032
9033 @Override
9034 public boolean areAllItemsEnabled() {
9035 return false;
9036 }
9037
9038 @Override
9039 public boolean isEnabled(int position) {
9040 Container item = item(position);
9041 if (item == null) {
9042 return false;
9043 }
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009044 return Container.OPTION_ENABLED == item.mEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009045 }
9046 }
9047
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009048 private InvokeListBox(String[] array, int[] enabled, int[] selected) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 mMultiple = true;
9050 mSelectedArray = selected;
9051
9052 int length = array.length;
9053 mContainers = new Container[length];
9054 for (int i = 0; i < length; i++) {
9055 mContainers[i] = new Container();
9056 mContainers[i].mString = array[i];
9057 mContainers[i].mEnabled = enabled[i];
9058 mContainers[i].mId = i;
9059 }
9060 }
9061
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009062 private InvokeListBox(String[] array, int[] enabled, int selection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009063 mSelection = selection;
9064 mMultiple = false;
9065
9066 int length = array.length;
9067 mContainers = new Container[length];
9068 for (int i = 0; i < length; i++) {
9069 mContainers[i] = new Container();
9070 mContainers[i].mString = array[i];
9071 mContainers[i].mEnabled = enabled[i];
9072 mContainers[i].mId = i;
9073 }
9074 }
9075
Leon Scroggins3667ce42009-05-13 15:58:03 -04009076 /*
9077 * Whenever the data set changes due to filtering, this class ensures
9078 * that the checked item remains checked.
9079 */
9080 private class SingleDataSetObserver extends DataSetObserver {
9081 private long mCheckedId;
9082 private ListView mListView;
9083 private Adapter mAdapter;
9084
9085 /*
9086 * Create a new observer.
9087 * @param id The ID of the item to keep checked.
9088 * @param l ListView for getting and clearing the checked states
9089 * @param a Adapter for getting the IDs
9090 */
9091 public SingleDataSetObserver(long id, ListView l, Adapter a) {
9092 mCheckedId = id;
9093 mListView = l;
9094 mAdapter = a;
9095 }
9096
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05009097 @Override
Leon Scroggins3667ce42009-05-13 15:58:03 -04009098 public void onChanged() {
9099 // The filter may have changed which item is checked. Find the
9100 // item that the ListView thinks is checked.
9101 int position = mListView.getCheckedItemPosition();
9102 long id = mAdapter.getItemId(position);
9103 if (mCheckedId != id) {
9104 // Clear the ListView's idea of the checked item, since
9105 // it is incorrect
9106 mListView.clearChoices();
9107 // Search for mCheckedId. If it is in the filtered list,
9108 // mark it as checked
9109 int count = mAdapter.getCount();
9110 for (int i = 0; i < count; i++) {
9111 if (mAdapter.getItemId(i) == mCheckedId) {
9112 mListView.setItemChecked(i, true);
9113 break;
9114 }
9115 }
9116 }
9117 }
Leon Scroggins3667ce42009-05-13 15:58:03 -04009118 }
9119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009120 public void run() {
9121 final ListView listView = (ListView) LayoutInflater.from(mContext)
9122 .inflate(com.android.internal.R.layout.select_dialog, null);
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05009123 final MyArrayListAdapter adapter = new MyArrayListAdapter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009124 AlertDialog.Builder b = new AlertDialog.Builder(mContext)
9125 .setView(listView).setCancelable(true)
9126 .setInverseBackgroundForced(true);
Cary Clarkd6982c92009-05-29 11:02:22 -04009127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009128 if (mMultiple) {
9129 b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
9130 public void onClick(DialogInterface dialog, int which) {
9131 mWebViewCore.sendMessage(
Cary Clarkd6982c92009-05-29 11:02:22 -04009132 EventHub.LISTBOX_CHOICES,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009133 adapter.getCount(), 0,
9134 listView.getCheckedItemPositions());
9135 }});
Leon Scroggins238ddbb2009-04-02 10:47:53 -07009136 b.setNegativeButton(android.R.string.cancel,
9137 new DialogInterface.OnClickListener() {
9138 public void onClick(DialogInterface dialog, int which) {
9139 mWebViewCore.sendMessage(
9140 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
9141 }});
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009142 }
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009143 mListBoxDialog = b.create();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009144 listView.setAdapter(adapter);
9145 listView.setFocusableInTouchMode(true);
9146 // There is a bug (1250103) where the checks in a ListView with
9147 // multiple items selected are associated with the positions, not
Cary Clarkd6982c92009-05-29 11:02:22 -04009148 // the ids, so the items do not properly retain their checks when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009149 // filtered. Do not allow filtering on multiple lists until
9150 // that bug is fixed.
Cary Clarkd6982c92009-05-29 11:02:22 -04009151
Leon Scroggins3667ce42009-05-13 15:58:03 -04009152 listView.setTextFilterEnabled(!mMultiple);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009153 if (mMultiple) {
9154 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
9155 int length = mSelectedArray.length;
9156 for (int i = 0; i < length; i++) {
9157 listView.setItemChecked(mSelectedArray[i], true);
9158 }
9159 } else {
9160 listView.setOnItemClickListener(new OnItemClickListener() {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05009161 public void onItemClick(AdapterView<?> parent, View v,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009162 int position, long id) {
Leon Scroggins244d2d42010-12-06 16:29:38 -05009163 // Rather than sending the message right away, send it
9164 // after the page regains focus.
9165 mListBoxMessage = Message.obtain(null,
9166 EventHub.SINGLE_LISTBOX_CHOICE, (int) id, 0);
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009167 mListBoxDialog.dismiss();
9168 mListBoxDialog = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009169 }
9170 });
9171 if (mSelection != -1) {
9172 listView.setSelection(mSelection);
9173 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
9174 listView.setItemChecked(mSelection, true);
Leon Scroggins3667ce42009-05-13 15:58:03 -04009175 DataSetObserver observer = new SingleDataSetObserver(
9176 adapter.getItemId(mSelection), listView, adapter);
9177 adapter.registerDataSetObserver(observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009178 }
9179 }
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009180 mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009181 public void onCancel(DialogInterface dialog) {
9182 mWebViewCore.sendMessage(
9183 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009184 mListBoxDialog = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009185 }
9186 });
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009187 mListBoxDialog.show();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009188 }
9189 }
9190
Leon Scroggins244d2d42010-12-06 16:29:38 -05009191 private Message mListBoxMessage;
9192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009193 /*
9194 * Request a dropdown menu for a listbox with multiple selection.
9195 *
9196 * @param array Labels for the listbox.
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009197 * @param enabledArray State for each element in the list. See static
9198 * integers in Container class.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009199 * @param selectedArray Which positions are initally selected.
9200 */
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009201 void requestListBox(String[] array, int[] enabledArray, int[]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009202 selectedArray) {
9203 mPrivateHandler.post(
9204 new InvokeListBox(array, enabledArray, selectedArray));
9205 }
9206
9207 /*
9208 * Request a dropdown menu for a listbox with single selection or a single
9209 * <select> element.
9210 *
9211 * @param array Labels for the listbox.
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009212 * @param enabledArray State for each element in the list. See static
9213 * integers in Container class.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009214 * @param selection Which position is initally selected.
9215 */
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009216 void requestListBox(String[] array, int[] enabledArray, int selection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009217 mPrivateHandler.post(
9218 new InvokeListBox(array, enabledArray, selection));
9219 }
9220
9221 // called by JNI
Leon Scroggins47fabbf2009-12-08 16:57:26 -05009222 private void sendMoveFocus(int frame, int node) {
9223 mWebViewCore.sendMessage(EventHub.SET_MOVE_FOCUS,
9224 new WebViewCore.CursorData(frame, node, 0, 0));
9225 }
9226
9227 // called by JNI
Cary Clarkd6982c92009-05-29 11:02:22 -04009228 private void sendMoveMouse(int frame, int node, int x, int y) {
9229 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
9230 new WebViewCore.CursorData(frame, node, x, y));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009231 }
9232
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009233 /*
9234 * Send a mouse move event to the webcore thread.
9235 *
Leon Scrogginsb6112132011-02-24 12:35:50 -05009236 * @param removeFocus Pass true to remove the WebTextView, if present.
9237 * @param stopPaintingCaret Stop drawing the blinking caret if true.
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009238 * called by JNI
9239 */
Leon Scrogginsb6112132011-02-24 12:35:50 -05009240 @SuppressWarnings("unused")
9241 private void sendMoveMouseIfLatest(boolean removeFocus, boolean stopPaintingCaret) {
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009242 if (removeFocus) {
Leon Scroggins2aed7762010-08-13 17:11:42 -04009243 clearTextEntry();
Cary Clark19436562009-06-04 16:25:07 -04009244 }
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009245 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST,
Leon Scrogginsb6112132011-02-24 12:35:50 -05009246 stopPaintingCaret ? 1 : 0, 0,
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009247 cursorData());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009248 }
9249
Leon Scrogginsd5188652011-01-19 17:01:55 -05009250 /**
9251 * Called by JNI to send a message to the webcore thread that the user
9252 * touched the webpage.
9253 * @param touchGeneration Generation number of the touch, to ignore touches
9254 * after a new one has been generated.
9255 * @param frame Pointer to the frame holding the node that was touched.
9256 * @param node Pointer to the node touched.
9257 * @param x x-position of the touch.
9258 * @param y y-position of the touch.
Leon Scrogginsd5188652011-01-19 17:01:55 -05009259 */
Cary Clarkd6982c92009-05-29 11:02:22 -04009260 private void sendMotionUp(int touchGeneration,
Leon Scroggins22e883d2011-01-31 10:54:19 -05009261 int frame, int node, int x, int y) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009262 WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
9263 touchUpData.mMoveGeneration = touchGeneration;
Cary Clarkd6982c92009-05-29 11:02:22 -04009264 touchUpData.mFrame = frame;
9265 touchUpData.mNode = node;
9266 touchUpData.mX = x;
9267 touchUpData.mY = y;
Patrick Scottcfa734a2011-02-22 11:19:02 -05009268 touchUpData.mNativeLayer = nativeScrollableLayer(
9269 x, y, touchUpData.mNativeLayerRect, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009270 mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
9271 }
9272
9273
9274 private int getScaledMaxXScroll() {
9275 int width;
9276 if (mHeightCanMeasure == false) {
9277 width = getViewWidth() / 4;
9278 } else {
9279 Rect visRect = new Rect();
9280 calcOurVisibleRect(visRect);
9281 width = visRect.width() / 2;
9282 }
9283 // FIXME the divisor should be retrieved from somewhere
Leon Scroggins0236e672009-09-02 21:12:08 -04009284 return viewToContentX(width);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009285 }
9286
9287 private int getScaledMaxYScroll() {
9288 int height;
9289 if (mHeightCanMeasure == false) {
9290 height = getViewHeight() / 4;
9291 } else {
9292 Rect visRect = new Rect();
9293 calcOurVisibleRect(visRect);
9294 height = visRect.height() / 2;
9295 }
9296 // FIXME the divisor should be retrieved from somewhere
9297 // the closest thing today is hard-coded into ScrollView.java
9298 // (from ScrollView.java, line 363) int maxJump = height/2;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04009299 return Math.round(height * mZoomManager.getInvScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009300 }
9301
9302 /**
9303 * Called by JNI to invalidate view
9304 */
9305 private void viewInvalidate() {
9306 invalidate();
9307 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009308
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009309 /**
Leon Scroggins9ab32b62010-05-03 14:19:50 +01009310 * Pass the key directly to the page. This assumes that
9311 * nativePageShouldHandleShiftAndArrows() returned true.
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009312 */
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07009313 private void letPageHandleNavKey(int keyCode, long time, boolean down, int metaState) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009314 int keyEventAction;
9315 int eventHubAction;
9316 if (down) {
9317 keyEventAction = KeyEvent.ACTION_DOWN;
9318 eventHubAction = EventHub.KEY_DOWN;
9319 playSoundEffect(keyCodeToSoundsEffect(keyCode));
9320 } else {
9321 keyEventAction = KeyEvent.ACTION_UP;
9322 eventHubAction = EventHub.KEY_UP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009323 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07009324
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009325 KeyEvent event = new KeyEvent(time, time, keyEventAction, keyCode,
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07009326 1, (metaState & KeyEvent.META_SHIFT_ON)
9327 | (metaState & KeyEvent.META_ALT_ON)
9328 | (metaState & KeyEvent.META_SYM_ON)
Jeff Brown6b53e8d2010-11-10 16:03:06 -08009329 , KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009330 mWebViewCore.sendMessage(eventHubAction, event);
9331 }
9332
9333 // return true if the key was handled
9334 private boolean navHandledKey(int keyCode, int count, boolean noScroll,
9335 long time) {
9336 if (mNativeClass == 0) {
9337 return false;
Cary Clark215b72c2009-06-26 14:38:43 -04009338 }
Cary Clark32820242010-12-03 10:27:20 -05009339 mInitialHitTestResult = null;
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009340 mLastCursorTime = time;
9341 mLastCursorBounds = nativeGetCursorRingBounds();
9342 boolean keyHandled
9343 = nativeMoveCursor(keyCode, count, noScroll) == false;
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04009344 if (DebugFlags.WEB_VIEW) {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009345 Log.v(LOGTAG, "navHandledKey mLastCursorBounds=" + mLastCursorBounds
9346 + " mLastCursorTime=" + mLastCursorTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009347 + " handled=" + keyHandled);
9348 }
Leon Scrogginscef1c592011-01-26 11:13:24 -05009349 if (keyHandled == false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009350 return keyHandled;
9351 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009352 Rect contentCursorRingBounds = nativeGetCursorRingBounds();
9353 if (contentCursorRingBounds.isEmpty()) return keyHandled;
Mike Reede9e86b82009-09-15 11:26:53 -04009354 Rect viewCursorRingBounds = contentToViewRect(contentCursorRingBounds);
Cary Clarka3ee56f2011-01-10 11:20:56 -05009355 // set last touch so that context menu related functions will work
9356 mLastTouchX = (viewCursorRingBounds.left + viewCursorRingBounds.right) / 2;
9357 mLastTouchY = (viewCursorRingBounds.top + viewCursorRingBounds.bottom) / 2;
Leon Scrogginscef1c592011-01-26 11:13:24 -05009358 if (mHeightCanMeasure == false) {
9359 return keyHandled;
9360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009361 Rect visRect = new Rect();
9362 calcOurVisibleRect(visRect);
9363 Rect outset = new Rect(visRect);
9364 int maxXScroll = visRect.width() / 2;
9365 int maxYScroll = visRect.height() / 2;
9366 outset.inset(-maxXScroll, -maxYScroll);
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009367 if (Rect.intersects(outset, viewCursorRingBounds) == false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009368 return keyHandled;
9369 }
9370 // FIXME: Necessary because ScrollView/ListView do not scroll left/right
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009371 int maxH = Math.min(viewCursorRingBounds.right - visRect.right,
9372 maxXScroll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009373 if (maxH > 0) {
9374 pinScrollBy(maxH, 0, true, 0);
9375 } else {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009376 maxH = Math.max(viewCursorRingBounds.left - visRect.left,
9377 -maxXScroll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009378 if (maxH < 0) {
9379 pinScrollBy(maxH, 0, true, 0);
9380 }
9381 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009382 if (mLastCursorBounds.isEmpty()) return keyHandled;
9383 if (mLastCursorBounds.equals(contentCursorRingBounds)) {
9384 return keyHandled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009385 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009386 if (DebugFlags.WEB_VIEW) {
9387 Log.v(LOGTAG, "navHandledKey contentCursorRingBounds="
9388 + contentCursorRingBounds);
9389 }
9390 requestRectangleOnScreen(viewCursorRingBounds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009391 return keyHandled;
9392 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009394 /**
Svetoslav Ganov12bed782011-01-03 14:14:50 -08009395 * @return Whether accessibility script has been injected.
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07009396 */
Svetoslav Ganov12bed782011-01-03 14:14:50 -08009397 private boolean accessibilityScriptInjected() {
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07009398 // TODO: Maybe the injected script should announce its presence in
9399 // the page meta-tag so the nativePageShouldHandleShiftAndArrows
9400 // will check that as one of the conditions it looks for
Svetoslav Ganov12bed782011-01-03 14:14:50 -08009401 return mAccessibilityScriptInjected;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07009402 }
9403
9404 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009405 * Set the background color. It's white by default. Pass
9406 * zero to make the view transparent.
9407 * @param color the ARGB color described by Color.java
9408 */
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08009409 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009410 public void setBackgroundColor(int color) {
9411 mBackgroundColor = color;
9412 mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color);
9413 }
9414
Kristian Monsenfc771652011-05-10 16:44:05 +01009415 /**
9416 * @deprecated This method is now obsolete.
9417 */
9418 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009419 public void debugDump() {
Steve Block51b08912011-04-27 15:04:48 +01009420 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009421 nativeDebugDump();
9422 mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
9423 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009425 /**
Mike Reedefe2c722009-10-14 09:42:02 -04009426 * Draw the HTML page into the specified canvas. This call ignores any
9427 * view-specific zoom, scroll offset, or other changes. It does not draw
9428 * any view-specific chrome, such as progress or URL bars.
9429 *
9430 * @hide only needs to be accessible to Browser and testing
9431 */
9432 public void drawPage(Canvas canvas) {
George Mount82ed95f2011-11-15 11:27:47 -08009433 calcOurContentVisibleRectF(mVisibleContentRect);
9434 nativeDraw(canvas, mVisibleContentRect, 0, 0, false);
Mike Reedefe2c722009-10-14 09:42:02 -04009435 }
9436
9437 /**
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08009438 * Enable the communication b/t the webView and VideoViewProxy
9439 *
9440 * @hide only used by the Browser
9441 */
9442 public void setHTML5VideoViewProxy(HTML5VideoViewProxy proxy) {
9443 mHTML5VideoViewProxy = proxy;
9444 }
9445
9446 /**
Ben Murdochecbc65c2010-01-13 10:54:56 +00009447 * Set the time to wait between passing touches to WebCore. See also the
9448 * TOUCH_SENT_INTERVAL member for further discussion.
9449 *
9450 * @hide This is only used by the DRT test application.
9451 */
9452 public void setTouchInterval(int interval) {
9453 mCurrentTouchInterval = interval;
9454 }
9455
9456 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009457 * Update our cache with updatedText.
9458 * @param updatedText The new text to put in our cache.
John Reck4bfd6f02011-06-09 16:59:40 -07009459 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009460 */
John Reck4bfd6f02011-06-09 16:59:40 -07009461 protected void updateCachedTextfield(String updatedText) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009462 // Also place our generation number so that when we look at the cache
9463 // we recognize that it is up to date.
9464 nativeUpdateCachedTextfield(updatedText, mTextGeneration);
9465 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009466
Ben Murdoch62275a42010-09-07 11:27:28 +01009467 /*package*/ void autoFillForm(int autoFillQueryId) {
9468 mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM, autoFillQueryId, /* unused */0);
9469 }
9470
Ben Murdoch1708ad52010-11-11 15:56:16 +00009471 /* package */ ViewManager getViewManager() {
9472 return mViewManager;
9473 }
9474
Steve Block51b08912011-04-27 15:04:48 +01009475 private static void checkThread() {
Steve Block08d584c2011-05-17 19:05:03 +01009476 if (Looper.myLooper() != Looper.getMainLooper()) {
Steve Block7a01d942011-09-26 12:30:31 +01009477 Throwable throwable = new Throwable(
9478 "Warning: A WebView method was called on thread '" +
Steve Block08d584c2011-05-17 19:05:03 +01009479 Thread.currentThread().getName() + "'. " +
9480 "All WebView methods must be called on the UI thread. " +
9481 "Future versions of WebView may not support use on other threads.");
Steve Block7a01d942011-09-26 12:30:31 +01009482 Log.w(LOGTAG, Log.getStackTraceString(throwable));
9483 StrictMode.onWebViewMethodCalledOnWrongThread(throwable);
Steve Block51b08912011-04-27 15:04:48 +01009484 }
9485 }
9486
Chris Craik555c55e2011-07-28 15:39:43 -07009487 /** @hide send content invalidate */
9488 protected void contentInvalidateAll() {
John Reckc87b7702011-08-29 11:45:30 -07009489 if (mWebViewCore != null && !mBlockWebkitViewMessages) {
9490 mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL);
9491 }
Chris Craik555c55e2011-07-28 15:39:43 -07009492 }
9493
9494 /** @hide call pageSwapCallback upon next page swap */
9495 protected void registerPageSwapCallback() {
9496 nativeRegisterPageSwapCallback();
9497 }
9498
Chris Craik445ab742011-07-13 13:19:37 -07009499 /**
9500 * Begin collecting per-tile profiling data
9501 *
9502 * @hide only used by profiling tests
9503 */
9504 public void tileProfilingStart() {
9505 nativeTileProfilingStart();
9506 }
9507 /**
9508 * Return per-tile profiling data
9509 *
9510 * @hide only used by profiling tests
9511 */
9512 public float tileProfilingStop() {
9513 return nativeTileProfilingStop();
9514 }
9515
9516 /** @hide only used by profiling tests */
9517 public void tileProfilingClear() {
9518 nativeTileProfilingClear();
9519 }
9520 /** @hide only used by profiling tests */
9521 public int tileProfilingNumFrames() {
9522 return nativeTileProfilingNumFrames();
9523 }
9524 /** @hide only used by profiling tests */
9525 public int tileProfilingNumTilesInFrame(int frame) {
9526 return nativeTileProfilingNumTilesInFrame(frame);
9527 }
9528 /** @hide only used by profiling tests */
Chris Craik21555ab2011-07-21 11:52:19 -07009529 public int tileProfilingGetInt(int frame, int tile, String key) {
9530 return nativeTileProfilingGetInt(frame, tile, key);
Chris Craik445ab742011-07-13 13:19:37 -07009531 }
9532 /** @hide only used by profiling tests */
Chris Craik21555ab2011-07-21 11:52:19 -07009533 public float tileProfilingGetFloat(int frame, int tile, String key) {
9534 return nativeTileProfilingGetFloat(frame, tile, key);
Chris Craik445ab742011-07-13 13:19:37 -07009535 }
9536
Cary Clark1cb97ee2009-12-11 12:10:36 -05009537 private native int nativeCacheHitFramePointer();
Cary Clarkb2601352011-01-11 11:32:01 -05009538 private native boolean nativeCacheHitIsPlugin();
Cary Clark1cb97ee2009-12-11 12:10:36 -05009539 private native Rect nativeCacheHitNodeBounds();
9540 private native int nativeCacheHitNodePointer();
Leon Scroggins4890feb2009-07-02 10:37:10 -04009541 /* package */ native void nativeClearCursor();
John Reck0507ac42011-11-21 13:30:32 -08009542 private native void nativeCreate(int ptr, String drawableDir, boolean isHighEndGfx);
Cary Clarkd6982c92009-05-29 11:02:22 -04009543 private native int nativeCursorFramePointer();
9544 private native Rect nativeCursorNodeBounds();
Cary Clarkaffa5d22010-01-07 12:18:23 -05009545 private native int nativeCursorNodePointer();
Cary Clarkd6982c92009-05-29 11:02:22 -04009546 private native boolean nativeCursorIntersects(Rect visibleRect);
9547 private native boolean nativeCursorIsAnchor();
9548 private native boolean nativeCursorIsTextInput();
Cary Clarked56eda2009-06-18 09:48:47 -04009549 private native Point nativeCursorPosition();
Cary Clarkd6982c92009-05-29 11:02:22 -04009550 private native String nativeCursorText();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009551 /**
9552 * Returns true if the native cursor node says it wants to handle key events
9553 * (ala plugins). This can only be called if mNativeClass is non-zero!
9554 */
Cary Clark2f1d60c2009-06-03 08:05:53 -04009555 private native boolean nativeCursorWantsKeyEvents();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009556 private native void nativeDebugDump();
9557 private native void nativeDestroy();
Grace Kloba8abd50b2010-07-08 15:02:14 -07009558
9559 /**
9560 * Draw the picture set with a background color and extra. If
9561 * "splitIfNeeded" is true and the return value is not 0, the return value
9562 * MUST be passed to WebViewCore with SPLIT_PICTURE_SET message so that the
9563 * native allocation can be freed.
9564 */
George Mount82ed95f2011-11-15 11:27:47 -08009565 private native int nativeDraw(Canvas canvas, RectF visibleRect,
9566 int color, int extra, boolean splitIfNeeded);
Cary Clarkd6982c92009-05-29 11:02:22 -04009567 private native void nativeDumpDisplayTree(String urlOrNull);
John Reckb61bfed2011-10-13 19:07:50 -07009568 private native boolean nativeEvaluateLayersAnimations(int nativeInstance);
9569 private native int nativeGetDrawGLFunction(int nativeInstance, Rect rect,
George Mount82ed95f2011-11-15 11:27:47 -08009570 Rect viewRect, RectF visibleRect, float scale, int extras);
9571 private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect,
9572 RectF visibleRect);
Cary Clark924af702010-06-04 16:37:43 -04009573 private native void nativeExtendSelection(int x, int y);
Leon Scroggins4f4a5672010-10-19 13:58:11 -04009574 private native int nativeFindAll(String findLower, String findUpper,
9575 boolean sameAsLastSearch);
Cary Clarkd6982c92009-05-29 11:02:22 -04009576 private native void nativeFindNext(boolean forward);
Leon Scroggins3a503392010-01-06 17:04:38 -05009577 /* package */ native int nativeFocusCandidateFramePointer();
Leon Scrogginsf9b1a092010-03-31 15:32:36 -04009578 /* package */ native boolean nativeFocusCandidateHasNextTextfield();
Leon Scroggins69ec5c22010-04-22 16:27:21 -04009579 /* package */ native boolean nativeFocusCandidateIsPassword();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009580 private native boolean nativeFocusCandidateIsRtlText();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009581 private native boolean nativeFocusCandidateIsTextInput();
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05009582 /* package */ native int nativeFocusCandidateMaxLength();
Leon Scrogginsae0238c2011-01-05 15:12:55 -05009583 /* package */ native boolean nativeFocusCandidateIsAutoComplete();
Michael Kolb64b4f162011-10-11 14:16:50 -07009584 /* package */ native boolean nativeFocusCandidateIsSpellcheck();
Leon Scroggins0ca70882009-06-26 17:45:29 -04009585 /* package */ native String nativeFocusCandidateName();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009586 private native Rect nativeFocusCandidateNodeBounds();
Leon Scrogginsdfc07272010-10-12 13:40:23 -04009587 /**
9588 * @return A Rect with left, top, right, bottom set to the corresponding
9589 * padding values in the focus candidate, if it is a textfield/textarea with
9590 * a style. Otherwise return null. This is not actually a rectangle; Rect
9591 * is being used to pass four integers.
9592 */
9593 private native Rect nativeFocusCandidatePaddingRect();
Leon Scroggins69ec5c22010-04-22 16:27:21 -04009594 /* package */ native int nativeFocusCandidatePointer();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009595 private native String nativeFocusCandidateText();
Leon Scroggins56a102c2010-11-12 14:40:07 -05009596 /* package */ native float nativeFocusCandidateTextSize();
Leon Scroggins1ca56262010-11-18 14:03:03 -05009597 /* package */ native int nativeFocusCandidateLineHeight();
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05009598 /**
9599 * Returns an integer corresponding to WebView.cpp::type.
9600 * See WebTextView.setType()
9601 */
9602 private native int nativeFocusCandidateType();
Michael Kolb5da91bd2011-11-29 15:29:03 -08009603 private native int nativeFocusCandidateLayerId();
Derek Sollenberger718d69f2009-10-19 15:56:43 -04009604 private native boolean nativeFocusIsPlugin();
Cary Clarke84a0db2010-03-17 15:58:20 -04009605 private native Rect nativeFocusNodeBounds();
Leon Scroggins4890feb2009-07-02 10:37:10 -04009606 /* package */ native int nativeFocusNodePointer();
Cary Clarkd6982c92009-05-29 11:02:22 -04009607 private native Rect nativeGetCursorRingBounds();
Cary Clark57d2c3a2009-12-23 13:57:15 -05009608 private native String nativeGetSelection();
Cary Clarkd6982c92009-05-29 11:02:22 -04009609 private native boolean nativeHasCursorNode();
9610 private native boolean nativeHasFocusNode();
Cary Clarke872f3a2009-06-11 09:51:11 -04009611 private native void nativeHideCursor();
Cary Clark924af702010-06-04 16:37:43 -04009612 private native boolean nativeHitSelection(int x, int y);
Cary Clarkd6982c92009-05-29 11:02:22 -04009613 private native String nativeImageURI(int x, int y);
Cary Clark6f5dfc62010-11-11 13:09:20 -05009614 private native Rect nativeLayerBounds(int layer);
Leon Scroggins1be40982010-03-01 11:20:31 -05009615 /* package */ native boolean nativeMoveCursorToNextTextInput();
Cary Clarkd6982c92009-05-29 11:02:22 -04009616 // return true if the page has been scrolled
9617 private native boolean nativeMotionUp(int x, int y, int slop);
9618 // returns false if it handled the key
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009619 private native boolean nativeMoveCursor(int keyCode, int count,
Cary Clarkd6982c92009-05-29 11:02:22 -04009620 boolean noScroll);
9621 private native int nativeMoveGeneration();
Cary Clark924af702010-06-04 16:37:43 -04009622 private native void nativeMoveSelection(int x, int y);
Leon Scroggins9ab32b62010-05-03 14:19:50 +01009623 /**
9624 * @return true if the page should get the shift and arrow keys, rather
9625 * than select text/navigation.
9626 *
9627 * If the focus is a plugin, or if the focus and cursor match and are
9628 * a contentEditable element, then the page should handle these keys.
9629 */
9630 private native boolean nativePageShouldHandleShiftAndArrows();
Cary Clark1cb97ee2009-12-11 12:10:36 -05009631 private native boolean nativePointInNavCache(int x, int y, int slop);
Cary Clarkd6982c92009-05-29 11:02:22 -04009632 // Like many other of our native methods, you must make sure that
9633 // mNativeClass is not null before calling this method.
Cary Clark924af702010-06-04 16:37:43 -04009634 private native void nativeResetSelection();
Cary Clark2cdee232010-12-29 14:59:24 -05009635 private native Point nativeSelectableText();
Cary Clark924af702010-06-04 16:37:43 -04009636 private native void nativeSelectAll();
Cary Clarkd6982c92009-05-29 11:02:22 -04009637 private native void nativeSelectBestAt(Rect rect);
Svetoslav Ganov9504f572011-01-14 11:38:17 -08009638 private native void nativeSelectAt(int x, int y);
Cary Clark924af702010-06-04 16:37:43 -04009639 private native int nativeSelectionX();
9640 private native int nativeSelectionY();
Leon Scroggins6a367f52010-05-06 17:37:40 -04009641 private native int nativeFindIndex();
Cary Clark924af702010-06-04 16:37:43 -04009642 private native void nativeSetExtendSelection();
Cary Clarkde023c12010-03-03 10:05:16 -05009643 private native void nativeSetFindIsEmpty();
9644 private native void nativeSetFindIsUp(boolean isUp);
Cary Clarkd6982c92009-05-29 11:02:22 -04009645 private native void nativeSetHeightCanMeasure(boolean measure);
Nicolas Roard3cb5ded2011-02-23 18:18:46 -08009646 private native void nativeSetBaseLayer(int layer, Region invalRegion,
Chris Craik5cf78f72011-07-28 11:34:31 -07009647 boolean showVisualIndicator, boolean isPictureAfterFirstLayout,
9648 boolean registerPageSwapCallback);
John Reck816c0de2011-06-02 16:04:53 -07009649 private native int nativeGetBaseLayer();
Cary Clarke60cb7f2010-08-25 14:56:00 -04009650 private native void nativeShowCursorTimed();
Grace Kloba8abd50b2010-07-08 15:02:14 -07009651 private native void nativeReplaceBaseContent(int content);
9652 private native void nativeCopyBaseContentToPicture(Picture pict);
9653 private native boolean nativeHasContent();
John Reckb61bfed2011-10-13 19:07:50 -07009654 private native void nativeSetSelectionPointer(int nativeInstance,
9655 boolean set, float scale, int x, int y);
Cary Clark924af702010-06-04 16:37:43 -04009656 private native boolean nativeStartSelection(int x, int y);
Cary Clarkd9fd8572011-02-03 05:25:05 -05009657 private native void nativeStopGL();
Cary Clark31b83672010-03-09 09:20:34 -05009658 private native Rect nativeSubtractLayers(Rect content);
Cary Clarkd6982c92009-05-29 11:02:22 -04009659 private native int nativeTextGeneration();
Chris Craik555c55e2011-07-28 15:39:43 -07009660 private native void nativeRegisterPageSwapCallback();
Chris Craik445ab742011-07-13 13:19:37 -07009661 private native void nativeTileProfilingStart();
9662 private native float nativeTileProfilingStop();
9663 private native void nativeTileProfilingClear();
9664 private native int nativeTileProfilingNumFrames();
9665 private native int nativeTileProfilingNumTilesInFrame(int frame);
Chris Craik21555ab2011-07-21 11:52:19 -07009666 private native int nativeTileProfilingGetInt(int frame, int tile, String key);
9667 private native float nativeTileProfilingGetFloat(int frame, int tile, String key);
Cary Clarkd6982c92009-05-29 11:02:22 -04009668 // Never call this version except by updateCachedTextfield(String) -
9669 // we always want to pass in our generation number.
9670 private native void nativeUpdateCachedTextfield(String updatedText,
9671 int generation);
Cary Clark924af702010-06-04 16:37:43 -04009672 private native boolean nativeWordSelection(int x, int y);
Grace Kloba8b97e4b2009-07-28 13:11:38 -07009673 // return NO_LEFTEDGE means failure.
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04009674 static final int NO_LEFTEDGE = -1;
9675 native int nativeGetBlockLeftEdge(int x, int y, float scale);
Patrick Scotta3ebcc92010-07-16 11:52:22 -04009676
Derek Sollenberger1d335f32011-07-08 11:28:23 -04009677 private native void nativeUseHardwareAccelSkia(boolean enabled);
Ben Murdochfa148f62011-02-01 20:51:27 +00009678
Patrick Scotta3ebcc92010-07-16 11:52:22 -04009679 // Returns a pointer to the scrollable LayerAndroid at the given point.
Cary Clarkb9aaa772011-01-07 16:14:54 -05009680 private native int nativeScrollableLayer(int x, int y, Rect scrollRect,
9681 Rect scrollBounds);
Leon Scrogginsd5188652011-01-19 17:01:55 -05009682 /**
9683 * Scroll the specified layer.
9684 * @param layer Id of the layer to scroll, as determined by nativeScrollableLayer.
9685 * @param newX Destination x position to which to scroll.
9686 * @param newY Destination y position to which to scroll.
9687 * @return True if the layer is successfully scrolled.
9688 */
9689 private native boolean nativeScrollLayer(int layer, int newX, int newY);
Chris Craik58d94af2011-08-18 11:42:13 -07009690 private native void nativeSetIsScrolling(boolean isScrolling);
John Reck9b90d552011-06-14 15:19:17 -07009691 private native int nativeGetBackgroundColor();
Nicolas Roard872cf222011-08-18 11:53:04 -07009692 native boolean nativeSetProperty(String key, String value);
John Reck637758942011-07-15 11:14:43 -07009693 native String nativeGetProperty(String key);
John Reckeffabe82011-10-27 09:09:36 -07009694 private native void nativeGetTextSelectionRegion(int instance, Region region);
9695 private native void nativeGetSelectionHandles(int instance, int[] handles);
John Reckfaa42db2011-09-07 11:33:34 -07009696 /**
9697 * See {@link ComponentCallbacks2} for the trim levels and descriptions
9698 */
9699 private static native void nativeOnTrimMemory(int level);
John Reck5f1c5492011-11-09 16:23:07 -08009700 private static native void nativeSetPauseDrawing(int instance, boolean pause);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009701}