blob: 0acd748c411517f5f20b603ff4453fc13a47be67 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.AlertDialog;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040021import android.content.BroadcastReceiver;
Dianne Hackborn90d5e8c2010-08-05 13:47:55 -070022import android.content.ClipboardManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.Context;
24import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.DialogInterface.OnCancelListener;
Adam Powell637d3372010-08-25 14:37:03 -070026import android.content.Intent;
27import android.content.IntentFilter;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040028import android.content.pm.PackageInfo;
29import android.content.pm.PackageManager;
Leon Scrogginscdaff15bd2011-03-04 12:30:03 -050030import android.content.res.AssetManager;
Cary Clarkc5cd5e92010-11-22 15:20:02 -050031import android.content.res.Configuration;
Leon Scroggins3667ce42009-05-13 15:58:03 -040032import android.database.DataSetObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.Bitmap;
Adam Powell637d3372010-08-25 14:37:03 -070034import android.graphics.BitmapFactory;
35import android.graphics.BitmapShader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.graphics.Canvas;
37import android.graphics.Color;
Grace Kloba178db412010-05-18 22:22:23 -070038import android.graphics.CornerPathEffect;
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;
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -080047import android.graphics.SurfaceTexture;
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;
57import android.os.Message;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -070058import android.provider.Settings;
Svetoslav Ganovda355512010-05-12 22:04:44 -070059import android.speech.tts.TextToSpeech;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.text.Selection;
61import android.text.Spannable;
62import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.util.EventLog;
64import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.view.Gravity;
Svetoslav Ganov9504f572011-01-14 11:38:17 -080066import android.view.HardwareCanvas;
Jeff Brown33bbfd22011-02-24 20:55:35 -080067import android.view.InputDevice;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080068import android.view.KeyCharacterMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.view.KeyEvent;
70import android.view.LayoutInflater;
71import android.view.MotionEvent;
Grace Kloba3a0def22010-01-23 21:11:54 -080072import android.view.ScaleGestureDetector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.view.SoundEffectConstants;
74import android.view.VelocityTracker;
75import android.view.View;
76import android.view.ViewConfiguration;
77import android.view.ViewGroup;
Leon Scroggins7f7bd522010-11-05 11:23:31 -040078import android.view.ViewParent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.view.ViewTreeObserver;
Svetoslav Ganovda355512010-05-12 22:04:44 -070080import android.view.accessibility.AccessibilityManager;
Derek Sollenberger7cabb032010-01-21 10:37:38 -050081import android.view.inputmethod.EditorInfo;
82import android.view.inputmethod.InputConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.view.inputmethod.InputMethodManager;
Leon Scrogginsd3465f62009-06-02 10:57:54 -040084import android.webkit.WebTextView.AutoCompleteAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.webkit.WebViewCore.EventHub;
Grace Klobac2242f22010-03-05 14:00:26 -080086import android.webkit.WebViewCore.TouchEventData;
Grace Kloba178db412010-05-18 22:22:23 -070087import android.webkit.WebViewCore.TouchHighlightData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.widget.AbsoluteLayout;
Leon Scroggins3667ce42009-05-13 15:58:03 -040089import android.widget.Adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.widget.AdapterView;
Michael Kolb73980a92010-08-05 16:32:51 -070091import android.widget.AdapterView.OnItemClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.widget.ArrayAdapter;
Leon Scrogginsa8da1732009-10-19 19:04:30 -040093import android.widget.CheckedTextView;
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -040094import android.widget.LinearLayout;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.widget.ListView;
Adam Powell637d3372010-08-25 14:37:03 -070096import android.widget.OverScroller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.widget.Toast;
Michael Kolb73980a92010-08-05 16:32:51 -070098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import java.io.File;
100import java.io.FileInputStream;
101import java.io.FileNotFoundException;
102import java.io.FileOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import java.net.URLDecoder;
104import java.util.ArrayList;
Andrei Popescuf5dba882010-01-12 22:42:41 +0000105import java.util.HashMap;
Derek Sollenberger41d5e932010-08-23 14:51:41 -0400106import java.util.HashSet;
Adam Powell9d32d242010-03-29 16:02:07 -0700107import java.util.List;
Andrei Popescu4950b2b2009-09-03 13:56:07 +0100108import java.util.Map;
Andrei Popescua6d747d2010-02-11 13:19:21 +0000109import java.util.Set;
Leon Scroggins115626a2011-02-17 12:00:48 -0500110import java.util.Vector;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700111import java.util.regex.Matcher;
112import java.util.regex.Pattern;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Adam Powell637d3372010-08-25 14:37:03 -0700114import junit.framework.Assert;
115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116/**
Cary Clarkd6982c92009-05-29 11:02:22 -0400117 * <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 -0800118 * can roll your own web browser or simply display some online content within your Activity.
119 * It uses the WebKit rendering engine to display
120 * web pages and includes methods to navigate forward and backward
121 * through a history, zoom in and out, perform text searches and more.</p>
The Android Open Source Project10592532009-03-18 17:39:46 -0700122 * <p>To enable the built-in zoom, set
123 * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
124 * (introduced in API version 3).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 * <p>Note that, in order for your Activity to access the Internet and load web pages
Scott Main8b3cea02010-05-14 14:12:43 -0700126 * in a WebView, you must add the {@code INTERNET} permissions to your
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 * Android Manifest file:</p>
128 * <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100129 *
Scott Main8b3cea02010-05-14 14:12:43 -0700130 * <p>This must be a child of the <a
Ben Dodson4e8620f2010-08-25 10:55:47 -0700131 * href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code <manifest>}</a>
Scott Main8b3cea02010-05-14 14:12:43 -0700132 * element.</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100133 *
Scott Main41ec6532010-08-19 16:57:07 -0700134 * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-webview.html">Web View
135 * tutorial</a>.</p>
136 *
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100137 * <h3>Basic usage</h3>
138 *
139 * <p>By default, a WebView provides no browser-like widgets, does not
Scott Main8b3cea02010-05-14 14:12:43 -0700140 * enable JavaScript and web page errors are ignored. If your goal is only
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100141 * to display some HTML as a part of your UI, this is probably fine;
142 * the user won't need to interact with the web page beyond reading
143 * it, and the web page won't need to interact with the user. If you
Scott Main8b3cea02010-05-14 14:12:43 -0700144 * actually want a full-blown web browser, then you probably want to
145 * invoke the Browser application with a URL Intent rather than show it
146 * with a WebView. For example:
147 * <pre>
148 * Uri uri = Uri.parse("http://www.example.com");
149 * Intent intent = new Intent(Intent.ACTION_VIEW, uri);
150 * startActivity(intent);
151 * </pre>
152 * <p>See {@link android.content.Intent} for more information.</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100153 *
Ben Dodson4e8620f2010-08-25 10:55:47 -0700154 * <p>To provide a WebView in your own Activity, include a {@code <WebView>} in your layout,
Scott Main8b3cea02010-05-14 14:12:43 -0700155 * or set the entire Activity window as a WebView during {@link
156 * android.app.Activity#onCreate(Bundle) onCreate()}:</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100157 * <pre class="prettyprint">
158 * WebView webview = new WebView(this);
159 * setContentView(webview);
Scott Main8b3cea02010-05-14 14:12:43 -0700160 * </pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100161 *
Scott Main8b3cea02010-05-14 14:12:43 -0700162 * <p>Then load the desired web page:</p>
Scott Maine3b9f8b2010-05-18 08:41:36 -0700163 * <pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100164 * // Simplest usage: note that an exception will NOT be thrown
165 * // if there is an error loading this page (see below).
166 * webview.loadUrl("http://slashdot.org/");
167 *
Scott Main8b3cea02010-05-14 14:12:43 -0700168 * // OR, you can also load from an HTML string:
Scott Maine3b9f8b2010-05-18 08:41:36 -0700169 * String summary = "&lt;html>&lt;body>You scored &lt;b>192&lt;/b> points.&lt;/body>&lt;/html>";
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100170 * webview.loadData(summary, "text/html", "utf-8");
171 * // ... although note that there are restrictions on what this HTML can do.
Scott Main8b3cea02010-05-14 14:12:43 -0700172 * // See the JavaDocs for {@link #loadData(String,String,String) loadData()} and {@link
173 * #loadDataWithBaseURL(String,String,String,String,String) loadDataWithBaseURL()} for more info.
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100174 * </pre>
175 *
176 * <p>A WebView has several customization points where you can add your
177 * own behavior. These are:</p>
178 *
179 * <ul>
180 * <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass.
181 * This class is called when something that might impact a
182 * browser UI happens, for instance, progress updates and
Scott Main8b3cea02010-05-14 14:12:43 -0700183 * JavaScript alerts are sent here (see <a
184 * href="{@docRoot}guide/developing/debug-tasks.html#DebuggingWebPages">Debugging Tasks</a>).
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100185 * </li>
186 * <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
187 * It will be called when things happen that impact the
188 * rendering of the content, eg, errors or form submissions. You
Scott Main8b3cea02010-05-14 14:12:43 -0700189 * can also intercept URL loading here (via {@link
190 * android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String)
191 * shouldOverrideUrlLoading()}).</li>
192 * <li>Modifying the {@link android.webkit.WebSettings}, such as
193 * enabling JavaScript with {@link android.webkit.WebSettings#setJavaScriptEnabled(boolean)
194 * setJavaScriptEnabled()}. </li>
195 * <li>Adding JavaScript-to-Java interfaces with the {@link
196 * android.webkit.WebView#addJavascriptInterface} method.
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100197 * This lets you bind Java objects into the WebView so they can be
198 * controlled from the web pages JavaScript.</li>
199 * </ul>
200 *
201 * <p>Here's a more complicated example, showing error handling,
202 * settings, and progress notification:</p>
203 *
204 * <pre class="prettyprint">
205 * // Let's display the progress in the activity title bar, like the
206 * // browser app does.
207 * getWindow().requestFeature(Window.FEATURE_PROGRESS);
208 *
209 * webview.getSettings().setJavaScriptEnabled(true);
210 *
211 * final Activity activity = this;
212 * webview.setWebChromeClient(new WebChromeClient() {
213 * public void onProgressChanged(WebView view, int progress) {
214 * // Activities and WebViews measure progress with different scales.
215 * // The progress meter will automatically disappear when we reach 100%
216 * activity.setProgress(progress * 1000);
217 * }
218 * });
219 * webview.setWebViewClient(new WebViewClient() {
220 * public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
221 * Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
222 * }
223 * });
224 *
225 * webview.loadUrl("http://slashdot.org/");
226 * </pre>
227 *
228 * <h3>Cookie and window management</h3>
229 *
230 * <p>For obvious security reasons, your application has its own
Scott Main8b3cea02010-05-14 14:12:43 -0700231 * cache, cookie store etc.&mdash;it does not share the Browser
232 * application's data. Cookies are managed on a separate thread, so
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100233 * operations like index building don't block the UI
234 * thread. Follow the instructions in {@link android.webkit.CookieSyncManager}
235 * if you want to use cookies in your application.
236 * </p>
237 *
238 * <p>By default, requests by the HTML to open new windows are
239 * ignored. This is true whether they be opened by JavaScript or by
240 * the target attribute on a link. You can customize your
Scott Main8b3cea02010-05-14 14:12:43 -0700241 * {@link WebChromeClient} to provide your own behaviour for opening multiple windows,
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100242 * and render them in whatever manner you want.</p>
243 *
Scott Main8b3cea02010-05-14 14:12:43 -0700244 * <p>The standard behavior for an Activity is to be destroyed and
245 * recreated when the device orientation or any other configuration changes. This will cause
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100246 * the WebView to reload the current page. If you don't want that, you
Scott Main8b3cea02010-05-14 14:12:43 -0700247 * can set your Activity to handle the {@code orientation} and {@code keyboardHidden}
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100248 * changes, and then just leave the WebView alone. It'll automatically
Scott Main8b3cea02010-05-14 14:12:43 -0700249 * re-orient itself as appropriate. Read <a
250 * href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a> for
251 * more information about how to handle configuration changes during runtime.</p>
252 *
253 *
254 * <h3>Building web pages to support different screen densities</h3>
255 *
256 * <p>The screen density of a device is based on the screen resolution. A screen with low density
257 * has fewer available pixels per inch, where a screen with high density
Brad Fitzpatrick438d0592010-06-10 12:19:19 -0700258 * has more &mdash; sometimes significantly more &mdash; pixels per inch. The density of a
Scott Main8b3cea02010-05-14 14:12:43 -0700259 * screen is important because, other things being equal, a UI element (such as a button) whose
260 * height and width are defined in terms of screen pixels will appear larger on the lower density
261 * screen and smaller on the higher density screen.
262 * For simplicity, Android collapses all actual screen densities into three generalized densities:
263 * high, medium, and low.</p>
264 * <p>By default, WebView scales a web page so that it is drawn at a size that matches the default
265 * appearance on a medium density screen. So, it applies 1.5x scaling on a high density screen
266 * (because its pixels are smaller) and 0.75x scaling on a low density screen (because its pixels
267 * are bigger).
268 * Starting with API Level 5 (Android 2.0), WebView supports DOM, CSS, and meta tag features to help
269 * you (as a web developer) target screens with different screen densities.</p>
270 * <p>Here's a summary of the features you can use to handle different screen densities:</p>
271 * <ul>
272 * <li>The {@code window.devicePixelRatio} DOM property. The value of this property specifies the
273 * default scaling factor used for the current device. For example, if the value of {@code
274 * window.devicePixelRatio} is "1.0", then the device is considered a medium density (mdpi) device
275 * and default scaling is not applied to the web page; if the value is "1.5", then the device is
276 * considered a high density device (hdpi) and the page content is scaled 1.5x; if the
277 * value is "0.75", then the device is considered a low density device (ldpi) and the content is
278 * scaled 0.75x. However, if you specify the {@code "target-densitydpi"} meta property
279 * (discussed below), then you can stop this default scaling behavior.</li>
280 * <li>The {@code -webkit-device-pixel-ratio} CSS media query. Use this to specify the screen
281 * densities for which this style sheet is to be used. The corresponding value should be either
282 * "0.75", "1", or "1.5", to indicate that the styles are for devices with low density, medium
283 * density, or high density screens, respectively. For example:
284 * <pre>
285 * &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" /&gt;</pre>
286 * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5,
287 * which is the high density pixel ratio.</p>
288 * </li>
289 * <li>The {@code target-densitydpi} property for the {@code viewport} meta tag. You can use
290 * this to specify the target density for which the web page is designed, using the following
291 * values:
292 * <ul>
293 * <li>{@code device-dpi} - Use the device's native dpi as the target dpi. Default scaling never
294 * occurs.</li>
295 * <li>{@code high-dpi} - Use hdpi as the target dpi. Medium and low density screens scale down
296 * as appropriate.</li>
297 * <li>{@code medium-dpi} - Use mdpi as the target dpi. High density screens scale up and
298 * low density screens scale down. This is also the default behavior.</li>
299 * <li>{@code low-dpi} - Use ldpi as the target dpi. Medium and high density screens scale up
300 * as appropriate.</li>
Ben Dodson4e8620f2010-08-25 10:55:47 -0700301 * <li><em>{@code <value>}</em> - Specify a dpi value to use as the target dpi (accepted
Scott Main8b3cea02010-05-14 14:12:43 -0700302 * values are 70-400).</li>
303 * </ul>
304 * <p>Here's an example meta tag to specify the target density:</p>
305 * <pre>&lt;meta name="viewport" content="target-densitydpi=device-dpi" /&gt;</pre></li>
306 * </ul>
307 * <p>If you want to modify your web page for different densities, by using the {@code
308 * -webkit-device-pixel-ratio} CSS media query and/or the {@code
309 * window.devicePixelRatio} DOM property, then you should set the {@code target-densitydpi} meta
310 * property to {@code device-dpi}. This stops Android from performing scaling in your web page and
311 * allows you to make the necessary adjustments for each density via CSS and JavaScript.</p>
312 *
Michael Kolb73980a92010-08-05 16:32:51 -0700313 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 */
Raphael30df2372010-03-06 10:09:54 -0800315@Widget
Cary Clarkd6982c92009-05-29 11:02:22 -0400316public class WebView extends AbsoluteLayout
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 implements ViewTreeObserver.OnGlobalFocusChangeListener,
318 ViewGroup.OnHierarchyChangeListener {
319
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800320 private class InnerGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
321 public void onGlobalLayout() {
322 if (isShown()) {
323 setGLRectViewport();
324 }
325 }
326 }
327
Teng-Hui Zhu55133372010-12-07 17:19:16 -0800328 private class InnerScrollChangedListener implements ViewTreeObserver.OnScrollChangedListener {
329 public void onScrollChanged() {
330 if (isShown()) {
331 setGLRectViewport();
332 }
333 }
334 }
335
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800336 // The listener to capture global layout change event.
Teng-Hui Zhu55133372010-12-07 17:19:16 -0800337 private InnerGlobalLayoutListener mGlobalLayoutListener = null;
338
339 // The listener to capture scroll event.
340 private InnerScrollChangedListener mScrollChangedListener = null;
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 // if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing
343 // the screen all-the-time. Good for profiling our drawing code
344 static private final boolean AUTO_REDRAW_HACK = false;
345 // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
346 private boolean mAutoRedraw;
347
Mattias Falk0ae2ec82010-09-16 16:24:46 +0200348 // Reference to the AlertDialog displayed by InvokeListBox.
349 // It's used to dismiss the dialog in destroy if not done before.
350 private AlertDialog mListBoxDialog = null;
351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 static final String LOGTAG = "webview";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
Derek Sollenberger90b6e482010-05-10 12:38:54 -0400354 private ZoomManager mZoomManager;
Cary Clarkd6982c92009-05-29 11:02:22 -0400355
Romain Guycabfcc12011-03-07 18:06:46 -0800356 private final Rect mGLRectViewport = new Rect();
357 private final Rect mViewRectViewport = new Rect();
Chet Haase91fc3cf2011-01-28 00:20:04 -0800358 private boolean mGLViewportEmpty = false;
Nicolas Roard12c18e62010-10-13 20:14:31 -0700359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 /**
361 * Transportation object for returning WebView across thread boundaries.
362 */
363 public class WebViewTransport {
364 private WebView mWebview;
365
366 /**
367 * Set the WebView to the transportation object.
368 * @param webview The WebView to transport.
369 */
370 public synchronized void setWebView(WebView webview) {
371 mWebview = webview;
372 }
373
374 /**
375 * Return the WebView object.
376 * @return WebView The transported WebView object.
377 */
378 public synchronized WebView getWebView() {
379 return mWebview;
380 }
381 }
382
383 // A final CallbackProxy shared by WebViewCore and BrowserFrame.
384 private final CallbackProxy mCallbackProxy;
385
386 private final WebViewDatabase mDatabase;
387
388 // SSL certificate for the main top-level page (if secure)
389 private SslCertificate mCertificate;
390
391 // Native WebView pointer that is 0 until the native object has been
392 // created.
393 private int mNativeClass;
394 // This would be final but it needs to be set to null when the WebView is
395 // destroyed.
396 private WebViewCore mWebViewCore;
397 // Handler for dispatching UI messages.
398 /* package */ final Handler mPrivateHandler = new PrivateHandler();
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400399 private WebTextView mWebTextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 // Used to ignore changes to webkit text that arrives to the UI side after
401 // more key events.
402 private int mTextGeneration;
403
Leon Scroggins IIIb24e18b2010-04-20 17:07:28 -0400404 /* package */ void incrementTextGeneration() { mTextGeneration++; }
405
Patrick Scott0a5ce012009-07-02 08:56:10 -0400406 // Used by WebViewCore to create child views.
407 /* package */ final ViewManager mViewManager;
408
Grace Kloba11438c32009-12-16 11:39:12 -0800409 // Used to display in full screen mode
410 PluginFullScreenHolder mFullScreenHolder;
411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 /**
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -0800413 * Position of the last touch event in pixels.
414 * Use integer to prevent loss of dragging delta calculation accuracy;
415 * which was done in float and converted to integer, and resulted in gradual
416 * and compounding touch position and view dragging mismatch.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 */
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -0800418 private int mLastTouchX;
419 private int mLastTouchY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420
421 /**
422 * Time of the last touch event.
423 */
424 private long mLastTouchTime;
425
426 /**
427 * Time of the last time sending touch event to WebViewCore
428 */
429 private long mLastSentTouchTime;
430
431 /**
432 * The minimum elapsed time before sending another ACTION_MOVE event to
Grace Kloba53d3c1e2009-06-26 11:36:03 -0700433 * WebViewCore. This really should be tuned for each type of the devices.
434 * For example in Google Map api test case, it takes Dream device at least
435 * 150ms to do a full cycle in the WebViewCore by processing a touch event,
436 * triggering the layout and drawing the picture. While the same process
437 * takes 60+ms on the current high speed device. If we make
438 * TOUCH_SENT_INTERVAL too small, there will be multiple touch events sent
439 * to WebViewCore queue and the real layout and draw events will be pushed
440 * to further, which slows down the refresh rate. Choose 50 to favor the
441 * current high speed devices. For Dream like devices, 100 is a better
442 * choice. Maybe make this in the buildspec later.
Huahui Wue2975f12010-12-14 13:45:28 -0800443 * (Update 12/14/2010: changed to 0 since current device should be able to
444 * handle the raw events and Map team voted to have the raw events too.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 */
Huahui Wue2975f12010-12-14 13:45:28 -0800446 private static final int TOUCH_SENT_INTERVAL = 0;
Ben Murdochecbc65c2010-01-13 10:54:56 +0000447 private int mCurrentTouchInterval = TOUCH_SENT_INTERVAL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448
449 /**
450 * Helper class to get velocity for fling
451 */
452 VelocityTracker mVelocityTracker;
Romain Guy4296fc42009-07-06 11:48:52 -0700453 private int mMaximumFling;
Cary Clark278ce052009-08-31 16:08:42 -0400454 private float mLastVelocity;
455 private float mLastVelX;
456 private float mLastVelY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457
Patrick Scott62310912010-12-06 17:44:50 -0500458 // The id of the native layer being scrolled.
Patrick Scotta3ebcc92010-07-16 11:52:22 -0400459 private int mScrollingLayer;
Patrick Scott62310912010-12-06 17:44:50 -0500460 private Rect mScrollingLayerRect = new Rect();
Patrick Scotta3ebcc92010-07-16 11:52:22 -0400461
Grace Kloba3c19d992010-05-17 19:19:06 -0700462 // only trigger accelerated fling if the new velocity is at least
463 // MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION times of the previous velocity
464 private static final float MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION = 0.2f;
465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 /**
467 * Touch mode
468 */
469 private int mTouchMode = TOUCH_DONE_MODE;
470 private static final int TOUCH_INIT_MODE = 1;
471 private static final int TOUCH_DRAG_START_MODE = 2;
472 private static final int TOUCH_DRAG_MODE = 3;
473 private static final int TOUCH_SHORTPRESS_START_MODE = 4;
474 private static final int TOUCH_SHORTPRESS_MODE = 5;
Grace Kloba04b28682009-09-14 14:38:37 -0700475 private static final int TOUCH_DOUBLE_TAP_MODE = 6;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 private static final int TOUCH_DONE_MODE = 7;
Cary Clark924af702010-06-04 16:37:43 -0400477 private static final int TOUCH_PINCH_DRAG = 8;
Patrick Scotta3ebcc92010-07-16 11:52:22 -0400478 private static final int TOUCH_DRAG_LAYER_MODE = 9;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479
480 // Whether to forward the touch events to WebCore
Huahui Wu5d4064c2011-01-21 16:10:23 -0800481 // Can only be set by WebKit via JNI.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 private boolean mForwardTouchEvents = false;
483
Grace Klobac2242f22010-03-05 14:00:26 -0800484 // Whether to prevent default during touch. The initial value depends on
485 // mForwardTouchEvents. If WebCore wants all the touch events, it says yes
486 // for touch down. Otherwise UI will wait for the answer of the first
487 // confirmed move before taking over the control.
488 private static final int PREVENT_DEFAULT_NO = 0;
489 private static final int PREVENT_DEFAULT_MAYBE_YES = 1;
490 private static final int PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN = 2;
491 private static final int PREVENT_DEFAULT_YES = 3;
492 private static final int PREVENT_DEFAULT_IGNORE = 4;
493 private int mPreventDefault = PREVENT_DEFAULT_IGNORE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494
Grace Klobac2242f22010-03-05 14:00:26 -0800495 // true when the touch movement exceeds the slop
496 private boolean mConfirmMove;
Grace Kloba5f68d6f2009-12-08 18:42:54 -0800497
Grace Klobac2242f22010-03-05 14:00:26 -0800498 // if true, touch events will be first processed by WebCore, if prevent
499 // default is not set, the UI will continue handle them.
500 private boolean mDeferTouchProcess;
501
502 // to avoid interfering with the current touch events, track them
503 // separately. Currently no snapping or fling in the deferred process mode
504 private int mDeferTouchMode = TOUCH_DONE_MODE;
505 private float mLastDeferTouchX;
506 private float mLastDeferTouchY;
Grace Kloba5f68d6f2009-12-08 18:42:54 -0800507
Leon Scroggins72543e12009-07-23 15:29:45 -0400508 // To keep track of whether the current drag was initiated by a WebTextView,
509 // so that we know not to hide the cursor
510 boolean mDragFromTextInput;
511
Cary Clarkd6982c92009-05-29 11:02:22 -0400512 // Whether or not to draw the cursor ring.
513 private boolean mDrawCursorRing = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514
Mike Reedd205d5b2009-05-27 11:02:29 -0400515 // true if onPause has been called (and not onResume)
516 private boolean mIsPaused;
517
Cary Clarkb8491342010-11-29 16:23:19 -0500518 private HitTestResult mInitialHitTestResult;
519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 /**
521 * Customizable constant
522 */
523 // pre-computed square of ViewConfiguration.getScaledTouchSlop()
524 private int mTouchSlopSquare;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700525 // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
526 private int mDoubleTapSlopSquare;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700527 // pre-computed density adjusted navigation slop
528 private int mNavSlop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 // This should be ViewConfiguration.getTapTimeout()
530 // But system time out is 100ms, which is too short for the browser.
531 // In the browser, if it switches out of tap too soon, jump tap won't work.
532 private static final int TAP_TIMEOUT = 200;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 // This should be ViewConfiguration.getLongPressTimeout()
534 // But system time out is 500ms, which is too short for the browser.
535 // With a short timeout, it's difficult to treat trigger a short press.
536 private static final int LONG_PRESS_TIMEOUT = 1000;
537 // needed to avoid flinging after a pause of no movement
538 private static final int MIN_FLING_TIME = 250;
Cary Clark25415e22009-10-12 13:41:28 -0400539 // draw unfiltered after drag is held without movement
540 private static final int MOTIONLESS_TIME = 100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 // The amount of content to overlap between two screens when going through
542 // pages with the space bar, in pixels.
543 private static final int PAGE_SCROLL_OVERLAP = 24;
544
545 /**
546 * These prevent calling requestLayout if either dimension is fixed. This
547 * depends on the layout parameters and the measure specs.
548 */
549 boolean mWidthCanMeasure;
550 boolean mHeightCanMeasure;
551
552 // Remember the last dimensions we sent to the native side so we can avoid
553 // sending the same dimensions more than once.
554 int mLastWidthSent;
555 int mLastHeightSent;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -0800556 // Since view height sent to webkit could be fixed to avoid relayout, this
557 // value records the last sent actual view height.
558 int mLastActualHeightSent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559
560 private int mContentWidth; // cache of value from WebViewCore
561 private int mContentHeight; // cache of value from WebViewCore
562
Cary Clarkd6982c92009-05-29 11:02:22 -0400563 // Need to have the separate control for horizontal and vertical scrollbar
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 // style than the View's single scrollbar style
565 private boolean mOverlayHorizontalScrollbar = true;
566 private boolean mOverlayVerticalScrollbar = false;
567
568 // our standard speed. this way small distances will be traversed in less
569 // time than large distances, but we cap the duration, so that very large
570 // distances won't take too long to get there.
571 private static final int STD_SPEED = 480; // pixels per second
572 // time for the longest scroll animation
573 private static final int MAX_DURATION = 750; // milliseconds
Leon Scroggins03c87bf2009-09-18 15:05:59 -0400574 private static final int SLIDE_TITLE_DURATION = 500; // milliseconds
Adam Powell637d3372010-08-25 14:37:03 -0700575
576 // Used by OverScrollGlow
577 OverScroller mScroller;
578
579 private boolean mInOverScrollMode = false;
580 private static Paint mOverScrollBackground;
581 private static Paint mOverScrollBorder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582
583 private boolean mWrapContent;
Cary Clark25415e22009-10-12 13:41:28 -0400584 private static final int MOTIONLESS_FALSE = 0;
585 private static final int MOTIONLESS_PENDING = 1;
586 private static final int MOTIONLESS_TRUE = 2;
Grace Kloba9b657802010-04-08 13:46:23 -0700587 private static final int MOTIONLESS_IGNORE = 3;
Cary Clark25415e22009-10-12 13:41:28 -0400588 private int mHeldMotionless;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589
Svetoslav Ganovda355512010-05-12 22:04:44 -0700590 // An instance for injecting accessibility in WebViews with disabled
591 // JavaScript or ones for which no accessibility script exists
592 private AccessibilityInjector mAccessibilityInjector;
593
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700594 // flag indicating if accessibility script is injected so we
595 // know to handle Shift and arrows natively first
596 private boolean mAccessibilityScriptInjected;
597
Grace Kloba178db412010-05-18 22:22:23 -0700598 // the color used to highlight the touch rectangles
599 private static final int mHightlightColor = 0x33000000;
600 // the round corner for the highlight path
601 private static final float TOUCH_HIGHLIGHT_ARC = 5.0f;
602 // the region indicating where the user touched on the screen
603 private Region mTouchHighlightRegion = new Region();
604 // the paint for the touch highlight
605 private Paint mTouchHightlightPaint;
606 // debug only
607 private static final boolean DEBUG_TOUCH_HIGHLIGHT = true;
608 private static final int TOUCH_HIGHLIGHT_ELAPSE_TIME = 2000;
609 private Paint mTouchCrossHairColor;
610 private int mTouchHighlightX;
611 private int mTouchHighlightY;
612
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -0800613 // Basically this proxy is used to tell the Video to update layer tree at
614 // SetBaseLayer time and to pause when WebView paused.
615 private HTML5VideoViewProxy mHTML5VideoViewProxy;
616
Grace Klobac2242f22010-03-05 14:00:26 -0800617 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 * Private message ids
619 */
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400620 private static final int REMEMBER_PASSWORD = 1;
621 private static final int NEVER_REMEMBER_PASSWORD = 2;
622 private static final int SWITCH_TO_SHORTPRESS = 3;
623 private static final int SWITCH_TO_LONGPRESS = 4;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700624 private static final int RELEASE_SINGLE_TAP = 5;
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400625 private static final int REQUEST_FORM_DATA = 6;
Grace Kloba96949ef2010-01-25 09:53:01 -0800626 private static final int RESUME_WEBCORE_PRIORITY = 7;
Cary Clark25415e22009-10-12 13:41:28 -0400627 private static final int DRAG_HELD_MOTIONLESS = 8;
628 private static final int AWAKEN_SCROLL_BARS = 9;
Grace Klobac2242f22010-03-05 14:00:26 -0800629 private static final int PREVENT_DEFAULT_TIMEOUT = 10;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500630 private static final int SCROLL_SELECT_TEXT = 11;
631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632
Grace Klobac2242f22010-03-05 14:00:26 -0800633 private static final int FIRST_PRIVATE_MSG_ID = REMEMBER_PASSWORD;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500634 private static final int LAST_PRIVATE_MSG_ID = SCROLL_SELECT_TEXT;
Grace Klobac2242f22010-03-05 14:00:26 -0800635
636 /*
637 * Package message ids
638 */
Grace Klobac2242f22010-03-05 14:00:26 -0800639 static final int SCROLL_TO_MSG_ID = 101;
Grace Klobac2242f22010-03-05 14:00:26 -0800640 static final int NEW_PICTURE_MSG_ID = 105;
641 static final int UPDATE_TEXT_ENTRY_MSG_ID = 106;
642 static final int WEBCORE_INITIALIZED_MSG_ID = 107;
643 static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 108;
644 static final int UPDATE_ZOOM_RANGE = 109;
Leon Scroggins9ab32b62010-05-03 14:19:50 +0100645 static final int UNHANDLED_NAV_KEY = 110;
Grace Klobac2242f22010-03-05 14:00:26 -0800646 static final int CLEAR_TEXT_ENTRY = 111;
647 static final int UPDATE_TEXT_SELECTION_MSG_ID = 112;
648 static final int SHOW_RECT_MSG_ID = 113;
649 static final int LONG_PRESS_CENTER = 114;
650 static final int PREVENT_TOUCH_ID = 115;
651 static final int WEBCORE_NEED_TOUCH_EVENTS = 116;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 // obj=Rect in doc coordinates
Grace Klobac2242f22010-03-05 14:00:26 -0800653 static final int INVAL_RECT_MSG_ID = 117;
654 static final int REQUEST_KEYBOARD = 118;
655 static final int DO_MOTION_UP = 119;
656 static final int SHOW_FULLSCREEN = 120;
657 static final int HIDE_FULLSCREEN = 121;
658 static final int DOM_FOCUS_CHANGED = 122;
Grace Kloba8abd50b2010-07-08 15:02:14 -0700659 static final int REPLACE_BASE_CONTENT = 123;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -0400660 static final int FORM_DID_BLUR = 124;
Grace Klobac2242f22010-03-05 14:00:26 -0800661 static final int RETURN_LABEL = 125;
662 static final int FIND_AGAIN = 126;
Grace Klobae8300a12010-03-12 13:32:55 -0800663 static final int CENTER_FIT_RECT = 127;
Leon Scrogginsb4157792010-03-18 12:42:33 -0400664 static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128;
Grace Kloba50004bc2010-04-13 22:58:51 -0700665 static final int SET_SCROLLBAR_MODES = 129;
Svetoslav Ganovda355512010-05-12 22:04:44 -0700666 static final int SELECTION_STRING_CHANGED = 130;
Grace Kloba178db412010-05-18 22:22:23 -0700667 static final int SET_TOUCH_HIGHLIGHT_RECTS = 131;
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -0700668 static final int SAVE_WEBARCHIVE_FINISHED = 132;
Cary Clarkd6982c92009-05-29 11:02:22 -0400669
Ben Murdoch62275a42010-09-07 11:27:28 +0100670 static final int SET_AUTOFILLABLE = 133;
Ben Murdoch961d55f2010-12-02 13:58:24 +0000671 static final int AUTOFILL_COMPLETE = 134;
Ben Murdoch62275a42010-09-07 11:27:28 +0100672
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800673 static final int SELECT_AT = 135;
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -0500674 static final int SCREEN_ON = 136;
Nicolas Roard0e778a12011-03-11 14:29:05 -0800675 static final int ENTER_FULLSCREEN_VIDEO = 137;
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800676
Grace Klobac2242f22010-03-05 14:00:26 -0800677 private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
Grace Kloba178db412010-05-18 22:22:23 -0700678 private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
Grace Klobac2242f22010-03-05 14:00:26 -0800679
680 static final String[] HandlerPrivateDebugString = {
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400681 "REMEMBER_PASSWORD", // = 1;
682 "NEVER_REMEMBER_PASSWORD", // = 2;
683 "SWITCH_TO_SHORTPRESS", // = 3;
684 "SWITCH_TO_LONGPRESS", // = 4;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700685 "RELEASE_SINGLE_TAP", // = 5;
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400686 "REQUEST_FORM_DATA", // = 6;
Grace Kloba96949ef2010-01-25 09:53:01 -0800687 "RESUME_WEBCORE_PRIORITY", // = 7;
Cary Clark25415e22009-10-12 13:41:28 -0400688 "DRAG_HELD_MOTIONLESS", // = 8;
689 "AWAKEN_SCROLL_BARS", // = 9;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500690 "PREVENT_DEFAULT_TIMEOUT", // = 10;
691 "SCROLL_SELECT_TEXT" // = 11;
Grace Klobac2242f22010-03-05 14:00:26 -0800692 };
693
694 static final String[] HandlerPackageDebugString = {
695 "SCROLL_TO_MSG_ID", // = 101;
Patrick Scottfa8be1c2011-02-02 14:09:34 -0500696 "102", // = 102;
697 "103", // = 103;
698 "104", // = 104;
Grace Klobac2242f22010-03-05 14:00:26 -0800699 "NEW_PICTURE_MSG_ID", // = 105;
700 "UPDATE_TEXT_ENTRY_MSG_ID", // = 106;
701 "WEBCORE_INITIALIZED_MSG_ID", // = 107;
702 "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 108;
703 "UPDATE_ZOOM_RANGE", // = 109;
Leon Scroggins9ab32b62010-05-03 14:19:50 +0100704 "UNHANDLED_NAV_KEY", // = 110;
Grace Klobac2242f22010-03-05 14:00:26 -0800705 "CLEAR_TEXT_ENTRY", // = 111;
706 "UPDATE_TEXT_SELECTION_MSG_ID", // = 112;
707 "SHOW_RECT_MSG_ID", // = 113;
708 "LONG_PRESS_CENTER", // = 114;
709 "PREVENT_TOUCH_ID", // = 115;
710 "WEBCORE_NEED_TOUCH_EVENTS", // = 116;
711 "INVAL_RECT_MSG_ID", // = 117;
712 "REQUEST_KEYBOARD", // = 118;
713 "DO_MOTION_UP", // = 119;
714 "SHOW_FULLSCREEN", // = 120;
715 "HIDE_FULLSCREEN", // = 121;
716 "DOM_FOCUS_CHANGED", // = 122;
Grace Kloba8abd50b2010-07-08 15:02:14 -0700717 "REPLACE_BASE_CONTENT", // = 123;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -0400718 "FORM_DID_BLUR", // = 124;
Grace Klobac2242f22010-03-05 14:00:26 -0800719 "RETURN_LABEL", // = 125;
Grace Klobae8300a12010-03-12 13:32:55 -0800720 "FIND_AGAIN", // = 126;
Leon Scrogginsb4157792010-03-18 12:42:33 -0400721 "CENTER_FIT_RECT", // = 127;
Grace Kloba50004bc2010-04-13 22:58:51 -0700722 "REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128;
Grace Kloba178db412010-05-18 22:22:23 -0700723 "SET_SCROLLBAR_MODES", // = 129;
724 "SELECTION_STRING_CHANGED", // = 130;
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -0700725 "SET_TOUCH_HIGHLIGHT_RECTS", // = 131;
Ben Murdoch62275a42010-09-07 11:27:28 +0100726 "SAVE_WEBARCHIVE_FINISHED", // = 132;
Ben Murdoch961d55f2010-12-02 13:58:24 +0000727 "SET_AUTOFILLABLE", // = 133;
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800728 "AUTOFILL_COMPLETE", // = 134;
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -0500729 "SELECT_AT", // = 135;
Nicolas Roard0e778a12011-03-11 14:29:05 -0800730 "SCREEN_ON", // = 136;
731 "ENTER_FULLSCREEN_VIDEO" // = 137;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 };
733
Grace Klobaa4fa1072009-11-09 12:01:50 -0800734 // If the site doesn't use the viewport meta tag to specify the viewport,
735 // use DEFAULT_VIEWPORT_WIDTH as the default viewport width
Shimeng (Simon) Wang14bcc0e2010-09-17 10:12:05 -0700736 static final int DEFAULT_VIEWPORT_WIDTH = 980;
Grace Klobaa4fa1072009-11-09 12:01:50 -0800737
738 // normally we try to fit the content to the minimum preferred width
739 // calculated by the Webkit. To avoid the bad behavior when some site's
740 // minimum preferred width keeps growing when changing the viewport width or
741 // the minimum preferred width is huge, an upper limit is needed.
742 static int sMaxViewportWidth = DEFAULT_VIEWPORT_WIDTH;
743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 // initial scale in percent. 0 means using default.
Grace Kloba16efce72009-11-10 15:49:03 -0800745 private int mInitialScaleInPercent = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746
Patrick Scottfa8be1c2011-02-02 14:09:34 -0500747 // Whether or not a scroll event should be sent to webkit. This is only set
748 // to false when restoring the scroll position.
749 private boolean mSendScrollEvent = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750
751 private int mSnapScrollMode = SNAP_NONE;
Cary Clarkac492e12009-10-14 14:53:37 -0400752 private static final int SNAP_NONE = 0;
753 private static final int SNAP_LOCK = 1; // not a separate state
754 private static final int SNAP_X = 2; // may be combined with SNAP_LOCK
755 private static final int SNAP_Y = 4; // may be combined with SNAP_LOCK
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 private boolean mSnapPositive;
Cary Clarkd6982c92009-05-29 11:02:22 -0400757
Cary Clark2ec30692010-02-23 10:50:38 -0500758 // keep these in sync with their counterparts in WebView.cpp
759 private static final int DRAW_EXTRAS_NONE = 0;
760 private static final int DRAW_EXTRAS_FIND = 1;
761 private static final int DRAW_EXTRAS_SELECTION = 2;
762 private static final int DRAW_EXTRAS_CURSOR_RING = 3;
763
Grace Kloba50004bc2010-04-13 22:58:51 -0700764 // keep this in sync with WebCore:ScrollbarMode in WebKit
765 private static final int SCROLLBAR_AUTO = 0;
766 private static final int SCROLLBAR_ALWAYSOFF = 1;
767 // as we auto fade scrollbar, this is ignored.
768 private static final int SCROLLBAR_ALWAYSON = 2;
769 private int mHorizontalScrollBarMode = SCROLLBAR_AUTO;
770 private int mVerticalScrollBarMode = SCROLLBAR_AUTO;
771
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700772 // constants for determining script injection strategy
773 private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1;
774 private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0;
775 private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1;
776
Svetoslav Ganovda355512010-05-12 22:04:44 -0700777 // the alias via which accessibility JavaScript interface is exposed
778 private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
779
780 // JavaScript to inject the script chooser which will
781 // pick the right script for the current URL
782 private static final String ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT =
783 "javascript:(function() {" +
784 " var chooser = document.createElement('script');" +
785 " chooser.type = 'text/javascript';" +
786 " chooser.src = 'https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js';" +
787 " document.getElementsByTagName('head')[0].appendChild(chooser);" +
788 " })();";
789
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700790 // Regular expression that matches the "axs" URL parameter.
791 // The value of 0 means the accessibility script is opted out
792 // The value of 1 means the accessibility script is already injected
793 private static final String PATTERN_MATCH_AXS_URL_PARAMETER = "(\\?axs=(0|1))|(&axs=(0|1))";
794
Svetoslav Ganov4acac232011-02-02 15:22:24 -0800795 // TextToSpeech instance exposed to JavaScript to the injected screenreader.
796 private TextToSpeech mTextToSpeech;
797
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700798 // variable to cache the above pattern in case accessibility is enabled.
799 private Pattern mMatchAxsUrlParameterPattern;
800
Adam Powell637d3372010-08-25 14:37:03 -0700801 /**
802 * Max distance to overscroll by in pixels.
803 * This how far content can be pulled beyond its normal bounds by the user.
804 */
805 private int mOverscrollDistance;
806
807 /**
808 * Max distance to overfling by in pixels.
809 * This is how far flinged content can move beyond the end of its normal bounds.
810 */
811 private int mOverflingDistance;
812
813 private OverScrollGlow mOverScrollGlow;
814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 // Used to match key downs and key ups
Leon Scroggins115626a2011-02-17 12:00:48 -0500816 private Vector<Integer> mKeysPressed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817
818 /* package */ static boolean mLogEvent = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819
820 // for event log
821 private long mLastTouchUpTime = 0;
822
Ben Murdochdb8d19c2010-10-29 11:44:17 +0100823 private WebViewCore.AutoFillData mAutoFillData;
Ben Murdoch62275a42010-09-07 11:27:28 +0100824
Kristian Monsencbb59db2011-05-09 16:04:34 +0100825 private static boolean sNotificationsEnabled = true;
826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 /**
828 * URI scheme for telephone number
829 */
830 public static final String SCHEME_TEL = "tel:";
831 /**
832 * URI scheme for email address
833 */
834 public static final String SCHEME_MAILTO = "mailto:";
835 /**
836 * URI scheme for map address
837 */
838 public static final String SCHEME_GEO = "geo:0,0?q=";
Cary Clarkd6982c92009-05-29 11:02:22 -0400839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 private int mBackgroundColor = Color.WHITE;
841
Cary Clark6f5dfc62010-11-11 13:09:20 -0500842 private static final long SELECT_SCROLL_INTERVAL = 1000 / 60; // 60 / second
843 private int mAutoScrollX = 0;
844 private int mAutoScrollY = 0;
Cary Clarkb9aaa772011-01-07 16:14:54 -0500845 private int mMinAutoScrollX = 0;
846 private int mMaxAutoScrollX = 0;
847 private int mMinAutoScrollY = 0;
848 private int mMaxAutoScrollY = 0;
849 private Rect mScrollingLayerBounds = new Rect();
Cary Clark6f5dfc62010-11-11 13:09:20 -0500850 private boolean mSentAutoScrollMessage = false;
851
Adam Powell4fb35d42011-03-03 17:54:55 -0800852 // used for serializing asynchronously handled touch events.
853 private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 // Used to notify listeners of a new picture.
856 private PictureListener mPictureListener;
857 /**
858 * Interface to listen for new pictures as they change.
Kristian Monsenfc771652011-05-10 16:44:05 +0100859 * @deprecated This interface is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 */
Kristian Monsenfc771652011-05-10 16:44:05 +0100861 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 public interface PictureListener {
863 /**
864 * Notify the listener that the picture has changed.
865 * @param view The WebView that owns the picture.
866 * @param picture The new picture.
Kristian Monsenfc771652011-05-10 16:44:05 +0100867 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 */
Kristian Monsenfc771652011-05-10 16:44:05 +0100869 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 public void onNewPicture(WebView view, Picture picture);
871 }
872
Leon Scroggins3246c222009-05-26 09:51:23 -0400873 // FIXME: Want to make this public, but need to change the API file.
874 public /*static*/ class HitTestResult {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 /**
876 * Default HitTestResult, where the target is unknown
877 */
878 public static final int UNKNOWN_TYPE = 0;
879 /**
Steve Block1854ddb2011-04-19 12:18:19 +0100880 * @deprecated This type is no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 */
Steve Block1854ddb2011-04-19 12:18:19 +0100882 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 public static final int ANCHOR_TYPE = 1;
884 /**
885 * HitTestResult for hitting a phone number
886 */
887 public static final int PHONE_TYPE = 2;
888 /**
889 * HitTestResult for hitting a map address
890 */
891 public static final int GEO_TYPE = 3;
892 /**
893 * HitTestResult for hitting an email address
894 */
895 public static final int EMAIL_TYPE = 4;
896 /**
897 * HitTestResult for hitting an HTML::img tag
898 */
899 public static final int IMAGE_TYPE = 5;
900 /**
Steve Block1854ddb2011-04-19 12:18:19 +0100901 * @deprecated This type is no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 */
Steve Block1854ddb2011-04-19 12:18:19 +0100903 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 public static final int IMAGE_ANCHOR_TYPE = 6;
905 /**
906 * HitTestResult for hitting a HTML::a tag with src=http
907 */
908 public static final int SRC_ANCHOR_TYPE = 7;
909 /**
910 * HitTestResult for hitting a HTML::a tag with src=http + HTML::img
911 */
912 public static final int SRC_IMAGE_ANCHOR_TYPE = 8;
913 /**
914 * HitTestResult for hitting an edit text area
915 */
916 public static final int EDIT_TEXT_TYPE = 9;
917
918 private int mType;
919 private String mExtra;
920
921 HitTestResult() {
922 mType = UNKNOWN_TYPE;
923 }
924
925 private void setType(int type) {
926 mType = type;
927 }
928
929 private void setExtra(String extra) {
930 mExtra = extra;
931 }
932
933 public int getType() {
934 return mType;
935 }
936
937 public String getExtra() {
938 return mExtra;
939 }
940 }
941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 /**
943 * Construct a new WebView with a Context object.
944 * @param context A Context object used to access application assets.
945 */
946 public WebView(Context context) {
947 this(context, null);
948 }
949
950 /**
951 * Construct a new WebView with layout parameters.
952 * @param context A Context object used to access application assets.
953 * @param attrs An AttributeSet passed to our parent.
954 */
955 public WebView(Context context, AttributeSet attrs) {
956 this(context, attrs, com.android.internal.R.attr.webViewStyle);
957 }
958
959 /**
960 * Construct a new WebView with layout parameters and a default style.
961 * @param context A Context object used to access application assets.
962 * @param attrs An AttributeSet passed to our parent.
963 * @param defStyle The default style resource ID.
964 */
965 public WebView(Context context, AttributeSet attrs, int defStyle) {
Elliott Slaughterf21d2e32010-07-14 18:08:54 -0700966 this(context, attrs, defStyle, false);
967 }
968
969 /**
970 * Construct a new WebView with layout parameters and a default style.
971 * @param context A Context object used to access application assets.
972 * @param attrs An AttributeSet passed to our parent.
973 * @param defStyle The default style resource ID.
974 */
975 public WebView(Context context, AttributeSet attrs, int defStyle,
976 boolean privateBrowsing) {
977 this(context, attrs, defStyle, null, privateBrowsing);
Andrei Popescu4950b2b2009-09-03 13:56:07 +0100978 }
979
980 /**
981 * Construct a new WebView with layout parameters, a default style and a set
982 * of custom Javscript interfaces to be added to the WebView at initialization
Romain Guy01d0fbf2009-12-01 14:52:19 -0800983 * time. This guarantees that these interfaces will be available when the JS
Andrei Popescu4950b2b2009-09-03 13:56:07 +0100984 * context is initialized.
985 * @param context A Context object used to access application assets.
986 * @param attrs An AttributeSet passed to our parent.
987 * @param defStyle The default style resource ID.
Steve Block81f19ff2010-11-01 13:23:24 +0000988 * @param javaScriptInterfaces is a Map of interface names, as keys, and
Andrei Popescu4950b2b2009-09-03 13:56:07 +0100989 * object implementing those interfaces, as values.
990 * @hide pending API council approval.
991 */
992 protected WebView(Context context, AttributeSet attrs, int defStyle,
Steve Block81f19ff2010-11-01 13:23:24 +0000993 Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 super(context, attrs, defStyle);
Steve Block51b08912011-04-27 15:04:48 +0100995 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996
Kristian Monsend89a30a2010-11-16 18:11:59 +0000997 // Used by the chrome stack to find application paths
998 JniUtil.setContext(context);
999
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 mCallbackProxy = new CallbackProxy(context, this);
Grace Kloba9a67c822009-12-20 11:33:58 -08001001 mViewManager = new ViewManager(this);
Ben Murdochd2e91d12011-02-25 17:11:02 +00001002 L10nUtils.setApplicationContext(context.getApplicationContext());
Steve Block81f19ff2010-11-01 13:23:24 +00001003 mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 mDatabase = WebViewDatabase.getInstance(context);
Adam Powell637d3372010-08-25 14:37:03 -07001005 mScroller = new OverScroller(context, null, 0, 0, false); //TODO Use OverScroller's flywheel
Derek Sollenberger03e48912010-05-18 17:03:42 -04001006 mZoomManager = new ZoomManager(this, mCallbackProxy);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001007
Derek Sollenberger90b6e482010-05-10 12:38:54 -04001008 /* The init method must follow the creation of certain member variables,
1009 * such as the mZoomManager.
1010 */
1011 init();
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001012 setupPackageListener(context);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001013 setupProxyListener(context);
Grace Kloba3a0def22010-01-23 21:11:54 -08001014 updateMultiTouchSupport(context);
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07001015
1016 if (privateBrowsing) {
1017 startPrivateBrowsing();
1018 }
Ben Murdochffcc49e2010-10-28 18:24:57 +01001019
Ben Murdoch01b04e12010-11-08 10:49:16 +00001020 mAutoFillData = new WebViewCore.AutoFillData();
Grace Kloba3a0def22010-01-23 21:11:54 -08001021 }
1022
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001023 private static class ProxyReceiver extends BroadcastReceiver {
1024 @Override
1025 public void onReceive(Context context, Intent intent) {
1026 if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) {
1027 handleProxyBroadcast(intent);
1028 }
1029 }
1030 }
1031
Kristian Monsen9437d912010-12-23 15:39:31 +00001032 /*
Kristian Monsencbb59db2011-05-09 16:04:34 +01001033 * Receiver for PROXY_CHANGE_ACTION, will be null when it is not added handling broadcasts.
Kristian Monsen9437d912010-12-23 15:39:31 +00001034 */
Kristian Monsencbb59db2011-05-09 16:04:34 +01001035 private static ProxyReceiver sProxyReceiver;
Kristian Monsen9437d912010-12-23 15:39:31 +00001036
Kristian Monsencbb59db2011-05-09 16:04:34 +01001037 /*
1038 * @param context This method expects this to be a valid context
1039 */
Kristian Monsen9437d912010-12-23 15:39:31 +00001040 private static synchronized void setupProxyListener(Context context) {
Kristian Monsencbb59db2011-05-09 16:04:34 +01001041 if (sProxyReceiver != null || sNotificationsEnabled == false) {
Kristian Monsen9437d912010-12-23 15:39:31 +00001042 return;
1043 }
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001044 IntentFilter filter = new IntentFilter();
1045 filter.addAction(Proxy.PROXY_CHANGE_ACTION);
Kristian Monsencbb59db2011-05-09 16:04:34 +01001046 sProxyReceiver = new ProxyReceiver();
Kristian Monsen9437d912010-12-23 15:39:31 +00001047 Intent currentProxy = context.getApplicationContext().registerReceiver(
Kristian Monsencbb59db2011-05-09 16:04:34 +01001048 sProxyReceiver, filter);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001049 if (currentProxy != null) {
1050 handleProxyBroadcast(currentProxy);
1051 }
1052 }
1053
Kristian Monsencbb59db2011-05-09 16:04:34 +01001054 /*
1055 * @param context This method expects this to be a valid context
1056 */
1057 private static synchronized void disableProxyListener(Context context) {
1058 if (sProxyReceiver == null)
1059 return;
1060
1061 context.getApplicationContext().unregisterReceiver(sProxyReceiver);
1062 sProxyReceiver = null;
1063 }
1064
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001065 private static void handleProxyBroadcast(Intent intent) {
1066 ProxyProperties proxyProperties = (ProxyProperties)intent.getExtra(Proxy.EXTRA_PROXY_INFO);
1067 if (proxyProperties == null || proxyProperties.getHost() == null) {
1068 WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, "");
1069 return;
1070 }
1071
1072 String host = proxyProperties.getHost();
1073 int port = proxyProperties.getPort();
1074 if (port != 0)
Kristian Monsen6f6b6402011-01-18 14:01:45 +00001075 host += ":" + port;
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001076
1077 // TODO: Handle exclusion list
1078 // The plan is to make an AndroidProxyResolver, and handle the blacklist
1079 // there
1080 String exclusionList = proxyProperties.getExclusionList();
1081 WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, host);
1082 }
1083
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001084 /*
Kristian Monsen4190aab2010-12-16 18:39:21 +00001085 * A variable to track if there is a receiver added for ACTION_PACKAGE_ADDED
1086 * or ACTION_PACKAGE_REMOVED.
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001087 */
Kristian Monsen4190aab2010-12-16 18:39:21 +00001088 private static boolean sPackageInstallationReceiverAdded = false;
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001089
1090 /*
1091 * A set of Google packages we monitor for the
1092 * navigator.isApplicationInstalled() API. Add additional packages as
1093 * needed.
1094 */
1095 private static Set<String> sGoogleApps;
1096 static {
1097 sGoogleApps = new HashSet<String>();
1098 sGoogleApps.add("com.google.android.youtube");
1099 }
1100
Kristian Monsen4190aab2010-12-16 18:39:21 +00001101 private static class PackageListener extends BroadcastReceiver {
1102 @Override
1103 public void onReceive(Context context, Intent intent) {
1104 final String action = intent.getAction();
1105 final String packageName = intent.getData().getSchemeSpecificPart();
1106 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1107 if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) {
1108 // if it is replacing, refreshPlugins() when adding
1109 return;
1110 }
1111
1112 if (sGoogleApps.contains(packageName)) {
1113 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
1114 WebViewCore.sendStaticMessage(EventHub.ADD_PACKAGE_NAME, packageName);
1115 } else {
1116 WebViewCore.sendStaticMessage(EventHub.REMOVE_PACKAGE_NAME, packageName);
1117 }
1118 }
1119
1120 PluginManager pm = PluginManager.getInstance(context);
1121 if (pm.containsPluginPermissionAndSignatures(packageName)) {
1122 pm.refreshPlugins(Intent.ACTION_PACKAGE_ADDED.equals(action));
1123 }
1124 }
1125 }
1126
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001127 private void setupPackageListener(Context context) {
1128
1129 /*
1130 * we must synchronize the instance check and the creation of the
1131 * receiver to ensure that only ONE receiver exists for all WebView
1132 * instances.
1133 */
1134 synchronized (WebView.class) {
1135
1136 // if the receiver already exists then we do not need to register it
1137 // again
Kristian Monsen4190aab2010-12-16 18:39:21 +00001138 if (sPackageInstallationReceiverAdded) {
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001139 return;
1140 }
1141
1142 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
1143 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1144 filter.addDataScheme("package");
Kristian Monsen4190aab2010-12-16 18:39:21 +00001145 BroadcastReceiver packageListener = new PackageListener();
1146 context.getApplicationContext().registerReceiver(packageListener, filter);
1147 sPackageInstallationReceiverAdded = true;
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001148 }
1149
1150 // check if any of the monitored apps are already installed
1151 AsyncTask<Void, Void, Set<String>> task = new AsyncTask<Void, Void, Set<String>>() {
1152
1153 @Override
1154 protected Set<String> doInBackground(Void... unused) {
1155 Set<String> installedPackages = new HashSet<String>();
1156 PackageManager pm = mContext.getPackageManager();
Kristian Monsen63a1b0c2011-03-09 13:54:54 +00001157 for (String name : sGoogleApps) {
1158 try {
1159 PackageInfo pInfo = pm.getPackageInfo(name,
1160 PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
1161 installedPackages.add(name);
Steve Block51b08912011-04-27 15:04:48 +01001162 } catch (PackageManager.NameNotFoundException e) {
Kristian Monsen63a1b0c2011-03-09 13:54:54 +00001163 // package not found
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001164 }
1165 }
1166 return installedPackages;
1167 }
1168
1169 // Executes on the UI thread
1170 @Override
1171 protected void onPostExecute(Set<String> installedPackages) {
Derek Sollenbergerc92de672010-09-01 08:55:22 -04001172 if (mWebViewCore != null) {
1173 mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, installedPackages);
1174 }
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001175 }
1176 };
1177 task.execute();
1178 }
1179
Grace Kloba3a0def22010-01-23 21:11:54 -08001180 void updateMultiTouchSupport(Context context) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04001181 mZoomManager.updateMultiTouchSupport(context);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001182 }
1183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 private void init() {
1185 setWillNotDraw(false);
1186 setFocusable(true);
1187 setFocusableInTouchMode(true);
1188 setClickable(true);
1189 setLongClickable(true);
1190
Romain Guy4296fc42009-07-06 11:48:52 -07001191 final ViewConfiguration configuration = ViewConfiguration.get(getContext());
Grace Kloba8b97e4b2009-07-28 13:11:38 -07001192 int slop = configuration.getScaledTouchSlop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 mTouchSlopSquare = slop * slop;
1194 mMinLockSnapReverseDistance = slop;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07001195 slop = configuration.getScaledDoubleTapSlop();
1196 mDoubleTapSlopSquare = slop * slop;
Grace Kloba25737912009-06-19 12:42:47 -07001197 final float density = getContext().getResources().getDisplayMetrics().density;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001198 // use one line height, 16 based on our current default font, for how
1199 // far we allow a touch be away from the edge of a link
Grace Kloba25737912009-06-19 12:42:47 -07001200 mNavSlop = (int) (16 * density);
Derek Sollenberger90b6e482010-05-10 12:38:54 -04001201 mZoomManager.init(density);
Romain Guy4296fc42009-07-06 11:48:52 -07001202 mMaximumFling = configuration.getScaledMaximumFlingVelocity();
Patrick Scotta3ebcc92010-07-16 11:52:22 -04001203
1204 // Compute the inverse of the density squared.
1205 DRAG_LAYER_INVERSE_DENSITY_SQUARED = 1 / (density * density);
Adam Powell637d3372010-08-25 14:37:03 -07001206
1207 mOverscrollDistance = configuration.getScaledOverscrollDistance();
1208 mOverflingDistance = configuration.getScaledOverflingDistance();
Teng-Hui Zhu15bfa532011-02-14 17:01:16 -08001209
1210 setScrollBarStyle(super.getScrollBarStyle());
Leon Scroggins115626a2011-02-17 12:00:48 -05001211 // Initially use a size of two, since the user is likely to only hold
1212 // down two keys at a time (shift + another key)
1213 mKeysPressed = new Vector<Integer>(2);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08001214 mHTML5VideoViewProxy = null ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216
Patrick Dubroye0a799a2011-05-04 16:19:22 -07001217 @Override
1218 public boolean shouldDelayChildPressedState() {
1219 return true;
1220 }
1221
Svetoslav Ganovda355512010-05-12 22:04:44 -07001222 /**
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001223 * Adds accessibility APIs to JavaScript.
Svetoslav Ganovda355512010-05-12 22:04:44 -07001224 *
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001225 * Note: This method is responsible to performing the necessary
1226 * check if the accessibility APIs should be exposed.
Svetoslav Ganovda355512010-05-12 22:04:44 -07001227 */
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001228 private void addAccessibilityApisToJavaScript() {
1229 if (AccessibilityManager.getInstance(mContext).isEnabled()
1230 && getSettings().getJavaScriptEnabled()) {
1231 // exposing the TTS for now ...
Michael Kolbc4ca53f2011-02-05 13:53:14 -08001232 mTextToSpeech = new TextToSpeech(getContext(), null);
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001233 addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
Svetoslav Ganovda355512010-05-12 22:04:44 -07001234 }
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001235 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001236
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001237 /**
1238 * Removes accessibility APIs from JavaScript.
1239 */
1240 private void removeAccessibilityApisFromJavaScript() {
1241 // exposing the TTS for now ...
1242 if (mTextToSpeech != null) {
1243 removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE);
1244 mTextToSpeech.shutdown();
1245 mTextToSpeech = null;
1246 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001247 }
1248
Adam Powell637d3372010-08-25 14:37:03 -07001249 @Override
1250 public void setOverScrollMode(int mode) {
1251 super.setOverScrollMode(mode);
1252 if (mode != OVER_SCROLL_NEVER) {
1253 if (mOverScrollGlow == null) {
1254 mOverScrollGlow = new OverScrollGlow(this);
1255 }
1256 } else {
1257 mOverScrollGlow = null;
1258 }
1259 }
1260
Grace Kloba0d8b77c2009-06-25 11:20:51 -07001261 /* package */void updateDefaultZoomDensity(int zoomDensity) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04001262 final float density = mContext.getResources().getDisplayMetrics().density
Grace Kloba0d8b77c2009-06-25 11:20:51 -07001263 * 100 / zoomDensity;
Derek Sollenberger03e48912010-05-18 17:03:42 -04001264 mNavSlop = (int) (16 * density);
1265 mZoomManager.updateDefaultZoomDensity(density);
Grace Kloba0d8b77c2009-06-25 11:20:51 -07001266 }
1267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 /* package */ boolean onSavePassword(String schemePlusHost, String username,
1269 String password, final Message resumeMsg) {
1270 boolean rVal = false;
1271 if (resumeMsg == null) {
1272 // null resumeMsg implies saving password silently
1273 mDatabase.setUsernamePassword(schemePlusHost, username, password);
1274 } else {
1275 final Message remember = mPrivateHandler.obtainMessage(
1276 REMEMBER_PASSWORD);
1277 remember.getData().putString("host", schemePlusHost);
1278 remember.getData().putString("username", username);
1279 remember.getData().putString("password", password);
1280 remember.obj = resumeMsg;
1281
1282 final Message neverRemember = mPrivateHandler.obtainMessage(
1283 NEVER_REMEMBER_PASSWORD);
1284 neverRemember.getData().putString("host", schemePlusHost);
1285 neverRemember.getData().putString("username", username);
1286 neverRemember.getData().putString("password", password);
1287 neverRemember.obj = resumeMsg;
1288
1289 new AlertDialog.Builder(getContext())
1290 .setTitle(com.android.internal.R.string.save_password_label)
1291 .setMessage(com.android.internal.R.string.save_password_message)
1292 .setPositiveButton(com.android.internal.R.string.save_password_notnow,
1293 new DialogInterface.OnClickListener() {
1294 public void onClick(DialogInterface dialog, int which) {
1295 resumeMsg.sendToTarget();
1296 }
1297 })
1298 .setNeutralButton(com.android.internal.R.string.save_password_remember,
1299 new DialogInterface.OnClickListener() {
1300 public void onClick(DialogInterface dialog, int which) {
1301 remember.sendToTarget();
1302 }
1303 })
1304 .setNegativeButton(com.android.internal.R.string.save_password_never,
1305 new DialogInterface.OnClickListener() {
1306 public void onClick(DialogInterface dialog, int which) {
1307 neverRemember.sendToTarget();
1308 }
1309 })
1310 .setOnCancelListener(new OnCancelListener() {
1311 public void onCancel(DialogInterface dialog) {
1312 resumeMsg.sendToTarget();
1313 }
1314 }).show();
1315 // Return true so that WebViewCore will pause while the dialog is
1316 // up.
1317 rVal = true;
1318 }
1319 return rVal;
1320 }
1321
1322 @Override
1323 public void setScrollBarStyle(int style) {
1324 if (style == View.SCROLLBARS_INSIDE_INSET
1325 || style == View.SCROLLBARS_OUTSIDE_INSET) {
1326 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
1327 } else {
1328 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
1329 }
1330 super.setScrollBarStyle(style);
1331 }
1332
1333 /**
1334 * Specify whether the horizontal scrollbar has overlay style.
1335 * @param overlay TRUE if horizontal scrollbar should have overlay style.
1336 */
1337 public void setHorizontalScrollbarOverlay(boolean overlay) {
Steve Block51b08912011-04-27 15:04:48 +01001338 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 mOverlayHorizontalScrollbar = overlay;
1340 }
1341
1342 /**
1343 * Specify whether the vertical scrollbar has overlay style.
1344 * @param overlay TRUE if vertical scrollbar should have overlay style.
1345 */
1346 public void setVerticalScrollbarOverlay(boolean overlay) {
Steve Block51b08912011-04-27 15:04:48 +01001347 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 mOverlayVerticalScrollbar = overlay;
1349 }
1350
1351 /**
1352 * Return whether horizontal scrollbar has overlay style
1353 * @return TRUE if horizontal scrollbar has overlay style.
1354 */
1355 public boolean overlayHorizontalScrollbar() {
Steve Block51b08912011-04-27 15:04:48 +01001356 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 return mOverlayHorizontalScrollbar;
1358 }
1359
1360 /**
1361 * Return whether vertical scrollbar has overlay style
1362 * @return TRUE if vertical scrollbar has overlay style.
1363 */
1364 public boolean overlayVerticalScrollbar() {
Steve Block51b08912011-04-27 15:04:48 +01001365 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 return mOverlayVerticalScrollbar;
1367 }
1368
1369 /*
1370 * Return the width of the view where the content of WebView should render
1371 * to.
Grace Kloba6ed525e2009-09-17 15:31:12 -07001372 * Note: this can be called from WebCoreThread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 */
Grace Kloba6ed525e2009-09-17 15:31:12 -07001374 /* package */ int getViewWidth() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) {
1376 return getWidth();
1377 } else {
Shimeng (Simon) Wang37127542010-12-03 16:34:00 -08001378 return Math.max(0, getWidth() - getVerticalScrollbarWidth());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 }
1380 }
1381
Michael Kolb601e7792011-02-23 17:43:16 -08001382 /**
Mike Reede8853fc2009-09-04 14:01:48 -04001383 * returns the height of the titlebarview (if any). Does not care about
1384 * scrolling
Michael Kolb75a03f92011-02-23 16:12:13 -08001385 * @hide
Mike Reede8853fc2009-09-04 14:01:48 -04001386 */
Michael Kolb75a03f92011-02-23 16:12:13 -08001387 protected int getTitleHeight() {
Mike Reede8853fc2009-09-04 14:01:48 -04001388 return mTitleBar != null ? mTitleBar.getHeight() : 0;
1389 }
1390
Michael Kolbe54f6652011-03-16 09:11:51 -07001391 /**
Mike Reede8853fc2009-09-04 14:01:48 -04001392 * Return the amount of the titlebarview (if any) that is visible
Michael Kolb73980a92010-08-05 16:32:51 -07001393 *
Michael Kolb24e53b02011-03-16 12:52:04 -07001394 * @deprecated This method is now obsolete.
Mike Reede8853fc2009-09-04 14:01:48 -04001395 */
Michael Kolb73980a92010-08-05 16:32:51 -07001396 public int getVisibleTitleHeight() {
Steve Block51b08912011-04-27 15:04:48 +01001397 checkThread();
Adam Powell637d3372010-08-25 14:37:03 -07001398 // need to restrict mScrollY due to over scroll
1399 return Math.max(getTitleHeight() - Math.max(0, mScrollY), 0);
Mike Reede8853fc2009-09-04 14:01:48 -04001400 }
1401
1402 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 * Return the height of the view where the content of WebView should render
Leon Scroggins0236e672009-09-02 21:12:08 -04001404 * to. Note that this excludes mTitleBar, if there is one.
Grace Kloba6ed525e2009-09-17 15:31:12 -07001405 * Note: this can be called from WebCoreThread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 */
Grace Kloba6ed525e2009-09-17 15:31:12 -07001407 /* package */ int getViewHeight() {
Grace Kloba8eff73f2009-09-24 09:34:32 -07001408 return getViewHeightWithTitle() - getVisibleTitleHeight();
1409 }
1410
1411 private int getViewHeightWithTitle() {
Leon Scroggins0236e672009-09-02 21:12:08 -04001412 int height = getHeight();
Mike Reede8853fc2009-09-04 14:01:48 -04001413 if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) {
Leon Scroggins0236e672009-09-02 21:12:08 -04001414 height -= getHorizontalScrollbarHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 }
Grace Kloba8eff73f2009-09-24 09:34:32 -07001416 return height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 }
1418
1419 /**
1420 * @return The SSL certificate for the main top-level page or null if
1421 * there is no certificate (the site is not secure).
1422 */
1423 public SslCertificate getCertificate() {
Steve Block51b08912011-04-27 15:04:48 +01001424 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 return mCertificate;
1426 }
1427
1428 /**
1429 * Sets the SSL certificate for the main top-level page.
1430 */
1431 public void setCertificate(SslCertificate certificate) {
Steve Block51b08912011-04-27 15:04:48 +01001432 checkThread();
Brian Carlstromdba8cb72010-03-18 16:56:41 -07001433 if (DebugFlags.WEB_VIEW) {
1434 Log.v(LOGTAG, "setCertificate=" + certificate);
1435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 // here, the certificate can be null (if the site is not secure)
1437 mCertificate = certificate;
1438 }
1439
1440 //-------------------------------------------------------------------------
1441 // Methods called by activity
1442 //-------------------------------------------------------------------------
1443
1444 /**
1445 * Save the username and password for a particular host in the WebView's
1446 * internal database.
1447 * @param host The host that required the credentials.
1448 * @param username The username for the given host.
1449 * @param password The password for the given host.
1450 */
1451 public void savePassword(String host, String username, String password) {
Steve Block51b08912011-04-27 15:04:48 +01001452 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 mDatabase.setUsernamePassword(host, username, password);
1454 }
1455
1456 /**
1457 * Set the HTTP authentication credentials for a given host and realm.
1458 *
1459 * @param host The host for the credentials.
1460 * @param realm The realm for the credentials.
1461 * @param username The username for the password. If it is null, it means
1462 * password can't be saved.
1463 * @param password The password
1464 */
1465 public void setHttpAuthUsernamePassword(String host, String realm,
1466 String username, String password) {
Steve Block51b08912011-04-27 15:04:48 +01001467 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
1469 }
1470
1471 /**
1472 * Retrieve the HTTP authentication username and password for a given
1473 * host & realm pair
1474 *
1475 * @param host The host for which the credentials apply.
1476 * @param realm The realm for which the credentials apply.
1477 * @return String[] if found, String[0] is username, which can be null and
1478 * String[1] is password. Return null if it can't find anything.
1479 */
1480 public String[] getHttpAuthUsernamePassword(String host, String realm) {
Steve Block51b08912011-04-27 15:04:48 +01001481 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 return mDatabase.getHttpAuthUsernamePassword(host, realm);
1483 }
1484
1485 /**
Leon Scroggins05919f22010-09-14 17:22:36 -04001486 * Remove Find or Select ActionModes, if active.
1487 */
1488 private void clearActionModes() {
1489 if (mSelectCallback != null) {
1490 mSelectCallback.finish();
1491 }
1492 if (mFindCallback != null) {
1493 mFindCallback.finish();
1494 }
1495 }
1496
1497 /**
1498 * Called to clear state when moving from one page to another, or changing
1499 * in some other way that makes elements associated with the current page
1500 * (such as WebTextView or ActionModes) no longer relevant.
1501 */
1502 private void clearHelpers() {
1503 clearTextEntry();
1504 clearActionModes();
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04001505 dismissFullScreenMode();
Leon Scroggins05919f22010-09-14 17:22:36 -04001506 }
1507
1508 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 * Destroy the internal state of the WebView. This method should be called
1510 * after the WebView has been removed from the view system. No other
1511 * methods may be called on a WebView after destroy.
1512 */
1513 public void destroy() {
Steve Block51b08912011-04-27 15:04:48 +01001514 checkThread();
1515 destroyImpl();
1516 }
1517
1518 private void destroyImpl() {
Leon Scroggins05919f22010-09-14 17:22:36 -04001519 clearHelpers();
Mattias Falk0ae2ec82010-09-16 16:24:46 +02001520 if (mListBoxDialog != null) {
1521 mListBoxDialog.dismiss();
1522 mListBoxDialog = null;
1523 }
Cary Clarkd9fd8572011-02-03 05:25:05 -05001524 if (mNativeClass != 0) nativeStopGL();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 if (mWebViewCore != null) {
1526 // Set the handlers to null before destroying WebViewCore so no
Cary Clarkd6982c92009-05-29 11:02:22 -04001527 // more messages will be posted.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 mCallbackProxy.setWebViewClient(null);
1529 mCallbackProxy.setWebChromeClient(null);
1530 // Tell WebViewCore to destroy itself
Andrei Popescu04098572010-03-09 12:23:19 +00001531 synchronized (this) {
1532 WebViewCore webViewCore = mWebViewCore;
1533 mWebViewCore = null; // prevent using partial webViewCore
1534 webViewCore.destroy();
1535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 // Remove any pending messages that might not be serviced yet.
1537 mPrivateHandler.removeCallbacksAndMessages(null);
1538 mCallbackProxy.removeCallbacksAndMessages(null);
1539 // Wake up the WebCore thread just in case it is waiting for a
Steve Block81f19ff2010-11-01 13:23:24 +00001540 // JavaScript dialog.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 synchronized (mCallbackProxy) {
1542 mCallbackProxy.notify();
1543 }
1544 }
1545 if (mNativeClass != 0) {
1546 nativeDestroy();
1547 mNativeClass = 0;
1548 }
1549 }
1550
1551 /**
1552 * Enables platform notifications of data state and proxy changes.
Kristian Monsencbb59db2011-05-09 16:04:34 +01001553 * Notifications are enabled by default.
Kristian Monsenfc771652011-05-10 16:44:05 +01001554 *
1555 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001557 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 public static void enablePlatformNotifications() {
Steve Block51b08912011-04-27 15:04:48 +01001559 checkThread();
Kristian Monsencbb59db2011-05-09 16:04:34 +01001560 synchronized (WebView.class) {
1561 Network.enablePlatformNotifications();
1562 sNotificationsEnabled = true;
1563 Context context = JniUtil.getContext();
1564 if (context != null)
1565 setupProxyListener(context);
1566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 }
1568
1569 /**
Kristian Monsencbb59db2011-05-09 16:04:34 +01001570 * Disables platform notifications of data state and proxy changes.
1571 * Notifications are enabled by default.
Kristian Monsenfc771652011-05-10 16:44:05 +01001572 *
1573 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001575 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 public static void disablePlatformNotifications() {
Steve Block51b08912011-04-27 15:04:48 +01001577 checkThread();
Kristian Monsencbb59db2011-05-09 16:04:34 +01001578 synchronized (WebView.class) {
1579 Network.disablePlatformNotifications();
1580 sNotificationsEnabled = false;
1581 Context context = JniUtil.getContext();
1582 if (context != null)
1583 disableProxyListener(context);
1584 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 }
Cary Clarkd6982c92009-05-29 11:02:22 -04001586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 /**
Feng Qianb3081372009-06-29 15:55:18 -07001588 * Sets JavaScript engine flags.
1589 *
1590 * @param flags JS engine flags in a String
1591 *
1592 * @hide pending API solidification
1593 */
1594 public void setJsFlags(String flags) {
Steve Block51b08912011-04-27 15:04:48 +01001595 checkThread();
Feng Qianb3081372009-06-29 15:55:18 -07001596 mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
1597 }
1598
1599 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 * Inform WebView of the network state. This is used to set
Steve Block81f19ff2010-11-01 13:23:24 +00001601 * the JavaScript property window.navigator.isOnline and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 * generates the online/offline event as specified in HTML5, sec. 5.7.7
1603 * @param networkUp boolean indicating if network is available
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 */
1605 public void setNetworkAvailable(boolean networkUp) {
Steve Block51b08912011-04-27 15:04:48 +01001606 checkThread();
Grace Klobaa72cc092009-04-02 08:50:17 -07001607 mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE,
1608 networkUp ? 1 : 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 }
1610
1611 /**
Andrei Popescuf5dba882010-01-12 22:42:41 +00001612 * Inform WebView about the current network type.
1613 * {@hide}
1614 */
1615 public void setNetworkType(String type, String subtype) {
Steve Block51b08912011-04-27 15:04:48 +01001616 checkThread();
Andrei Popescuf5dba882010-01-12 22:42:41 +00001617 Map<String, String> map = new HashMap<String, String>();
1618 map.put("type", type);
1619 map.put("subtype", subtype);
1620 mWebViewCore.sendMessage(EventHub.SET_NETWORK_TYPE, map);
1621 }
1622 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04001623 * Save the state of this WebView used in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 * {@link android.app.Activity#onSaveInstanceState}. Please note that this
1625 * method no longer stores the display data for this WebView. The previous
1626 * behavior could potentially leak files if {@link #restoreState} was never
1627 * called. See {@link #savePicture} and {@link #restorePicture} for saving
1628 * and restoring the display data.
1629 * @param outState The Bundle to store the WebView state.
1630 * @return The same copy of the back/forward list used to save the state. If
1631 * saveState fails, the returned list will be null.
1632 * @see #savePicture
1633 * @see #restorePicture
1634 */
1635 public WebBackForwardList saveState(Bundle outState) {
Steve Block51b08912011-04-27 15:04:48 +01001636 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 if (outState == null) {
1638 return null;
1639 }
1640 // We grab a copy of the back/forward list because a client of WebView
1641 // may have invalidated the history list by calling clearHistory.
1642 WebBackForwardList list = copyBackForwardList();
1643 final int currentIndex = list.getCurrentIndex();
1644 final int size = list.getSize();
1645 // We should fail saving the state if the list is empty or the index is
1646 // not in a valid range.
1647 if (currentIndex < 0 || currentIndex >= size || size == 0) {
1648 return null;
1649 }
1650 outState.putInt("index", currentIndex);
1651 // FIXME: This should just be a byte[][] instead of ArrayList but
1652 // Parcel.java does not have the code to handle multi-dimensional
1653 // arrays.
1654 ArrayList<byte[]> history = new ArrayList<byte[]>(size);
1655 for (int i = 0; i < size; i++) {
1656 WebHistoryItem item = list.getItemAtIndex(i);
Cary Clark4fbf81b2009-09-29 16:07:56 -04001657 if (null == item) {
1658 // FIXME: this shouldn't happen
1659 // need to determine how item got set to null
1660 Log.w(LOGTAG, "saveState: Unexpected null history item.");
1661 return null;
1662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 byte[] data = item.getFlattenedData();
1664 if (data == null) {
1665 // It would be very odd to not have any data for a given history
1666 // item. And we will fail to rebuild the history list without
1667 // flattened data.
1668 return null;
1669 }
1670 history.add(data);
1671 }
1672 outState.putSerializable("history", history);
1673 if (mCertificate != null) {
1674 outState.putBundle("certificate",
1675 SslCertificate.saveState(mCertificate));
1676 }
Elliott Slaughterd6284792010-08-18 18:17:52 -07001677 outState.putBoolean("privateBrowsingEnabled", isPrivateBrowsingEnabled());
Shimeng (Simon) Wang4ae1f6f2010-08-26 10:58:38 -07001678 mZoomManager.saveZoomState(outState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 return list;
1680 }
1681
1682 /**
1683 * Save the current display data to the Bundle given. Used in conjunction
1684 * with {@link #saveState}.
1685 * @param b A Bundle to store the display data.
1686 * @param dest The file to store the serialized picture data. Will be
1687 * overwritten with this WebView's picture data.
1688 * @return True if the picture was successfully saved.
Kristian Monsenfc771652011-05-10 16:44:05 +01001689 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001691 @Deprecated
Patrick Scottda9a22b2010-04-08 08:32:52 -04001692 public boolean savePicture(Bundle b, final File dest) {
Steve Block51b08912011-04-27 15:04:48 +01001693 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 if (dest == null || b == null) {
1695 return false;
1696 }
1697 final Picture p = capturePicture();
Patrick Scottda9a22b2010-04-08 08:32:52 -04001698 // Use a temporary file while writing to ensure the destination file
1699 // contains valid data.
1700 final File temp = new File(dest.getPath() + ".writing");
1701 new Thread(new Runnable() {
1702 public void run() {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001703 FileOutputStream out = null;
Patrick Scottda9a22b2010-04-08 08:32:52 -04001704 try {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001705 out = new FileOutputStream(temp);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001706 p.writeToStream(out);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001707 // Writing the picture succeeded, rename the temporary file
1708 // to the destination.
1709 temp.renameTo(dest);
1710 } catch (Exception e) {
1711 // too late to do anything about it.
1712 } finally {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001713 if (out != null) {
1714 try {
1715 out.close();
1716 } catch (Exception e) {
1717 // Can't do anything about that
1718 }
1719 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001720 temp.delete();
1721 }
1722 }
1723 }).start();
1724 // now update the bundle
1725 b.putInt("scrollX", mScrollX);
1726 b.putInt("scrollY", mScrollY);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001727 mZoomManager.saveZoomState(b);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001728 return true;
1729 }
1730
1731 private void restoreHistoryPictureFields(Picture p, Bundle b) {
1732 int sx = b.getInt("scrollX", 0);
1733 int sy = b.getInt("scrollY", 0);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001734
Patrick Scottda9a22b2010-04-08 08:32:52 -04001735 mDrawHistory = true;
1736 mHistoryPicture = p;
Huahui Wu88b869a2011-03-17 17:42:12 -07001737
Patrick Scottda9a22b2010-04-08 08:32:52 -04001738 mScrollX = sx;
1739 mScrollY = sy;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001740 mZoomManager.restoreZoomState(b);
1741 final float scale = mZoomManager.getScale();
Patrick Scottda9a22b2010-04-08 08:32:52 -04001742 mHistoryWidth = Math.round(p.getWidth() * scale);
1743 mHistoryHeight = Math.round(p.getHeight() * scale);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001744
Patrick Scottda9a22b2010-04-08 08:32:52 -04001745 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 }
1747
1748 /**
1749 * Restore the display data that was save in {@link #savePicture}. Used in
1750 * conjunction with {@link #restoreState}.
1751 * @param b A Bundle containing the saved display data.
1752 * @param src The file where the picture data was stored.
1753 * @return True if the picture was successfully restored.
Kristian Monsenfc771652011-05-10 16:44:05 +01001754 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001756 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 public boolean restorePicture(Bundle b, File src) {
Steve Block51b08912011-04-27 15:04:48 +01001758 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 if (src == null || b == null) {
1760 return false;
1761 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001762 if (!src.exists()) {
1763 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001765 try {
1766 final FileInputStream in = new FileInputStream(src);
1767 final Bundle copy = new Bundle(b);
1768 new Thread(new Runnable() {
1769 public void run() {
Patrick Scottda9a22b2010-04-08 08:32:52 -04001770 try {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001771 final Picture p = Picture.createFromStream(in);
1772 if (p != null) {
1773 // Post a runnable on the main thread to update the
1774 // history picture fields.
1775 mPrivateHandler.post(new Runnable() {
1776 public void run() {
1777 restoreHistoryPictureFields(p, copy);
1778 }
1779 });
1780 }
1781 } finally {
1782 try {
1783 in.close();
1784 } catch (Exception e) {
1785 // Nothing we can do now.
1786 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001787 }
1788 }
1789 }).start();
1790 } catch (FileNotFoundException e){
1791 e.printStackTrace();
1792 }
1793 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 }
1795
1796 /**
1797 * Restore the state of this WebView from the given map used in
Cary Clarkd6982c92009-05-29 11:02:22 -04001798 * {@link android.app.Activity#onRestoreInstanceState}. This method should
1799 * be called to restore the state of the WebView before using the object. If
1800 * it is called after the WebView has had a chance to build state (load
1801 * pages, create a back/forward list, etc.) there may be undesirable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 * side-effects. Please note that this method no longer restores the
1803 * display data for this WebView. See {@link #savePicture} and {@link
1804 * #restorePicture} for saving and restoring the display data.
1805 * @param inState The incoming Bundle of state.
1806 * @return The restored back/forward list or null if restoreState failed.
1807 * @see #savePicture
1808 * @see #restorePicture
1809 */
1810 public WebBackForwardList restoreState(Bundle inState) {
Steve Block51b08912011-04-27 15:04:48 +01001811 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 WebBackForwardList returnList = null;
1813 if (inState == null) {
1814 return returnList;
1815 }
1816 if (inState.containsKey("index") && inState.containsKey("history")) {
1817 mCertificate = SslCertificate.restoreState(
1818 inState.getBundle("certificate"));
1819
1820 final WebBackForwardList list = mCallbackProxy.getBackForwardList();
1821 final int index = inState.getInt("index");
1822 // We can't use a clone of the list because we need to modify the
1823 // shared copy, so synchronize instead to prevent concurrent
1824 // modifications.
1825 synchronized (list) {
1826 final List<byte[]> history =
1827 (List<byte[]>) inState.getSerializable("history");
1828 final int size = history.size();
1829 // Check the index bounds so we don't crash in native code while
1830 // restoring the history index.
1831 if (index < 0 || index >= size) {
1832 return null;
1833 }
1834 for (int i = 0; i < size; i++) {
1835 byte[] data = history.remove(0);
1836 if (data == null) {
1837 // If we somehow have null data, we cannot reconstruct
1838 // the item and thus our history list cannot be rebuilt.
1839 return null;
1840 }
1841 WebHistoryItem item = new WebHistoryItem(data);
1842 list.addHistoryItem(item);
1843 }
1844 // Grab the most recent copy to return to the caller.
1845 returnList = copyBackForwardList();
1846 // Update the copy to have the correct index.
1847 returnList.setCurrentIndex(index);
1848 }
Elliott Slaughterd6284792010-08-18 18:17:52 -07001849 // Restore private browsing setting.
1850 if (inState.getBoolean("privateBrowsingEnabled")) {
1851 getSettings().setPrivateBrowsingEnabled(true);
1852 }
Shimeng (Simon) Wang4ae1f6f2010-08-26 10:58:38 -07001853 mZoomManager.restoreZoomState(inState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 // Remove all pending messages because we are restoring previous
1855 // state.
1856 mWebViewCore.removeMessages();
1857 // Send a restore state message.
1858 mWebViewCore.sendMessage(EventHub.RESTORE_STATE, index);
1859 }
1860 return returnList;
1861 }
1862
1863 /**
Grace Klobad0d9bc22010-01-26 18:08:28 -08001864 * Load the given url with the extra headers.
1865 * @param url The url of the resource to load.
1866 * @param extraHeaders The extra headers sent with this url. This should not
1867 * include the common headers like "user-agent". If it does, it
1868 * will be replaced by the intrinsic value of the WebView.
1869 */
1870 public void loadUrl(String url, Map<String, String> extraHeaders) {
Steve Block51b08912011-04-27 15:04:48 +01001871 checkThread();
1872 loadUrlImpl(url, extraHeaders);
1873 }
1874
1875 private void loadUrlImpl(String url, Map<String, String> extraHeaders) {
Grace Klobad0d9bc22010-01-26 18:08:28 -08001876 switchOutDrawHistory();
1877 WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
1878 arg.mUrl = url;
1879 arg.mExtraHeaders = extraHeaders;
1880 mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04001881 clearHelpers();
Grace Klobad0d9bc22010-01-26 18:08:28 -08001882 }
1883
1884 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 * Load the given url.
1886 * @param url The url of the resource to load.
1887 */
1888 public void loadUrl(String url) {
Steve Block51b08912011-04-27 15:04:48 +01001889 checkThread();
1890 loadUrlImpl(url);
1891 }
1892
1893 private void loadUrlImpl(String url) {
Patrick Scott4c3ca702009-07-15 15:41:05 -04001894 if (url == null) {
1895 return;
1896 }
Steve Block51b08912011-04-27 15:04:48 +01001897 loadUrlImpl(url, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 }
1899
1900 /**
Grace Kloba57534302009-05-22 18:55:02 -07001901 * Load the url with postData using "POST" method into the WebView. If url
1902 * is not a network url, it will be loaded with {link
1903 * {@link #loadUrl(String)} instead.
Cary Clarkd6982c92009-05-29 11:02:22 -04001904 *
Grace Kloba57534302009-05-22 18:55:02 -07001905 * @param url The url of the resource to load.
1906 * @param postData The data will be passed to "POST" request.
Grace Kloba57534302009-05-22 18:55:02 -07001907 */
1908 public void postUrl(String url, byte[] postData) {
Steve Block51b08912011-04-27 15:04:48 +01001909 checkThread();
Grace Kloba57534302009-05-22 18:55:02 -07001910 if (URLUtil.isNetworkUrl(url)) {
1911 switchOutDrawHistory();
Cary Clarkded054c2009-06-15 10:26:08 -04001912 WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
1913 arg.mUrl = url;
1914 arg.mPostData = postData;
Grace Kloba57534302009-05-22 18:55:02 -07001915 mWebViewCore.sendMessage(EventHub.POST_URL, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04001916 clearHelpers();
Grace Kloba57534302009-05-22 18:55:02 -07001917 } else {
Steve Block51b08912011-04-27 15:04:48 +01001918 loadUrlImpl(url);
Grace Kloba57534302009-05-22 18:55:02 -07001919 }
1920 }
1921
1922 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 * Load the given data into the WebView. This will load the data into
1924 * WebView using the data: scheme. Content loaded through this mechanism
1925 * does not have the ability to load content from the network.
Cary Clarkfc2ece42010-03-15 16:01:49 -04001926 * @param data A String of data in the given encoding. The date must
1927 * be URI-escaped -- '#', '%', '\', '?' should be replaced by %23, %25,
1928 * %27, %3f respectively.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 * @param mimeType The MIMEType of the data. i.e. text/html, image/jpeg
1930 * @param encoding The encoding of the data. i.e. utf-8, base64
1931 */
1932 public void loadData(String data, String mimeType, String encoding) {
Steve Block51b08912011-04-27 15:04:48 +01001933 checkThread();
1934 loadDataImpl(data, mimeType, encoding);
1935 }
1936
1937 private void loadDataImpl(String data, String mimeType, String encoding) {
1938 loadUrlImpl("data:" + mimeType + ";" + encoding + "," + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 }
1940
1941 /**
1942 * Load the given data into the WebView, use the provided URL as the base
1943 * URL for the content. The base URL is the URL that represents the page
Leon Scroggins1bb1a912010-03-23 15:39:46 -04001944 * that is loaded through this interface. As such, it is used to resolve any
1945 * relative URLs. The historyUrl is used for the history entry.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001946 * <p>
1947 * Note for post 1.0. Due to the change in the WebKit, the access to asset
1948 * files through "file:///android_asset/" for the sub resources is more
1949 * restricted. If you provide null or empty string as baseUrl, you won't be
1950 * able to access asset files. If the baseUrl is anything other than
1951 * http(s)/ftp(s)/about/javascript as scheme, you can access asset files for
1952 * sub resources.
Cary Clarkd6982c92009-05-29 11:02:22 -04001953 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 * @param baseUrl Url to resolve relative paths with, if null defaults to
1955 * "about:blank"
1956 * @param data A String of data in the given encoding.
1957 * @param mimeType The MIMEType of the data. i.e. text/html. If null,
1958 * defaults to "text/html"
1959 * @param encoding The encoding of the data. i.e. utf-8, us-ascii
Leon Scroggins1bb1a912010-03-23 15:39:46 -04001960 * @param historyUrl URL to use as the history entry. Can be null.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 */
1962 public void loadDataWithBaseURL(String baseUrl, String data,
Leon Scroggins1bb1a912010-03-23 15:39:46 -04001963 String mimeType, String encoding, String historyUrl) {
Steve Block51b08912011-04-27 15:04:48 +01001964 checkThread();
Cary Clarkd6982c92009-05-29 11:02:22 -04001965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
Steve Block51b08912011-04-27 15:04:48 +01001967 loadDataImpl(data, mimeType, encoding);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 return;
1969 }
1970 switchOutDrawHistory();
Cary Clarkded054c2009-06-15 10:26:08 -04001971 WebViewCore.BaseUrlData arg = new WebViewCore.BaseUrlData();
1972 arg.mBaseUrl = baseUrl;
1973 arg.mData = data;
1974 arg.mMimeType = mimeType;
1975 arg.mEncoding = encoding;
Leon Scroggins1bb1a912010-03-23 15:39:46 -04001976 arg.mHistoryUrl = historyUrl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04001978 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 }
1980
1981 /**
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07001982 * Saves the current view as a web archive.
1983 *
1984 * @param filename The filename where the archive should be placed.
1985 */
1986 public void saveWebArchive(String filename) {
Steve Block51b08912011-04-27 15:04:48 +01001987 checkThread();
1988 saveWebArchiveImpl(filename, false, null);
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07001989 }
1990
1991 /* package */ static class SaveWebArchiveMessage {
1992 SaveWebArchiveMessage (String basename, boolean autoname, ValueCallback<String> callback) {
1993 mBasename = basename;
1994 mAutoname = autoname;
1995 mCallback = callback;
1996 }
1997
1998 /* package */ final String mBasename;
1999 /* package */ final boolean mAutoname;
2000 /* package */ final ValueCallback<String> mCallback;
2001 /* package */ String mResultFile;
2002 }
2003
2004 /**
2005 * Saves the current view as a web archive.
2006 *
2007 * @param basename The filename where the archive should be placed.
2008 * @param autoname If false, takes basename to be a file. If true, basename
2009 * is assumed to be a directory in which a filename will be
2010 * chosen according to the url of the current page.
2011 * @param callback Called after the web archive has been saved. The
2012 * parameter for onReceiveValue will either be the filename
2013 * under which the file was saved, or null if saving the
2014 * file failed.
2015 */
2016 public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
Steve Block51b08912011-04-27 15:04:48 +01002017 checkThread();
2018 saveWebArchiveImpl(basename, autoname, callback);
2019 }
2020
2021 private void saveWebArchiveImpl(String basename, boolean autoname,
2022 ValueCallback<String> callback) {
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07002023 mWebViewCore.sendMessage(EventHub.SAVE_WEBARCHIVE,
2024 new SaveWebArchiveMessage(basename, autoname, callback));
2025 }
2026
2027 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 * Stop the current load.
2029 */
2030 public void stopLoading() {
Steve Block51b08912011-04-27 15:04:48 +01002031 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 // TODO: should we clear all the messages in the queue before sending
2033 // STOP_LOADING?
2034 switchOutDrawHistory();
2035 mWebViewCore.sendMessage(EventHub.STOP_LOADING);
2036 }
2037
2038 /**
2039 * Reload the current url.
2040 */
2041 public void reload() {
Steve Block51b08912011-04-27 15:04:48 +01002042 checkThread();
Leon Scroggins05919f22010-09-14 17:22:36 -04002043 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 switchOutDrawHistory();
2045 mWebViewCore.sendMessage(EventHub.RELOAD);
2046 }
2047
2048 /**
2049 * Return true if this WebView has a back history item.
2050 * @return True iff this WebView has a back history item.
2051 */
2052 public boolean canGoBack() {
Steve Block51b08912011-04-27 15:04:48 +01002053 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2055 synchronized (l) {
2056 if (l.getClearPending()) {
2057 return false;
2058 } else {
2059 return l.getCurrentIndex() > 0;
2060 }
2061 }
2062 }
2063
2064 /**
2065 * Go back in the history of this WebView.
2066 */
2067 public void goBack() {
Steve Block51b08912011-04-27 15:04:48 +01002068 checkThread();
2069 goBackOrForwardImpl(-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 }
2071
2072 /**
2073 * Return true if this WebView has a forward history item.
2074 * @return True iff this Webview has a forward history item.
2075 */
2076 public boolean canGoForward() {
Steve Block51b08912011-04-27 15:04:48 +01002077 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2079 synchronized (l) {
2080 if (l.getClearPending()) {
2081 return false;
2082 } else {
2083 return l.getCurrentIndex() < l.getSize() - 1;
2084 }
2085 }
2086 }
2087
2088 /**
2089 * Go forward in the history of this WebView.
2090 */
2091 public void goForward() {
Steve Block51b08912011-04-27 15:04:48 +01002092 checkThread();
2093 goBackOrForwardImpl(1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002094 }
2095
2096 /**
2097 * Return true if the page can go back or forward the given
2098 * number of steps.
2099 * @param steps The negative or positive number of steps to move the
2100 * history.
2101 */
2102 public boolean canGoBackOrForward(int steps) {
Steve Block51b08912011-04-27 15:04:48 +01002103 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2105 synchronized (l) {
2106 if (l.getClearPending()) {
2107 return false;
2108 } else {
2109 int newIndex = l.getCurrentIndex() + steps;
2110 return newIndex >= 0 && newIndex < l.getSize();
2111 }
2112 }
2113 }
2114
2115 /**
2116 * Go to the history item that is the number of steps away from
2117 * the current item. Steps is negative if backward and positive
2118 * if forward.
2119 * @param steps The number of steps to take back or forward in the back
2120 * forward list.
2121 */
2122 public void goBackOrForward(int steps) {
Steve Block51b08912011-04-27 15:04:48 +01002123 checkThread();
2124 goBackOrForwardImpl(steps);
2125 }
2126
2127 private void goBackOrForwardImpl(int steps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 goBackOrForward(steps, false);
2129 }
2130
2131 private void goBackOrForward(int steps, boolean ignoreSnapshot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 if (steps != 0) {
Leon Scroggins05919f22010-09-14 17:22:36 -04002133 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002134 mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps,
2135 ignoreSnapshot ? 1 : 0);
2136 }
2137 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002138
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002139 /**
2140 * Returns true if private browsing is enabled in this WebView.
2141 */
Elliott Slaughter7c2d1352010-08-20 15:57:18 -07002142 public boolean isPrivateBrowsingEnabled() {
Steve Block51b08912011-04-27 15:04:48 +01002143 checkThread();
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002144 return getSettings().isPrivateBrowsingEnabled();
2145 }
2146
Elliott Slaughter7c2d1352010-08-20 15:57:18 -07002147 private void startPrivateBrowsing() {
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002148 getSettings().setPrivateBrowsingEnabled(true);
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002149 }
2150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 private boolean extendScroll(int y) {
2152 int finalY = mScroller.getFinalY();
2153 int newY = pinLocY(finalY + y);
2154 if (newY == finalY) return false;
2155 mScroller.setFinalY(newY);
2156 mScroller.extendDuration(computeDuration(0, y));
2157 return true;
2158 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 /**
2161 * Scroll the contents of the view up by half the view size
2162 * @param top true to jump to the top of the page
2163 * @return true if the page was scrolled
2164 */
2165 public boolean pageUp(boolean top) {
Steve Block51b08912011-04-27 15:04:48 +01002166 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 if (mNativeClass == 0) {
2168 return false;
2169 }
Cary Clarke872f3a2009-06-11 09:51:11 -04002170 nativeClearCursor(); // start next trackball movement from page edge
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 if (top) {
2172 // go to the top of the document
2173 return pinScrollTo(mScrollX, 0, true, 0);
2174 }
2175 // Page up
2176 int h = getHeight();
2177 int y;
2178 if (h > 2 * PAGE_SCROLL_OVERLAP) {
2179 y = -h + PAGE_SCROLL_OVERLAP;
2180 } else {
2181 y = -h / 2;
2182 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002183 return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 : extendScroll(y);
2185 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 /**
2188 * Scroll the contents of the view down by half the page size
2189 * @param bottom true to jump to bottom of page
2190 * @return true if the page was scrolled
2191 */
2192 public boolean pageDown(boolean bottom) {
Steve Block51b08912011-04-27 15:04:48 +01002193 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 if (mNativeClass == 0) {
2195 return false;
2196 }
Cary Clarke872f3a2009-06-11 09:51:11 -04002197 nativeClearCursor(); // start next trackball movement from page edge
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198 if (bottom) {
Adam Powell637d3372010-08-25 14:37:03 -07002199 return pinScrollTo(mScrollX, computeRealVerticalScrollRange(), true, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 }
2201 // Page down.
2202 int h = getHeight();
2203 int y;
2204 if (h > 2 * PAGE_SCROLL_OVERLAP) {
2205 y = h - PAGE_SCROLL_OVERLAP;
2206 } else {
2207 y = h / 2;
2208 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002209 return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 : extendScroll(y);
2211 }
2212
2213 /**
2214 * Clear the view so that onDraw() will draw nothing but white background,
2215 * and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY
2216 */
2217 public void clearView() {
Steve Block51b08912011-04-27 15:04:48 +01002218 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 mContentWidth = 0;
2220 mContentHeight = 0;
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07002221 setBaseLayer(0, null, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
2223 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002225 /**
2226 * Return a new picture that captures the current display of the webview.
2227 * This is a copy of the display, and will be unaffected if the webview
2228 * later loads a different URL.
2229 *
2230 * @return a picture containing the current contents of the view. Note this
2231 * picture is of the entire document, and is not restricted to the
2232 * bounds of the view.
2233 */
2234 public Picture capturePicture() {
Steve Block51b08912011-04-27 15:04:48 +01002235 checkThread();
Cary Clark5ffbb812010-10-08 15:38:39 -04002236 if (mNativeClass == 0) return null;
Grace Kloba8abd50b2010-07-08 15:02:14 -07002237 Picture result = new Picture();
2238 nativeCopyBaseContentToPicture(result);
2239 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 }
2241
2242 /**
2243 * Return true if the browser is displaying a TextView for text input.
2244 */
2245 private boolean inEditingMode() {
Leon Scroggins63284ed2010-04-09 14:54:46 -04002246 return mWebTextView != null && mWebTextView.getParent() != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 }
2248
Leon Scroggins6088e832010-02-17 13:17:32 -05002249 /**
2250 * Remove the WebTextView.
Leon Scroggins6088e832010-02-17 13:17:32 -05002251 */
Leon Scroggins2aed7762010-08-13 17:11:42 -04002252 private void clearTextEntry() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002253 if (inEditingMode()) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04002254 mWebTextView.remove();
Leon Scroggins III6f992702010-08-12 14:24:00 -04002255 } else {
2256 // The keyboard may be open with the WebView as the served view
2257 hideSoftKeyboard();
2258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 }
2260
Cary Clarkd6982c92009-05-29 11:02:22 -04002261 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 * Return the current scale of the WebView
2263 * @return The current scale.
2264 */
2265 public float getScale() {
Steve Block51b08912011-04-27 15:04:48 +01002266 checkThread();
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002267 return mZoomManager.getScale();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002268 }
2269
2270 /**
2271 * Set the initial scale for the WebView. 0 means default. If
2272 * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
2273 * way. Otherwise it starts with 100%. If initial scale is greater than 0,
2274 * WebView starts will this value as initial scale.
2275 *
2276 * @param scaleInPercent The initial scale in percent.
2277 */
2278 public void setInitialScale(int scaleInPercent) {
Steve Block51b08912011-04-27 15:04:48 +01002279 checkThread();
Derek Sollenberger341e22f2010-06-02 12:34:34 -04002280 mZoomManager.setInitialScaleInPercent(scaleInPercent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002281 }
2282
2283 /**
2284 * Invoke the graphical zoom picker widget for this WebView. This will
2285 * result in the zoom widget appearing on the screen to control the zoom
2286 * level of this WebView.
2287 */
2288 public void invokeZoomPicker() {
Steve Block51b08912011-04-27 15:04:48 +01002289 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 if (!getSettings().supportZoom()) {
2291 Log.w(LOGTAG, "This WebView doesn't support zoom.");
2292 return;
2293 }
Leon Scroggins05919f22010-09-14 17:22:36 -04002294 clearHelpers();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04002295 mZoomManager.invokeZoomPicker();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002296 }
2297
2298 /**
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04002299 * Return a HitTestResult based on the current cursor node. If a HTML::a tag
Steve Block81f19ff2010-11-01 13:23:24 +00002300 * is found and the anchor has a non-JavaScript url, the HitTestResult type
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002301 * is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
Steve Block81f19ff2010-11-01 13:23:24 +00002302 * 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 -08002303 * be UNKNOWN_TYPE and the url has to be retrieved through
2304 * {@link #requestFocusNodeHref} asynchronously. If a HTML::img tag is
2305 * found, the HitTestResult type is set to IMAGE_TYPE and the url is set in
2306 * the "extra" field. A type of
2307 * SRC_IMAGE_ANCHOR_TYPE indicates an anchor with a url that has an image as
2308 * a child node. If a phone number is found, the HitTestResult type is set
2309 * to PHONE_TYPE and the phone number is set in the "extra" field of
2310 * HitTestResult. If a map address is found, the HitTestResult type is set
2311 * to GEO_TYPE and the address is set in the "extra" field of HitTestResult.
2312 * If an email address is found, the HitTestResult type is set to EMAIL_TYPE
2313 * and the email is set in the "extra" field of HitTestResult. Otherwise,
2314 * HitTestResult type is set to UNKNOWN_TYPE.
2315 */
2316 public HitTestResult getHitTestResult() {
Steve Block51b08912011-04-27 15:04:48 +01002317 checkThread();
Cary Clarkb8491342010-11-29 16:23:19 -05002318 return hitTestResult(mInitialHitTestResult);
2319 }
2320
2321 private HitTestResult hitTestResult(HitTestResult fallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 if (mNativeClass == 0) {
2323 return null;
2324 }
2325
2326 HitTestResult result = new HitTestResult();
Cary Clarkd6982c92009-05-29 11:02:22 -04002327 if (nativeHasCursorNode()) {
2328 if (nativeCursorIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002329 result.setType(HitTestResult.EDIT_TEXT_TYPE);
Cary Clarkd6982c92009-05-29 11:02:22 -04002330 } else {
2331 String text = nativeCursorText();
2332 if (text != null) {
2333 if (text.startsWith(SCHEME_TEL)) {
2334 result.setType(HitTestResult.PHONE_TYPE);
2335 result.setExtra(text.substring(SCHEME_TEL.length()));
2336 } else if (text.startsWith(SCHEME_MAILTO)) {
2337 result.setType(HitTestResult.EMAIL_TYPE);
2338 result.setExtra(text.substring(SCHEME_MAILTO.length()));
2339 } else if (text.startsWith(SCHEME_GEO)) {
2340 result.setType(HitTestResult.GEO_TYPE);
2341 result.setExtra(URLDecoder.decode(text
2342 .substring(SCHEME_GEO.length())));
2343 } else if (nativeCursorIsAnchor()) {
2344 result.setType(HitTestResult.SRC_ANCHOR_TYPE);
2345 result.setExtra(text);
2346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002347 }
2348 }
Cary Clarkb8491342010-11-29 16:23:19 -05002349 } else if (fallback != null) {
2350 /* If webkit causes a rebuild while the long press is in progress,
2351 * the cursor node may be reset, even if it is still around. This
2352 * uses the cursor node saved when the touch began. Since the
2353 * nativeImageURI below only changes the result if it is successful,
2354 * this uses the data beneath the touch if available or the original
2355 * tap data otherwise.
2356 */
2357 Log.v(LOGTAG, "hitTestResult use fallback");
2358 result = fallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002359 }
2360 int type = result.getType();
2361 if (type == HitTestResult.UNKNOWN_TYPE
2362 || type == HitTestResult.SRC_ANCHOR_TYPE) {
2363 // Now check to see if it is an image.
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002364 int contentX = viewToContentX(mLastTouchX + mScrollX);
2365 int contentY = viewToContentY(mLastTouchY + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 String text = nativeImageURI(contentX, contentY);
2367 if (text != null) {
Cary Clarkd6982c92009-05-29 11:02:22 -04002368 result.setType(type == HitTestResult.UNKNOWN_TYPE ?
2369 HitTestResult.IMAGE_TYPE :
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002370 HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
2371 result.setExtra(text);
2372 }
2373 }
2374 return result;
2375 }
2376
Leon Scrogginse26efa32009-12-15 16:38:45 -05002377 // Called by JNI when the DOM has changed the focus. Clear the focus so
2378 // that new keys will go to the newly focused field
2379 private void domChangedFocus() {
2380 if (inEditingMode()) {
2381 mPrivateHandler.obtainMessage(DOM_FOCUS_CHANGED).sendToTarget();
2382 }
2383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 /**
Cary Clark861368a2010-12-15 11:24:37 -05002385 * Request the anchor or image element URL at the last tapped point.
2386 * If hrefMsg is null, this method returns immediately and does not
2387 * dispatch hrefMsg to its target. If the tapped point hits an image,
2388 * an anchor, or an image in an anchor, the message associates
2389 * strings in named keys in its data. The value paired with the key
2390 * may be an empty string.
Cary Clarkd6982c92009-05-29 11:02:22 -04002391 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 * @param hrefMsg This message will be dispatched with the result of the
Cary Clark861368a2010-12-15 11:24:37 -05002393 * request. The message data contains three keys:
2394 * - "url" returns the anchor's href attribute.
2395 * - "title" returns the anchor's text.
2396 * - "src" returns the image's src attribute.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 */
2398 public void requestFocusNodeHref(Message hrefMsg) {
Steve Block51b08912011-04-27 15:04:48 +01002399 checkThread();
Cary Clarke41bb532010-11-30 15:59:59 -05002400 if (hrefMsg == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002401 return;
2402 }
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002403 int contentX = viewToContentX(mLastTouchX + mScrollX);
2404 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clark3ecd7db2011-02-24 14:58:23 -05002405 if (nativeHasCursorNode()) {
2406 Rect cursorBounds = nativeGetCursorRingBounds();
2407 if (!cursorBounds.contains(contentX, contentY)) {
2408 int slop = viewToContentDimension(mNavSlop);
2409 cursorBounds.inset(-slop, -slop);
2410 if (cursorBounds.contains(contentX, contentY)) {
2411 contentX = (int) cursorBounds.centerX();
2412 contentY = (int) cursorBounds.centerY();
2413 }
2414 }
2415 }
Cary Clarke41bb532010-11-30 15:59:59 -05002416 mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
2417 contentX, contentY, hrefMsg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002418 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002420 /**
2421 * Request the url of the image last touched by the user. msg will be sent
2422 * to its target with a String representing the url as its object.
Cary Clarkd6982c92009-05-29 11:02:22 -04002423 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002424 * @param msg This message will be dispatched with the result of the request
2425 * as the data member with "url" as key. The result can be null.
2426 */
2427 public void requestImageRef(Message msg) {
Steve Block51b08912011-04-27 15:04:48 +01002428 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04002429 if (0 == mNativeClass) return; // client isn't initialized
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002430 int contentX = viewToContentX(mLastTouchX + mScrollX);
2431 int contentY = viewToContentY(mLastTouchY + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002432 String ref = nativeImageURI(contentX, contentY);
2433 Bundle data = msg.getData();
2434 data.putString("url", ref);
2435 msg.setData(data);
2436 msg.sendToTarget();
2437 }
2438
Derek Sollenberger87b17be52010-06-01 11:49:31 -04002439 static int pinLoc(int x, int viewMax, int docMax) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002440// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax);
2441 if (docMax < viewMax) { // the doc has room on the sides for "blank"
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002442 // pin the short document to the top/left of the screen
2443 x = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002444// Log.d(LOGTAG, "--- center " + x);
2445 } else if (x < 0) {
2446 x = 0;
2447// Log.d(LOGTAG, "--- zero");
2448 } else if (x + viewMax > docMax) {
2449 x = docMax - viewMax;
2450// Log.d(LOGTAG, "--- pin " + x);
2451 }
2452 return x;
2453 }
2454
2455 // Expects x in view coordinates
Derek Sollenberger03e48912010-05-18 17:03:42 -04002456 int pinLocX(int x) {
Adam Powell637d3372010-08-25 14:37:03 -07002457 if (mInOverScrollMode) return x;
2458 return pinLoc(x, getViewWidth(), computeRealHorizontalScrollRange());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459 }
2460
2461 // Expects y in view coordinates
Derek Sollenberger03e48912010-05-18 17:03:42 -04002462 int pinLocY(int y) {
Adam Powell637d3372010-08-25 14:37:03 -07002463 if (mInOverScrollMode) return y;
Mike Reede5e63f42010-03-19 14:38:23 -04002464 return pinLoc(y, getViewHeightWithTitle(),
Adam Powell637d3372010-08-25 14:37:03 -07002465 computeRealVerticalScrollRange() + getTitleHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002466 }
2467
Leon Scroggins0236e672009-09-02 21:12:08 -04002468 /**
2469 * A title bar which is embedded in this WebView, and scrolls along with it
2470 * vertically, but not horizontally.
2471 */
2472 private View mTitleBar;
2473
2474 /**
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002475 * the title bar rendering gravity
2476 */
2477 private int mTitleGravity;
2478
2479 /**
Leon Scroggins0236e672009-09-02 21:12:08 -04002480 * Add or remove a title bar to be embedded into the WebView, and scroll
2481 * along with it vertically, while remaining in view horizontally. Pass
2482 * null to remove the title bar from the WebView, and return to drawing
2483 * the WebView normally without translating to account for the title bar.
2484 * @hide
2485 */
Leon Scroggins078c52c2009-09-04 16:58:09 -04002486 public void setEmbeddedTitleBar(View v) {
2487 if (mTitleBar == v) return;
2488 if (mTitleBar != null) {
Leon Scroggins0236e672009-09-02 21:12:08 -04002489 removeView(mTitleBar);
Leon Scroggins078c52c2009-09-04 16:58:09 -04002490 }
2491 if (null != v) {
Leon Scroggins0236e672009-09-02 21:12:08 -04002492 addView(v, new AbsoluteLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08002493 ViewGroup.LayoutParams.MATCH_PARENT,
Leon Scroggins078c52c2009-09-04 16:58:09 -04002494 ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0));
Leon Scroggins0236e672009-09-02 21:12:08 -04002495 }
2496 mTitleBar = v;
2497 }
2498
2499 /**
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002500 * Set where to render the embedded title bar
2501 * NO_GRAVITY at the top of the page
2502 * TOP at the top of the screen
2503 * @hide
2504 */
2505 public void setTitleBarGravity(int gravity) {
2506 mTitleGravity = gravity;
Michael Kolb63052ac2011-04-06 16:32:38 -07002507 // force refresh
2508 invalidate();
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002509 }
2510
2511 /**
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002512 * Given a distance in view space, convert it to content space. Note: this
2513 * does not reflect translation, just scaling, so this should not be called
2514 * with coordinates, but should be called for dimensions like width or
2515 * height.
2516 */
2517 private int viewToContentDimension(int d) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002518 return Math.round(d * mZoomManager.getInvScale());
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002519 }
2520
2521 /**
Leon Scroggins0236e672009-09-02 21:12:08 -04002522 * Given an x coordinate in view space, convert it to content space. Also
2523 * may be used for absolute heights (such as for the WebTextView's
2524 * textSize, which is unaffected by the height of the title bar).
2525 */
2526 /*package*/ int viewToContentX(int x) {
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002527 return viewToContentDimension(x);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 }
2529
Leon Scroggins0236e672009-09-02 21:12:08 -04002530 /**
2531 * Given a y coordinate in view space, convert it to content space.
2532 * Takes into account the height of the title bar if there is one
2533 * embedded into the WebView.
2534 */
2535 /*package*/ int viewToContentY(int y) {
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002536 return viewToContentDimension(y - getTitleHeight());
Mike Reede8853fc2009-09-04 14:01:48 -04002537 }
2538
2539 /**
Nicolas Roard46318cf2010-05-10 15:15:51 -07002540 * Given a x coordinate in view space, convert it to content space.
2541 * Returns the result as a float.
2542 */
2543 private float viewToContentXf(int x) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002544 return x * mZoomManager.getInvScale();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002545 }
2546
2547 /**
2548 * Given a y coordinate in view space, convert it to content space.
2549 * Takes into account the height of the title bar if there is one
2550 * embedded into the WebView. Returns the result as a float.
2551 */
2552 private float viewToContentYf(int y) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002553 return (y - getTitleHeight()) * mZoomManager.getInvScale();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002554 }
2555
2556 /**
Mike Reede8853fc2009-09-04 14:01:48 -04002557 * Given a distance in content space, convert it to view space. Note: this
2558 * does not reflect translation, just scaling, so this should not be called
2559 * with coordinates, but should be called for dimensions like width or
2560 * height.
2561 */
2562 /*package*/ int contentToViewDimension(int d) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002563 return Math.round(d * mZoomManager.getScale());
Leon Scroggins0236e672009-09-02 21:12:08 -04002564 }
2565
2566 /**
2567 * Given an x coordinate in content space, convert it to view
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002568 * space.
Leon Scroggins0236e672009-09-02 21:12:08 -04002569 */
2570 /*package*/ int contentToViewX(int x) {
Mike Reede8853fc2009-09-04 14:01:48 -04002571 return contentToViewDimension(x);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 }
2573
Leon Scroggins0236e672009-09-02 21:12:08 -04002574 /**
2575 * Given a y coordinate in content space, convert it to view
2576 * space. Takes into account the height of the title bar.
2577 */
2578 /*package*/ int contentToViewY(int y) {
Mike Reede8853fc2009-09-04 14:01:48 -04002579 return contentToViewDimension(y) + getTitleHeight();
Leon Scroggins0236e672009-09-02 21:12:08 -04002580 }
2581
Mike Reede9e86b82009-09-15 11:26:53 -04002582 private Rect contentToViewRect(Rect x) {
2583 return new Rect(contentToViewX(x.left), contentToViewY(x.top),
2584 contentToViewX(x.right), contentToViewY(x.bottom));
2585 }
2586
2587 /* To invalidate a rectangle in content coordinates, we need to transform
2588 the rect into view coordinates, so we can then call invalidate(...).
2589
2590 Normally, we would just call contentToView[XY](...), which eventually
2591 calls Math.round(coordinate * mActualScale). However, for invalidates,
2592 we need to account for the slop that occurs with antialiasing. To
2593 address that, we are a little more liberal in the size of the rect that
2594 we invalidate.
2595
2596 This liberal calculation calls floor() for the top/left, and ceil() for
2597 the bottom/right coordinates. This catches the possible extra pixels of
2598 antialiasing that we might have missed with just round().
2599 */
2600
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002601 // Called by JNI to invalidate the View, given rectangle coordinates in
2602 // content space
2603 private void viewInvalidate(int l, int t, int r, int b) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002604 final float scale = mZoomManager.getScale();
Mike Reede9e86b82009-09-15 11:26:53 -04002605 final int dy = getTitleHeight();
2606 invalidate((int)Math.floor(l * scale),
2607 (int)Math.floor(t * scale) + dy,
2608 (int)Math.ceil(r * scale),
2609 (int)Math.ceil(b * scale) + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 }
2611
2612 // Called by JNI to invalidate the View after a delay, given rectangle
2613 // coordinates in content space
2614 private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002615 final float scale = mZoomManager.getScale();
Mike Reede9e86b82009-09-15 11:26:53 -04002616 final int dy = getTitleHeight();
2617 postInvalidateDelayed(delay,
2618 (int)Math.floor(l * scale),
2619 (int)Math.floor(t * scale) + dy,
2620 (int)Math.ceil(r * scale),
2621 (int)Math.ceil(b * scale) + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002622 }
2623
Mike Reede9e86b82009-09-15 11:26:53 -04002624 private void invalidateContentRect(Rect r) {
2625 viewInvalidate(r.left, r.top, r.right, r.bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002626 }
2627
Cary Clark278ce052009-08-31 16:08:42 -04002628 // stop the scroll animation, and don't let a subsequent fling add
2629 // to the existing velocity
2630 private void abortAnimation() {
2631 mScroller.abortAnimation();
2632 mLastVelocity = 0;
2633 }
2634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 /* call from webcoreview.draw(), so we're still executing in the UI thread
2636 */
2637 private void recordNewContentSize(int w, int h, boolean updateLayout) {
2638
2639 // premature data from webkit, ignore
2640 if ((w | h) == 0) {
2641 return;
2642 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 // don't abort a scroll animation if we didn't change anything
2645 if (mContentWidth != w || mContentHeight != h) {
2646 // record new dimensions
2647 mContentWidth = w;
2648 mContentHeight = h;
2649 // If history Picture is drawn, don't update scroll. They will be
2650 // updated when we get out of that mode.
2651 if (!mDrawHistory) {
2652 // repin our scroll, taking into account the new content size
Derek Sollenberger03e48912010-05-18 17:03:42 -04002653 updateScrollCoordinates(pinLocX(mScrollX), pinLocY(mScrollY));
Leon Scrogginsd84e7d52009-09-29 11:11:45 -04002654 if (!mScroller.isFinished()) {
2655 // We are in the middle of a scroll. Repin the final scroll
2656 // position.
2657 mScroller.setFinalX(pinLocX(mScroller.getFinalX()));
2658 mScroller.setFinalY(pinLocY(mScroller.getFinalY()));
2659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 }
2661 }
2662 contentSizeChanged(updateLayout);
2663 }
2664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002665 // Used to avoid sending many visible rect messages.
2666 private Rect mLastVisibleRectSent;
2667 private Rect mLastGlobalRect;
2668
Derek Sollenberger03e48912010-05-18 17:03:42 -04002669 Rect sendOurVisibleRect() {
Derek Sollenberger293c3602010-06-04 10:44:48 -04002670 if (mZoomManager.isPreventingWebkitUpdates()) return mLastVisibleRectSent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 Rect rect = new Rect();
2672 calcOurContentVisibleRect(rect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 // Rect.equals() checks for null input.
2674 if (!rect.equals(mLastVisibleRectSent)) {
Cary Clarked56eda2009-06-18 09:48:47 -04002675 Point pos = new Point(rect.left, rect.top);
John Reck636ce002011-01-30 16:23:09 -08002676 mWebViewCore.removeMessages(EventHub.SET_SCROLL_OFFSET);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002677 mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
Patrick Scottfa8be1c2011-02-02 14:09:34 -05002678 nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, pos);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679 mLastVisibleRectSent = rect;
Cary Clark32820242010-12-03 10:27:20 -05002680 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002681 }
2682 Rect globalRect = new Rect();
2683 if (getGlobalVisibleRect(globalRect)
2684 && !globalRect.equals(mLastGlobalRect)) {
Cary Clark3524be92009-06-22 13:09:11 -04002685 if (DebugFlags.WEB_VIEW) {
2686 Log.v(LOGTAG, "sendOurVisibleRect=(" + globalRect.left + ","
2687 + globalRect.top + ",r=" + globalRect.right + ",b="
2688 + globalRect.bottom);
2689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002690 // TODO: the global offset is only used by windowRect()
2691 // in ChromeClientAndroid ; other clients such as touch
2692 // and mouse events could return view + screen relative points.
2693 mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, globalRect);
2694 mLastGlobalRect = globalRect;
2695 }
2696 return rect;
2697 }
2698
2699 // Sets r to be the visible rectangle of our webview in view coordinates
2700 private void calcOurVisibleRect(Rect r) {
2701 Point p = new Point();
2702 getGlobalVisibleRect(r, p);
2703 r.offset(-p.x, -p.y);
2704 }
2705
2706 // Sets r to be our visible rectangle in content coordinates
2707 private void calcOurContentVisibleRect(Rect r) {
2708 calcOurVisibleRect(r);
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002709 r.left = viewToContentX(r.left);
Leon Scroggins37df6a82009-09-23 10:31:23 -04002710 // viewToContentY will remove the total height of the title bar. Add
2711 // the visible height back in to account for the fact that if the title
2712 // bar is partially visible, the part of the visible rect which is
2713 // displaying our content is displaced by that amount.
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002714 r.top = viewToContentY(r.top + getVisibleTitleHeight());
2715 r.right = viewToContentX(r.right);
2716 r.bottom = viewToContentY(r.bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 }
2718
Nicolas Roard46318cf2010-05-10 15:15:51 -07002719 // Sets r to be our visible rectangle in content coordinates. We use this
2720 // method on the native side to compute the position of the fixed layers.
2721 // Uses floating coordinates (necessary to correctly place elements when
2722 // the scale factor is not 1)
2723 private void calcOurContentVisibleRectF(RectF r) {
2724 Rect ri = new Rect(0,0,0,0);
2725 calcOurVisibleRect(ri);
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002726 r.left = viewToContentXf(ri.left);
Nicolas Roard46318cf2010-05-10 15:15:51 -07002727 // viewToContentY will remove the total height of the title bar. Add
2728 // the visible height back in to account for the fact that if the title
2729 // bar is partially visible, the part of the visible rect which is
2730 // displaying our content is displaced by that amount.
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002731 r.top = viewToContentYf(ri.top + getVisibleTitleHeight());
2732 r.right = viewToContentXf(ri.right);
2733 r.bottom = viewToContentYf(ri.bottom);
Nicolas Roard46318cf2010-05-10 15:15:51 -07002734 }
2735
Grace Klobaef347ef2009-07-30 11:20:32 -07002736 static class ViewSizeData {
2737 int mWidth;
2738 int mHeight;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08002739 float mHeightWidthRatio;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08002740 int mActualViewHeight;
Grace Klobaef347ef2009-07-30 11:20:32 -07002741 int mTextWrapWidth;
Grace Kloba3a0def22010-01-23 21:11:54 -08002742 int mAnchorX;
2743 int mAnchorY;
Grace Klobaef347ef2009-07-30 11:20:32 -07002744 float mScale;
Cary Clark6d45acc2009-08-27 15:42:57 -04002745 boolean mIgnoreHeight;
Grace Klobaef347ef2009-07-30 11:20:32 -07002746 }
2747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 /**
2749 * Compute unzoomed width and height, and if they differ from the last
Derek Sollenberger03e48912010-05-18 17:03:42 -04002750 * values we sent, send them to webkit (to be used as new viewport)
2751 *
2752 * @param force ensures that the message is sent to webkit even if the width
2753 * or height has not changed since the last message
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002754 *
2755 * @return true if new values were sent
2756 */
Derek Sollenberger03e48912010-05-18 17:03:42 -04002757 boolean sendViewSizeZoom(boolean force) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04002758 if (mZoomManager.isPreventingWebkitUpdates()) return false;
Grace Kloba3a0def22010-01-23 21:11:54 -08002759
Grace Klobaef347ef2009-07-30 11:20:32 -07002760 int viewWidth = getViewWidth();
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002761 int newWidth = Math.round(viewWidth * mZoomManager.getInvScale());
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08002762 // This height could be fixed and be different from actual visible height.
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08002763 int viewHeight = getViewHeightWithTitle() - getTitleHeight();
2764 int newHeight = Math.round(viewHeight * mZoomManager.getInvScale());
2765 // Make the ratio more accurate than (newHeight / newWidth), since the
2766 // latter both are calculated and rounded.
2767 float heightWidthRatio = (float) viewHeight / viewWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002768 /*
2769 * Because the native side may have already done a layout before the
2770 * View system was able to measure us, we have to send a height of 0 to
2771 * remove excess whitespace when we grow our width. This will trigger a
2772 * layout and a change in content size. This content size change will
2773 * mean that contentSizeChanged will either call this method directly or
2774 * indirectly from onSizeChanged.
2775 */
2776 if (newWidth > mLastWidthSent && mWrapContent) {
2777 newHeight = 0;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08002778 heightWidthRatio = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779 }
Shimeng (Simon) Wang6a0b5ca2011-02-08 09:49:35 -08002780 // Actual visible content height.
2781 int actualViewHeight = Math.round(getViewHeight() * mZoomManager.getInvScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 // Avoid sending another message if the dimensions have not changed.
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08002783 if (newWidth != mLastWidthSent || newHeight != mLastHeightSent || force ||
2784 actualViewHeight != mLastActualHeightSent) {
Grace Klobaef347ef2009-07-30 11:20:32 -07002785 ViewSizeData data = new ViewSizeData();
2786 data.mWidth = newWidth;
2787 data.mHeight = newHeight;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08002788 data.mHeightWidthRatio = heightWidthRatio;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08002789 data.mActualViewHeight = actualViewHeight;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002790 data.mTextWrapWidth = Math.round(viewWidth / mZoomManager.getTextWrapScale());
2791 data.mScale = mZoomManager.getScale();
Derek Sollenberger293c3602010-06-04 10:44:48 -04002792 data.mIgnoreHeight = mZoomManager.isFixedLengthAnimationInProgress()
2793 && !mHeightCanMeasure;
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04002794 data.mAnchorX = mZoomManager.getDocumentAnchorX();
2795 data.mAnchorY = mZoomManager.getDocumentAnchorY();
Grace Klobaef347ef2009-07-30 11:20:32 -07002796 mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002797 mLastWidthSent = newWidth;
2798 mLastHeightSent = newHeight;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08002799 mLastActualHeightSent = actualViewHeight;
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04002800 mZoomManager.clearDocumentAnchor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002801 return true;
2802 }
2803 return false;
2804 }
2805
Adam Powell637d3372010-08-25 14:37:03 -07002806 private int computeRealHorizontalScrollRange() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002807 if (mDrawHistory) {
2808 return mHistoryWidth;
2809 } else {
Grace Klobae621d6f2009-09-11 13:20:39 -07002810 // to avoid rounding error caused unnecessary scrollbar, use floor
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002811 return (int) Math.floor(mContentWidth * mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002812 }
2813 }
2814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002815 @Override
Adam Powell637d3372010-08-25 14:37:03 -07002816 protected int computeHorizontalScrollRange() {
2817 int range = computeRealHorizontalScrollRange();
2818
2819 // Adjust reported range if overscrolled to compress the scroll bars
2820 final int scrollX = mScrollX;
2821 final int overscrollRight = computeMaxScrollX();
2822 if (scrollX < 0) {
2823 range -= scrollX;
2824 } else if (scrollX > overscrollRight) {
2825 range += scrollX - overscrollRight;
2826 }
2827
2828 return range;
2829 }
2830
2831 @Override
2832 protected int computeHorizontalScrollOffset() {
2833 return Math.max(mScrollX, 0);
2834 }
2835
2836 private int computeRealVerticalScrollRange() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002837 if (mDrawHistory) {
2838 return mHistoryHeight;
2839 } else {
Grace Klobae621d6f2009-09-11 13:20:39 -07002840 // to avoid rounding error caused unnecessary scrollbar, use floor
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002841 return (int) Math.floor(mContentHeight * mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002842 }
2843 }
2844
Leon Scroggins0236e672009-09-02 21:12:08 -04002845 @Override
Adam Powell637d3372010-08-25 14:37:03 -07002846 protected int computeVerticalScrollRange() {
2847 int range = computeRealVerticalScrollRange();
2848
2849 // Adjust reported range if overscrolled to compress the scroll bars
2850 final int scrollY = mScrollY;
2851 final int overscrollBottom = computeMaxScrollY();
2852 if (scrollY < 0) {
2853 range -= scrollY;
2854 } else if (scrollY > overscrollBottom) {
2855 range += scrollY - overscrollBottom;
2856 }
2857
2858 return range;
2859 }
2860
2861 @Override
Leon Scroggins0236e672009-09-02 21:12:08 -04002862 protected int computeVerticalScrollOffset() {
Mike Reede8853fc2009-09-04 14:01:48 -04002863 return Math.max(mScrollY - getTitleHeight(), 0);
Leon Scroggins0236e672009-09-02 21:12:08 -04002864 }
2865
2866 @Override
2867 protected int computeVerticalScrollExtent() {
2868 return getViewHeight();
2869 }
2870
Mike Reede8853fc2009-09-04 14:01:48 -04002871 /** @hide */
2872 @Override
2873 protected void onDrawVerticalScrollBar(Canvas canvas,
2874 Drawable scrollBar,
2875 int l, int t, int r, int b) {
Adam Powell637d3372010-08-25 14:37:03 -07002876 if (mScrollY < 0) {
2877 t -= mScrollY;
2878 }
Mike Reede8853fc2009-09-04 14:01:48 -04002879 scrollBar.setBounds(l, t + getVisibleTitleHeight(), r, b);
2880 scrollBar.draw(canvas);
2881 }
2882
Adam Powell637d3372010-08-25 14:37:03 -07002883 @Override
2884 protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
2885 boolean clampedY) {
Patrick Scott62310912010-12-06 17:44:50 -05002886 // Special-case layer scrolling so that we do not trigger normal scroll
2887 // updating.
2888 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
2889 nativeScrollLayer(mScrollingLayer, scrollX, scrollY);
2890 mScrollingLayerRect.left = scrollX;
2891 mScrollingLayerRect.top = scrollY;
2892 invalidate();
2893 return;
2894 }
Adam Powell637d3372010-08-25 14:37:03 -07002895 mInOverScrollMode = false;
2896 int maxX = computeMaxScrollX();
2897 int maxY = computeMaxScrollY();
2898 if (maxX == 0) {
2899 // do not over scroll x if the page just fits the screen
2900 scrollX = pinLocX(scrollX);
2901 } else if (scrollX < 0 || scrollX > maxX) {
2902 mInOverScrollMode = true;
2903 }
2904 if (scrollY < 0 || scrollY > maxY) {
2905 mInOverScrollMode = true;
2906 }
2907
2908 int oldX = mScrollX;
2909 int oldY = mScrollY;
2910
2911 super.scrollTo(scrollX, scrollY);
2912
2913 if (mOverScrollGlow != null) {
2914 mOverScrollGlow.pullGlow(mScrollX, mScrollY, oldX, oldY, maxX, maxY);
2915 }
2916 }
2917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002918 /**
2919 * Get the url for the current page. This is not always the same as the url
2920 * passed to WebViewClient.onPageStarted because although the load for
2921 * that url has begun, the current page may not have changed.
2922 * @return The url for the current page.
2923 */
2924 public String getUrl() {
Steve Block51b08912011-04-27 15:04:48 +01002925 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
2927 return h != null ? h.getUrl() : null;
2928 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04002931 * Get the original url for the current page. This is not always the same
2932 * as the url passed to WebViewClient.onPageStarted because although the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002933 * load for that url has begun, the current page may not have changed.
2934 * Also, there may have been redirects resulting in a different url to that
2935 * originally requested.
2936 * @return The url that was originally requested for the current page.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002937 */
2938 public String getOriginalUrl() {
Steve Block51b08912011-04-27 15:04:48 +01002939 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002940 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
2941 return h != null ? h.getOriginalUrl() : null;
2942 }
2943
2944 /**
2945 * Get the title for the current page. This is the title of the current page
2946 * until WebViewClient.onReceivedTitle is called.
2947 * @return The title for the current page.
2948 */
2949 public String getTitle() {
Steve Block51b08912011-04-27 15:04:48 +01002950 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002951 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
2952 return h != null ? h.getTitle() : null;
2953 }
2954
2955 /**
2956 * Get the favicon for the current page. This is the favicon of the current
2957 * page until WebViewClient.onReceivedIcon is called.
2958 * @return The favicon for the current page.
2959 */
2960 public Bitmap getFavicon() {
Steve Block51b08912011-04-27 15:04:48 +01002961 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
2963 return h != null ? h.getFavicon() : null;
2964 }
2965
2966 /**
Ben Murdoch372dfc82010-07-01 15:56:01 +01002967 * Get the touch icon url for the apple-touch-icon <link> element, or
2968 * a URL on this site's server pointing to the standard location of a
2969 * touch icon.
Patrick Scott2ba12622009-08-04 13:20:05 -04002970 * @hide
2971 */
2972 public String getTouchIconUrl() {
2973 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
2974 return h != null ? h.getTouchIconUrl() : null;
2975 }
2976
2977 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 * Get the progress for the current page.
2979 * @return The progress for the current page between 0 and 100.
2980 */
2981 public int getProgress() {
Steve Block51b08912011-04-27 15:04:48 +01002982 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 return mCallbackProxy.getProgress();
2984 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 /**
2987 * @return the height of the HTML content.
2988 */
2989 public int getContentHeight() {
Steve Block51b08912011-04-27 15:04:48 +01002990 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002991 return mContentHeight;
2992 }
2993
2994 /**
Leon Scrogginsea96d1e2009-09-23 13:41:01 -04002995 * @return the width of the HTML content.
2996 * @hide
2997 */
2998 public int getContentWidth() {
2999 return mContentWidth;
3000 }
3001
3002 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003003 * Pause all layout, parsing, and JavaScript timers for all webviews. This
Mike Reedd205d5b2009-05-27 11:02:29 -04003004 * is a global requests, not restricted to just this webview. This can be
3005 * useful if the application has been paused.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003006 */
3007 public void pauseTimers() {
Steve Block51b08912011-04-27 15:04:48 +01003008 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003009 mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
3010 }
3011
3012 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003013 * Resume all layout, parsing, and JavaScript timers for all webviews.
Mike Reedd205d5b2009-05-27 11:02:29 -04003014 * This will resume dispatching all timers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003015 */
3016 public void resumeTimers() {
Steve Block51b08912011-04-27 15:04:48 +01003017 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018 mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
3019 }
3020
3021 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003022 * Call this to pause any extra processing associated with this WebView and
3023 * its associated DOM, plugins, JavaScript etc. For example, if the WebView
3024 * is taken offscreen, this could be called to reduce unnecessary CPU or
3025 * network traffic. When the WebView is again "active", call onResume().
Mike Reedd205d5b2009-05-27 11:02:29 -04003026 *
Steve Block81f19ff2010-11-01 13:23:24 +00003027 * Note that this differs from pauseTimers(), which affects all WebViews.
Mike Reedd205d5b2009-05-27 11:02:29 -04003028 */
3029 public void onPause() {
Steve Block51b08912011-04-27 15:04:48 +01003030 checkThread();
Mike Reedd205d5b2009-05-27 11:02:29 -04003031 if (!mIsPaused) {
3032 mIsPaused = true;
3033 mWebViewCore.sendMessage(EventHub.ON_PAUSE);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08003034 // We want to pause the current playing video when switching out
3035 // from the current WebView/tab.
3036 if (mHTML5VideoViewProxy != null) {
3037 mHTML5VideoViewProxy.pauseAndDispatch();
3038 }
Mike Reedd205d5b2009-05-27 11:02:29 -04003039 }
3040 }
3041
3042 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003043 * Call this to resume a WebView after a previous call to onPause().
Mike Reedd205d5b2009-05-27 11:02:29 -04003044 */
3045 public void onResume() {
Steve Block51b08912011-04-27 15:04:48 +01003046 checkThread();
Mike Reedd205d5b2009-05-27 11:02:29 -04003047 if (mIsPaused) {
3048 mIsPaused = false;
3049 mWebViewCore.sendMessage(EventHub.ON_RESUME);
3050 }
3051 }
3052
3053 /**
3054 * Returns true if the view is paused, meaning onPause() was called. Calling
3055 * onResume() sets the paused state back to false.
3056 * @hide
3057 */
3058 public boolean isPaused() {
3059 return mIsPaused;
3060 }
3061
3062 /**
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003063 * Call this to inform the view that memory is low so that it can
3064 * free any available memory.
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003065 */
3066 public void freeMemory() {
Steve Block51b08912011-04-27 15:04:48 +01003067 checkThread();
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003068 mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
3069 }
3070
3071 /**
Mike Hearnadcd2ed2009-01-21 16:44:36 +01003072 * Clear the resource cache. Note that the cache is per-application, so
3073 * this will clear the cache for all WebViews used.
3074 *
3075 * @param includeDiskFiles If false, only the RAM cache is cleared.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 */
3077 public void clearCache(boolean includeDiskFiles) {
Steve Block51b08912011-04-27 15:04:48 +01003078 checkThread();
Mike Hearnadcd2ed2009-01-21 16:44:36 +01003079 // Note: this really needs to be a static method as it clears cache for all
3080 // WebView. But we need mWebViewCore to send message to WebCore thread, so
3081 // we can't make this static.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003082 mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
3083 includeDiskFiles ? 1 : 0, 0);
3084 }
3085
3086 /**
3087 * Make sure that clearing the form data removes the adapter from the
3088 * currently focused textfield if there is one.
3089 */
3090 public void clearFormData() {
Steve Block51b08912011-04-27 15:04:48 +01003091 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 if (inEditingMode()) {
3093 AutoCompleteAdapter adapter = null;
Leon Scrogginsd3465f62009-06-02 10:57:54 -04003094 mWebTextView.setAdapterCustom(adapter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 }
3096 }
3097
3098 /**
3099 * Tell the WebView to clear its internal back/forward list.
3100 */
3101 public void clearHistory() {
Steve Block51b08912011-04-27 15:04:48 +01003102 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 mCallbackProxy.getBackForwardList().setClearPending();
3104 mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
3105 }
3106
3107 /**
3108 * Clear the SSL preferences table stored in response to proceeding with SSL
3109 * certificate errors.
3110 */
3111 public void clearSslPreferences() {
Steve Block51b08912011-04-27 15:04:48 +01003112 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113 mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
3114 }
3115
3116 /**
3117 * Return the WebBackForwardList for this WebView. This contains the
3118 * back/forward list for use in querying each item in the history stack.
3119 * This is a copy of the private WebBackForwardList so it contains only a
3120 * snapshot of the current state. Multiple calls to this method may return
3121 * different objects. The object returned from this method will not be
3122 * updated to reflect any new state.
3123 */
3124 public WebBackForwardList copyBackForwardList() {
Steve Block51b08912011-04-27 15:04:48 +01003125 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 return mCallbackProxy.getBackForwardList().clone();
3127 }
3128
3129 /*
3130 * Highlight and scroll to the next occurance of String in findAll.
Cary Clarkd6982c92009-05-29 11:02:22 -04003131 * Wraps the page infinitely, and scrolls. Must be called after
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003132 * calling findAll.
3133 *
3134 * @param forward Direction to search.
3135 */
3136 public void findNext(boolean forward) {
Steve Block51b08912011-04-27 15:04:48 +01003137 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04003138 if (0 == mNativeClass) return; // client isn't initialized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003139 nativeFindNext(forward);
3140 }
3141
3142 /*
3143 * Find all instances of find on the page and highlight them.
3144 * @param find String to find.
3145 * @return int The number of occurances of the String "find"
3146 * that were found.
3147 */
3148 public int findAll(String find) {
Steve Block51b08912011-04-27 15:04:48 +01003149 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04003150 if (0 == mNativeClass) return 0; // client isn't initialized
Cary Clarkde023c12010-03-03 10:05:16 -05003151 int result = find != null ? nativeFindAll(find.toLowerCase(),
Leon Scroggins4f4a5672010-10-19 13:58:11 -04003152 find.toUpperCase(), find.equalsIgnoreCase(mLastFind)) : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 invalidate();
Leon Scroggins5de63892009-10-29 09:48:43 -04003154 mLastFind = find;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003155 return result;
3156 }
3157
Cary Clark3403eb32010-03-03 10:05:16 -05003158 /**
Leon Scroggins93553d72011-03-08 11:43:40 -05003159 * Start an ActionMode for finding text in this WebView. Only works if this
3160 * WebView is attached to the view system.
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003161 * @param text If non-null, will be the initial text to search for.
3162 * Otherwise, the last String searched for in this WebView will
3163 * be used to start.
Leon Scroggins571354f2011-01-04 10:12:41 -05003164 * @param showIme If true, show the IME, assuming the user will begin typing.
3165 * If false and text is non-null, perform a find all.
3166 * @return boolean True if the find dialog is shown, false otherwise.
Cary Clarkde023c12010-03-03 10:05:16 -05003167 */
Leon Scroggins571354f2011-01-04 10:12:41 -05003168 public boolean showFindDialog(String text, boolean showIme) {
Steve Block51b08912011-04-27 15:04:48 +01003169 checkThread();
Leon Scroggins19abf2d2011-01-10 14:50:04 -05003170 FindActionModeCallback callback = new FindActionModeCallback(mContext);
Leon Scroggins93553d72011-03-08 11:43:40 -05003171 if (getParent() == null || startActionMode(callback) == null) {
Leon Scroggins571354f2011-01-04 10:12:41 -05003172 // Could not start the action mode, so end Find on page
Leon Scroggins571354f2011-01-04 10:12:41 -05003173 return false;
3174 }
Leon Scroggins19abf2d2011-01-10 14:50:04 -05003175 mFindCallback = callback;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003176 setFindIsUp(true);
3177 mFindCallback.setWebView(this);
Leon Scroggins571354f2011-01-04 10:12:41 -05003178 if (showIme) {
3179 mFindCallback.showSoftInput();
3180 } else if (text != null) {
3181 mFindCallback.setText(text);
3182 mFindCallback.findAll();
3183 return true;
3184 }
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003185 if (text == null) {
3186 text = mLastFind;
3187 }
3188 if (text != null) {
3189 mFindCallback.setText(text);
3190 }
Leon Scroggins571354f2011-01-04 10:12:41 -05003191 return true;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003192 }
3193
3194 /**
3195 * Keep track of the find callback so that we can remove its titlebar if
3196 * necessary.
3197 */
3198 private FindActionModeCallback mFindCallback;
3199
3200 /**
3201 * Toggle whether the find dialog is showing, for both native and Java.
3202 */
3203 private void setFindIsUp(boolean isUp) {
Cary Clarkde023c12010-03-03 10:05:16 -05003204 mFindIsUp = isUp;
Cary Clarkde023c12010-03-03 10:05:16 -05003205 if (0 == mNativeClass) return; // client isn't initialized
3206 nativeSetFindIsUp(isUp);
3207 }
3208
Leon Scroggins III26723fc2010-04-19 13:21:42 -04003209 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003210 * Return the index of the currently highlighted match.
Leon Scroggins III26723fc2010-04-19 13:21:42 -04003211 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003212 int findIndex() {
Leon Scroggins6a367f52010-05-06 17:37:40 -04003213 if (0 == mNativeClass) return -1;
3214 return nativeFindIndex();
3215 }
3216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 // Used to know whether the find dialog is open. Affects whether
3218 // or not we draw the highlights for matches.
3219 private boolean mFindIsUp;
Cary Clarkde023c12010-03-03 10:05:16 -05003220
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003221 // Keep track of the last string sent, so we can search again when find is
3222 // reopened.
Leon Scroggins5de63892009-10-29 09:48:43 -04003223 private String mLastFind;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04003226 * Return the first substring consisting of the address of a physical
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 * location. Currently, only addresses in the United States are detected,
3228 * and consist of:
3229 * - a house number
3230 * - a street name
3231 * - a street type (Road, Circle, etc), either spelled out or abbreviated
3232 * - a city name
3233 * - a state or territory, either spelled out or two-letter abbr.
3234 * - an optional 5 digit or 9 digit zip code.
3235 *
3236 * All names must be correctly capitalized, and the zip code, if present,
3237 * must be valid for the state. The street type must be a standard USPS
3238 * spelling or abbreviation. The state or territory must also be spelled
Cary Clarkd6982c92009-05-29 11:02:22 -04003239 * or abbreviated using USPS standards. The house number may not exceed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 * five digits.
3241 * @param addr The string to search for addresses.
3242 *
3243 * @return the address, or if no address is found, return null.
3244 */
3245 public static String findAddress(String addr) {
Steve Block51b08912011-04-27 15:04:48 +01003246 checkThread();
Cary Clark3e399de2009-06-17 10:00:57 -04003247 return findAddress(addr, false);
3248 }
3249
3250 /**
3251 * @hide
3252 * Return the first substring consisting of the address of a physical
3253 * location. Currently, only addresses in the United States are detected,
3254 * and consist of:
3255 * - a house number
3256 * - a street name
3257 * - a street type (Road, Circle, etc), either spelled out or abbreviated
3258 * - a city name
3259 * - a state or territory, either spelled out or two-letter abbr.
3260 * - an optional 5 digit or 9 digit zip code.
3261 *
3262 * Names are optionally capitalized, and the zip code, if present,
3263 * must be valid for the state. The street type must be a standard USPS
3264 * spelling or abbreviation. The state or territory must also be spelled
3265 * or abbreviated using USPS standards. The house number may not exceed
3266 * five digits.
3267 * @param addr The string to search for addresses.
3268 * @param caseInsensitive addr Set to true to make search ignore case.
3269 *
3270 * @return the address, or if no address is found, return null.
3271 */
3272 public static String findAddress(String addr, boolean caseInsensitive) {
3273 return WebViewCore.nativeFindAddress(addr, caseInsensitive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 }
3275
3276 /*
3277 * Clear the highlighting surrounding text matches created by findAll.
3278 */
3279 public void clearMatches() {
Steve Block51b08912011-04-27 15:04:48 +01003280 checkThread();
Cary Clark32847a92009-11-17 16:04:18 -05003281 if (mNativeClass == 0)
3282 return;
Cary Clarkde023c12010-03-03 10:05:16 -05003283 nativeSetFindIsEmpty();
3284 invalidate();
3285 }
3286
3287 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003288 * Called when the find ActionMode ends.
Cary Clarkde023c12010-03-03 10:05:16 -05003289 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003290 void notifyFindDialogDismissed() {
3291 mFindCallback = null;
Shimeng (Simon) Wang4d8ef422010-03-22 17:06:17 -07003292 if (mWebViewCore == null) {
3293 return;
3294 }
Cary Clarkde023c12010-03-03 10:05:16 -05003295 clearMatches();
3296 setFindIsUp(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 // Now that the dialog has been removed, ensure that we scroll to a
3298 // location that is not beyond the end of the page.
3299 pinScrollTo(mScrollX, mScrollY, false, 0);
3300 invalidate();
3301 }
3302
3303 /**
3304 * Query the document to see if it contains any image references. The
3305 * message object will be dispatched with arg1 being set to 1 if images
3306 * were found and 0 if the document does not reference any images.
3307 * @param response The message that will be dispatched with the result.
3308 */
3309 public void documentHasImages(Message response) {
Steve Block51b08912011-04-27 15:04:48 +01003310 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003311 if (response == null) {
3312 return;
3313 }
3314 mWebViewCore.sendMessage(EventHub.DOC_HAS_IMAGES, response);
3315 }
3316
Michael Kolb73980a92010-08-05 16:32:51 -07003317 /**
3318 * Request the scroller to abort any ongoing animation
3319 *
3320 * @hide
3321 */
3322 public void stopScroll() {
3323 mScroller.forceFinished(true);
3324 mLastVelocity = 0;
3325 }
3326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 @Override
3328 public void computeScroll() {
3329 if (mScroller.computeScrollOffset()) {
3330 int oldX = mScrollX;
3331 int oldY = mScrollY;
Adam Powell637d3372010-08-25 14:37:03 -07003332 int x = mScroller.getCurrX();
3333 int y = mScroller.getCurrY();
3334 invalidate(); // So we draw again
3335
3336 if (!mScroller.isFinished()) {
Patrick Scott62310912010-12-06 17:44:50 -05003337 int rangeX = computeMaxScrollX();
3338 int rangeY = computeMaxScrollY();
3339 int overflingDistance = mOverflingDistance;
3340
3341 // Use the layer's scroll data if needed.
3342 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
3343 oldX = mScrollingLayerRect.left;
3344 oldY = mScrollingLayerRect.top;
3345 rangeX = mScrollingLayerRect.right;
3346 rangeY = mScrollingLayerRect.bottom;
3347 // No overscrolling for layers.
3348 overflingDistance = 0;
3349 }
3350
Adam Powell637d3372010-08-25 14:37:03 -07003351 overScrollBy(x - oldX, y - oldY, oldX, oldY,
3352 rangeX, rangeY,
Patrick Scott62310912010-12-06 17:44:50 -05003353 overflingDistance, overflingDistance, false);
Adam Powell637d3372010-08-25 14:37:03 -07003354
3355 if (mOverScrollGlow != null) {
3356 mOverScrollGlow.absorbGlow(x, y, oldX, oldY, rangeX, rangeY);
3357 }
3358 } else {
Patrick Scott62310912010-12-06 17:44:50 -05003359 if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
3360 mScrollX = x;
3361 mScrollY = y;
3362 } else {
3363 // Update the layer position instead of WebView.
3364 nativeScrollLayer(mScrollingLayer, x, y);
3365 mScrollingLayerRect.left = x;
3366 mScrollingLayerRect.top = y;
3367 }
Adam Powell4c3ce842010-11-23 17:39:56 -08003368 abortAnimation();
3369 mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
3370 WebViewCore.resumePriority();
Cary Clark0df02692010-11-24 11:01:37 -05003371 if (!mSelectingText) {
3372 WebViewCore.resumeUpdatePicture(mWebViewCore);
3373 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05003374 if (oldX != mScrollX || oldY != mScrollY) {
3375 sendOurVisibleRect();
3376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 }
3378 } else {
3379 super.computeScroll();
3380 }
3381 }
3382
3383 private static int computeDuration(int dx, int dy) {
3384 int distance = Math.max(Math.abs(dx), Math.abs(dy));
3385 int duration = distance * 1000 / STD_SPEED;
3386 return Math.min(duration, MAX_DURATION);
3387 }
3388
3389 // helper to pin the scrollBy parameters (already in view coordinates)
3390 // returns true if the scroll was changed
3391 private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) {
3392 return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
3393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 // helper to pin the scrollTo parameters (already in view coordinates)
3395 // returns true if the scroll was changed
3396 private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) {
3397 x = pinLocX(x);
3398 y = pinLocY(y);
3399 int dx = x - mScrollX;
3400 int dy = y - mScrollY;
3401
3402 if ((dx | dy) == 0) {
3403 return false;
3404 }
Cary Clark21a97ef2010-11-16 09:59:40 -05003405 abortAnimation();
Leon Scrogginsd55de402009-09-17 14:19:49 -04003406 if (animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 // Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 mScroller.startScroll(mScrollX, mScrollY, dx, dy,
3409 animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
Mike Cleronf116bf82009-09-27 19:14:12 -07003410 awakenScrollBars(mScroller.getDuration());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 invalidate();
3412 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003413 scrollTo(x, y);
3414 }
3415 return true;
3416 }
3417
3418 // Scale from content to view coordinates, and pin.
3419 // Also called by jni webview.cpp
Leon Scroggins4c943042009-07-31 15:05:42 -04003420 private boolean setContentScrollBy(int cx, int cy, boolean animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003421 if (mDrawHistory) {
3422 // disallow WebView to change the scroll position as History Picture
3423 // is used in the view system.
3424 // TODO: as we switchOutDrawHistory when trackball or navigation
3425 // keys are hit, this should be safe. Right?
Leon Scroggins4c943042009-07-31 15:05:42 -04003426 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 }
Mike Reede8853fc2009-09-04 14:01:48 -04003428 cx = contentToViewDimension(cx);
3429 cy = contentToViewDimension(cy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 if (mHeightCanMeasure) {
3431 // move our visible rect according to scroll request
3432 if (cy != 0) {
3433 Rect tempRect = new Rect();
3434 calcOurVisibleRect(tempRect);
3435 tempRect.offset(cx, cy);
3436 requestRectangleOnScreen(tempRect);
3437 }
3438 // FIXME: We scroll horizontally no matter what because currently
3439 // ScrollView and ListView will not scroll horizontally.
3440 // FIXME: Why do we only scroll horizontally if there is no
3441 // vertical scroll?
3442// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
Leon Scroggins4c943042009-07-31 15:05:42 -04003443 return cy == 0 && cx != 0 && pinScrollBy(cx, 0, animate, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003444 } else {
Leon Scroggins4c943042009-07-31 15:05:42 -04003445 return pinScrollBy(cx, cy, animate, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003446 }
3447 }
3448
Leon Scroggins405d7852009-11-02 14:50:54 -08003449 /**
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003450 * Called by CallbackProxy when the page starts loading.
3451 * @param url The URL of the page which has started loading.
3452 */
3453 /* package */ void onPageStarted(String url) {
3454 // every time we start a new page, we want to reset the
3455 // WebView certificate: if the new site is secure, we
3456 // will reload it and get a new certificate set;
3457 // if the new site is not secure, the certificate must be
3458 // null, and that will be the case
3459 setCertificate(null);
3460
3461 // reset the flag since we set to true in if need after
3462 // loading is see onPageFinished(Url)
3463 mAccessibilityScriptInjected = false;
3464 }
3465
3466 /**
Leon Scroggins405d7852009-11-02 14:50:54 -08003467 * Called by CallbackProxy when the page finishes loading.
3468 * @param url The URL of the page which has finished loading.
3469 */
3470 /* package */ void onPageFinished(String url) {
3471 if (mPageThatNeedsToSlideTitleBarOffScreen != null) {
3472 // If the user is now on a different page, or has scrolled the page
3473 // past the point where the title bar is offscreen, ignore the
3474 // scroll request.
3475 if (mPageThatNeedsToSlideTitleBarOffScreen.equals(url)
3476 && mScrollX == 0 && mScrollY == 0) {
3477 pinScrollTo(0, mYDistanceToSlideTitleOffScreen, true,
3478 SLIDE_TITLE_DURATION);
3479 }
3480 mPageThatNeedsToSlideTitleBarOffScreen = null;
3481 }
Shimeng (Simon) Wangd75fd492011-02-16 14:52:13 -08003482 mZoomManager.onPageFinished(url);
Svetoslav Ganovda355512010-05-12 22:04:44 -07003483 injectAccessibilityForUrl(url);
3484 }
3485
3486 /**
3487 * This method injects accessibility in the loaded document if accessibility
3488 * is enabled. If JavaScript is enabled we try to inject a URL specific script.
3489 * If no URL specific script is found or JavaScript is disabled we fallback to
3490 * the default {@link AccessibilityInjector} implementation.
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003491 * </p>
3492 * If the URL has the "axs" paramter set to 1 it has already done the
3493 * script injection so we do nothing. If the parameter is set to 0
3494 * the URL opts out accessibility script injection so we fall back to
3495 * the default {@link AccessibilityInjector}.
3496 * </p>
3497 * Note: If the user has not opted-in the accessibility script injection no scripts
3498 * are injected rather the default {@link AccessibilityInjector} implementation
3499 * is used.
Svetoslav Ganovda355512010-05-12 22:04:44 -07003500 *
3501 * @param url The URL loaded by this {@link WebView}.
3502 */
3503 private void injectAccessibilityForUrl(String url) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08003504 if (mWebViewCore == null) {
3505 return;
3506 }
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003507 AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
3508
3509 if (!accessibilityManager.isEnabled()) {
Svetoslav Ganovda355512010-05-12 22:04:44 -07003510 // it is possible that accessibility was turned off between reloads
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003511 ensureAccessibilityScriptInjectorInstance(false);
3512 return;
3513 }
3514
3515 if (!getSettings().getJavaScriptEnabled()) {
3516 // no JS so we fallback to the basic buil-in support
3517 ensureAccessibilityScriptInjectorInstance(true);
3518 return;
3519 }
3520
3521 // check the URL "axs" parameter to choose appropriate action
3522 int axsParameterValue = getAxsUrlParameterValue(url);
3523 if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED) {
3524 boolean onDeviceScriptInjectionEnabled = (Settings.Secure.getInt(mContext
3525 .getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
3526 if (onDeviceScriptInjectionEnabled) {
3527 ensureAccessibilityScriptInjectorInstance(false);
3528 // neither script injected nor script injection opted out => we inject
3529 loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
3530 // TODO: Set this flag after successfull script injection. Maybe upon injection
3531 // the chooser should update the meta tag and we check it to declare success
3532 mAccessibilityScriptInjected = true;
3533 } else {
3534 // injection disabled so we fallback to the basic built-in support
3535 ensureAccessibilityScriptInjectorInstance(true);
3536 }
3537 } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) {
3538 // injection opted out so we fallback to the basic buil-in support
3539 ensureAccessibilityScriptInjectorInstance(true);
3540 } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
3541 ensureAccessibilityScriptInjectorInstance(false);
3542 // the URL provides accessibility but we still need to add our generic script
3543 loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
3544 } else {
3545 Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
3546 }
3547 }
3548
3549 /**
3550 * Ensures the instance of the {@link AccessibilityInjector} to be present ot not.
3551 *
3552 * @param present True to ensure an insance, false to ensure no instance.
3553 */
3554 private void ensureAccessibilityScriptInjectorInstance(boolean present) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08003555 if (present) {
3556 if (mAccessibilityInjector == null) {
3557 mAccessibilityInjector = new AccessibilityInjector(this);
3558 }
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003559 } else {
Svetoslav Ganovda355512010-05-12 22:04:44 -07003560 mAccessibilityInjector = null;
3561 }
Leon Scroggins405d7852009-11-02 14:50:54 -08003562 }
3563
3564 /**
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003565 * Gets the "axs" URL parameter value.
3566 *
3567 * @param url A url to fetch the paramter from.
3568 * @return The parameter value if such, -1 otherwise.
3569 */
3570 private int getAxsUrlParameterValue(String url) {
3571 if (mMatchAxsUrlParameterPattern == null) {
3572 mMatchAxsUrlParameterPattern = Pattern.compile(PATTERN_MATCH_AXS_URL_PARAMETER);
3573 }
3574 Matcher matcher = mMatchAxsUrlParameterPattern.matcher(url);
3575 if (matcher.find()) {
3576 String keyValuePair = url.substring(matcher.start(), matcher.end());
3577 return Integer.parseInt(keyValuePair.split("=")[1]);
3578 }
3579 return -1;
3580 }
3581
3582 /**
Leon Scroggins405d7852009-11-02 14:50:54 -08003583 * The URL of a page that sent a message to scroll the title bar off screen.
3584 *
3585 * Many mobile sites tell the page to scroll to (0,1) in order to scroll the
3586 * title bar off the screen. Sometimes, the scroll position is set before
3587 * the page finishes loading. Rather than scrolling while the page is still
3588 * loading, keep track of the URL and new scroll position so we can perform
3589 * the scroll once the page finishes loading.
3590 */
3591 private String mPageThatNeedsToSlideTitleBarOffScreen;
3592
3593 /**
3594 * The destination Y scroll position to be used when the page finishes
3595 * loading. See mPageThatNeedsToSlideTitleBarOffScreen.
3596 */
3597 private int mYDistanceToSlideTitleOffScreen;
3598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003599 // scale from content to view coordinates, and pin
Leon Scroggins83d4ba82009-09-17 17:27:13 -04003600 // return true if pin caused the final x/y different than the request cx/cy,
3601 // and a future scroll may reach the request cx/cy after our size has
3602 // changed
3603 // return false if the view scroll to the exact position as it is requested,
3604 // where negative numbers are taken to mean 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003605 private boolean setContentScrollTo(int cx, int cy) {
3606 if (mDrawHistory) {
3607 // disallow WebView to change the scroll position as History Picture
3608 // is used in the view system.
3609 // One known case where this is called is that WebCore tries to
3610 // restore the scroll position. As history Picture already uses the
3611 // saved scroll position, it is ok to skip this.
3612 return false;
3613 }
Leon Scrogginsd7b95aa2009-09-21 13:27:02 -04003614 int vx;
3615 int vy;
3616 if ((cx | cy) == 0) {
3617 // If the page is being scrolled to (0,0), do not add in the title
3618 // bar's height, and simply scroll to (0,0). (The only other work
3619 // in contentToView_ is to multiply, so this would not change 0.)
3620 vx = 0;
3621 vy = 0;
3622 } else {
3623 vx = contentToViewX(cx);
3624 vy = contentToViewY(cy);
3625 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003626// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
3627// vx + " " + vy + "]");
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003628 // Some mobile sites attempt to scroll the title bar off the page by
Leon Scrogginsd7b95aa2009-09-21 13:27:02 -04003629 // scrolling to (0,1). If we are at the top left corner of the
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003630 // page, assume this is an attempt to scroll off the title bar, and
3631 // animate the title bar off screen slowly enough that the user can see
3632 // it.
Leon Scroggins405d7852009-11-02 14:50:54 -08003633 if (cx == 0 && cy == 1 && mScrollX == 0 && mScrollY == 0
3634 && mTitleBar != null) {
3635 // FIXME: 100 should be defined somewhere as our max progress.
3636 if (getProgress() < 100) {
3637 // Wait to scroll the title bar off screen until the page has
3638 // finished loading. Keep track of the URL and the destination
3639 // Y position
3640 mPageThatNeedsToSlideTitleBarOffScreen = getUrl();
3641 mYDistanceToSlideTitleOffScreen = vy;
3642 } else {
3643 pinScrollTo(vx, vy, true, SLIDE_TITLE_DURATION);
3644 }
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003645 // Since we are animating, we have not yet reached the desired
3646 // scroll position. Do not return true to request another attempt
3647 return false;
3648 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003649 pinScrollTo(vx, vy, false, 0);
Leon Scroggins83d4ba82009-09-17 17:27:13 -04003650 // If the request was to scroll to a negative coordinate, treat it as if
3651 // it was a request to scroll to 0
3652 if ((mScrollX != vx && cx >= 0) || (mScrollY != vy && cy >= 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 return true;
3654 } else {
3655 return false;
3656 }
3657 }
3658
3659 // scale from content to view coordinates, and pin
3660 private void spawnContentScrollTo(int cx, int cy) {
3661 if (mDrawHistory) {
3662 // disallow WebView to change the scroll position as History Picture
3663 // is used in the view system.
3664 return;
3665 }
Leon Scroggins0236e672009-09-02 21:12:08 -04003666 int vx = contentToViewX(cx);
3667 int vy = contentToViewY(cy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668 pinScrollTo(vx, vy, true, 0);
3669 }
3670
3671 /**
3672 * These are from webkit, and are in content coordinate system (unzoomed)
3673 */
3674 private void contentSizeChanged(boolean updateLayout) {
3675 // suppress 0,0 since we usually see real dimensions soon after
3676 // this avoids drawing the prev content in a funny place. If we find a
3677 // way to consolidate these notifications, this check may become
3678 // obsolete
3679 if ((mContentWidth | mContentHeight) == 0) {
3680 return;
3681 }
3682
3683 if (mHeightCanMeasure) {
Mike Reede8853fc2009-09-04 14:01:48 -04003684 if (getMeasuredHeight() != contentToViewDimension(mContentHeight)
Grace Kloba3f9faf42009-10-13 14:13:54 -07003685 || updateLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003686 requestLayout();
3687 }
3688 } else if (mWidthCanMeasure) {
Mike Reede8853fc2009-09-04 14:01:48 -04003689 if (getMeasuredWidth() != contentToViewDimension(mContentWidth)
Grace Kloba3f9faf42009-10-13 14:13:54 -07003690 || updateLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003691 requestLayout();
3692 }
3693 } else {
3694 // If we don't request a layout, try to send our view size to the
3695 // native side to ensure that WebCore has the correct dimensions.
Derek Sollenberger03e48912010-05-18 17:03:42 -04003696 sendViewSizeZoom(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003697 }
3698 }
3699
3700 /**
3701 * Set the WebViewClient that will receive various notifications and
3702 * requests. This will replace the current handler.
3703 * @param client An implementation of WebViewClient.
3704 */
3705 public void setWebViewClient(WebViewClient client) {
Steve Block51b08912011-04-27 15:04:48 +01003706 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 mCallbackProxy.setWebViewClient(client);
3708 }
3709
3710 /**
Grace Kloba94ab3b62009-10-07 18:00:19 -07003711 * Gets the WebViewClient
3712 * @return the current WebViewClient instance.
3713 *
3714 *@hide pending API council approval.
3715 */
3716 public WebViewClient getWebViewClient() {
3717 return mCallbackProxy.getWebViewClient();
3718 }
3719
3720 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 * Register the interface to be used when content can not be handled by
3722 * the rendering engine, and should be downloaded instead. This will replace
3723 * the current handler.
3724 * @param listener An implementation of DownloadListener.
3725 */
3726 public void setDownloadListener(DownloadListener listener) {
Steve Block51b08912011-04-27 15:04:48 +01003727 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003728 mCallbackProxy.setDownloadListener(listener);
3729 }
3730
3731 /**
3732 * Set the chrome handler. This is an implementation of WebChromeClient for
Steve Block81f19ff2010-11-01 13:23:24 +00003733 * use in handling JavaScript dialogs, favicons, titles, and the progress.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 * This will replace the current handler.
3735 * @param client An implementation of WebChromeClient.
3736 */
3737 public void setWebChromeClient(WebChromeClient client) {
Steve Block51b08912011-04-27 15:04:48 +01003738 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 mCallbackProxy.setWebChromeClient(client);
3740 }
3741
3742 /**
Andrei Popescu6fa29582009-06-19 14:54:09 +01003743 * Gets the chrome handler.
3744 * @return the current WebChromeClient instance.
3745 *
3746 * @hide API council approval.
3747 */
3748 public WebChromeClient getWebChromeClient() {
3749 return mCallbackProxy.getWebChromeClient();
3750 }
3751
3752 /**
Patrick Scott0b2e84b2010-03-02 08:58:44 -05003753 * Set the back/forward list client. This is an implementation of
3754 * WebBackForwardListClient for handling new items and changes in the
3755 * history index.
3756 * @param client An implementation of WebBackForwardListClient.
3757 * {@hide}
3758 */
3759 public void setWebBackForwardListClient(WebBackForwardListClient client) {
3760 mCallbackProxy.setWebBackForwardListClient(client);
3761 }
3762
3763 /**
3764 * Gets the WebBackForwardListClient.
3765 * {@hide}
3766 */
3767 public WebBackForwardListClient getWebBackForwardListClient() {
3768 return mCallbackProxy.getWebBackForwardListClient();
3769 }
3770
3771 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003772 * Set the Picture listener. This is an interface used to receive
3773 * notifications of a new Picture.
3774 * @param listener An implementation of WebView.PictureListener.
Kristian Monsenfc771652011-05-10 16:44:05 +01003775 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 */
Kristian Monsenfc771652011-05-10 16:44:05 +01003777 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003778 public void setPictureListener(PictureListener listener) {
Steve Block51b08912011-04-27 15:04:48 +01003779 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 mPictureListener = listener;
3781 }
3782
3783 /**
3784 * {@hide}
3785 */
3786 /* FIXME: Debug only! Remove for SDK! */
3787 public void externalRepresentation(Message callback) {
3788 mWebViewCore.sendMessage(EventHub.REQUEST_EXT_REPRESENTATION, callback);
3789 }
3790
3791 /**
3792 * {@hide}
3793 */
3794 /* FIXME: Debug only! Remove for SDK! */
3795 public void documentAsText(Message callback) {
3796 mWebViewCore.sendMessage(EventHub.REQUEST_DOC_AS_TEXT, callback);
3797 }
3798
3799 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003800 * Use this function to bind an object to JavaScript so that the
3801 * methods can be accessed from JavaScript.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003802 * <p><strong>IMPORTANT:</strong>
3803 * <ul>
3804 * <li> Using addJavascriptInterface() allows JavaScript to control your
3805 * application. This can be a very useful feature or a dangerous security
3806 * issue. When the HTML in the WebView is untrustworthy (for example, part
3807 * or all of the HTML is provided by some person or process), then an
3808 * attacker could inject HTML that will execute your code and possibly any
3809 * code of the attacker's choosing.<br>
3810 * Do not use addJavascriptInterface() unless all of the HTML in this
3811 * WebView was written by you.</li>
3812 * <li> The Java object that is bound runs in another thread and not in
3813 * the thread that it was constructed in.</li>
3814 * </ul></p>
Steve Block81f19ff2010-11-01 13:23:24 +00003815 * @param obj The class instance to bind to JavaScript, null instances are
Steve Block544295e2010-12-02 18:40:06 +00003816 * ignored.
Steve Block689a3422010-12-07 18:18:26 +00003817 * @param interfaceName The name to used to expose the instance in
3818 * JavaScript.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003819 */
3820 public void addJavascriptInterface(Object obj, String interfaceName) {
Steve Block51b08912011-04-27 15:04:48 +01003821 checkThread();
Steve Block544295e2010-12-02 18:40:06 +00003822 if (obj == null) {
3823 return;
3824 }
Cary Clarkded054c2009-06-15 10:26:08 -04003825 WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
3826 arg.mObject = obj;
3827 arg.mInterfaceName = interfaceName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
3829 }
3830
3831 /**
Steve Block689a3422010-12-07 18:18:26 +00003832 * Removes a previously added JavaScript interface with the given name.
3833 * @param interfaceName The name of the interface to remove.
3834 */
3835 public void removeJavascriptInterface(String interfaceName) {
Steve Block51b08912011-04-27 15:04:48 +01003836 checkThread();
Svetoslav Ganovfa443142011-03-02 14:54:03 -08003837 if (mWebViewCore != null) {
3838 WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
3839 arg.mInterfaceName = interfaceName;
3840 mWebViewCore.sendMessage(EventHub.REMOVE_JS_INTERFACE, arg);
3841 }
Steve Block689a3422010-12-07 18:18:26 +00003842 }
3843
3844 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003845 * Return the WebSettings object used to control the settings for this
3846 * WebView.
3847 * @return A WebSettings object that can be used to control this WebView's
3848 * settings.
3849 */
3850 public WebSettings getSettings() {
Steve Block51b08912011-04-27 15:04:48 +01003851 checkThread();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04003852 return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003853 }
3854
3855 /**
3856 * Return the list of currently loaded plugins.
3857 * @return The list of currently loaded plugins.
Andrei Popescu385df692009-08-13 11:59:57 +01003858 *
Kristian Monsenf0d97312011-01-12 19:15:35 +00003859 * @hide
Andrei Popescu385df692009-08-13 11:59:57 +01003860 * @deprecated This was used for Gears, which has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003861 */
Andrei Popescu385df692009-08-13 11:59:57 +01003862 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003863 public static synchronized PluginList getPluginList() {
Steve Block51b08912011-04-27 15:04:48 +01003864 checkThread();
Grace Klobabb245ea2009-11-10 13:13:24 -08003865 return new PluginList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003866 }
3867
3868 /**
Kristian Monsenf0d97312011-01-12 19:15:35 +00003869 * @hide
Andrei Popescu385df692009-08-13 11:59:57 +01003870 * @deprecated This was used for Gears, which has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003871 */
Andrei Popescu385df692009-08-13 11:59:57 +01003872 @Deprecated
Steve Block51b08912011-04-27 15:04:48 +01003873 public void refreshPlugins(boolean reloadOpenPages) {
3874 checkThread();
3875 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876
3877 //-------------------------------------------------------------------------
3878 // Override View methods
3879 //-------------------------------------------------------------------------
3880
3881 @Override
3882 protected void finalize() throws Throwable {
Cary Clark9a4c0632009-08-10 16:40:08 -04003883 try {
Steve Block51b08912011-04-27 15:04:48 +01003884 destroyImpl();
Cary Clark9a4c0632009-08-10 16:40:08 -04003885 } finally {
3886 super.finalize();
3887 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003888 }
Cary Clarkd6982c92009-05-29 11:02:22 -04003889
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 @Override
Leon Scroggins0236e672009-09-02 21:12:08 -04003891 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
3892 if (child == mTitleBar) {
3893 // When drawing the title bar, move it horizontally to always show
Adam Powell9d32d242010-03-29 16:02:07 -07003894 // at the top of the WebView.
Leon Scroggins0236e672009-09-02 21:12:08 -04003895 mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft());
Michael Kolbc4ca53f2011-02-05 13:53:14 -08003896 int newTop = 0;
3897 if (mTitleGravity == Gravity.NO_GRAVITY) {
3898 newTop = Math.min(0, mScrollY);
3899 } else if (mTitleGravity == Gravity.TOP) {
3900 newTop = mScrollY;
3901 }
Michael Kolb75a03f92011-02-23 16:12:13 -08003902 mTitleBar.setBottom(newTop + mTitleBar.getHeight());
Mindy Pereira3331f2b2010-12-03 09:58:37 -08003903 mTitleBar.setTop(newTop);
Leon Scroggins0236e672009-09-02 21:12:08 -04003904 }
3905 return super.drawChild(canvas, child, drawingTime);
3906 }
3907
Mike Reed19f3f0e2009-11-12 12:50:20 -05003908 private void drawContent(Canvas canvas) {
Grace Kloba04b28682009-09-14 14:38:37 -07003909 // Update the buttons in the picture, so when we draw the picture
3910 // to the screen, they are in the correct state.
3911 // Tell the native side if user is a) touching the screen,
3912 // b) pressing the trackball down, or c) pressing the enter key
3913 // If the cursor is on a button, we need to draw it in the pressed
3914 // state.
3915 // If mNativeClass is 0, we should not reach here, so we do not
3916 // need to check it again.
3917 nativeRecordButtons(hasFocus() && hasWindowFocus(),
Mike Reed19f3f0e2009-11-12 12:50:20 -05003918 mTouchMode == TOUCH_SHORTPRESS_START_MODE
3919 || mTrackballDown || mGotCenterDown, false);
Grace Kloba04b28682009-09-14 14:38:37 -07003920 drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
Mike Reed19f3f0e2009-11-12 12:50:20 -05003921 }
3922
Adam Powell637d3372010-08-25 14:37:03 -07003923 /**
3924 * Draw the background when beyond bounds
3925 * @param canvas Canvas to draw into
3926 */
3927 private void drawOverScrollBackground(Canvas canvas) {
3928 if (mOverScrollBackground == null) {
3929 mOverScrollBackground = new Paint();
3930 Bitmap bm = BitmapFactory.decodeResource(
3931 mContext.getResources(),
3932 com.android.internal.R.drawable.status_bar_background);
3933 mOverScrollBackground.setShader(new BitmapShader(bm,
3934 Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
3935 mOverScrollBorder = new Paint();
3936 mOverScrollBorder.setStyle(Paint.Style.STROKE);
3937 mOverScrollBorder.setStrokeWidth(0);
3938 mOverScrollBorder.setColor(0xffbbbbbb);
3939 }
3940
3941 int top = 0;
3942 int right = computeRealHorizontalScrollRange();
3943 int bottom = top + computeRealVerticalScrollRange();
3944 // first draw the background and anchor to the top of the view
3945 canvas.save();
3946 canvas.translate(mScrollX, mScrollY);
3947 canvas.clipRect(-mScrollX, top - mScrollY, right - mScrollX, bottom
3948 - mScrollY, Region.Op.DIFFERENCE);
3949 canvas.drawPaint(mOverScrollBackground);
3950 canvas.restore();
3951 // then draw the border
3952 canvas.drawRect(-1, top - 1, right, bottom, mOverScrollBorder);
3953 // next clip the region for the content
3954 canvas.clipRect(0, top, right, bottom);
3955 }
3956
Mike Reed19f3f0e2009-11-12 12:50:20 -05003957 @Override
3958 protected void onDraw(Canvas canvas) {
3959 // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
3960 if (mNativeClass == 0) {
3961 return;
3962 }
3963
Grace Klobae47ac472010-03-11 14:53:07 -08003964 // if both mContentWidth and mContentHeight are 0, it means there is no
3965 // valid Picture passed to WebView yet. This can happen when WebView
3966 // just starts. Draw the background and return.
3967 if ((mContentWidth | mContentHeight) == 0 && mHistoryPicture == null) {
3968 canvas.drawColor(mBackgroundColor);
3969 return;
3970 }
3971
Ben Murdoch811ba6c2011-01-26 10:19:39 +00003972 if (canvas.isHardwareAccelerated()) {
3973 mZoomManager.setHardwareAccelerated();
3974 }
3975
Mike Reed19f3f0e2009-11-12 12:50:20 -05003976 int saveCount = canvas.save();
Adam Powell637d3372010-08-25 14:37:03 -07003977 if (mInOverScrollMode && !getSettings()
3978 .getUseWebViewBackgroundForOverscrollBackground()) {
3979 drawOverScrollBackground(canvas);
3980 }
Mike Reed19f3f0e2009-11-12 12:50:20 -05003981 if (mTitleBar != null) {
Michael Kolb75a03f92011-02-23 16:12:13 -08003982 canvas.translate(0, getTitleHeight());
Mike Reed19f3f0e2009-11-12 12:50:20 -05003983 }
Bjorn Bringertc9332fa2010-10-13 17:24:27 +01003984 drawContent(canvas);
Leon Scroggins0236e672009-09-02 21:12:08 -04003985 canvas.restoreToCount(saveCount);
Cary Clarkd6982c92009-05-29 11:02:22 -04003986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003987 if (AUTO_REDRAW_HACK && mAutoRedraw) {
3988 invalidate();
3989 }
Leon Scroggins56426252010-11-01 15:45:37 -04003990 if (inEditingMode()) {
3991 mWebTextView.onDrawSubstitute();
3992 }
Nicolas Roard38863332010-01-04 19:30:55 +00003993 mWebViewCore.signalRepaintDone();
Grace Kloba178db412010-05-18 22:22:23 -07003994
Adam Powell637d3372010-08-25 14:37:03 -07003995 if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas)) {
3996 invalidate();
3997 }
3998
Grace Kloba178db412010-05-18 22:22:23 -07003999 // paint the highlight in the end
4000 if (!mTouchHighlightRegion.isEmpty()) {
4001 if (mTouchHightlightPaint == null) {
4002 mTouchHightlightPaint = new Paint();
4003 mTouchHightlightPaint.setColor(mHightlightColor);
4004 mTouchHightlightPaint.setAntiAlias(true);
4005 mTouchHightlightPaint.setPathEffect(new CornerPathEffect(
4006 TOUCH_HIGHLIGHT_ARC));
4007 }
4008 canvas.drawPath(mTouchHighlightRegion.getBoundaryPath(),
4009 mTouchHightlightPaint);
4010 }
4011 if (DEBUG_TOUCH_HIGHLIGHT) {
4012 if (getSettings().getNavDump()) {
4013 if ((mTouchHighlightX | mTouchHighlightY) != 0) {
4014 if (mTouchCrossHairColor == null) {
4015 mTouchCrossHairColor = new Paint();
4016 mTouchCrossHairColor.setColor(Color.RED);
4017 }
4018 canvas.drawLine(mTouchHighlightX - mNavSlop,
4019 mTouchHighlightY - mNavSlop, mTouchHighlightX
4020 + mNavSlop + 1, mTouchHighlightY + mNavSlop
4021 + 1, mTouchCrossHairColor);
4022 canvas.drawLine(mTouchHighlightX + mNavSlop + 1,
4023 mTouchHighlightY - mNavSlop, mTouchHighlightX
4024 - mNavSlop,
4025 mTouchHighlightY + mNavSlop + 1,
4026 mTouchCrossHairColor);
4027 }
4028 }
4029 }
4030 }
4031
4032 private void removeTouchHighlight(boolean removePendingMessage) {
4033 if (removePendingMessage) {
4034 mWebViewCore.removeMessages(EventHub.GET_TOUCH_HIGHLIGHT_RECTS);
4035 }
4036 mWebViewCore.sendMessage(EventHub.REMOVE_TOUCH_HIGHLIGHT_RECTS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004037 }
4038
4039 @Override
4040 public void setLayoutParams(ViewGroup.LayoutParams params) {
4041 if (params.height == LayoutParams.WRAP_CONTENT) {
4042 mWrapContent = true;
4043 }
4044 super.setLayoutParams(params);
4045 }
4046
4047 @Override
4048 public boolean performLongClick() {
Grace Kloba98e6fcf2010-01-27 15:20:30 -08004049 // performLongClick() is the result of a delayed message. If we switch
4050 // to windows overview, the WebView will be temporarily removed from the
4051 // view system. In that case, do nothing.
4052 if (getParent() == null) return false;
Adam Powellbe366682010-09-12 12:47:04 -07004053
4054 // A multi-finger gesture can look like a long press; make sure we don't take
4055 // long press actions if we're scaling.
4056 final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
4057 if (detector != null && detector.isInProgress()) {
4058 return false;
4059 }
Michael Kolbc4ca53f2011-02-05 13:53:14 -08004060
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004061 if (mNativeClass != 0 && nativeCursorIsTextInput()) {
4062 // Send the click so that the textfield is in focus
Leon Scroggins1d96ca02009-10-23 11:49:03 -04004063 centerKeyPressOnTextField();
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004064 rebuildWebTextView();
Leon Scroggins2c8e0512010-05-11 15:50:27 -04004065 } else {
Leon Scroggins2aed7762010-08-13 17:11:42 -04004066 clearTextEntry();
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004067 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004068 if (inEditingMode()) {
Leon Scrogginsfcf57762010-12-14 18:09:23 -05004069 // Since we just called rebuildWebTextView, the layout is not set
4070 // properly. Update it so it can correctly find the word to select.
4071 mWebTextView.ensureLayout();
4072 // Provide a touch down event to WebTextView, which will allow it
4073 // to store the location to use in performLongClick.
4074 AbsoluteLayout.LayoutParams params
4075 = (AbsoluteLayout.LayoutParams) mWebTextView.getLayoutParams();
4076 MotionEvent fake = MotionEvent.obtain(mLastTouchTime,
4077 mLastTouchTime, MotionEvent.ACTION_DOWN,
4078 mLastTouchX - params.x + mScrollX,
4079 mLastTouchY - params.y + mScrollY, 0);
4080 mWebTextView.dispatchTouchEvent(fake);
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004081 return mWebTextView.performLongClick();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004082 }
Cary Clark1e8e10d2010-11-17 13:49:25 -05004083 if (mSelectingText) return false; // long click does nothing on selection
Cary Clark924af702010-06-04 16:37:43 -04004084 /* if long click brings up a context menu, the super function
4085 * returns true and we're done. Otherwise, nothing happened when
4086 * the user clicked. */
4087 if (super.performLongClick()) {
4088 return true;
4089 }
4090 /* In the case where the application hasn't already handled the long
4091 * click action, look for a word under the click. If one is found,
4092 * animate the text selection into view.
4093 * FIXME: no animation code yet */
Cary Clarkfc8bf742010-11-22 11:02:29 -05004094 return selectText();
4095 }
4096
4097 /**
4098 * Select the word at the last click point.
4099 *
4100 * @hide pending API council approval
4101 */
4102 public boolean selectText() {
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08004103 int x = viewToContentX(mLastTouchX + mScrollX);
4104 int y = viewToContentY(mLastTouchY + mScrollY);
Cary Clark2cdee232010-12-29 14:59:24 -05004105 return selectText(x, y);
4106 }
4107
4108 /**
4109 * Select the word at the indicated content coordinates.
4110 */
4111 boolean selectText(int x, int y) {
Cary Clark03f00222011-02-10 19:37:15 -05004112 if (!setUpSelect(true, x, y)) {
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05004113 return false;
4114 }
Cary Clark03f00222011-02-10 19:37:15 -05004115 nativeSetExtendSelection();
4116 mDrawSelectionPointer = false;
4117 mSelectionStarted = true;
4118 mTouchMode = TOUCH_DRAG_MODE;
4119 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004120 }
4121
Cary Clarkc5cd5e92010-11-22 15:20:02 -05004122 private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
4123
4124 @Override
4125 protected void onConfigurationChanged(Configuration newConfig) {
4126 if (mSelectingText && mOrientation != newConfig.orientation) {
4127 selectionDone();
4128 }
4129 mOrientation = newConfig.orientation;
4130 }
4131
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04004132 /**
4133 * Keep track of the Callback so we can end its ActionMode or remove its
4134 * titlebar.
4135 */
4136 private SelectActionModeCallback mSelectCallback;
4137
Leon Scroggins63356742010-12-15 17:37:08 -05004138 // These values are possible options for didUpdateWebTextViewDimensions.
4139 private static final int FULLY_ON_SCREEN = 0;
4140 private static final int INTERSECTS_SCREEN = 1;
4141 private static final int ANYWHERE = 2;
4142
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004143 /**
4144 * Check to see if the focused textfield/textarea is still on screen. If it
4145 * is, update the the dimensions and location of WebTextView. Otherwise,
4146 * remove the WebTextView. Should be called when the zoom level changes.
Leon Scroggins63356742010-12-15 17:37:08 -05004147 * @param intersection How to determine whether the textfield/textarea is
4148 * still on screen.
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004149 * @return boolean True if the textfield/textarea is still on screen and the
4150 * dimensions/location of WebTextView have been updated.
4151 */
Leon Scroggins63356742010-12-15 17:37:08 -05004152 private boolean didUpdateWebTextViewDimensions(int intersection) {
Cary Clark5da9aeb2009-10-06 17:40:53 -04004153 Rect contentBounds = nativeFocusCandidateNodeBounds();
4154 Rect vBox = contentToViewRect(contentBounds);
4155 Rect visibleRect = new Rect();
4156 calcOurVisibleRect(visibleRect);
Leon Scrogginsbcbf5642010-02-17 17:56:51 -05004157 // If the textfield is on screen, place the WebTextView in
4158 // its new place, accounting for our new scroll/zoom values,
4159 // and adjust its textsize.
Leon Scroggins63356742010-12-15 17:37:08 -05004160 boolean onScreen;
4161 switch (intersection) {
4162 case FULLY_ON_SCREEN:
4163 onScreen = visibleRect.contains(vBox);
4164 break;
4165 case INTERSECTS_SCREEN:
4166 onScreen = Rect.intersects(visibleRect, vBox);
4167 break;
4168 case ANYWHERE:
4169 onScreen = true;
4170 break;
4171 default:
4172 throw new AssertionError(
4173 "invalid parameter passed to didUpdateWebTextViewDimensions");
4174 }
4175 if (onScreen) {
Cary Clark5da9aeb2009-10-06 17:40:53 -04004176 mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
4177 vBox.height());
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004178 mWebTextView.updateTextSize();
4179 updateWebTextViewPadding();
Cary Clark5da9aeb2009-10-06 17:40:53 -04004180 return true;
4181 } else {
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004182 // The textfield is now off screen. The user probably
4183 // was not zooming to see the textfield better. Remove
4184 // the WebTextView. If the user types a key, and the
4185 // textfield is still in focus, we will reconstruct
4186 // the WebTextView and scroll it back on screen.
4187 mWebTextView.remove();
Cary Clark5da9aeb2009-10-06 17:40:53 -04004188 return false;
4189 }
4190 }
4191
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07004192 void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator,
4193 boolean isPictureAfterFirstLayout) {
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004194 if (mNativeClass == 0)
4195 return;
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07004196 nativeSetBaseLayer(layer, invalRegion, showVisualIndicator,
4197 isPictureAfterFirstLayout);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08004198 if (mHTML5VideoViewProxy != null) {
4199 mHTML5VideoViewProxy.setBaseLayer(layer);
4200 }
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004201 }
4202
Derek Sollenberger293c3602010-06-04 10:44:48 -04004203 private void onZoomAnimationStart() {
4204 // If it is in password mode, turn it off so it does not draw misplaced.
4205 if (inEditingMode() && nativeFocusCandidateIsPassword()) {
4206 mWebTextView.setInPassword(false);
4207 }
4208 }
4209
4210 private void onZoomAnimationEnd() {
4211 // adjust the edit text view if needed
Leon Scroggins63356742010-12-15 17:37:08 -05004212 if (inEditingMode() && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004213 && nativeFocusCandidateIsPassword()) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04004214 // If it is a password field, start drawing the WebTextView once
4215 // again.
4216 mWebTextView.setInPassword(true);
4217 }
4218 }
4219
4220 void onFixedLengthZoomAnimationStart() {
4221 WebViewCore.pauseUpdatePicture(getWebViewCore());
4222 onZoomAnimationStart();
4223 }
4224
4225 void onFixedLengthZoomAnimationEnd() {
Cary Clark0df02692010-11-24 11:01:37 -05004226 if (!mSelectingText) {
4227 WebViewCore.resumeUpdatePicture(mWebViewCore);
4228 }
Derek Sollenberger293c3602010-06-04 10:44:48 -04004229 onZoomAnimationEnd();
4230 }
4231
Grace Kloba8abd50b2010-07-08 15:02:14 -07004232 private static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG |
4233 Paint.DITHER_FLAG |
4234 Paint.SUBPIXEL_TEXT_FLAG;
4235 private static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG |
4236 Paint.DITHER_FLAG;
4237
4238 private final DrawFilter mZoomFilter =
4239 new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
4240 // If we need to trade better quality for speed, set mScrollFilter to null
4241 private final DrawFilter mScrollFilter =
4242 new PaintFlagsDrawFilter(SCROLL_BITS, 0);
4243
Cary Clarkd6982c92009-05-29 11:02:22 -04004244 private void drawCoreAndCursorRing(Canvas canvas, int color,
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004245 boolean drawCursorRing) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004246 if (mDrawHistory) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04004247 canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004248 canvas.drawPicture(mHistoryPicture);
4249 return;
4250 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004251 if (mNativeClass == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252
Derek Sollenberger293c3602010-06-04 10:44:48 -04004253 boolean animateZoom = mZoomManager.isFixedLengthAnimationInProgress();
Grace Klobac2242f22010-03-05 14:00:26 -08004254 boolean animateScroll = ((!mScroller.isFinished()
Cary Clark25415e22009-10-12 13:41:28 -04004255 || mVelocityTracker != null)
4256 && (mTouchMode != TOUCH_DRAG_MODE ||
Grace Klobac2242f22010-03-05 14:00:26 -08004257 mHeldMotionless != MOTIONLESS_TRUE))
4258 || mDeferTouchMode == TOUCH_DRAG_MODE;
Cary Clark25415e22009-10-12 13:41:28 -04004259 if (mTouchMode == TOUCH_DRAG_MODE) {
4260 if (mHeldMotionless == MOTIONLESS_PENDING) {
4261 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
4262 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
4263 mHeldMotionless = MOTIONLESS_FALSE;
4264 }
4265 if (mHeldMotionless == MOTIONLESS_FALSE) {
4266 mPrivateHandler.sendMessageDelayed(mPrivateHandler
4267 .obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
4268 mHeldMotionless = MOTIONLESS_PENDING;
4269 }
4270 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004271 if (animateZoom) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04004272 mZoomManager.animateZoom(canvas);
Romain Guyd6cf4772011-03-04 17:10:54 -08004273 } else if (!canvas.isHardwareAccelerated()) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04004274 canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004275 }
4276
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004277 boolean UIAnimationsRunning = false;
4278 // Currently for each draw we compute the animation values;
4279 // We may in the future decide to do that independently.
4280 if (mNativeClass != 0 && nativeEvaluateLayersAnimations()) {
4281 UIAnimationsRunning = true;
4282 // If we have unfinished (or unstarted) animations,
Nicolas Roardf2674c12011-03-16 16:04:57 -07004283 // we ask for a repaint. We only need to do this in software
4284 // rendering (with hardware rendering we already have a different
4285 // method of requesting a repaint)
4286 if (!canvas.isHardwareAccelerated())
4287 invalidate();
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004288 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004289
Cary Clark2ec30692010-02-23 10:50:38 -05004290 // decide which adornments to draw
4291 int extras = DRAW_EXTRAS_NONE;
4292 if (mFindIsUp) {
Cary Clark924af702010-06-04 16:37:43 -04004293 extras = DRAW_EXTRAS_FIND;
4294 } else if (mSelectingText) {
4295 extras = DRAW_EXTRAS_SELECTION;
4296 nativeSetSelectionPointer(mDrawSelectionPointer,
4297 mZoomManager.getInvScale(),
4298 mSelectX, mSelectY - getTitleHeight());
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004299 } else if (drawCursorRing) {
Cary Clark2ec30692010-02-23 10:50:38 -05004300 extras = DRAW_EXTRAS_CURSOR_RING;
4301 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05004302 if (DebugFlags.WEB_VIEW) {
4303 Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp
4304 + " mSelectingText=" + mSelectingText
4305 + " nativePageShouldHandleShiftAndArrows()="
4306 + nativePageShouldHandleShiftAndArrows()
4307 + " animateZoom=" + animateZoom
4308 + " extras=" + extras);
4309 }
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004310
4311 if (canvas.isHardwareAccelerated()) {
Chet Haase91fc3cf2011-01-28 00:20:04 -08004312 int functor = nativeGetDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
Romain Guycabfcc12011-03-07 18:06:46 -08004313 mGLViewportEmpty ? null : mViewRectViewport, getScale(), extras);
Chet Haasedaf98e92011-01-10 14:10:36 -08004314 ((HardwareCanvas) canvas).callDrawGLFunction(functor);
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004315 } else {
4316 DrawFilter df = null;
4317 if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) {
4318 df = mZoomFilter;
4319 } else if (animateScroll) {
4320 df = mScrollFilter;
4321 }
4322 canvas.setDrawFilter(df);
Patrick Scott85b69e02011-01-25 15:19:45 -05004323 // XXX: Revisit splitting content. Right now it causes a
4324 // synchronization problem with layers.
4325 int content = nativeDraw(canvas, color, extras, false);
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004326 canvas.setDrawFilter(null);
4327 if (content != 0) {
4328 mWebViewCore.sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0);
4329 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004330 }
Cary Clark2ec30692010-02-23 10:50:38 -05004331
4332 if (extras == DRAW_EXTRAS_CURSOR_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004333 if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
4334 mTouchMode = TOUCH_SHORTPRESS_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004336 }
Cary Clark5da9aeb2009-10-06 17:40:53 -04004337 if (mFocusSizeChanged) {
4338 mFocusSizeChanged = false;
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004339 // If we are zooming, this will get handled above, when the zoom
4340 // finishes. We also do not need to do this unless the WebTextView
4341 // is showing.
4342 if (!animateZoom && inEditingMode()) {
Leon Scroggins63356742010-12-15 17:37:08 -05004343 didUpdateWebTextViewDimensions(ANYWHERE);
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004344 }
Cary Clark5da9aeb2009-10-06 17:40:53 -04004345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004346 }
4347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004348 // draw history
4349 private boolean mDrawHistory = false;
4350 private Picture mHistoryPicture = null;
4351 private int mHistoryWidth = 0;
4352 private int mHistoryHeight = 0;
4353
4354 // Only check the flag, can be called from WebCore thread
4355 boolean drawHistory() {
4356 return mDrawHistory;
4357 }
4358
Derek Sollenberger341e22f2010-06-02 12:34:34 -04004359 int getHistoryPictureWidth() {
4360 return (mHistoryPicture != null) ? mHistoryPicture.getWidth() : 0;
4361 }
4362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004363 // Should only be called in UI thread
4364 void switchOutDrawHistory() {
4365 if (null == mWebViewCore) return; // CallbackProxy may trigger this
Grace Kloba8abd50b2010-07-08 15:02:14 -07004366 if (mDrawHistory && (getProgress() == 100 || nativeHasContent())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004367 mDrawHistory = false;
Patrick Scottda9a22b2010-04-08 08:32:52 -04004368 mHistoryPicture = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004369 invalidate();
4370 int oldScrollX = mScrollX;
4371 int oldScrollY = mScrollY;
4372 mScrollX = pinLocX(mScrollX);
4373 mScrollY = pinLocY(mScrollY);
4374 if (oldScrollX != mScrollX || oldScrollY != mScrollY) {
Grace Kloba327dce92010-04-02 15:38:55 -07004375 onScrollChanged(mScrollX, mScrollY, oldScrollX, oldScrollY);
4376 } else {
4377 sendOurVisibleRect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004379 }
4380 }
4381
Cary Clarkd6982c92009-05-29 11:02:22 -04004382 WebViewCore.CursorData cursorData() {
4383 WebViewCore.CursorData result = new WebViewCore.CursorData();
4384 result.mMoveGeneration = nativeMoveGeneration();
4385 result.mFrame = nativeCursorFramePointer();
Cary Clarked56eda2009-06-18 09:48:47 -04004386 Point position = nativeCursorPosition();
4387 result.mX = position.x;
4388 result.mY = position.y;
Cary Clarkd6982c92009-05-29 11:02:22 -04004389 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004390 }
Cary Clarkd6982c92009-05-29 11:02:22 -04004391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004392 /**
4393 * Delete text from start to end in the focused textfield. If there is no
Cary Clarkd6982c92009-05-29 11:02:22 -04004394 * focus, or if start == end, silently fail. If start and end are out of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004395 * order, swap them.
4396 * @param start Beginning of selection to delete.
4397 * @param end End of selection to delete.
4398 */
4399 /* package */ void deleteSelection(int start, int end) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004400 mTextGeneration++;
Leon Scroggins6679f2f2009-08-12 18:48:10 -04004401 WebViewCore.TextSelectionData data
4402 = new WebViewCore.TextSelectionData(start, end);
4403 mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
4404 data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004405 }
4406
4407 /**
4408 * Set the selection to (start, end) in the focused textfield. If start and
4409 * end are out of order, swap them.
4410 * @param start Beginning of selection.
4411 * @param end End of selection.
4412 */
4413 /* package */ void setSelection(int start, int end) {
Leon Scrogginsacea08d2010-05-27 15:09:32 -04004414 if (mWebViewCore != null) {
4415 mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end);
4416 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004417 }
4418
Derek Sollenberger7cabb032010-01-21 10:37:38 -05004419 @Override
4420 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
4421 InputConnection connection = super.onCreateInputConnection(outAttrs);
4422 outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_FULLSCREEN;
4423 return connection;
4424 }
4425
Leon Scroggins04e0a102010-01-08 16:19:27 -05004426 /**
4427 * Called in response to a message from webkit telling us that the soft
4428 * keyboard should be launched.
4429 */
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004430 private void displaySoftKeyboard(boolean isTextView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004431 InputMethodManager imm = (InputMethodManager)
4432 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004433
Shimeng (Simon) Wang7924a4a2010-09-14 13:20:46 -07004434 // bring it back to the default level scale so that user can enter text
Shimeng (Simon) Wang6c09ef02010-09-09 13:56:34 -07004435 boolean zoom = mZoomManager.getScale() < mZoomManager.getDefaultScale();
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004436 if (zoom) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04004437 mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
Shimeng (Simon) Wang6c09ef02010-09-09 13:56:34 -07004438 mZoomManager.setZoomScale(mZoomManager.getDefaultScale(), false);
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004439 }
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004440 if (isTextView) {
Leon Scroggins04e0a102010-01-08 16:19:27 -05004441 rebuildWebTextView();
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004442 if (inEditingMode()) {
Leon Scrogginsd69b7012011-03-09 16:18:28 -05004443 imm.showSoftInput(mWebTextView, 0, mWebTextView.getResultReceiver());
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004444 if (zoom) {
Leon Scroggins63356742010-12-15 17:37:08 -05004445 didUpdateWebTextViewDimensions(INTERSECTS_SCREEN);
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004446 }
4447 return;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07004448 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004449 }
Leon Scroggins200c13d2010-05-14 15:35:42 -04004450 // Used by plugins and contentEditable.
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004451 // Also used if the navigation cache is out of date, and
4452 // does not recognize that a textfield is in focus. In that
4453 // case, use WebView as the targeted view.
4454 // see http://b/issue?id=2457459
4455 imm.showSoftInput(this, 0);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004456 }
4457
4458 // Called by WebKit to instruct the UI to hide the keyboard
4459 private void hideSoftKeyboard() {
Leon Scrogginsf2e17a82010-09-24 15:58:50 -04004460 InputMethodManager imm = InputMethodManager.peekInstance();
4461 if (imm != null && (imm.isActive(this)
4462 || (inEditingMode() && imm.isActive(mWebTextView)))) {
Leon Scroggins III71d17e42010-09-02 12:53:08 -04004463 imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
4464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004465 }
4466
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004467 /*
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004468 * This method checks the current focus and cursor and potentially rebuilds
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004469 * mWebTextView to have the appropriate properties, such as password,
4470 * multiline, and what text it contains. It also removes it if necessary.
4471 */
Leon Scroggins01058282009-07-30 16:33:56 -04004472 /* package */ void rebuildWebTextView() {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004473 // If the WebView does not have focus, do nothing until it gains focus.
Grace Kloba04b28682009-09-14 14:38:37 -07004474 if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004475 return;
4476 }
4477 boolean alreadyThere = inEditingMode();
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004478 // inEditingMode can only return true if mWebTextView is non-null,
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004479 // so we can safely call remove() if (alreadyThere)
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004480 if (0 == mNativeClass || !nativeFocusCandidateIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004481 if (alreadyThere) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004482 mWebTextView.remove();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004483 }
4484 return;
4485 }
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004486 // At this point, we know we have found an input field, so go ahead
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004487 // and create the WebTextView if necessary.
4488 if (mWebTextView == null) {
Ben Murdochdb8d19c2010-10-29 11:44:17 +01004489 mWebTextView = new WebTextView(mContext, WebView.this, mAutoFillData.getQueryId());
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004490 // Initialize our generation number.
4491 mTextGeneration = 0;
4492 }
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004493 mWebTextView.updateTextSize();
Cary Clark3524be92009-06-22 13:09:11 -04004494 Rect visibleRect = new Rect();
4495 calcOurContentVisibleRect(visibleRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004496 // Note that sendOurVisibleRect calls viewToContent, so the coordinates
4497 // should be in content coordinates.
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004498 Rect bounds = nativeFocusCandidateNodeBounds();
Leon Scroggins6be3bf22009-12-08 13:43:47 -05004499 Rect vBox = contentToViewRect(bounds);
4500 mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
Cary Clarkd6982c92009-05-29 11:02:22 -04004501 if (!Rect.intersects(bounds, visibleRect)) {
Leon Scroggins3be1ffa2011-01-19 12:49:57 -05004502 revealSelection();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004503 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004504 String text = nativeFocusCandidateText();
4505 int nodePointer = nativeFocusCandidatePointer();
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004506 if (alreadyThere && mWebTextView.isSameTextField(nodePointer)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004507 // It is possible that we have the same textfield, but it has moved,
4508 // i.e. In the case of opening/closing the screen.
4509 // In that case, we need to set the dimensions, but not the other
4510 // aspects.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004511 // If the text has been changed by webkit, update it. However, if
4512 // there has been more UI text input, ignore it. We will receive
4513 // another update when that text is recognized.
Leon Scroggins6be3bf22009-12-08 13:43:47 -05004514 if (text != null && !text.equals(mWebTextView.getText().toString())
Cary Clarkd6982c92009-05-29 11:02:22 -04004515 && nativeTextGeneration() == mTextGeneration) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004516 mWebTextView.setTextAndKeepSelection(text);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004517 }
4518 } else {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004519 mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
4520 Gravity.RIGHT : Gravity.NO_GRAVITY);
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004521 // This needs to be called before setType, which may call
4522 // requestFormData, and it needs to have the correct nodePointer.
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004523 mWebTextView.setNodePointer(nodePointer);
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004524 mWebTextView.setType(nativeFocusCandidateType());
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004525 updateWebTextViewPadding();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004526 if (null == text) {
Cary Clark243ea062009-06-25 10:49:32 -04004527 if (DebugFlags.WEB_VIEW) {
4528 Log.v(LOGTAG, "rebuildWebTextView null == text");
4529 }
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04004530 text = "";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004531 }
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04004532 mWebTextView.setTextAndKeepSelection(text);
Leon Scroggins5c84bf02010-02-09 17:03:44 -05004533 InputMethodManager imm = InputMethodManager.peekInstance();
4534 if (imm != null && imm.isActive(mWebTextView)) {
4535 imm.restartInput(mWebTextView);
4536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004537 }
Leon Scrogginsf8ca2d72010-10-21 17:14:42 -04004538 if (isFocused()) {
4539 mWebTextView.requestFocus();
4540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004541 }
4542
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004543 /**
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004544 * Update the padding of mWebTextView based on the native textfield/textarea
4545 */
4546 void updateWebTextViewPadding() {
4547 Rect paddingRect = nativeFocusCandidatePaddingRect();
4548 if (paddingRect != null) {
4549 // Use contentToViewDimension since these are the dimensions of
4550 // the padding.
4551 mWebTextView.setPadding(
4552 contentToViewDimension(paddingRect.left),
4553 contentToViewDimension(paddingRect.top),
4554 contentToViewDimension(paddingRect.right),
4555 contentToViewDimension(paddingRect.bottom));
4556 }
4557 }
4558
4559 /**
Leon Scroggins200c13d2010-05-14 15:35:42 -04004560 * Tell webkit to put the cursor on screen.
4561 */
4562 /* package */ void revealSelection() {
4563 if (mWebViewCore != null) {
4564 mWebViewCore.sendMessage(EventHub.REVEAL_SELECTION);
4565 }
4566 }
4567
4568 /**
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004569 * Called by WebTextView to find saved form data associated with the
4570 * textfield
4571 * @param name Name of the textfield.
4572 * @param nodePointer Pointer to the node of the textfield, so it can be
4573 * compared to the currently focused textfield when the data is
4574 * retrieved.
Ben Murdoch62275a42010-09-07 11:27:28 +01004575 * @param autoFillable true if WebKit has determined this field is part of
4576 * a form that can be auto filled.
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004577 * @param autoComplete true if the attribute "autocomplete" is set to true
4578 * on the textfield.
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004579 */
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004580 /* package */ void requestFormData(String name, int nodePointer,
4581 boolean autoFillable, boolean autoComplete) {
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004582 if (mWebViewCore.getSettings().getSaveFormData()) {
4583 Message update = mPrivateHandler.obtainMessage(REQUEST_FORM_DATA);
4584 update.arg1 = nodePointer;
4585 RequestFormData updater = new RequestFormData(name, getUrl(),
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004586 update, autoFillable, autoComplete);
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004587 Thread t = new Thread(updater);
4588 t.start();
4589 }
4590 }
4591
Leon Scroggins3a503392010-01-06 17:04:38 -05004592 /**
4593 * Pass a message to find out the <label> associated with the <input>
4594 * identified by nodePointer
4595 * @param framePointer Pointer to the frame containing the <input> node
4596 * @param nodePointer Pointer to the node for which a <label> is desired.
4597 */
4598 /* package */ void requestLabel(int framePointer, int nodePointer) {
4599 mWebViewCore.sendMessage(EventHub.REQUEST_LABEL, framePointer,
4600 nodePointer);
4601 }
4602
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004603 /*
4604 * This class requests an Adapter for the WebTextView which shows past
4605 * entries stored in the database. It is a Runnable so that it can be done
4606 * in its own thread, without slowing down the UI.
4607 */
4608 private class RequestFormData implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609 private String mName;
4610 private String mUrl;
4611 private Message mUpdateMessage;
Ben Murdoch62275a42010-09-07 11:27:28 +01004612 private boolean mAutoFillable;
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004613 private boolean mAutoComplete;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004614
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004615 public RequestFormData(String name, String url, Message msg,
4616 boolean autoFillable, boolean autoComplete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004617 mName = name;
4618 mUrl = url;
4619 mUpdateMessage = msg;
Ben Murdoch62275a42010-09-07 11:27:28 +01004620 mAutoFillable = autoFillable;
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004621 mAutoComplete = autoComplete;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004622 }
4623
4624 public void run() {
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004625 ArrayList<String> pastEntries = new ArrayList<String>();
Ben Murdoch62275a42010-09-07 11:27:28 +01004626
4627 if (mAutoFillable) {
4628 // Note that code inside the adapter click handler in WebTextView depends
4629 // on the AutoFill item being at the top of the drop down list. If you change
4630 // the order, make sure to do it there too!
Ben Murdoch57914382010-11-16 11:50:39 +00004631 WebSettings settings = getSettings();
4632 if (settings != null && settings.getAutoFillProfile() != null) {
4633 pastEntries.add(getResources().getText(
4634 com.android.internal.R.string.autofill_this_form).toString() +
4635 " " +
4636 mAutoFillData.getPreviewString());
4637 mWebTextView.setAutoFillProfileIsSet(true);
4638 } else {
4639 // There is no autofill profile set up yet, so add an option that
4640 // will invite the user to set their profile up.
4641 pastEntries.add(getResources().getText(
4642 com.android.internal.R.string.setup_autofill).toString());
4643 mWebTextView.setAutoFillProfileIsSet(false);
4644 }
Ben Murdoch62275a42010-09-07 11:27:28 +01004645 }
4646
Leon Scrogginsae0238c2011-01-05 15:12:55 -05004647 if (mAutoComplete) {
4648 pastEntries.addAll(mDatabase.getFormData(mUrl, mName));
4649 }
Ben Murdoch62275a42010-09-07 11:27:28 +01004650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004651 if (pastEntries.size() > 0) {
4652 AutoCompleteAdapter adapter = new
4653 AutoCompleteAdapter(mContext, pastEntries);
Cary Clarkded054c2009-06-15 10:26:08 -04004654 mUpdateMessage.obj = adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004655 mUpdateMessage.sendToTarget();
4656 }
4657 }
4658 }
4659
Grace Kloba8ae1b412009-11-23 10:35:34 -08004660 /**
4661 * Dump the display tree to "/sdcard/displayTree.txt"
4662 *
4663 * @hide debug only
4664 */
4665 public void dumpDisplayTree() {
4666 nativeDumpDisplayTree(getUrl());
4667 }
4668
4669 /**
4670 * Dump the dom tree to adb shell if "toFile" is False, otherwise dump it to
4671 * "/sdcard/domTree.txt"
4672 *
4673 * @hide debug only
4674 */
4675 public void dumpDomTree(boolean toFile) {
4676 mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE, toFile ? 1 : 0, 0);
4677 }
4678
4679 /**
4680 * Dump the render tree to adb shell if "toFile" is False, otherwise dump it
4681 * to "/sdcard/renderTree.txt"
4682 *
4683 * @hide debug only
4684 */
4685 public void dumpRenderTree(boolean toFile) {
4686 mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE, toFile ? 1 : 0, 0);
4687 }
4688
Andrei Popescu5e7bb0a2010-02-01 22:32:16 +00004689 /**
Steve Block68dede32010-08-04 10:28:46 +01004690 * Called by DRT on UI thread, need to proxy to WebCore thread.
4691 *
4692 * @hide debug only
4693 */
4694 public void useMockDeviceOrientation() {
4695 mWebViewCore.sendMessage(EventHub.USE_MOCK_DEVICE_ORIENTATION);
4696 }
4697
4698 /**
4699 * Called by DRT on WebCore thread.
4700 *
4701 * @hide debug only
4702 */
4703 public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
4704 boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
Steve Blockf4a705f2010-08-11 13:08:24 +01004705 mWebViewCore.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta,
4706 canProvideGamma, gamma);
Steve Block68dede32010-08-04 10:28:46 +01004707 }
4708
4709 /**
Andrei Popescu5e7bb0a2010-02-01 22:32:16 +00004710 * Dump the V8 counters to standard output.
4711 * Note that you need a build with V8 and WEBCORE_INSTRUMENTATION set to
4712 * true. Otherwise, this will do nothing.
4713 *
4714 * @hide debug only
4715 */
4716 public void dumpV8Counters() {
4717 mWebViewCore.sendMessage(EventHub.DUMP_V8COUNTERS);
4718 }
4719
Leon Scrogginse3225672009-06-03 15:53:13 -04004720 // This is used to determine long press with the center key. Does not
4721 // affect long press with the trackball/touch.
4722 private boolean mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004723
4724 @Override
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04004725 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
4726 // send complex characters to webkit for use by JS and plugins
4727 if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getCharacters() != null) {
4728 // pass the key to DOM
4729 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
4730 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
4731 // return true as DOM handles the key
4732 return true;
4733 }
4734 return false;
4735 }
4736
Cary Clarkaa86ac82010-12-28 11:30:18 -05004737 private boolean isEnterActionKey(int keyCode) {
4738 return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
4739 || keyCode == KeyEvent.KEYCODE_ENTER
4740 || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
4741 }
4742
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04004743 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004744 public boolean onKeyDown(int keyCode, KeyEvent event) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04004745 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004746 Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
Cary Clarkaa86ac82010-12-28 11:30:18 -05004747 + "keyCode=" + keyCode
Cary Clark215b72c2009-06-26 14:38:43 -04004748 + ", " + event + ", unicode=" + event.getUnicodeChar());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004749 }
4750
Cary Clark122da932010-12-28 15:58:08 -05004751 // don't implement accelerator keys here; defer to host application
4752 if (event.isCtrlPressed()) {
4753 return false;
4754 }
4755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004756 if (mNativeClass == 0) {
4757 return false;
4758 }
4759
4760 // do this hack up front, so it always works, regardless of touch-mode
4761 if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) {
4762 mAutoRedraw = !mAutoRedraw;
4763 if (mAutoRedraw) {
4764 invalidate();
4765 }
4766 return true;
4767 }
4768
4769 // Bubble up the key event if
4770 // 1. it is a system key; or
Grace Kloba04b28682009-09-14 14:38:37 -07004771 // 2. the host application wants to handle it;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004772 if (event.isSystem()
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08004773 || mCallbackProxy.uiOverrideKeyEvent(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004774 return false;
4775 }
4776
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08004777 // accessibility support
Svetoslav Ganov12bed782011-01-03 14:14:50 -08004778 if (accessibilityScriptInjected()) {
Svetoslav Ganovb01c3d22011-01-11 14:19:17 -08004779 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
4780 // if an accessibility script is injected we delegate to it the key handling.
4781 // this script is a screen reader which is a fully fledged solution for blind
4782 // users to navigate in and interact with web pages.
4783 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
4784 return true;
4785 } else {
4786 // Clean up if accessibility was disabled after loading the current URL.
4787 mAccessibilityScriptInjected = false;
4788 }
4789 } else if (mAccessibilityInjector != null) {
4790 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
4791 if (mAccessibilityInjector.onKeyEvent(event)) {
4792 // if an accessibility injector is present (no JavaScript enabled or the site
4793 // opts out injecting our JavaScript screen reader) we let it decide whether
4794 // to act on and consume the event.
4795 return true;
4796 }
4797 } else {
4798 // Clean up if accessibility was disabled after loading the current URL.
4799 mAccessibilityInjector = null;
4800 }
Svetoslav Ganov12bed782011-01-03 14:14:50 -08004801 }
4802
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08004803 if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
Cary Clarka3ee56f2011-01-10 11:20:56 -05004804 if (event.hasNoModifiers()) {
4805 pageUp(false);
4806 return true;
4807 } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
4808 pageUp(true);
4809 return true;
4810 }
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08004811 }
4812
4813 if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
Cary Clarka3ee56f2011-01-10 11:20:56 -05004814 if (event.hasNoModifiers()) {
4815 pageDown(false);
4816 return true;
4817 } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
4818 pageDown(true);
4819 return true;
4820 }
4821 }
4822
4823 if (keyCode == KeyEvent.KEYCODE_MOVE_HOME && event.hasNoModifiers()) {
4824 pageUp(true);
4825 return true;
4826 }
4827
4828 if (keyCode == KeyEvent.KEYCODE_MOVE_END && event.hasNoModifiers()) {
4829 pageDown(true);
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08004830 return true;
4831 }
4832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004833 if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
4834 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004835 switchOutDrawHistory();
Svetoslav Ganov12bed782011-01-03 14:14:50 -08004836 if (nativePageShouldHandleShiftAndArrows()) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07004837 letPageHandleNavKey(keyCode, event.getEventTime(), true, event.getMetaState());
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05004838 return true;
4839 }
Cary Clarka3ee56f2011-01-10 11:20:56 -05004840 if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
4841 switch (keyCode) {
4842 case KeyEvent.KEYCODE_DPAD_UP:
4843 pageUp(true);
4844 return true;
4845 case KeyEvent.KEYCODE_DPAD_DOWN:
4846 pageDown(true);
4847 return true;
4848 case KeyEvent.KEYCODE_DPAD_LEFT:
4849 nativeClearCursor(); // start next trackball movement from page edge
4850 return pinScrollTo(0, mScrollY, true, 0);
4851 case KeyEvent.KEYCODE_DPAD_RIGHT:
4852 nativeClearCursor(); // start next trackball movement from page edge
4853 return pinScrollTo(mContentWidth, mScrollY, true, 0);
4854 }
4855 }
Cary Clark924af702010-06-04 16:37:43 -04004856 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04004857 int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
4858 ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
4859 int yRate = keyCode == KeyEvent.KEYCODE_DPAD_UP ?
4860 -1 : keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : 0;
4861 int multiplier = event.getRepeatCount() + 1;
4862 moveSelection(xRate * multiplier, yRate * multiplier);
4863 return true;
4864 }
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05004865 if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004866 playSoundEffect(keyCodeToSoundsEffect(keyCode));
4867 return true;
4868 }
4869 // Bubble up the key event as WebView doesn't handle it
4870 return false;
4871 }
4872
Cary Clark1477b8f2011-02-09 19:33:00 -05004873 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004874 switchOutDrawHistory();
Cary Clarkddbda002011-01-06 13:40:15 -05004875 boolean wantsKeyEvents = nativeCursorNodePointer() == 0
4876 || nativeCursorWantsKeyEvents();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004877 if (event.getRepeatCount() == 0) {
Cary Clark924af702010-06-04 16:37:43 -04004878 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04004879 return true; // discard press if copy in progress
4880 }
Leon Scrogginse3225672009-06-03 15:53:13 -04004881 mGotCenterDown = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004882 mPrivateHandler.sendMessageDelayed(mPrivateHandler
Leon Scrogginse3225672009-06-03 15:53:13 -04004883 .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004884 // Already checked mNativeClass, so we do not need to check it
4885 // again.
4886 nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
Cary Clarkddbda002011-01-06 13:40:15 -05004887 if (!wantsKeyEvents) return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004888 }
4889 // Bubble up the key event as WebView doesn't handle it
Cary Clarkddbda002011-01-06 13:40:15 -05004890 if (!wantsKeyEvents) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004891 }
4892
4893 if (getSettings().getNavDump()) {
4894 switch (keyCode) {
4895 case KeyEvent.KEYCODE_4:
Grace Kloba8ae1b412009-11-23 10:35:34 -08004896 dumpDisplayTree();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004897 break;
4898 case KeyEvent.KEYCODE_5:
4899 case KeyEvent.KEYCODE_6:
Grace Kloba8ae1b412009-11-23 10:35:34 -08004900 dumpDomTree(keyCode == KeyEvent.KEYCODE_5);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004901 break;
4902 case KeyEvent.KEYCODE_7:
4903 case KeyEvent.KEYCODE_8:
Grace Kloba8ae1b412009-11-23 10:35:34 -08004904 dumpRenderTree(keyCode == KeyEvent.KEYCODE_7);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004905 break;
4906 case KeyEvent.KEYCODE_9:
4907 nativeInstrumentReport();
4908 return true;
4909 }
4910 }
4911
Derek Sollenberger718d69f2009-10-19 15:56:43 -04004912 if (nativeCursorIsTextInput()) {
Leon Scroggins1cc24202009-06-16 10:10:28 -04004913 // This message will put the node in focus, for the DOM's notion
Leon Scrogginsb45a2632011-01-12 14:11:24 -05004914 // of focus.
4915 mWebViewCore.sendMessage(EventHub.FAKE_CLICK, nativeCursorFramePointer(),
Leon Scroggins01058282009-07-30 16:33:56 -04004916 nativeCursorNodePointer());
Leon Scroggins0658e8f2009-06-26 14:09:09 -04004917 // This will bring up the WebTextView and put it in focus, for
4918 // our view system's notion of focus
4919 rebuildWebTextView();
4920 // Now we need to pass the event to it
Leon Scrogginsc66f68a2009-10-02 15:12:30 -04004921 if (inEditingMode()) {
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04004922 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04004923 return mWebTextView.dispatchKeyEvent(event);
Leon Scrogginsc66f68a2009-10-02 15:12:30 -04004924 }
Leon Scroggins40981262009-07-01 10:57:47 -04004925 } else if (nativeHasFocusNode()) {
4926 // In this case, the cursor is not on a text input, but the focus
4927 // might be. Check it, and if so, hand over to the WebTextView.
4928 rebuildWebTextView();
4929 if (inEditingMode()) {
Leon Scroggins0aa341f2010-02-24 16:49:35 -05004930 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04004931 return mWebTextView.dispatchKeyEvent(event);
Leon Scroggins40981262009-07-01 10:57:47 -04004932 }
Cary Clark19436562009-06-04 16:25:07 -04004933 }
4934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004935 // TODO: should we pass all the keys to DOM or check the meta tag
Cary Clark2f1d60c2009-06-03 08:05:53 -04004936 if (nativeCursorWantsKeyEvents() || true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004937 // pass the key to DOM
4938 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
4939 // return true as DOM handles the key
4940 return true;
4941 }
4942
4943 // Bubble up the key event as WebView doesn't handle it
4944 return false;
4945 }
4946
4947 @Override
4948 public boolean onKeyUp(int keyCode, KeyEvent event) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04004949 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004950 Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
Cary Clark215b72c2009-06-26 14:38:43 -04004951 + ", " + event + ", unicode=" + event.getUnicodeChar());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004952 }
4953
4954 if (mNativeClass == 0) {
4955 return false;
4956 }
4957
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004958 // special CALL handling when cursor node's href is "tel:XXX"
Cary Clarkd6982c92009-05-29 11:02:22 -04004959 if (keyCode == KeyEvent.KEYCODE_CALL && nativeHasCursorNode()) {
4960 String text = nativeCursorText();
4961 if (!nativeCursorIsTextInput() && text != null
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004962 && text.startsWith(SCHEME_TEL)) {
4963 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
4964 getContext().startActivity(intent);
4965 return true;
4966 }
4967 }
4968
4969 // Bubble up the key event if
4970 // 1. it is a system key; or
4971 // 2. the host application wants to handle it;
Svetoslav Ganovda355512010-05-12 22:04:44 -07004972 if (event.isSystem()
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08004973 || mCallbackProxy.uiOverrideKeyEvent(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004974 return false;
4975 }
4976
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08004977 // accessibility support
Svetoslav Ganov12bed782011-01-03 14:14:50 -08004978 if (accessibilityScriptInjected()) {
Svetoslav Ganovb01c3d22011-01-11 14:19:17 -08004979 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
4980 // if an accessibility script is injected we delegate to it the key handling.
4981 // this script is a screen reader which is a fully fledged solution for blind
4982 // users to navigate in and interact with web pages.
4983 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
4984 return true;
4985 } else {
4986 // Clean up if accessibility was disabled after loading the current URL.
4987 mAccessibilityScriptInjected = false;
4988 }
4989 } else if (mAccessibilityInjector != null) {
4990 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
4991 if (mAccessibilityInjector.onKeyEvent(event)) {
4992 // if an accessibility injector is present (no JavaScript enabled or the site
4993 // opts out injecting our JavaScript screen reader) we let it decide whether to
4994 // act on and consume the event.
4995 return true;
4996 }
4997 } else {
4998 // Clean up if accessibility was disabled after loading the current URL.
4999 mAccessibilityInjector = null;
5000 }
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005001 }
5002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005003 if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
5004 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005005 if (nativePageShouldHandleShiftAndArrows()) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07005006 letPageHandleNavKey(keyCode, event.getEventTime(), false, event.getMetaState());
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05005007 return true;
5008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005009 // always handle the navigation keys in the UI thread
5010 // Bubble up the key event as WebView doesn't handle it
5011 return false;
5012 }
5013
Cary Clarkaa86ac82010-12-28 11:30:18 -05005014 if (isEnterActionKey(keyCode)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005015 // remove the long press message first
Leon Scrogginse3225672009-06-03 15:53:13 -04005016 mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
5017 mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005018
Cary Clark924af702010-06-04 16:37:43 -04005019 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04005020 if (mExtendSelection) {
Cary Clark924af702010-06-04 16:37:43 -04005021 copySelection();
5022 selectionDone();
Cary Clarkc05af372009-10-16 10:52:27 -04005023 } else {
5024 mExtendSelection = true;
Cary Clark924af702010-06-04 16:37:43 -04005025 nativeSetExtendSelection();
Cary Clark09e383c2009-10-26 16:43:58 -04005026 invalidate(); // draw the i-beam instead of the arrow
Cary Clarkc05af372009-10-16 10:52:27 -04005027 }
5028 return true; // discard press if copy in progress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005029 }
Grace Klobadd817492009-09-14 10:17:06 -07005030
5031 // perform the single click
5032 Rect visibleRect = sendOurVisibleRect();
5033 // Note that sendOurVisibleRect calls viewToContent, so the
5034 // coordinates should be in content coordinates.
5035 if (!nativeCursorIntersects(visibleRect)) {
5036 return false;
5037 }
Grace Klobadd817492009-09-14 10:17:06 -07005038 WebViewCore.CursorData data = cursorData();
5039 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
5040 playSoundEffect(SoundEffectConstants.CLICK);
Leon Scroggins1d60c5c2009-10-23 10:16:51 -04005041 if (nativeCursorIsTextInput()) {
5042 rebuildWebTextView();
Leon Scroggins1d96ca02009-10-23 11:49:03 -04005043 centerKeyPressOnTextField();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005044 if (inEditingMode()) {
5045 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005046 }
Leon Scroggins1d60c5c2009-10-23 10:16:51 -04005047 return true;
5048 }
Leon Scroggins2aed7762010-08-13 17:11:42 -04005049 clearTextEntry();
Cary Clarke60cb7f2010-08-25 14:56:00 -04005050 nativeShowCursorTimed();
Cary Clarkddbda002011-01-06 13:40:15 -05005051 if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
5052 return true;
5053 }
5054 if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) {
Grace Klobadd817492009-09-14 10:17:06 -07005055 mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
5056 nativeCursorNodePointer());
Cary Clarkddbda002011-01-06 13:40:15 -05005057 return true;
Grace Klobadd817492009-09-14 10:17:06 -07005058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005059 }
5060
5061 // TODO: should we pass all the keys to DOM or check the meta tag
Cary Clark2f1d60c2009-06-03 08:05:53 -04005062 if (nativeCursorWantsKeyEvents() || true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005063 // pass the key to DOM
5064 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
5065 // return true as DOM handles the key
5066 return true;
5067 }
5068
5069 // Bubble up the key event as WebView doesn't handle it
5070 return false;
5071 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005072
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005073 /*
Cary Clark03f00222011-02-10 19:37:15 -05005074 * Enter selecting text mode, and see if CAB should be shown.
5075 * Returns true if the WebView is now in
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005076 * selecting text mode (including if it was already in that mode, and this
5077 * method did nothing).
5078 */
Cary Clark03f00222011-02-10 19:37:15 -05005079 private boolean setUpSelect(boolean selectWord, int x, int y) {
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005080 if (0 == mNativeClass) return false; // client isn't initialized
5081 if (inFullScreenMode()) return false;
5082 if (mSelectingText) return true;
Cary Clark03f00222011-02-10 19:37:15 -05005083 nativeResetSelection();
5084 if (selectWord && !nativeWordSelection(x, y)) {
5085 selectionDone();
5086 return false;
5087 }
5088 mSelectCallback = new SelectActionModeCallback();
5089 mSelectCallback.setWebView(this);
5090 if (startActionMode(mSelectCallback) == null) {
5091 // There is no ActionMode, so do not allow the user to modify a
5092 // selection.
5093 selectionDone();
5094 return false;
5095 }
Cary Clark09e383c2009-10-26 16:43:58 -04005096 mExtendSelection = false;
Cary Clark924af702010-06-04 16:37:43 -04005097 mSelectingText = mDrawSelectionPointer = true;
5098 // don't let the picture change during text selection
5099 WebViewCore.pauseUpdatePicture(mWebViewCore);
Cary Clark09e383c2009-10-26 16:43:58 -04005100 if (nativeHasCursorNode()) {
5101 Rect rect = nativeCursorNodeBounds();
5102 mSelectX = contentToViewX(rect.left);
5103 mSelectY = contentToViewY(rect.top);
5104 } else if (mLastTouchY > getVisibleTitleHeight()) {
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08005105 mSelectX = mScrollX + mLastTouchX;
5106 mSelectY = mScrollY + mLastTouchY;
Cary Clark09e383c2009-10-26 16:43:58 -04005107 } else {
5108 mSelectX = mScrollX + getViewWidth() / 2;
5109 mSelectY = mScrollY + getViewHeightWithTitle() / 2;
5110 }
5111 nativeHideCursor();
Cary Clarkb9aaa772011-01-07 16:14:54 -05005112 mMinAutoScrollX = 0;
5113 mMaxAutoScrollX = getViewWidth();
5114 mMinAutoScrollY = 0;
5115 mMaxAutoScrollY = getViewHeightWithTitle();
5116 mScrollingLayer = nativeScrollableLayer(viewToContentX(mSelectX),
5117 viewToContentY(mSelectY), mScrollingLayerRect,
5118 mScrollingLayerBounds);
5119 if (mScrollingLayer != 0) {
5120 if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
5121 mMinAutoScrollX = Math.max(mMinAutoScrollX,
5122 contentToViewX(mScrollingLayerBounds.left));
5123 mMaxAutoScrollX = Math.min(mMaxAutoScrollX,
5124 contentToViewX(mScrollingLayerBounds.right));
5125 }
5126 if (mScrollingLayerRect.top != mScrollingLayerRect.bottom) {
5127 mMinAutoScrollY = Math.max(mMinAutoScrollY,
5128 contentToViewY(mScrollingLayerBounds.top));
5129 mMaxAutoScrollY = Math.min(mMaxAutoScrollY,
5130 contentToViewY(mScrollingLayerBounds.bottom));
5131 }
5132 }
5133 mMinAutoScrollX += SELECT_SCROLL;
5134 mMaxAutoScrollX -= SELECT_SCROLL;
5135 mMinAutoScrollY += SELECT_SCROLL;
5136 mMaxAutoScrollY -= SELECT_SCROLL;
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005137 return true;
Cary Clark09e383c2009-10-26 16:43:58 -04005138 }
5139
Cary Clark966641a2010-03-04 08:41:56 -05005140 /**
5141 * Use this method to put the WebView into text selection mode.
5142 * Do not rely on this functionality; it will be deprecated in the future.
Kristian Monsenfc771652011-05-10 16:44:05 +01005143 * @deprecated This method is now obsolete.
Cary Clark966641a2010-03-04 08:41:56 -05005144 */
Kristian Monsenfc771652011-05-10 16:44:05 +01005145 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005146 public void emulateShiftHeld() {
Steve Block51b08912011-04-27 15:04:48 +01005147 checkThread();
Cary Clark03f00222011-02-10 19:37:15 -05005148 setUpSelect(false, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005149 }
5150
Cary Clark924af702010-06-04 16:37:43 -04005151 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005152 * Select all of the text in this WebView.
Cary Clark2cdee232010-12-29 14:59:24 -05005153 *
5154 * @hide pending API council approval.
Cary Clark924af702010-06-04 16:37:43 -04005155 */
Cary Clark2cdee232010-12-29 14:59:24 -05005156 public void selectAll() {
Cary Clark924af702010-06-04 16:37:43 -04005157 if (0 == mNativeClass) return; // client isn't initialized
5158 if (inFullScreenMode()) return;
Cary Clark2cdee232010-12-29 14:59:24 -05005159 if (!mSelectingText) {
5160 // retrieve a point somewhere within the text
5161 Point select = nativeSelectableText();
5162 if (!selectText(select.x, select.y)) return;
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005163 }
Cary Clark924af702010-06-04 16:37:43 -04005164 nativeSelectAll();
5165 mDrawSelectionPointer = false;
5166 mExtendSelection = true;
5167 invalidate();
5168 }
5169
5170 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005171 * Called when the selection has been removed.
Cary Clark924af702010-06-04 16:37:43 -04005172 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005173 void selectionDone() {
Cary Clark924af702010-06-04 16:37:43 -04005174 if (mSelectingText) {
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005175 mSelectingText = false;
5176 // finish is idempotent, so this is fine even if selectionDone was
5177 // called by mSelectCallback.onDestroyActionMode
5178 mSelectCallback.finish();
5179 mSelectCallback = null;
Cary Clark0df02692010-11-24 11:01:37 -05005180 WebViewCore.resumePriority();
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005181 WebViewCore.resumeUpdatePicture(mWebViewCore);
Cary Clark924af702010-06-04 16:37:43 -04005182 invalidate(); // redraw without selection
Cary Clark6f5dfc62010-11-11 13:09:20 -05005183 mAutoScrollX = 0;
5184 mAutoScrollY = 0;
5185 mSentAutoScrollMessage = false;
Cary Clark924af702010-06-04 16:37:43 -04005186 }
5187 }
5188
5189 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005190 * Copy the selection to the clipboard
Cary Clark2cdee232010-12-29 14:59:24 -05005191 *
5192 * @hide pending API council approval.
Cary Clark924af702010-06-04 16:37:43 -04005193 */
Cary Clark2cdee232010-12-29 14:59:24 -05005194 public boolean copySelection() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005195 boolean copiedSomething = false;
Cary Clark924af702010-06-04 16:37:43 -04005196 String selection = getSelection();
Cary Clark7170bb62011-01-12 10:12:15 -05005197 if (selection != null && selection != "") {
Cary Clark924af702010-06-04 16:37:43 -04005198 if (DebugFlags.WEB_VIEW) {
5199 Log.v(LOGTAG, "copySelection \"" + selection + "\"");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005200 }
Cary Clark924af702010-06-04 16:37:43 -04005201 Toast.makeText(mContext
5202 , com.android.internal.R.string.text_copied
5203 , Toast.LENGTH_SHORT).show();
5204 copiedSomething = true;
Dianne Hackborn90d5e8c2010-08-05 13:47:55 -07005205 ClipboardManager cm = (ClipboardManager)getContext()
5206 .getSystemService(Context.CLIPBOARD_SERVICE);
5207 cm.setText(selection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 }
Cary Clark09e383c2009-10-26 16:43:58 -04005209 invalidate(); // remove selection region and pointer
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005210 return copiedSomething;
5211 }
5212
Cary Clark924af702010-06-04 16:37:43 -04005213 /**
Narayan Kamath9497c5f2011-02-22 12:05:34 +00005214 * @hide pending API Council approval.
5215 */
5216 public SearchBox getSearchBox() {
Michael Kolbb7481862011-03-03 17:09:19 -08005217 if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
5218 return null;
5219 }
Narayan Kamath9497c5f2011-02-22 12:05:34 +00005220 return mWebViewCore.getBrowserFrame().getSearchBox();
5221 }
5222
5223 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005224 * Returns the currently highlighted text as a string.
Cary Clark924af702010-06-04 16:37:43 -04005225 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005226 String getSelection() {
Cary Clark924af702010-06-04 16:37:43 -04005227 if (mNativeClass == 0) return "";
5228 return nativeGetSelection();
5229 }
5230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005231 @Override
5232 protected void onAttachedToWindow() {
5233 super.onAttachedToWindow();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005234 if (hasWindowFocus()) setActive(true);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005235 final ViewTreeObserver treeObserver = getViewTreeObserver();
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005236 if (mGlobalLayoutListener == null) {
5237 mGlobalLayoutListener = new InnerGlobalLayoutListener();
5238 treeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener);
5239 }
5240 if (mScrollChangedListener == null) {
5241 mScrollChangedListener = new InnerScrollChangedListener();
5242 treeObserver.addOnScrollChangedListener(mScrollChangedListener);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005243 }
Svetoslav Ganov4acac232011-02-02 15:22:24 -08005244
5245 addAccessibilityApisToJavaScript();
Adam Powell4fb35d42011-03-03 17:54:55 -08005246
5247 mTouchEventQueue.reset();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248 }
5249
5250 @Override
5251 protected void onDetachedFromWindow() {
Leon Scroggins05919f22010-09-14 17:22:36 -04005252 clearHelpers();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005253 mZoomManager.dismissZoomPicker();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005254 if (hasWindowFocus()) setActive(false);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005255
5256 final ViewTreeObserver treeObserver = getViewTreeObserver();
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005257 if (mGlobalLayoutListener != null) {
5258 treeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
5259 mGlobalLayoutListener = null;
5260 }
5261 if (mScrollChangedListener != null) {
5262 treeObserver.removeOnScrollChangedListener(mScrollChangedListener);
5263 mScrollChangedListener = null;
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005264 }
5265
Svetoslav Ganov4acac232011-02-02 15:22:24 -08005266 removeAccessibilityApisFromJavaScript();
5267
Grace Kloba378f0282010-03-26 15:01:30 -07005268 super.onDetachedFromWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005269 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005270
Steve Howard16bd9372010-04-12 14:46:09 -07005271 @Override
5272 protected void onVisibilityChanged(View changedView, int visibility) {
5273 super.onVisibilityChanged(changedView, visibility);
Derek Sollenbergerf39d2662010-06-24 16:41:04 -04005274 // The zoomManager may be null if the webview is created from XML that
5275 // specifies the view's visibility param as not visible (see http://b/2794841)
5276 if (visibility != View.VISIBLE && mZoomManager != null) {
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005277 mZoomManager.dismissZoomPicker();
Steve Howard16bd9372010-04-12 14:46:09 -07005278 }
5279 }
5280
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005281 /**
5282 * @deprecated WebView no longer needs to implement
5283 * ViewGroup.OnHierarchyChangeListener. This method does nothing now.
5284 */
5285 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 public void onChildViewAdded(View parent, View child) {}
Cary Clarkd6982c92009-05-29 11:02:22 -04005287
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005288 /**
5289 * @deprecated WebView no longer needs to implement
5290 * ViewGroup.OnHierarchyChangeListener. This method does nothing now.
5291 */
5292 @Deprecated
5293 public void onChildViewRemoved(View p, View child) {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005294
5295 /**
5296 * @deprecated WebView should not have implemented
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005297 * ViewTreeObserver.OnGlobalFocusChangeListener. This method does nothing now.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005298 */
5299 @Deprecated
5300 public void onGlobalFocusChanged(View oldFocus, View newFocus) {
5301 }
5302
Leon Scroggins40777232011-01-18 16:49:20 -05005303 void setActive(boolean active) {
Grace Kloba9b95ab12010-04-01 16:07:30 -07005304 if (active) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005305 if (hasFocus()) {
5306 // If our window regained focus, and we have focus, then begin
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005307 // drawing the cursor ring
Cary Clarkd6982c92009-05-29 11:02:22 -04005308 mDrawCursorRing = true;
Leon Scroggins2aed7762010-08-13 17:11:42 -04005309 setFocusControllerActive(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 if (mNativeClass != 0) {
5311 nativeRecordButtons(true, false, true);
5312 }
5313 } else {
Leon Scroggins2aed7762010-08-13 17:11:42 -04005314 if (!inEditingMode()) {
5315 // If our window gained focus, but we do not have it, do not
5316 // draw the cursor ring.
5317 mDrawCursorRing = false;
5318 setFocusControllerActive(false);
5319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005320 // We do not call nativeRecordButtons here because we assume
5321 // that when we lost focus, or window focus, it got called with
5322 // false for the first parameter
5323 }
5324 } else {
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005325 if (!mZoomManager.isZoomPickerVisible()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005326 /*
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005327 * The external zoom controls come in their own window, so our
5328 * window loses focus. Our policy is to not draw the cursor ring
5329 * if our window is not focused, but this is an exception since
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005330 * the user can still navigate the web page with the zoom
5331 * controls showing.
5332 */
Cary Clarkd6982c92009-05-29 11:02:22 -04005333 mDrawCursorRing = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005334 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005335 mKeysPressed.clear();
Grace Kloba378f0282010-03-26 15:01:30 -07005336 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
5337 mTouchMode = TOUCH_DONE_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005338 if (mNativeClass != 0) {
5339 nativeRecordButtons(false, false, true);
5340 }
Leon Scroggins2aed7762010-08-13 17:11:42 -04005341 setFocusControllerActive(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005342 }
5343 invalidate();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005344 }
5345
5346 // To avoid drawing the cursor ring, and remove the TextView when our window
5347 // loses focus.
5348 @Override
5349 public void onWindowFocusChanged(boolean hasWindowFocus) {
5350 setActive(hasWindowFocus);
5351 if (hasWindowFocus) {
Patrick Scott8a5d3352010-08-18 11:00:42 -04005352 JWebCoreJavaBridge.setActiveWebView(this);
Grace Kloba9b95ab12010-04-01 16:07:30 -07005353 } else {
Patrick Scott8a5d3352010-08-18 11:00:42 -04005354 JWebCoreJavaBridge.removeActiveWebView(this);
Grace Kloba9b95ab12010-04-01 16:07:30 -07005355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005356 super.onWindowFocusChanged(hasWindowFocus);
5357 }
5358
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005359 /*
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005360 * Pass a message to WebCore Thread, telling the WebCore::Page's
5361 * FocusController to be "inactive" so that it will
5362 * not draw the blinking cursor. It gets set to "active" to draw the cursor
5363 * in WebViewCore.cpp, when the WebCore thread receives key events/clicks.
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005364 */
Leon Scroggins2aed7762010-08-13 17:11:42 -04005365 /* package */ void setFocusControllerActive(boolean active) {
5366 if (mWebViewCore == null) return;
5367 mWebViewCore.sendMessage(EventHub.SET_ACTIVE, active ? 1 : 0, 0);
Leon Scroggins244d2d42010-12-06 16:29:38 -05005368 // Need to send this message after the document regains focus.
5369 if (active && mListBoxMessage != null) {
5370 mWebViewCore.sendMessage(mListBoxMessage);
5371 mListBoxMessage = null;
5372 }
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005373 }
5374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005375 @Override
5376 protected void onFocusChanged(boolean focused, int direction,
5377 Rect previouslyFocusedRect) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005378 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005379 Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction);
5380 }
5381 if (focused) {
5382 // When we regain focus, if we have window focus, resume drawing
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005383 // the cursor ring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005384 if (hasWindowFocus()) {
Cary Clarkd6982c92009-05-29 11:02:22 -04005385 mDrawCursorRing = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005386 if (mNativeClass != 0) {
5387 nativeRecordButtons(true, false, true);
5388 }
Leon Scroggins2aed7762010-08-13 17:11:42 -04005389 setFocusControllerActive(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005390 //} else {
5391 // The WebView has gained focus while we do not have
5392 // windowfocus. When our window lost focus, we should have
5393 // called nativeRecordButtons(false...)
5394 }
5395 } else {
5396 // When we lost focus, unless focus went to the TextView (which is
Cary Clarkd6982c92009-05-29 11:02:22 -04005397 // true if we are in editing mode), stop drawing the cursor ring.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005398 if (!inEditingMode()) {
Cary Clarkd6982c92009-05-29 11:02:22 -04005399 mDrawCursorRing = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005400 if (mNativeClass != 0) {
5401 nativeRecordButtons(false, false, true);
5402 }
Leon Scrogginsb4ffd112011-01-24 17:43:47 -05005403 setFocusControllerActive(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005404 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005405 mKeysPressed.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005406 }
5407
5408 super.onFocusChanged(focused, direction, previouslyFocusedRect);
5409 }
5410
Nicolas Roard12c18e62010-10-13 20:14:31 -07005411 void setGLRectViewport() {
Teng-Hui Zhue6fb0f12010-11-23 16:37:45 -08005412 // Use the getGlobalVisibleRect() to get the intersection among the parents
Chet Haase91fc3cf2011-01-28 00:20:04 -08005413 // visible == false means we're clipped - send a null rect down to indicate that
5414 // we should not draw
5415 boolean visible = getGlobalVisibleRect(mGLRectViewport);
5416 if (visible) {
5417 // Then need to invert the Y axis, just for GL
5418 View rootView = getRootView();
5419 int rootViewHeight = rootView.getHeight();
Romain Guycabfcc12011-03-07 18:06:46 -08005420 mViewRectViewport.set(mGLRectViewport);
Chet Haase91fc3cf2011-01-28 00:20:04 -08005421 int savedWebViewBottom = mGLRectViewport.bottom;
5422 mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
5423 mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
5424 mGLViewportEmpty = false;
5425 } else {
5426 mGLViewportEmpty = true;
5427 }
Romain Guycabfcc12011-03-07 18:06:46 -08005428 nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
5429 mGLViewportEmpty ? null : mViewRectViewport);
Nicolas Roard12c18e62010-10-13 20:14:31 -07005430 }
5431
Grace Kloba3f9faf42009-10-13 14:13:54 -07005432 /**
5433 * @hide
5434 */
5435 @Override
5436 protected boolean setFrame(int left, int top, int right, int bottom) {
5437 boolean changed = super.setFrame(left, top, right, bottom);
5438 if (!changed && mHeightCanMeasure) {
5439 // When mHeightCanMeasure is true, we will set mLastHeightSent to 0
5440 // in WebViewCore after we get the first layout. We do call
5441 // requestLayout() when we get contentSizeChanged(). But the View
5442 // system won't call onSizeChanged if the dimension is not changed.
5443 // In this case, we need to call sendViewSizeZoom() explicitly to
5444 // notify the WebKit about the new dimensions.
Derek Sollenberger03e48912010-05-18 17:03:42 -04005445 sendViewSizeZoom(false);
Grace Kloba3f9faf42009-10-13 14:13:54 -07005446 }
Nicolas Roard12c18e62010-10-13 20:14:31 -07005447 setGLRectViewport();
Grace Kloba3f9faf42009-10-13 14:13:54 -07005448 return changed;
5449 }
5450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005451 @Override
5452 protected void onSizeChanged(int w, int h, int ow, int oh) {
5453 super.onSizeChanged(w, h, ow, oh);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005454
Grace Klobaa4fa1072009-11-09 12:01:50 -08005455 // adjust the max viewport width depending on the view dimensions. This
5456 // is to ensure the scaling is not going insane. So do not shrink it if
5457 // the view size is temporarily smaller, e.g. when soft keyboard is up.
Derek Sollenberger4aef6972010-06-24 15:03:43 -04005458 int newMaxViewportWidth = (int) (Math.max(w, h) / mZoomManager.getDefaultMinZoomScale());
Grace Klobaa4fa1072009-11-09 12:01:50 -08005459 if (newMaxViewportWidth > sMaxViewportWidth) {
5460 sMaxViewportWidth = newMaxViewportWidth;
5461 }
5462
Derek Sollenberger341e22f2010-06-02 12:34:34 -04005463 mZoomManager.onSizeChanged(w, h, ow, oh);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005464 }
5465
5466 @Override
5467 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
5468 super.onScrollChanged(l, t, oldl, oldt);
Adam Powell637d3372010-08-25 14:37:03 -07005469 if (!mInOverScrollMode) {
5470 sendOurVisibleRect();
5471 // update WebKit if visible title bar height changed. The logic is same
5472 // as getVisibleTitleHeight.
5473 int titleHeight = getTitleHeight();
5474 if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
5475 sendViewSizeZoom(false);
5476 }
Mike Reedb64f6f82010-03-23 10:29:37 -04005477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005478 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 @Override
5481 public boolean dispatchKeyEvent(KeyEvent event) {
Leon Scroggins115626a2011-02-17 12:00:48 -05005482 switch (event.getAction()) {
5483 case KeyEvent.ACTION_DOWN:
5484 mKeysPressed.add(Integer.valueOf(event.getKeyCode()));
5485 break;
5486 case KeyEvent.ACTION_MULTIPLE:
5487 // Always accept the action.
5488 break;
5489 case KeyEvent.ACTION_UP:
5490 int location = mKeysPressed.indexOf(Integer.valueOf(event.getKeyCode()));
5491 if (location == -1) {
5492 // We did not receive the key down for this key, so do not
5493 // handle the key up.
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005494 return false;
Leon Scroggins115626a2011-02-17 12:00:48 -05005495 } else {
5496 // We did receive the key down. Handle the key up, and
5497 // remove it from our pressed keys.
5498 mKeysPressed.remove(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005499 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005500 break;
5501 default:
5502 // Accept the action. This should not happen, unless a new
5503 // action is added to KeyEvent.
5504 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005505 }
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005506 if (inEditingMode() && mWebTextView.isFocused()) {
5507 // Ensure that the WebTextView gets the event, even if it does
5508 // not currently have a bounds.
5509 return mWebTextView.dispatchKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005510 } else {
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005511 return super.dispatchKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005512 }
5513 }
5514
5515 // Here are the snap align logic:
5516 // 1. If it starts nearly horizontally or vertically, snap align;
5517 // 2. If there is a dramitic direction change, let it go;
5518 // 3. If there is a same direction back and forth, lock it.
5519
5520 // adjustable parameters
5521 private int mMinLockSnapReverseDistance;
5522 private static final float MAX_SLOPE_FOR_DIAG = 1.5f;
5523 private static final int MIN_BREAK_SNAP_CROSS_DISTANCE = 80;
5524
Grace Klobac2242f22010-03-05 14:00:26 -08005525 private boolean hitFocusedPlugin(int contentX, int contentY) {
Cary Clarke84a0db2010-03-17 15:58:20 -04005526 if (DebugFlags.WEB_VIEW) {
5527 Log.v(LOGTAG, "nativeFocusIsPlugin()=" + nativeFocusIsPlugin());
5528 Rect r = nativeFocusNodeBounds();
5529 Log.v(LOGTAG, "nativeFocusNodeBounds()=(" + r.left + ", " + r.top
5530 + ", " + r.right + ", " + r.bottom + ")");
5531 }
Grace Klobac2242f22010-03-05 14:00:26 -08005532 return nativeFocusIsPlugin()
Cary Clarke84a0db2010-03-17 15:58:20 -04005533 && nativeFocusNodeBounds().contains(contentX, contentY);
Grace Klobac2242f22010-03-05 14:00:26 -08005534 }
5535
5536 private boolean shouldForwardTouchEvent() {
5537 return mFullScreenHolder != null || (mForwardTouchEvents
Cary Clark924af702010-06-04 16:37:43 -04005538 && !mSelectingText
Adam Powella0def722011-03-14 17:54:10 -07005539 && mPreventDefault != PREVENT_DEFAULT_IGNORE
5540 && mPreventDefault != PREVENT_DEFAULT_NO);
Grace Klobac2242f22010-03-05 14:00:26 -08005541 }
5542
5543 private boolean inFullScreenMode() {
5544 return mFullScreenHolder != null;
5545 }
5546
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04005547 private void dismissFullScreenMode() {
5548 if (inFullScreenMode()) {
5549 mFullScreenHolder.dismiss();
5550 mFullScreenHolder = null;
5551 }
5552 }
5553
Derek Sollenberger293c3602010-06-04 10:44:48 -04005554 void onPinchToZoomAnimationStart() {
5555 // cancel the single touch handling
5556 cancelTouch();
5557 onZoomAnimationStart();
5558 }
5559
5560 void onPinchToZoomAnimationEnd(ScaleGestureDetector detector) {
5561 onZoomAnimationEnd();
5562 // start a drag, TOUCH_PINCH_DRAG, can't use TOUCH_INIT_MODE as
5563 // it may trigger the unwanted click, can't use TOUCH_DRAG_MODE
5564 // as it may trigger the unwanted fling.
5565 mTouchMode = TOUCH_PINCH_DRAG;
5566 mConfirmMove = true;
5567 startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime);
5568 }
5569
Patrick Scott62310912010-12-06 17:44:50 -05005570 // See if there is a layer at x, y and switch to TOUCH_DRAG_LAYER_MODE if a
5571 // layer is found.
Patrick Scott4b903782010-11-30 08:14:05 -05005572 private void startScrollingLayer(float x, float y) {
Patrick Scott62310912010-12-06 17:44:50 -05005573 int contentX = viewToContentX((int) x + mScrollX);
5574 int contentY = viewToContentY((int) y + mScrollY);
5575 mScrollingLayer = nativeScrollableLayer(contentX, contentY,
Cary Clarkb9aaa772011-01-07 16:14:54 -05005576 mScrollingLayerRect, mScrollingLayerBounds);
Patrick Scott62310912010-12-06 17:44:50 -05005577 if (mScrollingLayer != 0) {
5578 mTouchMode = TOUCH_DRAG_LAYER_MODE;
Patrick Scotta3ebcc92010-07-16 11:52:22 -04005579 }
5580 }
5581
5582 // 1/(density * density) used to compute the distance between points.
5583 // Computed in init().
5584 private float DRAG_LAYER_INVERSE_DENSITY_SQUARED;
5585
5586 // The distance between two points reported in onTouchEvent scaled by the
5587 // density of the screen.
5588 private static final int DRAG_LAYER_FINGER_DISTANCE = 20000;
5589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005590 @Override
5591 public boolean onTouchEvent(MotionEvent ev) {
Andy Stadlerb34fd1ff2010-09-27 15:51:09 -07005592 if (mNativeClass == 0 || (!isClickable() && !isLongClickable())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005593 return false;
5594 }
5595
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005596 if (DebugFlags.WEB_VIEW) {
Huahui Wu41865f42010-09-02 13:41:41 -07005597 Log.v(LOGTAG, ev + " at " + ev.getEventTime()
5598 + " mTouchMode=" + mTouchMode
5599 + " numPointers=" + ev.getPointerCount());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005600 }
5601
Adam Powell4fb35d42011-03-03 17:54:55 -08005602 // If WebKit wasn't interested in this multitouch gesture, enqueue
5603 // the event for handling directly rather than making the round trip
5604 // to WebKit and back.
5605 if (ev.getPointerCount() > 1 && mPreventDefault != PREVENT_DEFAULT_NO) {
5606 passMultiTouchToWebKit(ev, mTouchEventQueue.nextTouchSequence());
Adam Powelle33cef82011-02-23 16:51:20 -08005607 } else {
Adam Powell4fb35d42011-03-03 17:54:55 -08005608 mTouchEventQueue.enqueueTouchEvent(ev);
Huahui Wu41865f42010-09-02 13:41:41 -07005609 }
5610
Adam Powell4fb35d42011-03-03 17:54:55 -08005611 // Since all events are handled asynchronously, we always want the gesture stream.
5612 return true;
Huahui Wu0904c0d2011-01-07 17:30:53 -08005613 }
Patrick Scott4b903782010-11-30 08:14:05 -05005614
Huahui Wuf147d452011-01-12 14:02:36 -08005615 /*
5616 * Common code for single touch and multi-touch.
5617 * (x, y) denotes current focus point, which is the touch point for single touch
5618 * and the middle point for multi-touch.
5619 */
Huahui Wu1f301252011-01-19 17:32:32 -08005620 private boolean handleTouchEventCommon(MotionEvent ev, int action, int x, int y) {
Huahui Wu0904c0d2011-01-07 17:30:53 -08005621 long eventTime = ev.getEventTime();
Patrick Scotta3ebcc92010-07-16 11:52:22 -04005622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005623 // Due to the touch screen edge effect, a touch closer to the edge
5624 // always snapped to the edge. As getViewWidth() can be different from
5625 // getWidth() due to the scrollbar, adjusting the point to match
5626 // getViewWidth(). Same applied to the height.
Patrick Scotta3ebcc92010-07-16 11:52:22 -04005627 x = Math.min(x, getViewWidth() - 1);
5628 y = Math.min(y, getViewHeightWithTitle() - 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005629
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08005630 int deltaX = mLastTouchX - x;
5631 int deltaY = mLastTouchY - y;
5632 int contentX = viewToContentX(x + mScrollX);
5633 int contentY = viewToContentY(y + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005634
5635 switch (action) {
5636 case MotionEvent.ACTION_DOWN: {
Grace Klobac2242f22010-03-05 14:00:26 -08005637 mPreventDefault = PREVENT_DEFAULT_NO;
5638 mConfirmMove = false;
Cary Clarkb8491342010-11-29 16:23:19 -05005639 mInitialHitTestResult = null;
Grace Kloba04b28682009-09-14 14:38:37 -07005640 if (!mScroller.isFinished()) {
Cary Clark278ce052009-08-31 16:08:42 -04005641 // stop the current scroll animation, but if this is
5642 // the start of a fling, allow it to add to the current
5643 // fling's velocity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005644 mScroller.abortAnimation();
5645 mTouchMode = TOUCH_DRAG_START_MODE;
Grace Klobac2242f22010-03-05 14:00:26 -08005646 mConfirmMove = true;
Grace Kloba96949ef2010-01-25 09:53:01 -08005647 mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
Grace Kloba8b97e4b2009-07-28 13:11:38 -07005648 } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
5649 mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
Grace Kloba178db412010-05-18 22:22:23 -07005650 if (getSettings().supportTouchOnly()) {
5651 removeTouchHighlight(true);
5652 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07005653 if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
5654 mTouchMode = TOUCH_DOUBLE_TAP_MODE;
5655 } else {
5656 // commit the short press action for the previous tap
5657 doShortPress();
Grace Klobac2242f22010-03-05 14:00:26 -08005658 mTouchMode = TOUCH_INIT_MODE;
5659 mDeferTouchProcess = (!inFullScreenMode()
5660 && mForwardTouchEvents) ? hitFocusedPlugin(
5661 contentX, contentY) : false;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07005662 }
Grace Klobac2242f22010-03-05 14:00:26 -08005663 } else { // the normal case
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005664 mTouchMode = TOUCH_INIT_MODE;
Grace Klobac2242f22010-03-05 14:00:26 -08005665 mDeferTouchProcess = (!inFullScreenMode()
5666 && mForwardTouchEvents) ? hitFocusedPlugin(
5667 contentX, contentY) : false;
Cary Clark77d98f42009-07-31 09:40:38 -04005668 mWebViewCore.sendMessage(
5669 EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
Grace Kloba178db412010-05-18 22:22:23 -07005670 if (getSettings().supportTouchOnly()) {
5671 TouchHighlightData data = new TouchHighlightData();
5672 data.mX = contentX;
5673 data.mY = contentY;
5674 data.mSlop = viewToContentDimension(mNavSlop);
5675 mWebViewCore.sendMessageDelayed(
5676 EventHub.GET_TOUCH_HIGHLIGHT_RECTS, data,
5677 ViewConfiguration.getTapTimeout());
5678 if (DEBUG_TOUCH_HIGHLIGHT) {
5679 if (getSettings().getNavDump()) {
5680 mTouchHighlightX = (int) x + mScrollX;
5681 mTouchHighlightY = (int) y + mScrollY;
5682 mPrivateHandler.postDelayed(new Runnable() {
5683 public void run() {
5684 mTouchHighlightX = mTouchHighlightY = 0;
5685 invalidate();
5686 }
5687 }, TOUCH_HIGHLIGHT_ELAPSE_TIME);
5688 }
5689 }
5690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
Dan Egnor18e93962010-02-10 19:27:58 -08005692 EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005693 (eventTime - mLastTouchUpTime), eventTime);
5694 }
Cary Clark924af702010-06-04 16:37:43 -04005695 if (mSelectingText) {
5696 mDrawSelectionPointer = false;
5697 mSelectionStarted = nativeStartSelection(contentX, contentY);
5698 if (DebugFlags.WEB_VIEW) {
5699 Log.v(LOGTAG, "select=" + contentX + "," + contentY);
5700 }
5701 invalidate();
5702 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005703 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07005704 // Trigger the link
Cary Clark43f608f2011-02-18 11:30:12 -05005705 if (!mSelectingText && (mTouchMode == TOUCH_INIT_MODE
5706 || mTouchMode == TOUCH_DOUBLE_TAP_MODE)) {
Grace Klobac2242f22010-03-05 14:00:26 -08005707 mPrivateHandler.sendEmptyMessageDelayed(
5708 SWITCH_TO_SHORTPRESS, TAP_TIMEOUT);
5709 mPrivateHandler.sendEmptyMessageDelayed(
5710 SWITCH_TO_LONGPRESS, LONG_PRESS_TIMEOUT);
5711 if (inFullScreenMode() || mDeferTouchProcess) {
5712 mPreventDefault = PREVENT_DEFAULT_YES;
5713 } else if (mForwardTouchEvents) {
5714 mPreventDefault = PREVENT_DEFAULT_MAYBE_YES;
5715 } else {
5716 mPreventDefault = PREVENT_DEFAULT_NO;
5717 }
5718 // pass the touch events from UI thread to WebCore thread
5719 if (shouldForwardTouchEvent()) {
5720 TouchEventData ted = new TouchEventData();
5721 ted.mAction = action;
Huahui Wue838a422011-01-13 16:03:43 -08005722 ted.mIds = new int[1];
5723 ted.mIds[0] = ev.getPointerId(0);
Huahui Wu41865f42010-09-02 13:41:41 -07005724 ted.mPoints = new Point[1];
5725 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu88b869a2011-03-17 17:42:12 -07005726 ted.mPointsInView = new Point[1];
5727 ted.mPointsInView[0] = new Point(x, y);
Grace Klobac2242f22010-03-05 14:00:26 -08005728 ted.mMetaState = ev.getMetaState();
5729 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05005730 ted.mNativeLayer = nativeScrollableLayer(
5731 contentX, contentY, ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08005732 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07005733 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08005734 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
5735 if (mDeferTouchProcess) {
5736 // still needs to set them for compute deltaX/Y
5737 mLastTouchX = x;
5738 mLastTouchY = y;
5739 break;
5740 }
5741 if (!inFullScreenMode()) {
Ben Murdocha3f055e2010-05-26 18:46:56 +01005742 mPrivateHandler.removeMessages(PREVENT_DEFAULT_TIMEOUT);
Grace Klobac2242f22010-03-05 14:00:26 -08005743 mPrivateHandler.sendMessageDelayed(mPrivateHandler
5744 .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
5745 action, 0), TAP_TIMEOUT);
5746 }
5747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005748 }
Grace Kloba3a0def22010-01-23 21:11:54 -08005749 startTouch(x, y, eventTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005750 break;
5751 }
5752 case MotionEvent.ACTION_MOVE: {
Grace Klobac2242f22010-03-05 14:00:26 -08005753 boolean firstMove = false;
5754 if (!mConfirmMove && (deltaX * deltaX + deltaY * deltaY)
5755 >= mTouchSlopSquare) {
5756 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
5757 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
5758 mConfirmMove = true;
5759 firstMove = true;
5760 if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
5761 mTouchMode = TOUCH_INIT_MODE;
5762 }
Grace Kloba178db412010-05-18 22:22:23 -07005763 if (getSettings().supportTouchOnly()) {
5764 removeTouchHighlight(true);
5765 }
Grace Klobac2242f22010-03-05 14:00:26 -08005766 }
5767 // pass the touch events from UI thread to WebCore thread
5768 if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
5769 || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
5770 TouchEventData ted = new TouchEventData();
5771 ted.mAction = action;
Huahui Wue838a422011-01-13 16:03:43 -08005772 ted.mIds = new int[1];
5773 ted.mIds[0] = ev.getPointerId(0);
Huahui Wu41865f42010-09-02 13:41:41 -07005774 ted.mPoints = new Point[1];
5775 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu88b869a2011-03-17 17:42:12 -07005776 ted.mPointsInView = new Point[1];
5777 ted.mPointsInView[0] = new Point(x, y);
Grace Klobac2242f22010-03-05 14:00:26 -08005778 ted.mMetaState = ev.getMetaState();
5779 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05005780 ted.mNativeLayer = mScrollingLayer;
5781 ted.mNativeLayerRect.set(mScrollingLayerRect);
Adam Powellae9d2642011-03-08 16:00:30 -08005782 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07005783 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08005784 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
5785 mLastSentTouchTime = eventTime;
5786 if (mDeferTouchProcess) {
5787 break;
5788 }
5789 if (firstMove && !inFullScreenMode()) {
5790 mPrivateHandler.sendMessageDelayed(mPrivateHandler
5791 .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
5792 action, 0), TAP_TIMEOUT);
5793 }
5794 }
5795 if (mTouchMode == TOUCH_DONE_MODE
5796 || mPreventDefault == PREVENT_DEFAULT_YES) {
5797 // no dragging during scroll zoom animation, or when prevent
5798 // default is yes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005799 break;
5800 }
Grace Klobac2242f22010-03-05 14:00:26 -08005801 if (mVelocityTracker == null) {
5802 Log.e(LOGTAG, "Got null mVelocityTracker when "
5803 + "mPreventDefault = " + mPreventDefault
5804 + " mDeferTouchProcess = " + mDeferTouchProcess
5805 + " mTouchMode = " + mTouchMode);
Huahui Wu8465cc92011-01-12 10:17:19 -08005806 } else {
5807 mVelocityTracker.addMovement(ev);
Grace Klobac2242f22010-03-05 14:00:26 -08005808 }
Cary Clark924af702010-06-04 16:37:43 -04005809 if (mSelectingText && mSelectionStarted) {
5810 if (DebugFlags.WEB_VIEW) {
5811 Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005812 }
Leon Scroggins7f7bd522010-11-05 11:23:31 -04005813 ViewParent parent = getParent();
5814 if (parent != null) {
5815 parent.requestDisallowInterceptTouchEvent(true);
5816 }
Cary Clarkb9aaa772011-01-07 16:14:54 -05005817 mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL
5818 : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
5819 mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL
5820 : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
5821 if ((mAutoScrollX != 0 || mAutoScrollY != 0)
5822 && !mSentAutoScrollMessage) {
5823 mSentAutoScrollMessage = true;
5824 mPrivateHandler.sendEmptyMessageDelayed(
5825 SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
Cary Clark6f5dfc62010-11-11 13:09:20 -05005826 }
Cary Clarkaa86ac82010-12-28 11:30:18 -05005827 if (deltaX != 0 || deltaY != 0) {
5828 nativeExtendSelection(contentX, contentY);
5829 invalidate();
5830 }
Cary Clark924af702010-06-04 16:37:43 -04005831 break;
5832 }
Patrick Scotta3ebcc92010-07-16 11:52:22 -04005833
5834 if (mTouchMode != TOUCH_DRAG_MODE &&
5835 mTouchMode != TOUCH_DRAG_LAYER_MODE) {
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07005836
Grace Klobac2242f22010-03-05 14:00:26 -08005837 if (!mConfirmMove) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005838 break;
5839 }
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07005840
Grace Klobac2242f22010-03-05 14:00:26 -08005841 if (mPreventDefault == PREVENT_DEFAULT_MAYBE_YES
5842 || mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
Grace Klobaf58af622009-09-24 17:41:23 -07005843 // track mLastTouchTime as we may need to do fling at
5844 // ACTION_UP
5845 mLastTouchTime = eventTime;
5846 break;
5847 }
Adam Powell048a3a52010-09-08 23:59:37 -07005848
Huahui Wuc0109242011-01-14 12:51:12 -08005849 // Only lock dragging to one axis if we don't have a scale in progress.
5850 // Scaling implies free-roaming movement. Note this is only ever a question
5851 // if mZoomManager.supportsPanDuringZoom() is true.
5852 final ScaleGestureDetector detector =
5853 mZoomManager.getMultiTouchGestureDetector();
5854 if (detector == null || !detector.isInProgress()) {
5855 // if it starts nearly horizontal or vertical, enforce it
5856 int ax = Math.abs(deltaX);
5857 int ay = Math.abs(deltaY);
5858 if (ax > MAX_SLOPE_FOR_DIAG * ay) {
5859 mSnapScrollMode = SNAP_X;
5860 mSnapPositive = deltaX > 0;
5861 } else if (ay > MAX_SLOPE_FOR_DIAG * ax) {
5862 mSnapScrollMode = SNAP_Y;
5863 mSnapPositive = deltaY > 0;
5864 }
5865 }
5866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005867 mTouchMode = TOUCH_DRAG_MODE;
Romain Guyf7b4acc2009-12-01 16:24:45 -08005868 mLastTouchX = x;
5869 mLastTouchY = y;
Romain Guyf7b4acc2009-12-01 16:24:45 -08005870 deltaX = 0;
5871 deltaY = 0;
5872
Patrick Scott62310912010-12-06 17:44:50 -05005873 startScrollingLayer(x, y);
Grace Klobac2242f22010-03-05 14:00:26 -08005874 startDrag();
5875 }
5876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005877 // do pan
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005878 boolean done = false;
Cary Clark25415e22009-10-12 13:41:28 -04005879 boolean keepScrollBarsVisible = false;
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08005880 if (deltaX == 0 && deltaY == 0) {
Cary Clark25415e22009-10-12 13:41:28 -04005881 keepScrollBarsVisible = done = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005882 } else {
5883 if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
5884 int ax = Math.abs(deltaX);
5885 int ay = Math.abs(deltaY);
5886 if (mSnapScrollMode == SNAP_X) {
5887 // radical change means getting out of snap mode
5888 if (ay > MAX_SLOPE_FOR_DIAG * ax
5889 && ay > MIN_BREAK_SNAP_CROSS_DISTANCE) {
5890 mSnapScrollMode = SNAP_NONE;
5891 }
5892 // reverse direction means lock in the snap mode
Cary Clarkac492e12009-10-14 14:53:37 -04005893 if (ax > MAX_SLOPE_FOR_DIAG * ay &&
5894 (mSnapPositive
5895 ? deltaX < -mMinLockSnapReverseDistance
5896 : deltaX > mMinLockSnapReverseDistance)) {
5897 mSnapScrollMode |= SNAP_LOCK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005898 }
5899 } else {
5900 // radical change means getting out of snap mode
Cary Clarkac492e12009-10-14 14:53:37 -04005901 if (ax > MAX_SLOPE_FOR_DIAG * ay
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005902 && ax > MIN_BREAK_SNAP_CROSS_DISTANCE) {
5903 mSnapScrollMode = SNAP_NONE;
5904 }
5905 // reverse direction means lock in the snap mode
Cary Clarkac492e12009-10-14 14:53:37 -04005906 if (ay > MAX_SLOPE_FOR_DIAG * ax &&
5907 (mSnapPositive
5908 ? deltaY < -mMinLockSnapReverseDistance
5909 : deltaY > mMinLockSnapReverseDistance)) {
5910 mSnapScrollMode |= SNAP_LOCK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005911 }
5912 }
5913 }
Cary Clarkac492e12009-10-14 14:53:37 -04005914 if (mSnapScrollMode != SNAP_NONE) {
5915 if ((mSnapScrollMode & SNAP_X) == SNAP_X) {
5916 deltaY = 0;
Grace Kloba5b2c0562009-09-30 10:17:13 -07005917 } else {
Cary Clarkac492e12009-10-14 14:53:37 -04005918 deltaX = 0;
Grace Kloba5b2c0562009-09-30 10:17:13 -07005919 }
Cary Clarkac492e12009-10-14 14:53:37 -04005920 }
5921 if ((deltaX | deltaY) != 0) {
Cary Clarkac492e12009-10-14 14:53:37 -04005922 if (deltaX != 0) {
5923 mLastTouchX = x;
5924 }
5925 if (deltaY != 0) {
5926 mLastTouchY = y;
5927 }
5928 mHeldMotionless = MOTIONLESS_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005929 }
5930 mLastTouchTime = eventTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005931 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005932
Grace Klobac2242f22010-03-05 14:00:26 -08005933 doDrag(deltaX, deltaY);
Mike Reed19f3f0e2009-11-12 12:50:20 -05005934
Patrick Scotta3ebcc92010-07-16 11:52:22 -04005935 // Turn off scrollbars when dragging a layer.
5936 if (keepScrollBarsVisible &&
5937 mTouchMode != TOUCH_DRAG_LAYER_MODE) {
Cary Clark25415e22009-10-12 13:41:28 -04005938 if (mHeldMotionless != MOTIONLESS_TRUE) {
5939 mHeldMotionless = MOTIONLESS_TRUE;
5940 invalidate();
5941 }
Grace Kloba5b2c0562009-09-30 10:17:13 -07005942 // keep the scrollbar on the screen even there is no scroll
5943 awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
5944 false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005945 // return false to indicate that we can't pan out of the
5946 // view space
Cary Clark25415e22009-10-12 13:41:28 -04005947 return !done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005948 }
5949 break;
5950 }
5951 case MotionEvent.ACTION_UP: {
Leon Scroggins IIIae9f8e42010-04-14 16:06:06 -04005952 if (!isFocused()) requestFocus();
Grace Klobac2242f22010-03-05 14:00:26 -08005953 // pass the touch events from UI thread to WebCore thread
5954 if (shouldForwardTouchEvent()) {
5955 TouchEventData ted = new TouchEventData();
Huahui Wue838a422011-01-13 16:03:43 -08005956 ted.mIds = new int[1];
5957 ted.mIds[0] = ev.getPointerId(0);
Grace Klobac2242f22010-03-05 14:00:26 -08005958 ted.mAction = action;
Huahui Wu41865f42010-09-02 13:41:41 -07005959 ted.mPoints = new Point[1];
5960 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu88b869a2011-03-17 17:42:12 -07005961 ted.mPointsInView = new Point[1];
5962 ted.mPointsInView[0] = new Point(x, y);
Grace Klobac2242f22010-03-05 14:00:26 -08005963 ted.mMetaState = ev.getMetaState();
5964 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05005965 ted.mNativeLayer = mScrollingLayer;
5966 ted.mNativeLayerRect.set(mScrollingLayerRect);
Adam Powellae9d2642011-03-08 16:00:30 -08005967 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07005968 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08005969 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Mike Reed19f3f0e2009-11-12 12:50:20 -05005970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005971 mLastTouchUpTime = eventTime;
Cary Clarkb9aaa772011-01-07 16:14:54 -05005972 if (mSentAutoScrollMessage) {
5973 mAutoScrollX = mAutoScrollY = 0;
5974 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005975 switch (mTouchMode) {
Grace Kloba8b97e4b2009-07-28 13:11:38 -07005976 case TOUCH_DOUBLE_TAP_MODE: // double tap
5977 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
Grace Klobac2242f22010-03-05 14:00:26 -08005978 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
5979 if (inFullScreenMode() || mDeferTouchProcess) {
5980 TouchEventData ted = new TouchEventData();
Huahui Wue838a422011-01-13 16:03:43 -08005981 ted.mIds = new int[1];
5982 ted.mIds[0] = ev.getPointerId(0);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08005983 ted.mAction = WebViewCore.ACTION_DOUBLETAP;
Huahui Wu41865f42010-09-02 13:41:41 -07005984 ted.mPoints = new Point[1];
5985 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu88b869a2011-03-17 17:42:12 -07005986 ted.mPointsInView = new Point[1];
5987 ted.mPointsInView[0] = new Point(x, y);
Ben Murdoch8a032a32010-02-02 18:20:11 +00005988 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08005989 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05005990 ted.mNativeLayer = nativeScrollableLayer(
5991 contentX, contentY,
5992 ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08005993 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07005994 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08005995 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Grace Klobac2242f22010-03-05 14:00:26 -08005996 } else if (mPreventDefault != PREVENT_DEFAULT_YES){
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04005997 mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
Grace Klobac2242f22010-03-05 14:00:26 -08005998 mTouchMode = TOUCH_DONE_MODE;
Grace Kloba5f68d6f2009-12-08 18:42:54 -08005999 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006000 break;
Grace Klobaf58af622009-09-24 17:41:23 -07006001 case TOUCH_INIT_MODE: // tap
Grace Klobad66d84f2009-09-27 14:48:07 -07006002 case TOUCH_SHORTPRESS_START_MODE:
6003 case TOUCH_SHORTPRESS_MODE:
Grace Klobaf58af622009-09-24 17:41:23 -07006004 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
Grace Klobad66d84f2009-09-27 14:48:07 -07006005 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
Grace Klobac2242f22010-03-05 14:00:26 -08006006 if (mConfirmMove) {
Grace Klobaf58af622009-09-24 17:41:23 -07006007 Log.w(LOGTAG, "Miss a drag as we are waiting for" +
6008 " WebCore's response for touch down.");
Grace Klobac2242f22010-03-05 14:00:26 -08006009 if (mPreventDefault != PREVENT_DEFAULT_YES
Grace Klobad7625dd2010-03-04 11:46:12 -08006010 && (computeMaxScrollX() > 0
6011 || computeMaxScrollY() > 0)) {
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07006012 // If the user has performed a very quick touch
6013 // sequence it is possible that we may get here
6014 // before WebCore has had a chance to process the events.
6015 // In this case, any call to preventDefault in the
6016 // JS touch handler will not have been executed yet.
6017 // Hence we will see both the UI (now) and WebCore
6018 // (when context switches) handling the event,
6019 // regardless of whether the web developer actually
6020 // doeses preventDefault in their touch handler. This
6021 // is the nature of our asynchronous touch model.
6022
Grace Klobaf58af622009-09-24 17:41:23 -07006023 // we will not rewrite drag code here, but we
6024 // will try fling if it applies.
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006025 WebViewCore.reducePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006026 // to get better performance, pause updating the
6027 // picture
6028 WebViewCore.pauseUpdatePicture(mWebViewCore);
Grace Klobaf58af622009-09-24 17:41:23 -07006029 // fall through to TOUCH_DRAG_MODE
6030 } else {
Grace Klobac36862d52010-04-19 10:16:42 -07006031 // WebKit may consume the touch event and modify
6032 // DOM. drawContentPicture() will be called with
6033 // animateSroll as true for better performance.
6034 // Force redraw in high-quality.
6035 invalidate();
Grace Klobaf58af622009-09-24 17:41:23 -07006036 break;
6037 }
6038 } else {
Cary Clark924af702010-06-04 16:37:43 -04006039 if (mSelectingText) {
6040 // tapping on selection or controls does nothing
6041 if (!nativeHitSelection(contentX, contentY)) {
6042 selectionDone();
6043 }
6044 break;
6045 }
Grace Klobaec9a1042010-06-01 19:00:23 -07006046 // only trigger double tap if the WebView is
6047 // scalable
6048 if (mTouchMode == TOUCH_INIT_MODE
6049 && (canZoomIn() || canZoomOut())) {
Grace Klobac2242f22010-03-05 14:00:26 -08006050 mPrivateHandler.sendEmptyMessageDelayed(
6051 RELEASE_SINGLE_TAP, ViewConfiguration
6052 .getDoubleTapTimeout());
6053 } else {
6054 doShortPress();
Grace Klobaf58af622009-09-24 17:41:23 -07006055 }
6056 break;
6057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006058 case TOUCH_DRAG_MODE:
Patrick Scott2f492272010-12-03 09:52:35 -05006059 case TOUCH_DRAG_LAYER_MODE:
Cary Clark25415e22009-10-12 13:41:28 -04006060 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
6061 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006062 // if the user waits a while w/o moving before the
6063 // up, we don't want to do a fling
6064 if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
Grace Klobac2242f22010-03-05 14:00:26 -08006065 if (mVelocityTracker == null) {
6066 Log.e(LOGTAG, "Got null mVelocityTracker when "
6067 + "mPreventDefault = "
6068 + mPreventDefault
6069 + " mDeferTouchProcess = "
6070 + mDeferTouchProcess);
Huahui Wu8465cc92011-01-12 10:17:19 -08006071 } else {
6072 mVelocityTracker.addMovement(ev);
Grace Klobac2242f22010-03-05 14:00:26 -08006073 }
Grace Kloba9b657802010-04-08 13:46:23 -07006074 // set to MOTIONLESS_IGNORE so that it won't keep
6075 // removing and sending message in
6076 // drawCoreAndCursorRing()
6077 mHeldMotionless = MOTIONLESS_IGNORE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006078 doFling();
6079 break;
Adam Powell637d3372010-08-25 14:37:03 -07006080 } else {
6081 if (mScroller.springBack(mScrollX, mScrollY, 0,
6082 computeMaxScrollX(), 0,
6083 computeMaxScrollY())) {
6084 invalidate();
6085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006086 }
Grace Kloba9b657802010-04-08 13:46:23 -07006087 // redraw in high-quality, as we're done dragging
6088 mHeldMotionless = MOTIONLESS_TRUE;
6089 invalidate();
Grace Kloba524aab572010-04-07 11:12:52 -07006090 // fall through
6091 case TOUCH_DRAG_START_MODE:
6092 // TOUCH_DRAG_START_MODE should not happen for the real
6093 // device as we almost certain will get a MOVE. But this
6094 // is possible on emulator.
Cary Clark278ce052009-08-31 16:08:42 -04006095 mLastVelocity = 0;
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006096 WebViewCore.resumePriority();
Cary Clark0df02692010-11-24 11:01:37 -05006097 if (!mSelectingText) {
6098 WebViewCore.resumeUpdatePicture(mWebViewCore);
6099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006100 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006101 }
Grace Klobac2242f22010-03-05 14:00:26 -08006102 stopTouch();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006103 break;
6104 }
6105 case MotionEvent.ACTION_CANCEL: {
Grace Klobad7625dd2010-03-04 11:46:12 -08006106 if (mTouchMode == TOUCH_DRAG_MODE) {
Adam Powell637d3372010-08-25 14:37:03 -07006107 mScroller.springBack(mScrollX, mScrollY, 0,
6108 computeMaxScrollX(), 0, computeMaxScrollY());
Grace Klobac2242f22010-03-05 14:00:26 -08006109 invalidate();
Grace Klobad7625dd2010-03-04 11:46:12 -08006110 }
Grace Klobac2242f22010-03-05 14:00:26 -08006111 cancelWebCoreTouchEvent(contentX, contentY, false);
6112 cancelTouch();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006113 break;
6114 }
6115 }
6116 return true;
6117 }
Cary Clarkd6982c92009-05-29 11:02:22 -04006118
Adam Powell4fb35d42011-03-03 17:54:55 -08006119 private void passMultiTouchToWebKit(MotionEvent ev, long sequence) {
Huahui Wu41865f42010-09-02 13:41:41 -07006120 TouchEventData ted = new TouchEventData();
Huahui Wu1f301252011-01-19 17:32:32 -08006121 ted.mAction = ev.getActionMasked();
Huahui Wu41865f42010-09-02 13:41:41 -07006122 final int count = ev.getPointerCount();
Huahui Wue838a422011-01-13 16:03:43 -08006123 ted.mIds = new int[count];
Huahui Wu41865f42010-09-02 13:41:41 -07006124 ted.mPoints = new Point[count];
Huahui Wu88b869a2011-03-17 17:42:12 -07006125 ted.mPointsInView = new Point[count];
Huahui Wu41865f42010-09-02 13:41:41 -07006126 for (int c = 0; c < count; c++) {
Huahui Wue838a422011-01-13 16:03:43 -08006127 ted.mIds[c] = ev.getPointerId(c);
Huahui Wu41865f42010-09-02 13:41:41 -07006128 int x = viewToContentX((int) ev.getX(c) + mScrollX);
6129 int y = viewToContentY((int) ev.getY(c) + mScrollY);
6130 ted.mPoints[c] = new Point(x, y);
Huahui Wu88b869a2011-03-17 17:42:12 -07006131 ted.mPointsInView[c] = new Point((int) ev.getX(c), (int) ev.getY(c));
Huahui Wu41865f42010-09-02 13:41:41 -07006132 }
Huahui Wu2d3ef372011-03-13 18:13:42 -07006133 if (ted.mAction == MotionEvent.ACTION_POINTER_DOWN
6134 || ted.mAction == MotionEvent.ACTION_POINTER_UP) {
6135 ted.mActionIndex = ev.getActionIndex();
6136 }
Huahui Wu41865f42010-09-02 13:41:41 -07006137 ted.mMetaState = ev.getMetaState();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006138 ted.mReprocess = true;
6139 ted.mMotionEvent = MotionEvent.obtain(ev);
Adam Powell4fb35d42011-03-03 17:54:55 -08006140 ted.mSequence = sequence;
Adam Powell3c534772011-04-04 14:27:12 -07006141 mTouchEventQueue.preQueueTouchEventData(ted);
Huahui Wu41865f42010-09-02 13:41:41 -07006142 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6143 cancelLongPress();
6144 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
Huahui Wu41865f42010-09-02 13:41:41 -07006145 }
6146
Adam Powell8f626a12011-03-10 19:27:15 -08006147 void handleMultiTouchInWebView(MotionEvent ev) {
Huahui Wu0904c0d2011-01-07 17:30:53 -08006148 if (DebugFlags.WEB_VIEW) {
6149 Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime()
6150 + " mTouchMode=" + mTouchMode
6151 + " numPointers=" + ev.getPointerCount()
6152 + " scrolloffset=(" + mScrollX + "," + mScrollY + ")");
6153 }
6154
6155 final ScaleGestureDetector detector =
6156 mZoomManager.getMultiTouchGestureDetector();
Huahui Wu8465cc92011-01-12 10:17:19 -08006157
6158 // A few apps use WebView but don't instantiate gesture detector.
6159 // We don't need to support multi touch for them.
Huahui Wu1f301252011-01-19 17:32:32 -08006160 if (detector == null) return;
Huahui Wu8465cc92011-01-12 10:17:19 -08006161
Huahui Wu0904c0d2011-01-07 17:30:53 -08006162 float x = ev.getX();
6163 float y = ev.getY();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006164
Adam Powell8f626a12011-03-10 19:27:15 -08006165 if (mPreventDefault != PREVENT_DEFAULT_YES) {
6166 detector.onTouchEvent(ev);
Huahui Wu0904c0d2011-01-07 17:30:53 -08006167
Adam Powell8f626a12011-03-10 19:27:15 -08006168 if (detector.isInProgress()) {
6169 if (DebugFlags.WEB_VIEW) {
6170 Log.v(LOGTAG, "detector is in progress");
6171 }
6172 mLastTouchTime = ev.getEventTime();
6173 x = detector.getFocusX();
6174 y = detector.getFocusY();
Huahui Wuf147d452011-01-12 14:02:36 -08006175
Adam Powell8f626a12011-03-10 19:27:15 -08006176 cancelLongPress();
6177 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6178 if (!mZoomManager.supportsPanDuringZoom()) {
6179 return;
6180 }
6181 mTouchMode = TOUCH_DRAG_MODE;
6182 if (mVelocityTracker == null) {
6183 mVelocityTracker = VelocityTracker.obtain();
6184 }
Huahui Wu0904c0d2011-01-07 17:30:53 -08006185 }
6186 }
6187
Huahui Wuf147d452011-01-12 14:02:36 -08006188 int action = ev.getActionMasked();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006189 if (action == MotionEvent.ACTION_POINTER_DOWN) {
6190 cancelTouch();
6191 action = MotionEvent.ACTION_DOWN;
Adam Powell4fb35d42011-03-03 17:54:55 -08006192 } else if (action == MotionEvent.ACTION_POINTER_UP && ev.getPointerCount() == 2) {
Huahui Wu0904c0d2011-01-07 17:30:53 -08006193 // set mLastTouchX/Y to the remaining point
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006194 mLastTouchX = Math.round(x);
6195 mLastTouchY = Math.round(y);
Huahui Wu0904c0d2011-01-07 17:30:53 -08006196 } else if (action == MotionEvent.ACTION_MOVE) {
6197 // negative x or y indicate it is on the edge, skip it.
6198 if (x < 0 || y < 0) {
Huahui Wu1f301252011-01-19 17:32:32 -08006199 return;
Huahui Wu0904c0d2011-01-07 17:30:53 -08006200 }
6201 }
6202
Huahui Wu1f301252011-01-19 17:32:32 -08006203 handleTouchEventCommon(ev, action, Math.round(x), Math.round(y));
Huahui Wu0904c0d2011-01-07 17:30:53 -08006204 }
6205
Grace Klobac2242f22010-03-05 14:00:26 -08006206 private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
6207 if (shouldForwardTouchEvent()) {
6208 if (removeEvents) {
6209 mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
6210 }
6211 TouchEventData ted = new TouchEventData();
Huahui Wue838a422011-01-13 16:03:43 -08006212 ted.mIds = new int[1];
6213 ted.mIds[0] = 0;
Huahui Wu41865f42010-09-02 13:41:41 -07006214 ted.mPoints = new Point[1];
6215 ted.mPoints[0] = new Point(x, y);
Huahui Wu88b869a2011-03-17 17:42:12 -07006216 ted.mPointsInView = new Point[1];
6217 int viewX = contentToViewX(x) - mScrollX;
6218 int viewY = contentToViewY(y) - mScrollY;
6219 ted.mPointsInView[0] = new Point(viewX, viewY);
Grace Klobac2242f22010-03-05 14:00:26 -08006220 ted.mAction = MotionEvent.ACTION_CANCEL;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006221 ted.mNativeLayer = nativeScrollableLayer(
6222 x, y, ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08006223 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Grace Klobac2242f22010-03-05 14:00:26 -08006224 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6225 mPreventDefault = PREVENT_DEFAULT_IGNORE;
Adam Powellbaa33802011-03-25 13:58:19 -07006226
6227 if (removeEvents) {
6228 // Mark this after sending the message above; we should
6229 // be willing to ignore the cancel event that we just sent.
6230 mTouchEventQueue.ignoreCurrentlyMissingEvents();
6231 }
Grace Klobac2242f22010-03-05 14:00:26 -08006232 }
6233 }
6234
Grace Kloba3a0def22010-01-23 21:11:54 -08006235 private void startTouch(float x, float y, long eventTime) {
6236 // Remember where the motion event started
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006237 mLastTouchX = Math.round(x);
6238 mLastTouchY = Math.round(y);
Grace Kloba3a0def22010-01-23 21:11:54 -08006239 mLastTouchTime = eventTime;
6240 mVelocityTracker = VelocityTracker.obtain();
6241 mSnapScrollMode = SNAP_NONE;
Grace Kloba3a0def22010-01-23 21:11:54 -08006242 }
6243
Grace Klobac2242f22010-03-05 14:00:26 -08006244 private void startDrag() {
6245 WebViewCore.reducePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006246 // to get better performance, pause updating the picture
6247 WebViewCore.pauseUpdatePicture(mWebViewCore);
Grace Klobac2242f22010-03-05 14:00:26 -08006248 if (!mDragFromTextInput) {
6249 nativeHideCursor();
6250 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006251
6252 if (mHorizontalScrollBarMode != SCROLLBAR_ALWAYSOFF
6253 || mVerticalScrollBarMode != SCROLLBAR_ALWAYSOFF) {
6254 mZoomManager.invokeZoomPicker();
Grace Klobac2242f22010-03-05 14:00:26 -08006255 }
6256 }
6257
6258 private void doDrag(int deltaX, int deltaY) {
6259 if ((deltaX | deltaY) != 0) {
Patrick Scott62310912010-12-06 17:44:50 -05006260 int oldX = mScrollX;
6261 int oldY = mScrollY;
6262 int rangeX = computeMaxScrollX();
6263 int rangeY = computeMaxScrollY();
6264 int overscrollDistance = mOverscrollDistance;
Adam Powell637d3372010-08-25 14:37:03 -07006265
Patrick Scott62310912010-12-06 17:44:50 -05006266 // Check for the original scrolling layer in case we change
6267 // directions. mTouchMode might be TOUCH_DRAG_MODE if we have
6268 // reached the edge of a layer but mScrollingLayer will be non-zero
6269 // if we initiated the drag on a layer.
6270 if (mScrollingLayer != 0) {
6271 final int contentX = viewToContentDimension(deltaX);
6272 final int contentY = viewToContentDimension(deltaY);
6273
6274 // Check the scrolling bounds to see if we will actually do any
6275 // scrolling. The rectangle is in document coordinates.
6276 final int maxX = mScrollingLayerRect.right;
6277 final int maxY = mScrollingLayerRect.bottom;
6278 final int resultX = Math.max(0,
6279 Math.min(mScrollingLayerRect.left + contentX, maxX));
6280 final int resultY = Math.max(0,
6281 Math.min(mScrollingLayerRect.top + contentY, maxY));
6282
6283 if (resultX != mScrollingLayerRect.left ||
6284 resultY != mScrollingLayerRect.top) {
6285 // In case we switched to dragging the page.
6286 mTouchMode = TOUCH_DRAG_LAYER_MODE;
6287 deltaX = contentX;
6288 deltaY = contentY;
6289 oldX = mScrollingLayerRect.left;
6290 oldY = mScrollingLayerRect.top;
6291 rangeX = maxX;
6292 rangeY = maxY;
6293 } else {
6294 // Scroll the main page if we are not going to scroll the
6295 // layer. This does not reset mScrollingLayer in case the
6296 // user changes directions and the layer can scroll the
6297 // other way.
6298 mTouchMode = TOUCH_DRAG_MODE;
6299 }
6300 }
Adam Powell637d3372010-08-25 14:37:03 -07006301
6302 if (mOverScrollGlow != null) {
6303 mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
6304 }
6305
6306 overScrollBy(deltaX, deltaY, oldX, oldY,
6307 rangeX, rangeY,
6308 mOverscrollDistance, mOverscrollDistance, true);
6309 if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
6310 invalidate();
6311 }
Grace Klobac2242f22010-03-05 14:00:26 -08006312 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006313 mZoomManager.keepZoomPickerVisible();
Grace Klobac2242f22010-03-05 14:00:26 -08006314 }
6315
6316 private void stopTouch() {
Grace Klobac2242f22010-03-05 14:00:26 -08006317 // we also use mVelocityTracker == null to tell us that we are
6318 // not "moving around", so we can take the slower/prettier
6319 // mode in the drawing code
6320 if (mVelocityTracker != null) {
6321 mVelocityTracker.recycle();
6322 mVelocityTracker = null;
6323 }
Adam Powell637d3372010-08-25 14:37:03 -07006324
6325 // Release any pulled glows
6326 if (mOverScrollGlow != null) {
6327 mOverScrollGlow.releaseAll();
6328 }
Grace Klobac2242f22010-03-05 14:00:26 -08006329 }
6330
Grace Kloba3a0def22010-01-23 21:11:54 -08006331 private void cancelTouch() {
Grace Kloba3a0def22010-01-23 21:11:54 -08006332 // we also use mVelocityTracker == null to tell us that we are
6333 // not "moving around", so we can take the slower/prettier
6334 // mode in the drawing code
6335 if (mVelocityTracker != null) {
6336 mVelocityTracker.recycle();
6337 mVelocityTracker = null;
6338 }
Adam Powell637d3372010-08-25 14:37:03 -07006339
Cary Clark0df02692010-11-24 11:01:37 -05006340 if ((mTouchMode == TOUCH_DRAG_MODE
6341 || mTouchMode == TOUCH_DRAG_LAYER_MODE) && !mSelectingText) {
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006342 WebViewCore.resumePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006343 WebViewCore.resumeUpdatePicture(mWebViewCore);
Grace Kloba3a0def22010-01-23 21:11:54 -08006344 }
6345 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
6346 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6347 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
6348 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
Grace Kloba178db412010-05-18 22:22:23 -07006349 if (getSettings().supportTouchOnly()) {
6350 removeTouchHighlight(true);
6351 }
Grace Kloba3a0def22010-01-23 21:11:54 -08006352 mHeldMotionless = MOTIONLESS_TRUE;
6353 mTouchMode = TOUCH_DONE_MODE;
6354 nativeHideCursor();
6355 }
6356
Jeff Brown33bbfd22011-02-24 20:55:35 -08006357 @Override
6358 public boolean onGenericMotionEvent(MotionEvent event) {
6359 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
6360 switch (event.getAction()) {
6361 case MotionEvent.ACTION_SCROLL: {
6362 final float vscroll;
6363 final float hscroll;
6364 if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
6365 vscroll = 0;
6366 hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
6367 } else {
6368 vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
6369 hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
6370 }
6371 if (hscroll != 0 || vscroll != 0) {
6372 final int vdelta = (int) (vscroll * getVerticalScrollFactor());
6373 final int hdelta = (int) (hscroll * getHorizontalScrollFactor());
6374 if (pinScrollBy(hdelta, vdelta, true, 0)) {
6375 return true;
6376 }
6377 }
6378 }
6379 }
6380 }
6381 return super.onGenericMotionEvent(event);
6382 }
6383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006384 private long mTrackballFirstTime = 0;
6385 private long mTrackballLastTime = 0;
6386 private float mTrackballRemainsX = 0.0f;
6387 private float mTrackballRemainsY = 0.0f;
6388 private int mTrackballXMove = 0;
6389 private int mTrackballYMove = 0;
Cary Clark924af702010-06-04 16:37:43 -04006390 private boolean mSelectingText = false;
6391 private boolean mSelectionStarted = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006392 private boolean mExtendSelection = false;
Cary Clark924af702010-06-04 16:37:43 -04006393 private boolean mDrawSelectionPointer = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006394 private static final int TRACKBALL_KEY_TIMEOUT = 1000;
6395 private static final int TRACKBALL_TIMEOUT = 200;
6396 private static final int TRACKBALL_WAIT = 100;
6397 private static final int TRACKBALL_SCALE = 400;
6398 private static final int TRACKBALL_SCROLL_COUNT = 5;
6399 private static final int TRACKBALL_MOVE_COUNT = 10;
6400 private static final int TRACKBALL_MULTIPLIER = 3;
6401 private static final int SELECT_CURSOR_OFFSET = 16;
Cary Clark6f5dfc62010-11-11 13:09:20 -05006402 private static final int SELECT_SCROLL = 5;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006403 private int mSelectX = 0;
6404 private int mSelectY = 0;
Cary Clark5da9aeb2009-10-06 17:40:53 -04006405 private boolean mFocusSizeChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006406 private boolean mTrackballDown = false;
6407 private long mTrackballUpTime = 0;
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006408 private long mLastCursorTime = 0;
6409 private Rect mLastCursorBounds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006410
6411 // Set by default; BrowserActivity clears to interpret trackball data
Cary Clarkd6982c92009-05-29 11:02:22 -04006412 // directly for movement. Currently, the framework only passes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006413 // arrow key events, not trackball events, from one child to the next
6414 private boolean mMapTrackballToArrowKeys = true;
Cary Clarkd6982c92009-05-29 11:02:22 -04006415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006416 public void setMapTrackballToArrowKeys(boolean setMap) {
Steve Block51b08912011-04-27 15:04:48 +01006417 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006418 mMapTrackballToArrowKeys = setMap;
6419 }
6420
6421 void resetTrackballTime() {
6422 mTrackballLastTime = 0;
6423 }
6424
6425 @Override
6426 public boolean onTrackballEvent(MotionEvent ev) {
6427 long time = ev.getEventTime();
6428 if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
6429 if (ev.getY() > 0) pageDown(true);
6430 if (ev.getY() < 0) pageUp(true);
6431 return true;
6432 }
6433 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Cary Clark924af702010-06-04 16:37:43 -04006434 if (mSelectingText) {
Cary Clarkbadd8392009-10-15 13:32:08 -04006435 return true; // discard press if copy in progress
6436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006437 mTrackballDown = true;
Leon Scroggins3ccd3652009-06-26 17:22:50 -04006438 if (mNativeClass == 0) {
6439 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006440 }
Leon Scroggins3ccd3652009-06-26 17:22:50 -04006441 nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006442 if (time - mLastCursorTime <= TRACKBALL_TIMEOUT
6443 && !mLastCursorBounds.equals(nativeGetCursorRingBounds())) {
6444 nativeSelectBestAt(mLastCursorBounds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006445 }
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006446 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006447 Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
Cary Clarkd6982c92009-05-29 11:02:22 -04006448 + " time=" + time
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006449 + " mLastCursorTime=" + mLastCursorTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006450 }
6451 if (isInTouchMode()) requestFocusFromTouch();
6452 return false; // let common code in onKeyDown at it
Cary Clarkd6982c92009-05-29 11:02:22 -04006453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006454 if (ev.getAction() == MotionEvent.ACTION_UP) {
Leon Scrogginse3225672009-06-03 15:53:13 -04006455 // LONG_PRESS_CENTER is set in common onKeyDown
6456 mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006457 mTrackballDown = false;
6458 mTrackballUpTime = time;
Cary Clark924af702010-06-04 16:37:43 -04006459 if (mSelectingText) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006460 if (mExtendSelection) {
Cary Clark924af702010-06-04 16:37:43 -04006461 copySelection();
6462 selectionDone();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006463 } else {
6464 mExtendSelection = true;
Cary Clark924af702010-06-04 16:37:43 -04006465 nativeSetExtendSelection();
Cary Clark09e383c2009-10-26 16:43:58 -04006466 invalidate(); // draw the i-beam instead of the arrow
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006467 }
Cary Clarkbadd8392009-10-15 13:32:08 -04006468 return true; // discard press if copy in progress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006469 }
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006470 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006471 Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
Cary Clarkd6982c92009-05-29 11:02:22 -04006472 + " time=" + time
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006473 );
6474 }
6475 return false; // let common code in onKeyUp at it
6476 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07006477 if ((mMapTrackballToArrowKeys && (ev.getMetaState() & KeyEvent.META_SHIFT_ON) == 0) ||
Svetoslav Ganov12bed782011-01-03 14:14:50 -08006478 AccessibilityManager.getInstance(mContext).isEnabled()) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006479 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006480 return false;
6481 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006482 if (mTrackballDown) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006483 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006484 return true; // discard move if trackball is down
6485 }
6486 if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006487 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006488 return true;
6489 }
6490 // TODO: alternatively we can do panning as touch does
6491 switchOutDrawHistory();
6492 if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006493 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04006494 Log.v(LOGTAG, "onTrackballEvent time="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006495 + time + " last=" + mTrackballLastTime);
6496 }
6497 mTrackballFirstTime = time;
6498 mTrackballXMove = mTrackballYMove = 0;
6499 }
6500 mTrackballLastTime = time;
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006501 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006502 Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time);
6503 }
6504 mTrackballRemainsX += ev.getX();
6505 mTrackballRemainsY += ev.getY();
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07006506 doTrackball(time, ev.getMetaState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006507 return true;
6508 }
Cary Clarkd6982c92009-05-29 11:02:22 -04006509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006510 void moveSelection(float xRate, float yRate) {
6511 if (mNativeClass == 0)
6512 return;
6513 int width = getViewWidth();
6514 int height = getViewHeight();
Cary Clarkc05af372009-10-16 10:52:27 -04006515 mSelectX += xRate;
6516 mSelectY += yRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006517 int maxX = width + mScrollX;
6518 int maxY = height + mScrollY;
6519 mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
6520 , mSelectX));
6521 mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
6522 , mSelectY));
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006523 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04006524 Log.v(LOGTAG, "moveSelection"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006525 + " mSelectX=" + mSelectX
6526 + " mSelectY=" + mSelectY
6527 + " mScrollX=" + mScrollX
6528 + " mScrollY=" + mScrollY
6529 + " xRate=" + xRate
6530 + " yRate=" + yRate
6531 );
6532 }
Cary Clark924af702010-06-04 16:37:43 -04006533 nativeMoveSelection(viewToContentX(mSelectX), viewToContentY(mSelectY));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006534 int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
Cary Clarkd6982c92009-05-29 11:02:22 -04006535 : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006536 : 0;
6537 int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
Cary Clarkd6982c92009-05-29 11:02:22 -04006538 : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006539 : 0;
6540 pinScrollBy(scrollX, scrollY, true, 0);
6541 Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
6542 requestRectangleOnScreen(select);
6543 invalidate();
6544 }
6545
6546 private int scaleTrackballX(float xRate, int width) {
6547 int xMove = (int) (xRate / TRACKBALL_SCALE * width);
6548 int nextXMove = xMove;
6549 if (xMove > 0) {
6550 if (xMove > mTrackballXMove) {
6551 xMove -= mTrackballXMove;
6552 }
6553 } else if (xMove < mTrackballXMove) {
6554 xMove -= mTrackballXMove;
6555 }
6556 mTrackballXMove = nextXMove;
6557 return xMove;
6558 }
6559
6560 private int scaleTrackballY(float yRate, int height) {
6561 int yMove = (int) (yRate / TRACKBALL_SCALE * height);
6562 int nextYMove = yMove;
6563 if (yMove > 0) {
6564 if (yMove > mTrackballYMove) {
6565 yMove -= mTrackballYMove;
6566 }
6567 } else if (yMove < mTrackballYMove) {
6568 yMove -= mTrackballYMove;
6569 }
6570 mTrackballYMove = nextYMove;
6571 return yMove;
6572 }
6573
6574 private int keyCodeToSoundsEffect(int keyCode) {
6575 switch(keyCode) {
6576 case KeyEvent.KEYCODE_DPAD_UP:
6577 return SoundEffectConstants.NAVIGATION_UP;
6578 case KeyEvent.KEYCODE_DPAD_RIGHT:
6579 return SoundEffectConstants.NAVIGATION_RIGHT;
6580 case KeyEvent.KEYCODE_DPAD_DOWN:
6581 return SoundEffectConstants.NAVIGATION_DOWN;
6582 case KeyEvent.KEYCODE_DPAD_LEFT:
6583 return SoundEffectConstants.NAVIGATION_LEFT;
6584 }
6585 throw new IllegalArgumentException("keyCode must be one of " +
6586 "{KEYCODE_DPAD_UP, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_DOWN, " +
6587 "KEYCODE_DPAD_LEFT}.");
6588 }
6589
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07006590 private void doTrackball(long time, int metaState) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006591 int elapsed = (int) (mTrackballLastTime - mTrackballFirstTime);
6592 if (elapsed == 0) {
6593 elapsed = TRACKBALL_TIMEOUT;
6594 }
Cary Clarkd6982c92009-05-29 11:02:22 -04006595 float xRate = mTrackballRemainsX * 1000 / elapsed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006596 float yRate = mTrackballRemainsY * 1000 / elapsed;
Cary Clarkc05af372009-10-16 10:52:27 -04006597 int viewWidth = getViewWidth();
6598 int viewHeight = getViewHeight();
Cary Clark924af702010-06-04 16:37:43 -04006599 if (mSelectingText) {
6600 if (!mDrawSelectionPointer) {
6601 // The last selection was made by touch, disabling drawing the
6602 // selection pointer. Allow the trackball to adjust the
6603 // position of the touch control.
6604 mSelectX = contentToViewX(nativeSelectionX());
6605 mSelectY = contentToViewY(nativeSelectionY());
6606 mDrawSelectionPointer = mExtendSelection = true;
6607 nativeSetExtendSelection();
6608 }
Cary Clarkc05af372009-10-16 10:52:27 -04006609 moveSelection(scaleTrackballX(xRate, viewWidth),
6610 scaleTrackballY(yRate, viewHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006611 mTrackballRemainsX = mTrackballRemainsY = 0;
6612 return;
6613 }
6614 float ax = Math.abs(xRate);
6615 float ay = Math.abs(yRate);
6616 float maxA = Math.max(ax, ay);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006617 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006618 Log.v(LOGTAG, "doTrackball elapsed=" + elapsed
6619 + " xRate=" + xRate
6620 + " yRate=" + yRate
6621 + " mTrackballRemainsX=" + mTrackballRemainsX
6622 + " mTrackballRemainsY=" + mTrackballRemainsY);
6623 }
Cary Clarkc05af372009-10-16 10:52:27 -04006624 int width = mContentWidth - viewWidth;
6625 int height = mContentHeight - viewHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006626 if (width < 0) width = 0;
6627 if (height < 0) height = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006628 ax = Math.abs(mTrackballRemainsX * TRACKBALL_MULTIPLIER);
6629 ay = Math.abs(mTrackballRemainsY * TRACKBALL_MULTIPLIER);
6630 maxA = Math.max(ax, ay);
6631 int count = Math.max(0, (int) maxA);
6632 int oldScrollX = mScrollX;
6633 int oldScrollY = mScrollY;
6634 if (count > 0) {
Cary Clarkd6982c92009-05-29 11:02:22 -04006635 int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
6636 KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006637 mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
6638 KeyEvent.KEYCODE_DPAD_RIGHT;
6639 count = Math.min(count, TRACKBALL_MOVE_COUNT);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006640 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04006641 Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006642 + " count=" + count
6643 + " mTrackballRemainsX=" + mTrackballRemainsX
6644 + " mTrackballRemainsY=" + mTrackballRemainsY);
6645 }
Leon Scroggins9ab32b62010-05-03 14:19:50 +01006646 if (mNativeClass != 0 && nativePageShouldHandleShiftAndArrows()) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05006647 for (int i = 0; i < count; i++) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07006648 letPageHandleNavKey(selectKeyCode, time, true, metaState);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05006649 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07006650 letPageHandleNavKey(selectKeyCode, time, false, metaState);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05006651 } else if (navHandledKey(selectKeyCode, count, false, time)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006652 playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
6653 }
6654 mTrackballRemainsX = mTrackballRemainsY = 0;
6655 }
6656 if (count >= TRACKBALL_SCROLL_COUNT) {
6657 int xMove = scaleTrackballX(xRate, width);
6658 int yMove = scaleTrackballY(yRate, height);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006659 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006660 Log.v(LOGTAG, "doTrackball pinScrollBy"
6661 + " count=" + count
6662 + " xMove=" + xMove + " yMove=" + yMove
Cary Clarkd6982c92009-05-29 11:02:22 -04006663 + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
6664 + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006665 );
6666 }
6667 if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
6668 xMove = 0;
6669 }
6670 if (Math.abs(mScrollY - oldScrollY) > Math.abs(yMove)) {
6671 yMove = 0;
6672 }
6673 if (xMove != 0 || yMove != 0) {
6674 pinScrollBy(xMove, yMove, true, 0);
6675 }
Cary Clarkd6982c92009-05-29 11:02:22 -04006676 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006677 }
6678
Adam Powell637d3372010-08-25 14:37:03 -07006679 /**
6680 * Compute the maximum horizontal scroll position. Used by {@link OverScrollGlow}.
6681 * @return Maximum horizontal scroll position within real content
6682 */
6683 int computeMaxScrollX() {
6684 return Math.max(computeRealHorizontalScrollRange() - getViewWidth(), 0);
Grace Klobad7625dd2010-03-04 11:46:12 -08006685 }
6686
Adam Powell637d3372010-08-25 14:37:03 -07006687 /**
6688 * Compute the maximum vertical scroll position. Used by {@link OverScrollGlow}.
6689 * @return Maximum vertical scroll position within real content
6690 */
6691 int computeMaxScrollY() {
6692 return Math.max(computeRealVerticalScrollRange() + getTitleHeight()
Mike Reede5e63f42010-03-19 14:38:23 -04006693 - getViewHeightWithTitle(), 0);
Mike Reede8853fc2009-09-04 14:01:48 -04006694 }
6695
Derek Sollenberger03e48912010-05-18 17:03:42 -04006696 boolean updateScrollCoordinates(int x, int y) {
6697 int oldX = mScrollX;
6698 int oldY = mScrollY;
6699 mScrollX = x;
6700 mScrollY = y;
6701 if (oldX != mScrollX || oldY != mScrollY) {
6702 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
6703 return true;
6704 } else {
6705 return false;
6706 }
6707 }
6708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006709 public void flingScroll(int vx, int vy) {
Steve Block51b08912011-04-27 15:04:48 +01006710 checkThread();
Grace Klobad7625dd2010-03-04 11:46:12 -08006711 mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
Adam Powell637d3372010-08-25 14:37:03 -07006712 computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006713 invalidate();
6714 }
Cary Clarkd6982c92009-05-29 11:02:22 -04006715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006716 private void doFling() {
6717 if (mVelocityTracker == null) {
6718 return;
6719 }
Grace Klobad7625dd2010-03-04 11:46:12 -08006720 int maxX = computeMaxScrollX();
Mike Reede8853fc2009-09-04 14:01:48 -04006721 int maxY = computeMaxScrollY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006722
Romain Guy4296fc42009-07-06 11:48:52 -07006723 mVelocityTracker.computeCurrentVelocity(1000, mMaximumFling);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006724 int vx = (int) mVelocityTracker.getXVelocity();
6725 int vy = (int) mVelocityTracker.getYVelocity();
6726
Patrick Scott62310912010-12-06 17:44:50 -05006727 int scrollX = mScrollX;
6728 int scrollY = mScrollY;
6729 int overscrollDistance = mOverscrollDistance;
6730 int overflingDistance = mOverflingDistance;
6731
6732 // Use the layer's scroll data if applicable.
6733 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
6734 scrollX = mScrollingLayerRect.left;
6735 scrollY = mScrollingLayerRect.top;
6736 maxX = mScrollingLayerRect.right;
6737 maxY = mScrollingLayerRect.bottom;
6738 // No overscrolling for layers.
6739 overscrollDistance = overflingDistance = 0;
6740 }
6741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006742 if (mSnapScrollMode != SNAP_NONE) {
Cary Clarkac492e12009-10-14 14:53:37 -04006743 if ((mSnapScrollMode & SNAP_X) == SNAP_X) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006744 vy = 0;
6745 } else {
6746 vx = 0;
6747 }
6748 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006749 if (true /* EMG release: make our fling more like Maps' */) {
6750 // maps cuts their velocity in half
6751 vx = vx * 3 / 4;
6752 vy = vy * 3 / 4;
6753 }
Cary Clarkaa7caa62009-09-08 14:15:07 -04006754 if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) {
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006755 WebViewCore.resumePriority();
Cary Clark0df02692010-11-24 11:01:37 -05006756 if (!mSelectingText) {
6757 WebViewCore.resumeUpdatePicture(mWebViewCore);
6758 }
Patrick Scott62310912010-12-06 17:44:50 -05006759 if (mScroller.springBack(scrollX, scrollY, 0, maxX, 0, maxY)) {
Adam Powell637d3372010-08-25 14:37:03 -07006760 invalidate();
6761 }
Cary Clarkaa7caa62009-09-08 14:15:07 -04006762 return;
6763 }
Cary Clark278ce052009-08-31 16:08:42 -04006764 float currentVelocity = mScroller.getCurrVelocity();
Grace Kloba3c19d992010-05-17 19:19:06 -07006765 float velocity = (float) Math.hypot(vx, vy);
6766 if (mLastVelocity > 0 && currentVelocity > 0 && velocity
6767 > mLastVelocity * MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION) {
Cary Clark278ce052009-08-31 16:08:42 -04006768 float deltaR = (float) (Math.abs(Math.atan2(mLastVelY, mLastVelX)
6769 - Math.atan2(vy, vx)));
6770 final float circle = (float) (Math.PI) * 2.0f;
6771 if (deltaR > circle * 0.9f || deltaR < circle * 0.1f) {
6772 vx += currentVelocity * mLastVelX / mLastVelocity;
6773 vy += currentVelocity * mLastVelY / mLastVelocity;
Grace Kloba3c19d992010-05-17 19:19:06 -07006774 velocity = (float) Math.hypot(vx, vy);
Cary Clark278ce052009-08-31 16:08:42 -04006775 if (DebugFlags.WEB_VIEW) {
6776 Log.v(LOGTAG, "doFling vx= " + vx + " vy=" + vy);
6777 }
6778 } else if (DebugFlags.WEB_VIEW) {
6779 Log.v(LOGTAG, "doFling missed " + deltaR / circle);
6780 }
6781 } else if (DebugFlags.WEB_VIEW) {
6782 Log.v(LOGTAG, "doFling start last=" + mLastVelocity
Cary Clarkaa7caa62009-09-08 14:15:07 -04006783 + " current=" + currentVelocity
6784 + " vx=" + vx + " vy=" + vy
6785 + " maxX=" + maxX + " maxY=" + maxY
Patrick Scott62310912010-12-06 17:44:50 -05006786 + " scrollX=" + scrollX + " scrollY=" + scrollY
6787 + " layer=" + mScrollingLayer);
Cary Clark278ce052009-08-31 16:08:42 -04006788 }
Adam Powell637d3372010-08-25 14:37:03 -07006789
6790 // Allow sloppy flings without overscrolling at the edges.
Patrick Scott62310912010-12-06 17:44:50 -05006791 if ((scrollX == 0 || scrollX == maxX) && Math.abs(vx) < Math.abs(vy)) {
Adam Powell637d3372010-08-25 14:37:03 -07006792 vx = 0;
6793 }
Patrick Scott62310912010-12-06 17:44:50 -05006794 if ((scrollY == 0 || scrollY == maxY) && Math.abs(vy) < Math.abs(vx)) {
Adam Powell637d3372010-08-25 14:37:03 -07006795 vy = 0;
6796 }
6797
Patrick Scott62310912010-12-06 17:44:50 -05006798 if (overscrollDistance < overflingDistance) {
6799 if ((vx > 0 && scrollX == -overscrollDistance) ||
6800 (vx < 0 && scrollX == maxX + overscrollDistance)) {
Adam Powell637d3372010-08-25 14:37:03 -07006801 vx = 0;
6802 }
Patrick Scott62310912010-12-06 17:44:50 -05006803 if ((vy > 0 && scrollY == -overscrollDistance) ||
6804 (vy < 0 && scrollY == maxY + overscrollDistance)) {
Adam Powell637d3372010-08-25 14:37:03 -07006805 vy = 0;
6806 }
6807 }
6808
Cary Clark278ce052009-08-31 16:08:42 -04006809 mLastVelX = vx;
6810 mLastVelY = vy;
Grace Kloba3c19d992010-05-17 19:19:06 -07006811 mLastVelocity = velocity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006812
Adam Powell637d3372010-08-25 14:37:03 -07006813 // no horizontal overscroll if the content just fits
Patrick Scott62310912010-12-06 17:44:50 -05006814 mScroller.fling(scrollX, scrollY, -vx, -vy, 0, maxX, 0, maxY,
6815 maxX == 0 ? 0 : overflingDistance, overflingDistance);
Adam Powell637d3372010-08-25 14:37:03 -07006816 // Duration is calculated based on velocity. With range boundaries and overscroll
6817 // we may not know how long the final animation will take. (Hence the deprecation
6818 // warning on the call below.) It's not a big deal for scroll bars but if webcore
6819 // resumes during this effect we will take a performance hit. See computeScroll;
6820 // we resume webcore there when the animation is finished.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006821 final int time = mScroller.getDuration();
Patrick Scott5b87e292010-12-13 09:20:32 -05006822
6823 // Suppress scrollbars for layer scrolling.
6824 if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
6825 awakenScrollBars(time);
6826 }
6827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006828 invalidate();
6829 }
6830
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07006831 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006832 * Returns a view containing zoom controls i.e. +/- buttons. The caller is
6833 * in charge of installing this view to the view hierarchy. This view will
6834 * become visible when the user starts scrolling via touch and fade away if
6835 * the user does not interact with it.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07006836 * <p/>
The Android Open Source Project10592532009-03-18 17:39:46 -07006837 * API version 3 introduces a built-in zoom mechanism that is shown
6838 * automatically by the MapView. This is the preferred approach for
6839 * showing the zoom UI.
6840 *
6841 * @deprecated The built-in zoom mechanism is preferred, see
6842 * {@link WebSettings#setBuiltInZoomControls(boolean)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006843 */
The Android Open Source Project10592532009-03-18 17:39:46 -07006844 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006845 public View getZoomControls() {
Steve Block51b08912011-04-27 15:04:48 +01006846 checkThread();
The Android Open Source Project10592532009-03-18 17:39:46 -07006847 if (!getSettings().supportZoom()) {
6848 Log.w(LOGTAG, "This WebView doesn't support zoom.");
6849 return null;
6850 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006851 return mZoomManager.getExternalZoomPicker();
The Android Open Source Project10592532009-03-18 17:39:46 -07006852 }
6853
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006854 void dismissZoomControl() {
6855 mZoomManager.dismissZoomPicker();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006856 }
6857
Derek Sollenberger03e48912010-05-18 17:03:42 -04006858 float getDefaultZoomScale() {
Derek Sollenberger341e22f2010-06-02 12:34:34 -04006859 return mZoomManager.getDefaultScale();
Derek Sollenberger03e48912010-05-18 17:03:42 -04006860 }
6861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006862 /**
Grace Kloba6164ef12010-06-01 15:59:13 -07006863 * @return TRUE if the WebView can be zoomed in.
6864 */
6865 public boolean canZoomIn() {
Steve Block51b08912011-04-27 15:04:48 +01006866 checkThread();
Grace Kloba6164ef12010-06-01 15:59:13 -07006867 return mZoomManager.canZoomIn();
6868 }
6869
6870 /**
6871 * @return TRUE if the WebView can be zoomed out.
6872 */
6873 public boolean canZoomOut() {
Steve Block51b08912011-04-27 15:04:48 +01006874 checkThread();
Grace Kloba6164ef12010-06-01 15:59:13 -07006875 return mZoomManager.canZoomOut();
6876 }
6877
6878 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006879 * Perform zoom in in the webview
6880 * @return TRUE if zoom in succeeds. FALSE if no zoom changes.
6881 */
6882 public boolean zoomIn() {
Steve Block51b08912011-04-27 15:04:48 +01006883 checkThread();
Derek Sollenberger03e48912010-05-18 17:03:42 -04006884 return mZoomManager.zoomIn();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006885 }
6886
6887 /**
6888 * Perform zoom out in the webview
6889 * @return TRUE if zoom out succeeds. FALSE if no zoom changes.
6890 */
6891 public boolean zoomOut() {
Steve Block51b08912011-04-27 15:04:48 +01006892 checkThread();
Derek Sollenberger03e48912010-05-18 17:03:42 -04006893 return mZoomManager.zoomOut();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006894 }
6895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006896 private void updateSelection() {
6897 if (mNativeClass == 0) {
6898 return;
6899 }
6900 // mLastTouchX and mLastTouchY are the point in the current viewport
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006901 int contentX = viewToContentX(mLastTouchX + mScrollX);
6902 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clarke9290822011-02-22 13:20:56 -05006903 int slop = viewToContentDimension(mNavSlop);
6904 Rect rect = new Rect(contentX - slop, contentY - slop,
6905 contentX + slop, contentY + slop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006906 nativeSelectBestAt(rect);
Cary Clarkb8491342010-11-29 16:23:19 -05006907 mInitialHitTestResult = hitTestResult(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006908 }
6909
Leon Scroggins0f5ad842009-07-17 15:08:34 -04006910 /**
Leon Scrogginsd5188652011-01-19 17:01:55 -05006911 * Scroll the focused text field to match the WebTextView
Cary Clarkeaa18de2009-09-28 12:50:42 -04006912 * @param xPercent New x position of the WebTextView from 0 to 1.
Leon Scroggins72543e12009-07-23 15:29:45 -04006913 */
Leon Scrogginsd5188652011-01-19 17:01:55 -05006914 /*package*/ void scrollFocusedTextInputX(float xPercent) {
Leon Scroggins72543e12009-07-23 15:29:45 -04006915 if (!inEditingMode() || mWebViewCore == null) {
6916 return;
6917 }
Leon Scrogginsd5188652011-01-19 17:01:55 -05006918 mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0,
Cary Clarkeaa18de2009-09-28 12:50:42 -04006919 new Float(xPercent));
Leon Scroggins72543e12009-07-23 15:29:45 -04006920 }
6921
6922 /**
Leon Scrogginsd5188652011-01-19 17:01:55 -05006923 * Scroll the focused textarea vertically to match the WebTextView
6924 * @param y New y position of the WebTextView in view coordinates
6925 */
6926 /* package */ void scrollFocusedTextInputY(int y) {
Leon Scroggins22e883d2011-01-31 10:54:19 -05006927 if (!inEditingMode() || mWebViewCore == null) {
Leon Scrogginsd5188652011-01-19 17:01:55 -05006928 return;
6929 }
Leon Scroggins22e883d2011-01-31 10:54:19 -05006930 mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0, viewToContentDimension(y));
Leon Scrogginsd5188652011-01-19 17:01:55 -05006931 }
6932
6933 /**
Leon Scroggins0f5ad842009-07-17 15:08:34 -04006934 * Set our starting point and time for a drag from the WebTextView.
6935 */
6936 /*package*/ void initiateTextFieldDrag(float x, float y, long eventTime) {
6937 if (!inEditingMode()) {
6938 return;
6939 }
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006940 mLastTouchX = Math.round(x + mWebTextView.getLeft() - mScrollX);
6941 mLastTouchY = Math.round(y + mWebTextView.getTop() - mScrollY);
Leon Scroggins0f5ad842009-07-17 15:08:34 -04006942 mLastTouchTime = eventTime;
6943 if (!mScroller.isFinished()) {
Cary Clark278ce052009-08-31 16:08:42 -04006944 abortAnimation();
Grace Kloba96949ef2010-01-25 09:53:01 -08006945 mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
Leon Scroggins0f5ad842009-07-17 15:08:34 -04006946 }
6947 mSnapScrollMode = SNAP_NONE;
6948 mVelocityTracker = VelocityTracker.obtain();
6949 mTouchMode = TOUCH_DRAG_START_MODE;
6950 }
6951
6952 /**
6953 * Given a motion event from the WebTextView, set its location to our
6954 * coordinates, and handle the event.
6955 */
6956 /*package*/ boolean textFieldDrag(MotionEvent event) {
6957 if (!inEditingMode()) {
6958 return false;
6959 }
Leon Scroggins72543e12009-07-23 15:29:45 -04006960 mDragFromTextInput = true;
Leon Scroggins0f5ad842009-07-17 15:08:34 -04006961 event.offsetLocation((float) (mWebTextView.getLeft() - mScrollX),
6962 (float) (mWebTextView.getTop() - mScrollY));
Leon Scroggins72543e12009-07-23 15:29:45 -04006963 boolean result = onTouchEvent(event);
6964 mDragFromTextInput = false;
6965 return result;
Leon Scroggins0f5ad842009-07-17 15:08:34 -04006966 }
6967
Leon Scroggins6679f2f2009-08-12 18:48:10 -04006968 /**
Leon Scrogginsf90b1262009-11-24 14:49:21 -05006969 * Due a touch up from a WebTextView. This will be handled by webkit to
Leon Scroggins6679f2f2009-08-12 18:48:10 -04006970 * change the selection.
6971 * @param event MotionEvent in the WebTextView's coordinates.
6972 */
6973 /*package*/ void touchUpOnTextField(MotionEvent event) {
6974 if (!inEditingMode()) {
6975 return;
6976 }
Leon Scroggins0236e672009-09-02 21:12:08 -04006977 int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
6978 int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
Cary Clarke9290822011-02-22 13:20:56 -05006979 int slop = viewToContentDimension(mNavSlop);
6980 nativeMotionUp(x, y, slop);
Leon Scroggins6679f2f2009-08-12 18:48:10 -04006981 }
6982
Leon Scroggins1d96ca02009-10-23 11:49:03 -04006983 /**
6984 * Called when pressing the center key or trackball on a textfield.
6985 */
6986 /*package*/ void centerKeyPressOnTextField() {
6987 mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
6988 nativeCursorNodePointer());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 }
6990
6991 private void doShortPress() {
6992 if (mNativeClass == 0) {
6993 return;
6994 }
Grace Klobac2242f22010-03-05 14:00:26 -08006995 if (mPreventDefault == PREVENT_DEFAULT_YES) {
6996 return;
6997 }
6998 mTouchMode = TOUCH_DONE_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006999 switchOutDrawHistory();
7000 // mLastTouchX and mLastTouchY are the point in the current viewport
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007001 int contentX = viewToContentX(mLastTouchX + mScrollX);
7002 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clarke9290822011-02-22 13:20:56 -05007003 int slop = viewToContentDimension(mNavSlop);
Grace Kloba178db412010-05-18 22:22:23 -07007004 if (getSettings().supportTouchOnly()) {
7005 removeTouchHighlight(false);
7006 WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
7007 // use "0" as generation id to inform WebKit to use the same x/y as
7008 // it used when processing GET_TOUCH_HIGHLIGHT_RECTS
7009 touchUpData.mMoveGeneration = 0;
7010 mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
Cary Clarke9290822011-02-22 13:20:56 -05007011 } else if (nativePointInNavCache(contentX, contentY, slop)) {
Cary Clark1cb97ee2009-12-11 12:10:36 -05007012 WebViewCore.MotionUpData motionUpData = new WebViewCore
7013 .MotionUpData();
7014 motionUpData.mFrame = nativeCacheHitFramePointer();
7015 motionUpData.mNode = nativeCacheHitNodePointer();
7016 motionUpData.mBounds = nativeCacheHitNodeBounds();
7017 motionUpData.mX = contentX;
7018 motionUpData.mY = contentY;
7019 mWebViewCore.sendMessageAtFrontOfQueue(EventHub.VALID_NODE_BOUNDS,
7020 motionUpData);
7021 } else {
Cary Clarkbad0c542010-01-11 14:58:21 -05007022 doMotionUp(contentX, contentY);
Cary Clark1cb97ee2009-12-11 12:10:36 -05007023 }
7024 }
7025
Cary Clarkbad0c542010-01-11 14:58:21 -05007026 private void doMotionUp(int contentX, int contentY) {
Cary Clarke9290822011-02-22 13:20:56 -05007027 int slop = viewToContentDimension(mNavSlop);
7028 if (nativeMotionUp(contentX, contentY, slop) && mLogEvent) {
Dan Egnor18e93962010-02-10 19:27:58 -08007029 EventLog.writeEvent(EventLogTags.BROWSER_SNAP_CENTER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007030 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007031 if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007032 playSoundEffect(SoundEffectConstants.CLICK);
7033 }
7034 }
7035
Cary Clarkb2601352011-01-11 11:32:01 -05007036 /**
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007037 * Returns plugin bounds if x/y in content coordinates corresponds to a
7038 * plugin. Otherwise a NULL rectangle is returned.
Cary Clarkb2601352011-01-11 11:32:01 -05007039 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007040 Rect getPluginBounds(int x, int y) {
Cary Clarke9290822011-02-22 13:20:56 -05007041 int slop = viewToContentDimension(mNavSlop);
7042 if (nativePointInNavCache(x, y, slop) && nativeCacheHitIsPlugin()) {
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007043 return nativeCacheHitNodeBounds();
7044 } else {
7045 return null;
7046 }
Cary Clarkb2601352011-01-11 11:32:01 -05007047 }
7048
Grace Klobac6f95fe2010-03-10 13:25:34 -08007049 /*
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007050 * Return true if the rect (e.g. plugin) is fully visible and maximized
7051 * inside the WebView.
Grace Klobac6f95fe2010-03-10 13:25:34 -08007052 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007053 boolean isRectFitOnScreen(Rect rect) {
7054 final int rectWidth = rect.width();
7055 final int rectHeight = rect.height();
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04007056 final int viewWidth = getViewWidth();
7057 final int viewHeight = getViewHeightWithTitle();
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007058 float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight / rectHeight);
Derek Sollenberger369aca22010-06-09 14:11:59 -04007059 scale = mZoomManager.computeScaleWithLimits(scale);
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04007060 return !mZoomManager.willScaleTriggerZoom(scale)
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007061 && contentToViewX(rect.left) >= mScrollX
7062 && contentToViewX(rect.right) <= mScrollX + viewWidth
7063 && contentToViewY(rect.top) >= mScrollY
7064 && contentToViewY(rect.bottom) <= mScrollY + viewHeight;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007065 }
7066
7067 /*
Grace Klobae8300a12010-03-12 13:32:55 -08007068 * Maximize and center the rectangle, specified in the document coordinate
7069 * space, inside the WebView. If the zoom doesn't need to be changed, do an
7070 * animated scroll to center it. If the zoom needs to be changed, find the
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007071 * zoom center and do a smooth zoom transition. The rect is in document
7072 * coordinates
Grace Klobac6f95fe2010-03-10 13:25:34 -08007073 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007074 void centerFitRect(Rect rect) {
7075 final int rectWidth = rect.width();
7076 final int rectHeight = rect.height();
7077 final int viewWidth = getViewWidth();
7078 final int viewHeight = getViewHeightWithTitle();
7079 float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight
7080 / rectHeight);
Derek Sollenberger369aca22010-06-09 14:11:59 -04007081 scale = mZoomManager.computeScaleWithLimits(scale);
Derek Sollenberger03e48912010-05-18 17:03:42 -04007082 if (!mZoomManager.willScaleTriggerZoom(scale)) {
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007083 pinScrollTo(contentToViewX(rect.left + rectWidth / 2) - viewWidth / 2,
7084 contentToViewY(rect.top + rectHeight / 2) - viewHeight / 2,
Grace Klobac6f95fe2010-03-10 13:25:34 -08007085 true, 0);
7086 } else {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04007087 float actualScale = mZoomManager.getScale();
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007088 float oldScreenX = rect.left * actualScale - mScrollX;
7089 float rectViewX = rect.left * scale;
7090 float rectViewWidth = rectWidth * scale;
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007091 float newMaxWidth = mContentWidth * scale;
7092 float newScreenX = (viewWidth - rectViewWidth) / 2;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007093 // pin the newX to the WebView
Grace Klobae8300a12010-03-12 13:32:55 -08007094 if (newScreenX > rectViewX) {
7095 newScreenX = rectViewX;
7096 } else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) {
7097 newScreenX = viewWidth - (newMaxWidth - rectViewX);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007098 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007099 float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale)
7100 / (scale - actualScale);
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007101 float oldScreenY = rect.top * actualScale + getTitleHeight()
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007102 - mScrollY;
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007103 float rectViewY = rect.top * scale + getTitleHeight();
7104 float rectViewHeight = rectHeight * scale;
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007105 float newMaxHeight = mContentHeight * scale + getTitleHeight();
7106 float newScreenY = (viewHeight - rectViewHeight) / 2;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007107 // pin the newY to the WebView
Grace Klobae8300a12010-03-12 13:32:55 -08007108 if (newScreenY > rectViewY) {
7109 newScreenY = rectViewY;
7110 } else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) {
7111 newScreenY = viewHeight - (newMaxHeight - rectViewY);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007112 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007113 float zoomCenterY = (oldScreenY * scale - newScreenY * actualScale)
7114 / (scale - actualScale);
7115 mZoomManager.setZoomCenter(zoomCenterX, zoomCenterY);
Derek Sollenberger87b17be52010-06-01 11:49:31 -04007116 mZoomManager.startZoomAnimation(scale, false);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007117 }
7118 }
7119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007120 // Called by JNI to handle a touch on a node representing an email address,
7121 // address, or phone number
7122 private void overrideLoading(String url) {
7123 mCallbackProxy.uiOverrideUrlLoading(url);
7124 }
7125
7126 @Override
7127 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
Leon Scroggins III26723fc2010-04-19 13:21:42 -04007128 // FIXME: If a subwindow is showing find, and the user touches the
7129 // background window, it can steal focus.
7130 if (mFindIsUp) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007131 boolean result = false;
7132 if (inEditingMode()) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04007133 result = mWebTextView.requestFocus(direction,
7134 previouslyFocusedRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007135 } else {
7136 result = super.requestFocus(direction, previouslyFocusedRect);
Leon Scroggins572ba782011-01-28 11:25:53 -05007137 if (mWebViewCore.getSettings().getNeedInitialFocus() && !isInTouchMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007138 // For cases such as GMail, where we gain focus from a direction,
7139 // we want to move to the first available link.
7140 // FIXME: If there are no visible links, we may not want to
7141 int fakeKeyDirection = 0;
7142 switch(direction) {
7143 case View.FOCUS_UP:
7144 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_UP;
7145 break;
7146 case View.FOCUS_DOWN:
7147 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_DOWN;
7148 break;
7149 case View.FOCUS_LEFT:
7150 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_LEFT;
7151 break;
7152 case View.FOCUS_RIGHT:
7153 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_RIGHT;
7154 break;
7155 default:
7156 return result;
7157 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007158 if (mNativeClass != 0 && !nativeHasCursorNode()) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007159 navHandledKey(fakeKeyDirection, 1, true, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007160 }
7161 }
7162 }
7163 return result;
7164 }
7165
7166 @Override
7167 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
7168 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
7169
7170 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
7171 int heightSize = MeasureSpec.getSize(heightMeasureSpec);
7172 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
7173 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
7174
7175 int measuredHeight = heightSize;
7176 int measuredWidth = widthSize;
7177
7178 // Grab the content size from WebViewCore.
Grace Klobae621d6f2009-09-11 13:20:39 -07007179 int contentHeight = contentToViewDimension(mContentHeight);
7180 int contentWidth = contentToViewDimension(mContentWidth);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007181
7182// Log.d(LOGTAG, "------- measure " + heightMode);
7183
7184 if (heightMode != MeasureSpec.EXACTLY) {
7185 mHeightCanMeasure = true;
7186 measuredHeight = contentHeight;
7187 if (heightMode == MeasureSpec.AT_MOST) {
7188 // If we are larger than the AT_MOST height, then our height can
7189 // no longer be measured and we should scroll internally.
7190 if (measuredHeight > heightSize) {
7191 measuredHeight = heightSize;
7192 mHeightCanMeasure = false;
Dianne Hackborn189ee182010-12-02 21:48:53 -08007193 } else if (measuredHeight < heightSize) {
7194 measuredHeight |= MEASURED_STATE_TOO_SMALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007195 }
7196 }
7197 } else {
7198 mHeightCanMeasure = false;
7199 }
7200 if (mNativeClass != 0) {
7201 nativeSetHeightCanMeasure(mHeightCanMeasure);
7202 }
7203 // For the width, always use the given size unless unspecified.
7204 if (widthMode == MeasureSpec.UNSPECIFIED) {
7205 mWidthCanMeasure = true;
7206 measuredWidth = contentWidth;
7207 } else {
Dianne Hackborn189ee182010-12-02 21:48:53 -08007208 if (measuredWidth < contentWidth) {
7209 measuredWidth |= MEASURED_STATE_TOO_SMALL;
7210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007211 mWidthCanMeasure = false;
7212 }
7213
7214 synchronized (this) {
7215 setMeasuredDimension(measuredWidth, measuredHeight);
7216 }
7217 }
7218
7219 @Override
7220 public boolean requestChildRectangleOnScreen(View child,
7221 Rect rect,
7222 boolean immediate) {
Cary Clarkdc09b5a2010-12-07 08:48:10 -05007223 if (mNativeClass == 0) {
7224 return false;
7225 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007226 // don't scroll while in zoom animation. When it is done, we will adjust
7227 // the necessary components (e.g., WebTextView if it is in editing mode)
Derek Sollenberger293c3602010-06-04 10:44:48 -04007228 if (mZoomManager.isFixedLengthAnimationInProgress()) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04007229 return false;
7230 }
7231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007232 rect.offset(child.getLeft() - child.getScrollX(),
7233 child.getTop() - child.getScrollY());
7234
Cary Clark31b83672010-03-09 09:20:34 -05007235 Rect content = new Rect(viewToContentX(mScrollX),
7236 viewToContentY(mScrollY),
7237 viewToContentX(mScrollX + getWidth()
7238 - getVerticalScrollbarWidth()),
7239 viewToContentY(mScrollY + getViewHeightWithTitle()));
7240 content = nativeSubtractLayers(content);
7241 int screenTop = contentToViewY(content.top);
7242 int screenBottom = contentToViewY(content.bottom);
7243 int height = screenBottom - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007244 int scrollYDelta = 0;
7245
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007246 if (rect.bottom > screenBottom) {
7247 int oneThirdOfScreenHeight = height / 3;
7248 if (rect.height() > 2 * oneThirdOfScreenHeight) {
7249 // If the rectangle is too tall to fit in the bottom two thirds
7250 // of the screen, place it at the top.
7251 scrollYDelta = rect.top - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007252 } else {
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007253 // If the rectangle will still fit on screen, we want its
7254 // top to be in the top third of the screen.
7255 scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007256 }
7257 } else if (rect.top < screenTop) {
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007258 scrollYDelta = rect.top - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007259 }
7260
Cary Clark31b83672010-03-09 09:20:34 -05007261 int screenLeft = contentToViewX(content.left);
7262 int screenRight = contentToViewX(content.right);
7263 int width = screenRight - screenLeft;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007264 int scrollXDelta = 0;
7265
7266 if (rect.right > screenRight && rect.left > screenLeft) {
7267 if (rect.width() > width) {
7268 scrollXDelta += (rect.left - screenLeft);
7269 } else {
7270 scrollXDelta += (rect.right - screenRight);
7271 }
7272 } else if (rect.left < screenLeft) {
7273 scrollXDelta -= (screenLeft - rect.left);
7274 }
7275
7276 if ((scrollYDelta | scrollXDelta) != 0) {
7277 return pinScrollBy(scrollXDelta, scrollYDelta, !immediate, 0);
7278 }
7279
7280 return false;
7281 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007283 /* package */ void replaceTextfieldText(int oldStart, int oldEnd,
7284 String replace, int newStart, int newEnd) {
Cary Clarkded054c2009-06-15 10:26:08 -04007285 WebViewCore.ReplaceTextData arg = new WebViewCore.ReplaceTextData();
7286 arg.mReplace = replace;
7287 arg.mNewStart = newStart;
7288 arg.mNewEnd = newEnd;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07007289 mTextGeneration++;
Leon Scroggins43488fc2009-07-06 14:32:49 -04007290 arg.mTextGeneration = mTextGeneration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007291 mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
7292 }
7293
7294 /* package */ void passToJavaScript(String currentText, KeyEvent event) {
Cary Clarkded054c2009-06-15 10:26:08 -04007295 WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
7296 arg.mEvent = event;
7297 arg.mCurrentText = currentText;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007298 // Increase our text generation number, and pass it to webcore thread
7299 mTextGeneration++;
7300 mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
7301 // WebKit's document state is not saved until about to leave the page.
Cary Clarkd6982c92009-05-29 11:02:22 -04007302 // To make sure the host application, like Browser, has the up to date
7303 // document state when it goes to background, we force to save the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007304 // document state.
7305 mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
7306 mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
Cary Clarkd6982c92009-05-29 11:02:22 -04007307 cursorData(), 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007308 }
7309
Andrei Popescu04098572010-03-09 12:23:19 +00007310 /* package */ synchronized WebViewCore getWebViewCore() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007311 return mWebViewCore;
7312 }
7313
Adam Powell4fb35d42011-03-03 17:54:55 -08007314 /**
7315 * Used only by TouchEventQueue to store pending touch events.
7316 */
7317 private static class QueuedTouch {
7318 long mSequence;
7319 MotionEvent mEvent; // Optional
7320 TouchEventData mTed; // Optional
7321
7322 QueuedTouch mNext;
7323
7324 public QueuedTouch set(TouchEventData ted) {
7325 mSequence = ted.mSequence;
7326 mTed = ted;
7327 mEvent = null;
7328 mNext = null;
7329 return this;
7330 }
7331
7332 public QueuedTouch set(MotionEvent ev, long sequence) {
7333 mEvent = MotionEvent.obtain(ev);
7334 mSequence = sequence;
7335 mTed = null;
7336 mNext = null;
7337 return this;
7338 }
7339
7340 public QueuedTouch add(QueuedTouch other) {
7341 if (other.mSequence < mSequence) {
7342 other.mNext = this;
7343 return other;
7344 }
7345
7346 QueuedTouch insertAt = this;
7347 while (insertAt.mNext != null && insertAt.mNext.mSequence < other.mSequence) {
7348 insertAt = insertAt.mNext;
7349 }
7350 other.mNext = insertAt.mNext;
7351 insertAt.mNext = other;
7352 return this;
7353 }
7354 }
7355
7356 /**
7357 * WebView handles touch events asynchronously since some events must be passed to WebKit
7358 * for potentially slower processing. TouchEventQueue serializes touch events regardless
7359 * of which path they take to ensure that no events are ever processed out of order
7360 * by WebView.
7361 */
7362 private class TouchEventQueue {
7363 private long mNextTouchSequence = Long.MIN_VALUE + 1;
7364 private long mLastHandledTouchSequence = Long.MIN_VALUE;
Adam Powelld0197f32011-03-17 00:09:03 -07007365 private long mIgnoreUntilSequence = Long.MIN_VALUE + 1;
Adam Powell3c534772011-04-04 14:27:12 -07007366
7367 // Events waiting to be processed.
Adam Powell4fb35d42011-03-03 17:54:55 -08007368 private QueuedTouch mTouchEventQueue;
Adam Powell3c534772011-04-04 14:27:12 -07007369
7370 // Known events that are waiting on a response before being enqueued.
7371 private QueuedTouch mPreQueue;
7372
7373 // Pool of QueuedTouch objects saved for later use.
Adam Powell4fb35d42011-03-03 17:54:55 -08007374 private QueuedTouch mQueuedTouchRecycleBin;
7375 private int mQueuedTouchRecycleCount;
Adam Powell3c534772011-04-04 14:27:12 -07007376
Adam Powelld0197f32011-03-17 00:09:03 -07007377 private long mLastEventTime = Long.MAX_VALUE;
Adam Powell4fb35d42011-03-03 17:54:55 -08007378 private static final int MAX_RECYCLED_QUEUED_TOUCH = 15;
7379
Adam Powell80615b02011-03-10 15:53:24 -08007380 // milliseconds until we abandon hope of getting all of a previous gesture
Adam Powelld0197f32011-03-17 00:09:03 -07007381 private static final int QUEUED_GESTURE_TIMEOUT = 1000;
Adam Powell80615b02011-03-10 15:53:24 -08007382
Adam Powell4fb35d42011-03-03 17:54:55 -08007383 private QueuedTouch obtainQueuedTouch() {
7384 if (mQueuedTouchRecycleBin != null) {
7385 QueuedTouch result = mQueuedTouchRecycleBin;
7386 mQueuedTouchRecycleBin = result.mNext;
7387 mQueuedTouchRecycleCount--;
7388 return result;
7389 }
7390 return new QueuedTouch();
7391 }
7392
Adam Powell80615b02011-03-10 15:53:24 -08007393 /**
7394 * Allow events with any currently missing sequence numbers to be skipped in processing.
7395 */
7396 public void ignoreCurrentlyMissingEvents() {
7397 mIgnoreUntilSequence = mNextTouchSequence;
Adam Powell3c534772011-04-04 14:27:12 -07007398
7399 // Run any events we have available and complete, pre-queued or otherwise.
7400 runQueuedAndPreQueuedEvents();
7401 }
7402
7403 private void runQueuedAndPreQueuedEvents() {
7404 QueuedTouch qd = mPreQueue;
7405 boolean fromPreQueue = true;
7406 while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
7407 handleQueuedTouch(qd);
7408 QueuedTouch recycleMe = qd;
7409 if (fromPreQueue) {
7410 mPreQueue = qd.mNext;
7411 } else {
7412 mTouchEventQueue = qd.mNext;
7413 }
7414 recycleQueuedTouch(recycleMe);
7415 mLastHandledTouchSequence++;
7416
7417 long nextPre = mPreQueue != null ? mPreQueue.mSequence : Long.MAX_VALUE;
7418 long nextQueued = mTouchEventQueue != null ?
7419 mTouchEventQueue.mSequence : Long.MAX_VALUE;
7420 fromPreQueue = nextPre < nextQueued;
7421 qd = fromPreQueue ? mPreQueue : mTouchEventQueue;
7422 }
7423 }
7424
7425 /**
7426 * Add a TouchEventData to the pre-queue.
7427 *
7428 * An event in the pre-queue is an event that we know about that
7429 * has been sent to webkit, but that we haven't received back and
7430 * enqueued into the normal touch queue yet. If webkit ever times
7431 * out and we need to ignore currently missing events, we'll run
7432 * events from the pre-queue to patch the holes.
7433 *
7434 * @param ted TouchEventData to pre-queue
7435 */
7436 public void preQueueTouchEventData(TouchEventData ted) {
7437 QueuedTouch newTouch = obtainQueuedTouch().set(ted);
7438 if (mPreQueue == null) {
7439 mPreQueue = newTouch;
7440 } else {
7441 QueuedTouch insertionPoint = mPreQueue;
7442 while (insertionPoint.mNext != null &&
7443 insertionPoint.mNext.mSequence < newTouch.mSequence) {
7444 insertionPoint = insertionPoint.mNext;
7445 }
7446 newTouch.mNext = insertionPoint.mNext;
7447 insertionPoint.mNext = newTouch;
7448 }
Adam Powell80615b02011-03-10 15:53:24 -08007449 }
7450
Adam Powell4fb35d42011-03-03 17:54:55 -08007451 private void recycleQueuedTouch(QueuedTouch qd) {
7452 if (mQueuedTouchRecycleCount < MAX_RECYCLED_QUEUED_TOUCH) {
7453 qd.mNext = mQueuedTouchRecycleBin;
7454 mQueuedTouchRecycleBin = qd;
7455 mQueuedTouchRecycleCount++;
7456 }
7457 }
7458
7459 /**
7460 * Reset the touch event queue. This will dump any pending events
7461 * and reset the sequence numbering.
7462 */
7463 public void reset() {
7464 mNextTouchSequence = Long.MIN_VALUE + 1;
7465 mLastHandledTouchSequence = Long.MIN_VALUE;
Adam Powelld0197f32011-03-17 00:09:03 -07007466 mIgnoreUntilSequence = Long.MIN_VALUE + 1;
Adam Powell4fb35d42011-03-03 17:54:55 -08007467 while (mTouchEventQueue != null) {
7468 QueuedTouch recycleMe = mTouchEventQueue;
7469 mTouchEventQueue = mTouchEventQueue.mNext;
7470 recycleQueuedTouch(recycleMe);
7471 }
Adam Powell3c534772011-04-04 14:27:12 -07007472 while (mPreQueue != null) {
7473 QueuedTouch recycleMe = mPreQueue;
7474 mPreQueue = mPreQueue.mNext;
7475 recycleQueuedTouch(recycleMe);
7476 }
Adam Powell4fb35d42011-03-03 17:54:55 -08007477 }
7478
7479 /**
7480 * Return the next valid sequence number for tagging incoming touch events.
7481 * @return The next touch event sequence number
7482 */
7483 public long nextTouchSequence() {
7484 return mNextTouchSequence++;
7485 }
7486
7487 /**
7488 * Enqueue a touch event in the form of TouchEventData.
7489 * The sequence number will be read from the mSequence field of the argument.
7490 *
7491 * If the touch event's sequence number is the next in line to be processed, it will
7492 * be handled before this method returns. Any subsequent events that have already
7493 * been queued will also be processed in their proper order.
7494 *
7495 * @param ted Touch data to be processed in order.
Adam Powellbaa33802011-03-25 13:58:19 -07007496 * @return true if the event was processed before returning, false if it was just enqueued.
Adam Powell4fb35d42011-03-03 17:54:55 -08007497 */
Adam Powellbaa33802011-03-25 13:58:19 -07007498 public boolean enqueueTouchEvent(TouchEventData ted) {
Adam Powell3c534772011-04-04 14:27:12 -07007499 // Remove from the pre-queue if present
7500 QueuedTouch preQueue = mPreQueue;
7501 if (preQueue != null) {
7502 // On exiting this block, preQueue is set to the pre-queued QueuedTouch object
7503 // if it was present in the pre-queue, and removed from the pre-queue itself.
7504 if (preQueue.mSequence == ted.mSequence) {
7505 mPreQueue = preQueue.mNext;
7506 } else {
7507 QueuedTouch prev = preQueue;
7508 preQueue = null;
7509 while (prev.mNext != null) {
7510 if (prev.mNext.mSequence == ted.mSequence) {
7511 preQueue = prev.mNext;
7512 prev.mNext = preQueue.mNext;
7513 break;
7514 } else {
7515 prev = prev.mNext;
7516 }
7517 }
7518 }
7519 }
7520
Adam Powell80615b02011-03-10 15:53:24 -08007521 if (ted.mSequence < mLastHandledTouchSequence) {
7522 // Stale event and we already moved on; drop it. (Should not be common.)
7523 Log.w(LOGTAG, "Stale touch event " + MotionEvent.actionToString(ted.mAction) +
7524 " received from webcore; ignoring");
Adam Powellbaa33802011-03-25 13:58:19 -07007525 return false;
Adam Powell80615b02011-03-10 15:53:24 -08007526 }
7527
Adam Powelld0197f32011-03-17 00:09:03 -07007528 if (dropStaleGestures(ted.mMotionEvent, ted.mSequence)) {
Adam Powellbaa33802011-03-25 13:58:19 -07007529 return false;
Adam Powelld0197f32011-03-17 00:09:03 -07007530 }
Adam Powell80615b02011-03-10 15:53:24 -08007531
Adam Powell3c534772011-04-04 14:27:12 -07007532 // dropStaleGestures above might have fast-forwarded us to
7533 // an event we have already.
7534 runNextQueuedEvents();
7535
Adam Powell4fb35d42011-03-03 17:54:55 -08007536 if (mLastHandledTouchSequence + 1 == ted.mSequence) {
Adam Powell3c534772011-04-04 14:27:12 -07007537 if (preQueue != null) {
7538 recycleQueuedTouch(preQueue);
7539 preQueue = null;
7540 }
Adam Powell4fb35d42011-03-03 17:54:55 -08007541 handleQueuedTouchEventData(ted);
7542
7543 mLastHandledTouchSequence++;
7544
7545 // Do we have any more? Run them if so.
Adam Powell3c534772011-04-04 14:27:12 -07007546 runNextQueuedEvents();
Adam Powell4fb35d42011-03-03 17:54:55 -08007547 } else {
Adam Powell3c534772011-04-04 14:27:12 -07007548 // Reuse the pre-queued object if we had it.
7549 QueuedTouch qd = preQueue != null ? preQueue : obtainQueuedTouch().set(ted);
Adam Powell4fb35d42011-03-03 17:54:55 -08007550 mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
7551 }
Adam Powellbaa33802011-03-25 13:58:19 -07007552 return true;
Adam Powell4fb35d42011-03-03 17:54:55 -08007553 }
7554
7555 /**
7556 * Enqueue a touch event in the form of a MotionEvent from the framework.
7557 *
7558 * If the touch event's sequence number is the next in line to be processed, it will
7559 * be handled before this method returns. Any subsequent events that have already
7560 * been queued will also be processed in their proper order.
7561 *
7562 * @param ev MotionEvent to be processed in order
7563 */
7564 public void enqueueTouchEvent(MotionEvent ev) {
7565 final long sequence = nextTouchSequence();
Adam Powell80615b02011-03-10 15:53:24 -08007566
Adam Powelld0197f32011-03-17 00:09:03 -07007567 if (dropStaleGestures(ev, sequence)) {
7568 return;
7569 }
Adam Powell80615b02011-03-10 15:53:24 -08007570
Adam Powell3c534772011-04-04 14:27:12 -07007571 // dropStaleGestures above might have fast-forwarded us to
7572 // an event we have already.
7573 runNextQueuedEvents();
7574
Adam Powell4fb35d42011-03-03 17:54:55 -08007575 if (mLastHandledTouchSequence + 1 == sequence) {
7576 handleQueuedMotionEvent(ev);
7577
7578 mLastHandledTouchSequence++;
7579
7580 // Do we have any more? Run them if so.
Adam Powell3c534772011-04-04 14:27:12 -07007581 runNextQueuedEvents();
Adam Powell4fb35d42011-03-03 17:54:55 -08007582 } else {
7583 QueuedTouch qd = obtainQueuedTouch().set(ev, sequence);
7584 mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
7585 }
7586 }
7587
Adam Powell3c534772011-04-04 14:27:12 -07007588 private void runNextQueuedEvents() {
7589 QueuedTouch qd = mTouchEventQueue;
7590 while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
7591 handleQueuedTouch(qd);
7592 QueuedTouch recycleMe = qd;
7593 qd = qd.mNext;
7594 recycleQueuedTouch(recycleMe);
7595 mLastHandledTouchSequence++;
7596 }
7597 mTouchEventQueue = qd;
7598 }
7599
Adam Powelld0197f32011-03-17 00:09:03 -07007600 private boolean dropStaleGestures(MotionEvent ev, long sequence) {
7601 if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && !mConfirmMove) {
7602 // This is to make sure that we don't attempt to process a tap
7603 // or long press when webkit takes too long to get back to us.
7604 // The movement will be properly confirmed when we process the
7605 // enqueued event later.
7606 final int dx = Math.round(ev.getX()) - mLastTouchX;
7607 final int dy = Math.round(ev.getY()) - mLastTouchY;
7608 if (dx * dx + dy * dy > mTouchSlopSquare) {
7609 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
7610 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
7611 }
7612 }
Adam Powell8f626a12011-03-10 19:27:15 -08007613
Adam Powelld0197f32011-03-17 00:09:03 -07007614 if (mTouchEventQueue == null) {
7615 return sequence <= mLastHandledTouchSequence;
7616 }
Adam Powell8f626a12011-03-10 19:27:15 -08007617
Adam Powelld0197f32011-03-17 00:09:03 -07007618 // If we have a new down event and it's been a while since the last event
Adam Powell3c534772011-04-04 14:27:12 -07007619 // we saw, catch up as best we can and keep going.
Adam Powelld0197f32011-03-17 00:09:03 -07007620 if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) {
Adam Powell80615b02011-03-10 15:53:24 -08007621 long eventTime = ev.getEventTime();
Adam Powelld0197f32011-03-17 00:09:03 -07007622 long lastHandledEventTime = mLastEventTime;
7623 if (eventTime > lastHandledEventTime + QUEUED_GESTURE_TIMEOUT) {
Adam Powell80615b02011-03-10 15:53:24 -08007624 Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " +
Adam Powell3c534772011-04-04 14:27:12 -07007625 "Catching up.");
7626 runQueuedAndPreQueuedEvents();
7627
7628 // Drop leftovers that we truly don't have.
Adam Powell80615b02011-03-10 15:53:24 -08007629 QueuedTouch qd = mTouchEventQueue;
7630 while (qd != null && qd.mSequence < sequence) {
7631 QueuedTouch recycleMe = qd;
7632 qd = qd.mNext;
7633 recycleQueuedTouch(recycleMe);
7634 }
7635 mTouchEventQueue = qd;
7636 mLastHandledTouchSequence = sequence - 1;
7637 }
7638 }
7639
Adam Powelld0197f32011-03-17 00:09:03 -07007640 if (mIgnoreUntilSequence - 1 > mLastHandledTouchSequence) {
Adam Powell80615b02011-03-10 15:53:24 -08007641 QueuedTouch qd = mTouchEventQueue;
Adam Powelld0197f32011-03-17 00:09:03 -07007642 while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
Adam Powell80615b02011-03-10 15:53:24 -08007643 QueuedTouch recycleMe = qd;
7644 qd = qd.mNext;
7645 recycleQueuedTouch(recycleMe);
7646 }
7647 mTouchEventQueue = qd;
Adam Powelld0197f32011-03-17 00:09:03 -07007648 mLastHandledTouchSequence = mIgnoreUntilSequence - 1;
Adam Powell80615b02011-03-10 15:53:24 -08007649 }
Adam Powelld0197f32011-03-17 00:09:03 -07007650
Adam Powell3c534772011-04-04 14:27:12 -07007651 if (mPreQueue != null) {
7652 // Drop stale prequeued events
7653 QueuedTouch qd = mPreQueue;
7654 while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
7655 QueuedTouch recycleMe = qd;
7656 qd = qd.mNext;
7657 recycleQueuedTouch(recycleMe);
7658 }
7659 mPreQueue = qd;
7660 }
7661
Adam Powelld0197f32011-03-17 00:09:03 -07007662 return sequence <= mLastHandledTouchSequence;
Adam Powell80615b02011-03-10 15:53:24 -08007663 }
7664
Adam Powell4fb35d42011-03-03 17:54:55 -08007665 private void handleQueuedTouch(QueuedTouch qt) {
7666 if (qt.mTed != null) {
7667 handleQueuedTouchEventData(qt.mTed);
7668 } else {
7669 handleQueuedMotionEvent(qt.mEvent);
7670 qt.mEvent.recycle();
7671 }
7672 }
7673
7674 private void handleQueuedMotionEvent(MotionEvent ev) {
Adam Powelld0197f32011-03-17 00:09:03 -07007675 mLastEventTime = ev.getEventTime();
Adam Powell4fb35d42011-03-03 17:54:55 -08007676 int action = ev.getActionMasked();
7677 if (ev.getPointerCount() > 1) { // Multi-touch
Adam Powell4fb35d42011-03-03 17:54:55 -08007678 handleMultiTouchInWebView(ev);
7679 } else {
7680 final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
Adam Powell8f626a12011-03-10 19:27:15 -08007681 if (detector != null && mPreventDefault != PREVENT_DEFAULT_YES) {
Adam Powell4fb35d42011-03-03 17:54:55 -08007682 // ScaleGestureDetector needs a consistent event stream to operate properly.
7683 // It won't take any action with fewer than two pointers, but it needs to
7684 // update internal bookkeeping state.
7685 detector.onTouchEvent(ev);
7686 }
7687
7688 handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY()));
7689 }
7690 }
7691
7692 private void handleQueuedTouchEventData(TouchEventData ted) {
Adam Powelld0197f32011-03-17 00:09:03 -07007693 if (ted.mMotionEvent != null) {
7694 mLastEventTime = ted.mMotionEvent.getEventTime();
7695 }
Adam Powell4fb35d42011-03-03 17:54:55 -08007696 if (!ted.mReprocess) {
7697 if (ted.mAction == MotionEvent.ACTION_DOWN
7698 && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {
7699 // if prevent default is called from WebCore, UI
7700 // will not handle the rest of the touch events any
7701 // more.
7702 mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
7703 : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN;
7704 } else if (ted.mAction == MotionEvent.ACTION_MOVE
7705 && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
7706 // the return for the first ACTION_MOVE will decide
7707 // whether UI will handle touch or not. Currently no
7708 // support for alternating prevent default
7709 mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
7710 : PREVENT_DEFAULT_NO;
7711 }
7712 if (mPreventDefault == PREVENT_DEFAULT_YES) {
7713 mTouchHighlightRegion.setEmpty();
7714 }
7715 } else {
7716 if (ted.mPoints.length > 1) { // multi-touch
Adam Powell8f626a12011-03-10 19:27:15 -08007717 if (!ted.mNativeResult && mPreventDefault != PREVENT_DEFAULT_YES) {
Adam Powell4fb35d42011-03-03 17:54:55 -08007718 mPreventDefault = PREVENT_DEFAULT_NO;
7719 handleMultiTouchInWebView(ted.mMotionEvent);
7720 } else {
7721 mPreventDefault = PREVENT_DEFAULT_YES;
7722 }
7723 return;
7724 }
7725
7726 // prevent default is not called in WebCore, so the
7727 // message needs to be reprocessed in UI
7728 if (!ted.mNativeResult) {
7729 // Following is for single touch.
7730 switch (ted.mAction) {
7731 case MotionEvent.ACTION_DOWN:
Huahui Wu88b869a2011-03-17 17:42:12 -07007732 mLastDeferTouchX = ted.mPointsInView[0].x;
7733 mLastDeferTouchY = ted.mPointsInView[0].y;
Adam Powell4fb35d42011-03-03 17:54:55 -08007734 mDeferTouchMode = TOUCH_INIT_MODE;
7735 break;
7736 case MotionEvent.ACTION_MOVE: {
7737 // no snapping in defer process
Huahui Wu88b869a2011-03-17 17:42:12 -07007738 int x = ted.mPointsInView[0].x;
7739 int y = ted.mPointsInView[0].y;
7740
Adam Powell4fb35d42011-03-03 17:54:55 -08007741 if (mDeferTouchMode != TOUCH_DRAG_MODE) {
7742 mDeferTouchMode = TOUCH_DRAG_MODE;
7743 mLastDeferTouchX = x;
7744 mLastDeferTouchY = y;
7745 startScrollingLayer(x, y);
7746 startDrag();
7747 }
7748 int deltaX = pinLocX((int) (mScrollX
7749 + mLastDeferTouchX - x))
7750 - mScrollX;
7751 int deltaY = pinLocY((int) (mScrollY
7752 + mLastDeferTouchY - y))
7753 - mScrollY;
7754 doDrag(deltaX, deltaY);
7755 if (deltaX != 0) mLastDeferTouchX = x;
7756 if (deltaY != 0) mLastDeferTouchY = y;
7757 break;
7758 }
7759 case MotionEvent.ACTION_UP:
7760 case MotionEvent.ACTION_CANCEL:
7761 if (mDeferTouchMode == TOUCH_DRAG_MODE) {
7762 // no fling in defer process
7763 mScroller.springBack(mScrollX, mScrollY, 0,
7764 computeMaxScrollX(), 0,
7765 computeMaxScrollY());
7766 invalidate();
7767 WebViewCore.resumePriority();
7768 WebViewCore.resumeUpdatePicture(mWebViewCore);
7769 }
7770 mDeferTouchMode = TOUCH_DONE_MODE;
7771 break;
7772 case WebViewCore.ACTION_DOUBLETAP:
7773 // doDoubleTap() needs mLastTouchX/Y as anchor
Huahui Wu88b869a2011-03-17 17:42:12 -07007774 mLastDeferTouchX = ted.mPointsInView[0].x;
7775 mLastDeferTouchY = ted.mPointsInView[0].y;
Adam Powell4fb35d42011-03-03 17:54:55 -08007776 mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
7777 mDeferTouchMode = TOUCH_DONE_MODE;
7778 break;
7779 case WebViewCore.ACTION_LONGPRESS:
7780 HitTestResult hitTest = getHitTestResult();
7781 if (hitTest != null && hitTest.mType
7782 != HitTestResult.UNKNOWN_TYPE) {
7783 performLongClick();
7784 }
7785 mDeferTouchMode = TOUCH_DONE_MODE;
7786 break;
7787 }
7788 }
7789 }
7790 }
7791 }
7792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007793 //-------------------------------------------------------------------------
7794 // Methods can be called from a separate thread, like WebViewCore
7795 // If it needs to call the View system, it has to send message.
7796 //-------------------------------------------------------------------------
7797
7798 /**
7799 * General handler to receive message coming from webkit thread
7800 */
7801 class PrivateHandler extends Handler {
7802 @Override
7803 public void handleMessage(Message msg) {
Cary Clark3e88ddc2009-10-08 14:59:46 -04007804 // exclude INVAL_RECT_MSG_ID since it is frequently output
7805 if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) {
Grace Klobac2242f22010-03-05 14:00:26 -08007806 if (msg.what >= FIRST_PRIVATE_MSG_ID
7807 && msg.what <= LAST_PRIVATE_MSG_ID) {
7808 Log.v(LOGTAG, HandlerPrivateDebugString[msg.what
7809 - FIRST_PRIVATE_MSG_ID]);
7810 } else if (msg.what >= FIRST_PACKAGE_MSG_ID
7811 && msg.what <= LAST_PACKAGE_MSG_ID) {
7812 Log.v(LOGTAG, HandlerPackageDebugString[msg.what
7813 - FIRST_PACKAGE_MSG_ID]);
7814 } else {
7815 Log.v(LOGTAG, Integer.toString(msg.what));
7816 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007817 }
Grace Kloba207308a2009-09-27 11:44:14 -07007818 if (mWebViewCore == null) {
7819 // after WebView's destroy() is called, skip handling messages.
7820 return;
7821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007822 switch (msg.what) {
7823 case REMEMBER_PASSWORD: {
7824 mDatabase.setUsernamePassword(
7825 msg.getData().getString("host"),
7826 msg.getData().getString("username"),
7827 msg.getData().getString("password"));
7828 ((Message) msg.obj).sendToTarget();
7829 break;
7830 }
7831 case NEVER_REMEMBER_PASSWORD: {
7832 mDatabase.setUsernamePassword(
7833 msg.getData().getString("host"), null, null);
7834 ((Message) msg.obj).sendToTarget();
7835 break;
7836 }
Grace Klobac2242f22010-03-05 14:00:26 -08007837 case PREVENT_DEFAULT_TIMEOUT: {
7838 // if timeout happens, cancel it so that it won't block UI
7839 // to continue handling touch events
7840 if ((msg.arg1 == MotionEvent.ACTION_DOWN
7841 && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES)
7842 || (msg.arg1 == MotionEvent.ACTION_MOVE
7843 && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN)) {
7844 cancelWebCoreTouchEvent(
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007845 viewToContentX(mLastTouchX + mScrollX),
7846 viewToContentY(mLastTouchY + mScrollY),
Grace Klobac2242f22010-03-05 14:00:26 -08007847 true);
Grace Klobaf58af622009-09-24 17:41:23 -07007848 }
Grace Klobac2242f22010-03-05 14:00:26 -08007849 break;
7850 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05007851 case SCROLL_SELECT_TEXT: {
7852 if (mAutoScrollX == 0 && mAutoScrollY == 0) {
7853 mSentAutoScrollMessage = false;
7854 break;
7855 }
Cary Clarkb9aaa772011-01-07 16:14:54 -05007856 if (mScrollingLayer == 0) {
7857 pinScrollBy(mAutoScrollX, mAutoScrollY, true, 0);
7858 } else {
7859 mScrollingLayerRect.left += mAutoScrollX;
7860 mScrollingLayerRect.top += mAutoScrollY;
7861 nativeScrollLayer(mScrollingLayer,
7862 mScrollingLayerRect.left,
7863 mScrollingLayerRect.top);
7864 invalidate();
7865 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05007866 sendEmptyMessageDelayed(
7867 SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
7868 break;
7869 }
Grace Klobac2242f22010-03-05 14:00:26 -08007870 case SWITCH_TO_SHORTPRESS: {
Cary Clarkb8491342010-11-29 16:23:19 -05007871 mInitialHitTestResult = null; // set by updateSelection()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007872 if (mTouchMode == TOUCH_INIT_MODE) {
Grace Kloba178db412010-05-18 22:22:23 -07007873 if (!getSettings().supportTouchOnly()
7874 && mPreventDefault != PREVENT_DEFAULT_YES) {
Grace Klobac2242f22010-03-05 14:00:26 -08007875 mTouchMode = TOUCH_SHORTPRESS_START_MODE;
7876 updateSelection();
7877 } else {
7878 // set to TOUCH_SHORTPRESS_MODE so that it won't
7879 // trigger double tap any more
7880 mTouchMode = TOUCH_SHORTPRESS_MODE;
7881 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07007882 } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
7883 mTouchMode = TOUCH_DONE_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007884 }
7885 break;
7886 }
7887 case SWITCH_TO_LONGPRESS: {
Grace Kloba178db412010-05-18 22:22:23 -07007888 if (getSettings().supportTouchOnly()) {
7889 removeTouchHighlight(false);
7890 }
Grace Klobac2242f22010-03-05 14:00:26 -08007891 if (inFullScreenMode() || mDeferTouchProcess) {
7892 TouchEventData ted = new TouchEventData();
Grace Kloba5f68d6f2009-12-08 18:42:54 -08007893 ted.mAction = WebViewCore.ACTION_LONGPRESS;
Huahui Wue838a422011-01-13 16:03:43 -08007894 ted.mIds = new int[1];
7895 ted.mIds[0] = 0;
Huahui Wu41865f42010-09-02 13:41:41 -07007896 ted.mPoints = new Point[1];
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007897 ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX),
7898 viewToContentY(mLastTouchY + mScrollY));
Huahui Wu88b869a2011-03-17 17:42:12 -07007899 ted.mPointsInView = new Point[1];
7900 ted.mPointsInView[0] = new Point(mLastTouchX, mLastTouchY);
Grace Klobac2242f22010-03-05 14:00:26 -08007901 // metaState for long press is tricky. Should it be the
7902 // state when the press started or when the press was
7903 // released? Or some intermediary key state? For
7904 // simplicity for now, we don't set it.
Ben Murdoch8a032a32010-02-02 18:20:11 +00007905 ted.mMetaState = 0;
Grace Klobac2242f22010-03-05 14:00:26 -08007906 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05007907 ted.mNativeLayer = nativeScrollableLayer(
7908 ted.mPoints[0].x, ted.mPoints[0].y,
7909 ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08007910 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07007911 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08007912 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Grace Klobac2242f22010-03-05 14:00:26 -08007913 } else if (mPreventDefault != PREVENT_DEFAULT_YES) {
Grace Kloba6c451b72009-06-25 12:25:30 -07007914 mTouchMode = TOUCH_DONE_MODE;
Grace Klobac2242f22010-03-05 14:00:26 -08007915 performLongClick();
Grace Kloba6c451b72009-06-25 12:25:30 -07007916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007917 break;
7918 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07007919 case RELEASE_SINGLE_TAP: {
Grace Klobac2242f22010-03-05 14:00:26 -08007920 doShortPress();
Grace Kloba8b97e4b2009-07-28 13:11:38 -07007921 break;
7922 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05007923 case SCROLL_TO_MSG_ID: {
7924 // arg1 = animate, arg2 = onlyIfImeIsShowing
7925 // obj = Point(x, y)
7926 if (msg.arg2 == 1) {
Leon Scrogginsfe77eb62011-02-01 11:05:22 -05007927 // This scroll is intended to bring the textfield into
7928 // view, but is only necessary if the IME is showing
7929 InputMethodManager imm = InputMethodManager.peekInstance();
7930 if (imm == null || !imm.isAcceptingText()
7931 || (!imm.isActive(WebView.this) && (!inEditingMode()
7932 || !imm.isActive(mWebTextView)))) {
7933 break;
7934 }
7935 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05007936 final Point p = (Point) msg.obj;
7937 if (msg.arg1 == 1) {
7938 spawnContentScrollTo(p.x, p.y);
7939 } else {
7940 setContentScrollTo(p.x, p.y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007941 }
7942 break;
Patrick Scottfa8be1c2011-02-02 14:09:34 -05007943 }
Grace Kloba769ed212010-01-27 10:52:47 -08007944 case UPDATE_ZOOM_RANGE: {
Derek Sollenbergerb983c892010-06-28 08:38:28 -04007945 WebViewCore.ViewState viewState = (WebViewCore.ViewState) msg.obj;
Grace Kloba188bf8d2010-04-07 11:30:19 -07007946 // mScrollX contains the new minPrefWidth
Derek Sollenbergerb983c892010-06-28 08:38:28 -04007947 mZoomManager.updateZoomRange(viewState, getViewWidth(), viewState.mScrollX);
Grace Kloba769ed212010-01-27 10:52:47 -08007948 break;
7949 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07007950 case REPLACE_BASE_CONTENT: {
7951 nativeReplaceBaseContent(msg.arg1);
7952 break;
7953 }
Grace Klobae397a882009-08-06 12:04:14 -07007954 case NEW_PICTURE_MSG_ID: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007955 // called for new content
Derek Sollenberger341e22f2010-06-02 12:34:34 -04007956 final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
Derek Sollenbergerb983c892010-06-28 08:38:28 -04007957 WebViewCore.ViewState viewState = draw.mViewState;
7958 boolean isPictureAfterFirstLayout = viewState != null;
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07007959 setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
7960 getSettings().getShowVisualIndicator(),
7961 isPictureAfterFirstLayout);
7962 final Point viewSize = draw.mViewSize;
Derek Sollenbergerb983c892010-06-28 08:38:28 -04007963 if (isPictureAfterFirstLayout) {
Shimeng (Simon) Wang0a4a70d2010-06-30 11:48:05 -07007964 // Reset the last sent data here since dealing with new page.
7965 mLastWidthSent = 0;
Derek Sollenbergerb983c892010-06-28 08:38:28 -04007966 mZoomManager.onFirstLayout(draw);
Shimeng (Simon) Wang1c02c6a2010-03-04 18:06:49 -08007967 if (!mDrawHistory) {
Patrick Scottfa8be1c2011-02-02 14:09:34 -05007968 // Do not send the scroll event for this particular
7969 // scroll message. Note that a scroll event may
7970 // still be fired if the user scrolls before the
7971 // message can be handled.
7972 mSendScrollEvent = false;
Derek Sollenbergerb983c892010-06-28 08:38:28 -04007973 setContentScrollTo(viewState.mScrollX, viewState.mScrollY);
Patrick Scottfa8be1c2011-02-02 14:09:34 -05007974 mSendScrollEvent = true;
7975
Shimeng (Simon) Wang1c02c6a2010-03-04 18:06:49 -08007976 // As we are on a new page, remove the WebTextView. This
7977 // is necessary for page loads driven by webkit, and in
7978 // particular when the user was on a password field, so
7979 // the WebTextView was visible.
Leon Scroggins2aed7762010-08-13 17:11:42 -04007980 clearTextEntry();
Mike Reed8b302092009-11-12 12:50:20 -05007981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007982 }
Derek Sollenberger341e22f2010-06-02 12:34:34 -04007983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007984 // We update the layout (i.e. request a layout from the
7985 // view system) if the last view size that we sent to
7986 // WebCore matches the view size of the picture we just
7987 // received in the fixed dimension.
7988 final boolean updateLayout = viewSize.x == mLastWidthSent
7989 && viewSize.y == mLastHeightSent;
Shimeng (Simon) Wangc5661852011-02-10 13:32:53 -08007990 // Don't send scroll event for picture coming from webkit,
7991 // since the new picture may cause a scroll event to override
7992 // the saved history scroll position.
7993 mSendScrollEvent = false;
Derek Sollenberger7e6bf6f2010-10-28 09:33:47 -04007994 recordNewContentSize(draw.mContentSize.x,
7995 draw.mContentSize.y, updateLayout);
Shimeng (Simon) Wangc5661852011-02-10 13:32:53 -08007996 mSendScrollEvent = true;
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007997 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007998 Rect b = draw.mInvalRegion.getBounds();
7999 Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
8000 b.left+","+b.top+","+b.right+","+b.bottom+"}");
8001 }
Mike Reede9e86b82009-09-15 11:26:53 -04008002 invalidateContentRect(draw.mInvalRegion.getBounds());
Derek Sollenberger341e22f2010-06-02 12:34:34 -04008003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008004 if (mPictureListener != null) {
8005 mPictureListener.onNewPicture(WebView.this, capturePicture());
8006 }
Derek Sollenberger341e22f2010-06-02 12:34:34 -04008007
8008 // update the zoom information based on the new picture
8009 mZoomManager.onNewPicture(draw);
8010
Cary Clark5da9aeb2009-10-06 17:40:53 -04008011 if (draw.mFocusSizeChanged && inEditingMode()) {
8012 mFocusSizeChanged = true;
8013 }
Derek Sollenbergerb983c892010-06-28 08:38:28 -04008014 if (isPictureAfterFirstLayout) {
Grace Kloba9a67c822009-12-20 11:33:58 -08008015 mViewManager.postReadyToDrawAll();
8016 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008017 break;
Grace Klobae397a882009-08-06 12:04:14 -07008018 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008019 case WEBCORE_INITIALIZED_MSG_ID:
8020 // nativeCreate sets mNativeClass to a non-zero value
Leon Scrogginscdaff15bd2011-03-04 12:30:03 -05008021 String drawableDir = BrowserFrame.getRawResFilename(
8022 BrowserFrame.DRAWABLEDIR, mContext);
8023 AssetManager am = mContext.getAssets();
8024 nativeCreate(msg.arg1, drawableDir, am);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008025 break;
8026 case UPDATE_TEXTFIELD_TEXT_MSG_ID:
8027 // Make sure that the textfield is currently focused
Cary Clarkd6982c92009-05-29 11:02:22 -04008028 // and representing the same node as the pointer.
8029 if (inEditingMode() &&
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008030 mWebTextView.isSameTextField(msg.arg1)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008031 if (msg.getData().getBoolean("password")) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008032 Spannable text = (Spannable) mWebTextView.getText();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008033 int start = Selection.getSelectionStart(text);
8034 int end = Selection.getSelectionEnd(text);
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008035 mWebTextView.setInPassword(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008036 // Restore the selection, which may have been
8037 // ruined by setInPassword.
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008038 Spannable pword =
8039 (Spannable) mWebTextView.getText();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008040 Selection.setSelection(pword, start, end);
8041 // If the text entry has created more events, ignore
8042 // this one.
8043 } else if (msg.arg2 == mTextGeneration) {
Leon Scrogginsef7af282010-11-11 14:20:06 -05008044 String text = (String) msg.obj;
8045 if (null == text) {
8046 text = "";
8047 }
8048 mWebTextView.setTextAndKeepSelection(text);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008049 }
8050 }
8051 break;
Leon Scrogginsb4157792010-03-18 12:42:33 -04008052 case REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID:
8053 displaySoftKeyboard(true);
Leon Scroggins III901a7c22010-04-20 15:14:02 -04008054 // fall through to UPDATE_TEXT_SELECTION_MSG_ID
Leon Scroggins6679f2f2009-08-12 18:48:10 -04008055 case UPDATE_TEXT_SELECTION_MSG_ID:
Leon Scrogginsb4157792010-03-18 12:42:33 -04008056 updateTextSelectionFromMessage(msg.arg1, msg.arg2,
8057 (WebViewCore.TextSelectionData) msg.obj);
Leon Scroggins6679f2f2009-08-12 18:48:10 -04008058 break;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -04008059 case FORM_DID_BLUR:
8060 if (inEditingMode()
8061 && mWebTextView.isSameTextField(msg.arg1)) {
8062 hideSoftKeyboard();
8063 }
8064 break;
Leon Scroggins3a503392010-01-06 17:04:38 -05008065 case RETURN_LABEL:
8066 if (inEditingMode()
8067 && mWebTextView.isSameTextField(msg.arg1)) {
8068 mWebTextView.setHint((String) msg.obj);
8069 InputMethodManager imm
8070 = InputMethodManager.peekInstance();
8071 // The hint is propagated to the IME in
8072 // onCreateInputConnection. If the IME is already
8073 // active, restart it so that its hint text is updated.
8074 if (imm != null && imm.isActive(mWebTextView)) {
8075 imm.restartInput(mWebTextView);
8076 }
8077 }
8078 break;
Leon Scroggins9ab32b62010-05-03 14:19:50 +01008079 case UNHANDLED_NAV_KEY:
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008080 navHandledKey(msg.arg1, 1, false, 0);
Cary Clark215b72c2009-06-26 14:38:43 -04008081 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008082 case UPDATE_TEXT_ENTRY_MSG_ID:
Cary Clarkd6982c92009-05-29 11:02:22 -04008083 // this is sent after finishing resize in WebViewCore. Make
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008084 // sure the text edit box is still on the screen.
Cary Clarkd6982c92009-05-29 11:02:22 -04008085 if (inEditingMode() && nativeCursorIsTextInput()) {
Leon Scroggins4890feb2009-07-02 10:37:10 -04008086 rebuildWebTextView();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008088 break;
Cary Clark243ea062009-06-25 10:49:32 -04008089 case CLEAR_TEXT_ENTRY:
Leon Scroggins2aed7762010-08-13 17:11:42 -04008090 clearTextEntry();
Cary Clark243ea062009-06-25 10:49:32 -04008091 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008092 case INVAL_RECT_MSG_ID: {
8093 Rect r = (Rect)msg.obj;
8094 if (r == null) {
8095 invalidate();
8096 } else {
8097 // we need to scale r from content into view coords,
8098 // which viewInvalidate() does for us
8099 viewInvalidate(r.left, r.top, r.right, r.bottom);
8100 }
8101 break;
8102 }
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008103 case REQUEST_FORM_DATA:
Cary Clarkded054c2009-06-15 10:26:08 -04008104 AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj;
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008105 if (mWebTextView.isSameTextField(msg.arg1)) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008106 mWebTextView.setAdapterCustom(adapter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008107 }
8108 break;
Grace Kloba96949ef2010-01-25 09:53:01 -08008109 case RESUME_WEBCORE_PRIORITY:
Grace Klobaa7bc87c2010-01-29 14:56:25 -08008110 WebViewCore.resumePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07008111 WebViewCore.resumeUpdatePicture(mWebViewCore);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008112 break;
8113
Leon Scrogginse3225672009-06-03 15:53:13 -04008114 case LONG_PRESS_CENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008115 // as this is shared by keydown and trackballdown, reset all
8116 // the states
Leon Scrogginse3225672009-06-03 15:53:13 -04008117 mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008118 mTrackballDown = false;
Grace Kloba98e6fcf2010-01-27 15:20:30 -08008119 performLongClick();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008120 break;
8121
8122 case WEBCORE_NEED_TOUCH_EVENTS:
8123 mForwardTouchEvents = (msg.arg1 != 0);
8124 break;
8125
8126 case PREVENT_TOUCH_ID:
Grace Klobac2242f22010-03-05 14:00:26 -08008127 if (inFullScreenMode()) {
8128 break;
8129 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008130 TouchEventData ted = (TouchEventData) msg.obj;
Adam Powellae9d2642011-03-08 16:00:30 -08008131
Adam Powellbaa33802011-03-25 13:58:19 -07008132 if (mTouchEventQueue.enqueueTouchEvent(ted)) {
8133 // WebCore is responding to us; remove pending timeout.
8134 // It will be re-posted when needed.
8135 removeMessages(PREVENT_DEFAULT_TIMEOUT);
8136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008137 break;
8138
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04008139 case REQUEST_KEYBOARD:
8140 if (msg.arg1 == 0) {
8141 hideSoftKeyboard();
8142 } else {
Leon Scrogginsb4157792010-03-18 12:42:33 -04008143 displaySoftKeyboard(false);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04008144 }
8145 break;
8146
Leon Scroggins5de63892009-10-29 09:48:43 -04008147 case FIND_AGAIN:
8148 // Ignore if find has been dismissed.
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04008149 if (mFindIsUp && mFindCallback != null) {
8150 mFindCallback.findAll();
Leon Scroggins5de63892009-10-29 09:48:43 -04008151 }
8152 break;
8153
Cary Clark25415e22009-10-12 13:41:28 -04008154 case DRAG_HELD_MOTIONLESS:
8155 mHeldMotionless = MOTIONLESS_TRUE;
8156 invalidate();
8157 // fall through to keep scrollbars awake
8158
8159 case AWAKEN_SCROLL_BARS:
8160 if (mTouchMode == TOUCH_DRAG_MODE
8161 && mHeldMotionless == MOTIONLESS_TRUE) {
8162 awakenScrollBars(ViewConfiguration
8163 .getScrollDefaultDelay(), false);
8164 mPrivateHandler.sendMessageDelayed(mPrivateHandler
8165 .obtainMessage(AWAKEN_SCROLL_BARS),
8166 ViewConfiguration.getScrollDefaultDelay());
8167 }
8168 break;
Cary Clark1cb97ee2009-12-11 12:10:36 -05008169
8170 case DO_MOTION_UP:
Cary Clarkbad0c542010-01-11 14:58:21 -05008171 doMotionUp(msg.arg1, msg.arg2);
Cary Clark1cb97ee2009-12-11 12:10:36 -05008172 break;
8173
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -05008174 case SCREEN_ON:
8175 setKeepScreenOn(msg.arg1 == 1);
8176 break;
8177
Nicolas Roard0e778a12011-03-11 14:29:05 -08008178 case ENTER_FULLSCREEN_VIDEO:
8179 int layerId = msg.arg1;
Teng-Hui Zhu10ab6542011-03-16 16:42:32 -07008180
8181 String url = (String) msg.obj;
8182 if (mHTML5VideoViewProxy != null) {
8183 mHTML5VideoViewProxy.enterFullScreenVideo(layerId, url);
8184 }
Nicolas Roard0e778a12011-03-11 14:29:05 -08008185 break;
8186
Grace Kloba3a0def22010-01-23 21:11:54 -08008187 case SHOW_FULLSCREEN: {
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008188 View view = (View) msg.obj;
8189 int npp = msg.arg1;
Grace Kloba11438c32009-12-16 11:39:12 -08008190
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008191 if (inFullScreenMode()) {
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008192 Log.w(LOGTAG, "Should not have another full screen.");
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008193 dismissFullScreenMode();
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008194 }
8195 mFullScreenHolder = new PluginFullScreenHolder(WebView.this, npp);
8196 mFullScreenHolder.setContentView(view);
8197 mFullScreenHolder.setCancelable(false);
8198 mFullScreenHolder.setCanceledOnTouchOutside(false);
8199 mFullScreenHolder.show();
8200
8201 break;
8202 }
Grace Kloba11438c32009-12-16 11:39:12 -08008203 case HIDE_FULLSCREEN:
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008204 dismissFullScreenMode();
Grace Kloba11438c32009-12-16 11:39:12 -08008205 break;
8206
Leon Scrogginse26efa32009-12-15 16:38:45 -05008207 case DOM_FOCUS_CHANGED:
8208 if (inEditingMode()) {
8209 nativeClearCursor();
8210 rebuildWebTextView();
8211 }
8212 break;
8213
Grace Kloba3a0def22010-01-23 21:11:54 -08008214 case SHOW_RECT_MSG_ID: {
8215 WebViewCore.ShowRectData data = (WebViewCore.ShowRectData) msg.obj;
8216 int x = mScrollX;
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008217 int left = contentToViewX(data.mLeft);
Grace Kloba3a0def22010-01-23 21:11:54 -08008218 int width = contentToViewDimension(data.mWidth);
8219 int maxWidth = contentToViewDimension(data.mContentWidth);
8220 int viewWidth = getViewWidth();
8221 if (width < viewWidth) {
8222 // center align
8223 x += left + width / 2 - mScrollX - viewWidth / 2;
8224 } else {
8225 x += (int) (left + data.mXPercentInDoc * width
8226 - mScrollX - data.mXPercentInView * viewWidth);
8227 }
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008228 if (DebugFlags.WEB_VIEW) {
8229 Log.v(LOGTAG, "showRectMsg=(left=" + left + ",width=" +
8230 width + ",maxWidth=" + maxWidth +
8231 ",viewWidth=" + viewWidth + ",x="
8232 + x + ",xPercentInDoc=" + data.mXPercentInDoc +
8233 ",xPercentInView=" + data.mXPercentInView+ ")");
8234 }
Grace Kloba3a0def22010-01-23 21:11:54 -08008235 // use the passing content width to cap x as the current
8236 // mContentWidth may not be updated yet
8237 x = Math.max(0,
8238 (Math.min(maxWidth, x + viewWidth)) - viewWidth);
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008239 int top = contentToViewY(data.mTop);
Grace Kloba3a0def22010-01-23 21:11:54 -08008240 int height = contentToViewDimension(data.mHeight);
8241 int maxHeight = contentToViewDimension(data.mContentHeight);
8242 int viewHeight = getViewHeight();
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008243 int y = (int) (top + data.mYPercentInDoc * height -
8244 data.mYPercentInView * viewHeight);
8245 if (DebugFlags.WEB_VIEW) {
8246 Log.v(LOGTAG, "showRectMsg=(top=" + top + ",height=" +
8247 height + ",maxHeight=" + maxHeight +
8248 ",viewHeight=" + viewHeight + ",y="
8249 + y + ",yPercentInDoc=" + data.mYPercentInDoc +
8250 ",yPercentInView=" + data.mYPercentInView+ ")");
Grace Kloba3a0def22010-01-23 21:11:54 -08008251 }
8252 // use the passing content height to cap y as the current
8253 // mContentHeight may not be updated yet
8254 y = Math.max(0,
8255 (Math.min(maxHeight, y + viewHeight) - viewHeight));
Shimeng (Simon) Wangb7f17d42010-02-08 15:17:21 -08008256 // We need to take into account the visible title height
8257 // when scrolling since y is an absolute view position.
8258 y = Math.max(0, y - getVisibleTitleHeight());
Grace Kloba3a0def22010-01-23 21:11:54 -08008259 scrollTo(x, y);
8260 }
8261 break;
8262
Grace Klobae8300a12010-03-12 13:32:55 -08008263 case CENTER_FIT_RECT:
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05008264 centerFitRect((Rect)msg.obj);
Grace Klobae8300a12010-03-12 13:32:55 -08008265 break;
8266
Grace Kloba50004bc2010-04-13 22:58:51 -07008267 case SET_SCROLLBAR_MODES:
8268 mHorizontalScrollBarMode = msg.arg1;
8269 mVerticalScrollBarMode = msg.arg2;
8270 break;
8271
Svetoslav Ganovda355512010-05-12 22:04:44 -07008272 case SELECTION_STRING_CHANGED:
8273 if (mAccessibilityInjector != null) {
8274 String selectionString = (String) msg.obj;
8275 mAccessibilityInjector.onSelectionStringChange(selectionString);
8276 }
8277 break;
8278
Grace Kloba178db412010-05-18 22:22:23 -07008279 case SET_TOUCH_HIGHLIGHT_RECTS:
8280 invalidate(mTouchHighlightRegion.getBounds());
8281 mTouchHighlightRegion.setEmpty();
8282 if (msg.obj != null) {
8283 ArrayList<Rect> rects = (ArrayList<Rect>) msg.obj;
8284 for (Rect rect : rects) {
8285 Rect viewRect = contentToViewRect(rect);
8286 // some sites, like stories in nytimes.com, set
8287 // mouse event handler in the top div. It is not
8288 // user friendly to highlight the div if it covers
8289 // more than half of the screen.
8290 if (viewRect.width() < getWidth() >> 1
8291 || viewRect.height() < getHeight() >> 1) {
8292 mTouchHighlightRegion.union(viewRect);
8293 invalidate(viewRect);
8294 } else {
8295 Log.w(LOGTAG, "Skip the huge selection rect:"
8296 + viewRect);
8297 }
8298 }
8299 }
8300 break;
8301
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07008302 case SAVE_WEBARCHIVE_FINISHED:
8303 SaveWebArchiveMessage saveMessage = (SaveWebArchiveMessage)msg.obj;
8304 if (saveMessage.mCallback != null) {
8305 saveMessage.mCallback.onReceiveValue(saveMessage.mResultFile);
8306 }
8307 break;
8308
Ben Murdoch62275a42010-09-07 11:27:28 +01008309 case SET_AUTOFILLABLE:
Ben Murdochdb8d19c2010-10-29 11:44:17 +01008310 mAutoFillData = (WebViewCore.AutoFillData) msg.obj;
Ben Murdoch62275a42010-09-07 11:27:28 +01008311 if (mWebTextView != null) {
Ben Murdochdb8d19c2010-10-29 11:44:17 +01008312 mWebTextView.setAutoFillable(mAutoFillData.getQueryId());
Ben Murdoch62275a42010-09-07 11:27:28 +01008313 rebuildWebTextView();
8314 }
8315 break;
8316
Ben Murdoch961d55f2010-12-02 13:58:24 +00008317 case AUTOFILL_COMPLETE:
8318 if (mWebTextView != null) {
8319 // Clear the WebTextView adapter when AutoFill finishes
8320 // so that the drop down gets cleared.
8321 mWebTextView.setAdapterCustom(null);
8322 }
8323 break;
8324
Svetoslav Ganov9504f572011-01-14 11:38:17 -08008325 case SELECT_AT:
8326 nativeSelectAt(msg.arg1, msg.arg2);
8327 break;
8328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008329 default:
8330 super.handleMessage(msg);
8331 break;
8332 }
8333 }
8334 }
8335
Leon Scrogginsb4157792010-03-18 12:42:33 -04008336 /**
8337 * Used when receiving messages for REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID
8338 * and UPDATE_TEXT_SELECTION_MSG_ID. Update the selection of WebTextView.
8339 */
8340 private void updateTextSelectionFromMessage(int nodePointer,
8341 int textGeneration, WebViewCore.TextSelectionData data) {
8342 if (inEditingMode()
8343 && mWebTextView.isSameTextField(nodePointer)
8344 && textGeneration == mTextGeneration) {
8345 mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd);
8346 }
8347 }
8348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008349 // Class used to use a dropdown for a <select> element
8350 private class InvokeListBox implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008351 // Whether the listbox allows multiple selection.
8352 private boolean mMultiple;
8353 // Passed in to a list with multiple selection to tell
8354 // which items are selected.
8355 private int[] mSelectedArray;
Cary Clarkd6982c92009-05-29 11:02:22 -04008356 // Passed in to a list with single selection to tell
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008357 // where the initial selection is.
8358 private int mSelection;
8359
8360 private Container[] mContainers;
8361
8362 // Need these to provide stable ids to my ArrayAdapter,
8363 // which normally does not have stable ids. (Bug 1250098)
8364 private class Container extends Object {
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008365 /**
8366 * Possible values for mEnabled. Keep in sync with OptionStatus in
8367 * WebViewCore.cpp
8368 */
8369 final static int OPTGROUP = -1;
8370 final static int OPTION_DISABLED = 0;
8371 final static int OPTION_ENABLED = 1;
8372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008373 String mString;
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008374 int mEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008375 int mId;
8376
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08008377 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008378 public String toString() {
8379 return mString;
8380 }
8381 }
8382
8383 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04008384 * Subclass ArrayAdapter so we can disable OptionGroupLabels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008385 * and allow filtering.
8386 */
8387 private class MyArrayListAdapter extends ArrayAdapter<Container> {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008388 public MyArrayListAdapter() {
8389 super(mContext,
8390 mMultiple ? com.android.internal.R.layout.select_dialog_multichoice :
8391 com.android.internal.R.layout.webview_select_singlechoice,
8392 mContainers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008393 }
8394
8395 @Override
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008396 public View getView(int position, View convertView,
8397 ViewGroup parent) {
8398 // Always pass in null so that we will get a new CheckedTextView
8399 // Otherwise, an item which was previously used as an <optgroup>
8400 // element (i.e. has no check), could get used as an <option>
8401 // element, which needs a checkbox/radio, but it would not have
8402 // one.
8403 convertView = super.getView(position, null, parent);
8404 Container c = item(position);
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -04008405 if (c != null && Container.OPTION_ENABLED != c.mEnabled) {
8406 // ListView does not draw dividers between disabled and
8407 // enabled elements. Use a LinearLayout to provide dividers
8408 LinearLayout layout = new LinearLayout(mContext);
8409 layout.setOrientation(LinearLayout.VERTICAL);
8410 if (position > 0) {
8411 View dividerTop = new View(mContext);
8412 dividerTop.setBackgroundResource(
8413 android.R.drawable.divider_horizontal_bright);
8414 layout.addView(dividerTop);
8415 }
8416
8417 if (Container.OPTGROUP == c.mEnabled) {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008418 // Currently select_dialog_multichoice uses CheckedTextViews.
8419 // If that changes, the class cast will no longer be valid.
8420 if (mMultiple) {
8421 Assert.assertTrue(convertView instanceof CheckedTextView);
8422 ((CheckedTextView) convertView).setCheckMarkDrawable(null);
8423 }
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -04008424 } else {
8425 // c.mEnabled == Container.OPTION_DISABLED
8426 // Draw the disabled element in a disabled state.
8427 convertView.setEnabled(false);
8428 }
8429
8430 layout.addView(convertView);
8431 if (position < getCount() - 1) {
8432 View dividerBottom = new View(mContext);
8433 dividerBottom.setBackgroundResource(
8434 android.R.drawable.divider_horizontal_bright);
8435 layout.addView(dividerBottom);
8436 }
8437 return layout;
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008438 }
8439 return convertView;
8440 }
8441
8442 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008443 public boolean hasStableIds() {
Leon Scroggins3667ce42009-05-13 15:58:03 -04008444 // AdapterView's onChanged method uses this to determine whether
8445 // to restore the old state. Return false so that the old (out
8446 // of date) state does not replace the new, valid state.
8447 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008448 }
8449
8450 private Container item(int position) {
8451 if (position < 0 || position >= getCount()) {
8452 return null;
8453 }
8454 return (Container) getItem(position);
8455 }
8456
8457 @Override
8458 public long getItemId(int position) {
8459 Container item = item(position);
8460 if (item == null) {
8461 return -1;
8462 }
8463 return item.mId;
8464 }
8465
8466 @Override
8467 public boolean areAllItemsEnabled() {
8468 return false;
8469 }
8470
8471 @Override
8472 public boolean isEnabled(int position) {
8473 Container item = item(position);
8474 if (item == null) {
8475 return false;
8476 }
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008477 return Container.OPTION_ENABLED == item.mEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008478 }
8479 }
8480
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008481 private InvokeListBox(String[] array, int[] enabled, int[] selected) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008482 mMultiple = true;
8483 mSelectedArray = selected;
8484
8485 int length = array.length;
8486 mContainers = new Container[length];
8487 for (int i = 0; i < length; i++) {
8488 mContainers[i] = new Container();
8489 mContainers[i].mString = array[i];
8490 mContainers[i].mEnabled = enabled[i];
8491 mContainers[i].mId = i;
8492 }
8493 }
8494
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008495 private InvokeListBox(String[] array, int[] enabled, int selection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008496 mSelection = selection;
8497 mMultiple = false;
8498
8499 int length = array.length;
8500 mContainers = new Container[length];
8501 for (int i = 0; i < length; i++) {
8502 mContainers[i] = new Container();
8503 mContainers[i].mString = array[i];
8504 mContainers[i].mEnabled = enabled[i];
8505 mContainers[i].mId = i;
8506 }
8507 }
8508
Leon Scroggins3667ce42009-05-13 15:58:03 -04008509 /*
8510 * Whenever the data set changes due to filtering, this class ensures
8511 * that the checked item remains checked.
8512 */
8513 private class SingleDataSetObserver extends DataSetObserver {
8514 private long mCheckedId;
8515 private ListView mListView;
8516 private Adapter mAdapter;
8517
8518 /*
8519 * Create a new observer.
8520 * @param id The ID of the item to keep checked.
8521 * @param l ListView for getting and clearing the checked states
8522 * @param a Adapter for getting the IDs
8523 */
8524 public SingleDataSetObserver(long id, ListView l, Adapter a) {
8525 mCheckedId = id;
8526 mListView = l;
8527 mAdapter = a;
8528 }
8529
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008530 @Override
Leon Scroggins3667ce42009-05-13 15:58:03 -04008531 public void onChanged() {
8532 // The filter may have changed which item is checked. Find the
8533 // item that the ListView thinks is checked.
8534 int position = mListView.getCheckedItemPosition();
8535 long id = mAdapter.getItemId(position);
8536 if (mCheckedId != id) {
8537 // Clear the ListView's idea of the checked item, since
8538 // it is incorrect
8539 mListView.clearChoices();
8540 // Search for mCheckedId. If it is in the filtered list,
8541 // mark it as checked
8542 int count = mAdapter.getCount();
8543 for (int i = 0; i < count; i++) {
8544 if (mAdapter.getItemId(i) == mCheckedId) {
8545 mListView.setItemChecked(i, true);
8546 break;
8547 }
8548 }
8549 }
8550 }
Leon Scroggins3667ce42009-05-13 15:58:03 -04008551 }
8552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008553 public void run() {
8554 final ListView listView = (ListView) LayoutInflater.from(mContext)
8555 .inflate(com.android.internal.R.layout.select_dialog, null);
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008556 final MyArrayListAdapter adapter = new MyArrayListAdapter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008557 AlertDialog.Builder b = new AlertDialog.Builder(mContext)
8558 .setView(listView).setCancelable(true)
8559 .setInverseBackgroundForced(true);
Cary Clarkd6982c92009-05-29 11:02:22 -04008560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008561 if (mMultiple) {
8562 b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
8563 public void onClick(DialogInterface dialog, int which) {
8564 mWebViewCore.sendMessage(
Cary Clarkd6982c92009-05-29 11:02:22 -04008565 EventHub.LISTBOX_CHOICES,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566 adapter.getCount(), 0,
8567 listView.getCheckedItemPositions());
8568 }});
Leon Scroggins238ddbb2009-04-02 10:47:53 -07008569 b.setNegativeButton(android.R.string.cancel,
8570 new DialogInterface.OnClickListener() {
8571 public void onClick(DialogInterface dialog, int which) {
8572 mWebViewCore.sendMessage(
8573 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
8574 }});
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008575 }
Mattias Falk0ae2ec82010-09-16 16:24:46 +02008576 mListBoxDialog = b.create();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008577 listView.setAdapter(adapter);
8578 listView.setFocusableInTouchMode(true);
8579 // There is a bug (1250103) where the checks in a ListView with
8580 // multiple items selected are associated with the positions, not
Cary Clarkd6982c92009-05-29 11:02:22 -04008581 // the ids, so the items do not properly retain their checks when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008582 // filtered. Do not allow filtering on multiple lists until
8583 // that bug is fixed.
Cary Clarkd6982c92009-05-29 11:02:22 -04008584
Leon Scroggins3667ce42009-05-13 15:58:03 -04008585 listView.setTextFilterEnabled(!mMultiple);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008586 if (mMultiple) {
8587 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
8588 int length = mSelectedArray.length;
8589 for (int i = 0; i < length; i++) {
8590 listView.setItemChecked(mSelectedArray[i], true);
8591 }
8592 } else {
8593 listView.setOnItemClickListener(new OnItemClickListener() {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008594 public void onItemClick(AdapterView<?> parent, View v,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008595 int position, long id) {
Leon Scroggins244d2d42010-12-06 16:29:38 -05008596 // Rather than sending the message right away, send it
8597 // after the page regains focus.
8598 mListBoxMessage = Message.obtain(null,
8599 EventHub.SINGLE_LISTBOX_CHOICE, (int) id, 0);
Mattias Falk0ae2ec82010-09-16 16:24:46 +02008600 mListBoxDialog.dismiss();
8601 mListBoxDialog = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008602 }
8603 });
8604 if (mSelection != -1) {
8605 listView.setSelection(mSelection);
8606 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
8607 listView.setItemChecked(mSelection, true);
Leon Scroggins3667ce42009-05-13 15:58:03 -04008608 DataSetObserver observer = new SingleDataSetObserver(
8609 adapter.getItemId(mSelection), listView, adapter);
8610 adapter.registerDataSetObserver(observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008611 }
8612 }
Mattias Falk0ae2ec82010-09-16 16:24:46 +02008613 mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008614 public void onCancel(DialogInterface dialog) {
8615 mWebViewCore.sendMessage(
8616 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
Mattias Falk0ae2ec82010-09-16 16:24:46 +02008617 mListBoxDialog = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008618 }
8619 });
Mattias Falk0ae2ec82010-09-16 16:24:46 +02008620 mListBoxDialog.show();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008621 }
8622 }
8623
Leon Scroggins244d2d42010-12-06 16:29:38 -05008624 private Message mListBoxMessage;
8625
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008626 /*
8627 * Request a dropdown menu for a listbox with multiple selection.
8628 *
8629 * @param array Labels for the listbox.
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008630 * @param enabledArray State for each element in the list. See static
8631 * integers in Container class.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008632 * @param selectedArray Which positions are initally selected.
8633 */
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008634 void requestListBox(String[] array, int[] enabledArray, int[]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008635 selectedArray) {
8636 mPrivateHandler.post(
8637 new InvokeListBox(array, enabledArray, selectedArray));
8638 }
8639
8640 /*
8641 * Request a dropdown menu for a listbox with single selection or a single
8642 * <select> element.
8643 *
8644 * @param array Labels for the listbox.
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008645 * @param enabledArray State for each element in the list. See static
8646 * integers in Container class.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008647 * @param selection Which position is initally selected.
8648 */
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008649 void requestListBox(String[] array, int[] enabledArray, int selection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008650 mPrivateHandler.post(
8651 new InvokeListBox(array, enabledArray, selection));
8652 }
8653
8654 // called by JNI
Leon Scroggins47fabbf2009-12-08 16:57:26 -05008655 private void sendMoveFocus(int frame, int node) {
8656 mWebViewCore.sendMessage(EventHub.SET_MOVE_FOCUS,
8657 new WebViewCore.CursorData(frame, node, 0, 0));
8658 }
8659
8660 // called by JNI
Cary Clarkd6982c92009-05-29 11:02:22 -04008661 private void sendMoveMouse(int frame, int node, int x, int y) {
8662 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
8663 new WebViewCore.CursorData(frame, node, x, y));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008664 }
8665
Leon Scroggins0658e8f2009-06-26 14:09:09 -04008666 /*
8667 * Send a mouse move event to the webcore thread.
8668 *
Leon Scrogginsb6112132011-02-24 12:35:50 -05008669 * @param removeFocus Pass true to remove the WebTextView, if present.
8670 * @param stopPaintingCaret Stop drawing the blinking caret if true.
Leon Scroggins0658e8f2009-06-26 14:09:09 -04008671 * called by JNI
8672 */
Leon Scrogginsb6112132011-02-24 12:35:50 -05008673 @SuppressWarnings("unused")
8674 private void sendMoveMouseIfLatest(boolean removeFocus, boolean stopPaintingCaret) {
Leon Scroggins0658e8f2009-06-26 14:09:09 -04008675 if (removeFocus) {
Leon Scroggins2aed7762010-08-13 17:11:42 -04008676 clearTextEntry();
Cary Clark19436562009-06-04 16:25:07 -04008677 }
Leon Scroggins0658e8f2009-06-26 14:09:09 -04008678 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST,
Leon Scrogginsb6112132011-02-24 12:35:50 -05008679 stopPaintingCaret ? 1 : 0, 0,
Leon Scroggins0658e8f2009-06-26 14:09:09 -04008680 cursorData());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008681 }
8682
Leon Scrogginsd5188652011-01-19 17:01:55 -05008683 /**
8684 * Called by JNI to send a message to the webcore thread that the user
8685 * touched the webpage.
8686 * @param touchGeneration Generation number of the touch, to ignore touches
8687 * after a new one has been generated.
8688 * @param frame Pointer to the frame holding the node that was touched.
8689 * @param node Pointer to the node touched.
8690 * @param x x-position of the touch.
8691 * @param y y-position of the touch.
Leon Scrogginsd5188652011-01-19 17:01:55 -05008692 */
Cary Clarkd6982c92009-05-29 11:02:22 -04008693 private void sendMotionUp(int touchGeneration,
Leon Scroggins22e883d2011-01-31 10:54:19 -05008694 int frame, int node, int x, int y) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008695 WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
8696 touchUpData.mMoveGeneration = touchGeneration;
Cary Clarkd6982c92009-05-29 11:02:22 -04008697 touchUpData.mFrame = frame;
8698 touchUpData.mNode = node;
8699 touchUpData.mX = x;
8700 touchUpData.mY = y;
Patrick Scottcfa734a2011-02-22 11:19:02 -05008701 touchUpData.mNativeLayer = nativeScrollableLayer(
8702 x, y, touchUpData.mNativeLayerRect, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008703 mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
8704 }
8705
8706
8707 private int getScaledMaxXScroll() {
8708 int width;
8709 if (mHeightCanMeasure == false) {
8710 width = getViewWidth() / 4;
8711 } else {
8712 Rect visRect = new Rect();
8713 calcOurVisibleRect(visRect);
8714 width = visRect.width() / 2;
8715 }
8716 // FIXME the divisor should be retrieved from somewhere
Leon Scroggins0236e672009-09-02 21:12:08 -04008717 return viewToContentX(width);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008718 }
8719
8720 private int getScaledMaxYScroll() {
8721 int height;
8722 if (mHeightCanMeasure == false) {
8723 height = getViewHeight() / 4;
8724 } else {
8725 Rect visRect = new Rect();
8726 calcOurVisibleRect(visRect);
8727 height = visRect.height() / 2;
8728 }
8729 // FIXME the divisor should be retrieved from somewhere
8730 // the closest thing today is hard-coded into ScrollView.java
8731 // (from ScrollView.java, line 363) int maxJump = height/2;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04008732 return Math.round(height * mZoomManager.getInvScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008733 }
8734
8735 /**
8736 * Called by JNI to invalidate view
8737 */
8738 private void viewInvalidate() {
8739 invalidate();
8740 }
Cary Clarkd6982c92009-05-29 11:02:22 -04008741
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008742 /**
Leon Scroggins9ab32b62010-05-03 14:19:50 +01008743 * Pass the key directly to the page. This assumes that
8744 * nativePageShouldHandleShiftAndArrows() returned true.
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008745 */
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07008746 private void letPageHandleNavKey(int keyCode, long time, boolean down, int metaState) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008747 int keyEventAction;
8748 int eventHubAction;
8749 if (down) {
8750 keyEventAction = KeyEvent.ACTION_DOWN;
8751 eventHubAction = EventHub.KEY_DOWN;
8752 playSoundEffect(keyCodeToSoundsEffect(keyCode));
8753 } else {
8754 keyEventAction = KeyEvent.ACTION_UP;
8755 eventHubAction = EventHub.KEY_UP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008756 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07008757
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008758 KeyEvent event = new KeyEvent(time, time, keyEventAction, keyCode,
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07008759 1, (metaState & KeyEvent.META_SHIFT_ON)
8760 | (metaState & KeyEvent.META_ALT_ON)
8761 | (metaState & KeyEvent.META_SYM_ON)
Jeff Brown6b53e8d2010-11-10 16:03:06 -08008762 , KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008763 mWebViewCore.sendMessage(eventHubAction, event);
8764 }
8765
8766 // return true if the key was handled
8767 private boolean navHandledKey(int keyCode, int count, boolean noScroll,
8768 long time) {
8769 if (mNativeClass == 0) {
8770 return false;
Cary Clark215b72c2009-06-26 14:38:43 -04008771 }
Cary Clark32820242010-12-03 10:27:20 -05008772 mInitialHitTestResult = null;
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008773 mLastCursorTime = time;
8774 mLastCursorBounds = nativeGetCursorRingBounds();
8775 boolean keyHandled
8776 = nativeMoveCursor(keyCode, count, noScroll) == false;
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04008777 if (DebugFlags.WEB_VIEW) {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008778 Log.v(LOGTAG, "navHandledKey mLastCursorBounds=" + mLastCursorBounds
8779 + " mLastCursorTime=" + mLastCursorTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008780 + " handled=" + keyHandled);
8781 }
Leon Scrogginscef1c592011-01-26 11:13:24 -05008782 if (keyHandled == false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008783 return keyHandled;
8784 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008785 Rect contentCursorRingBounds = nativeGetCursorRingBounds();
8786 if (contentCursorRingBounds.isEmpty()) return keyHandled;
Mike Reede9e86b82009-09-15 11:26:53 -04008787 Rect viewCursorRingBounds = contentToViewRect(contentCursorRingBounds);
Cary Clarka3ee56f2011-01-10 11:20:56 -05008788 // set last touch so that context menu related functions will work
8789 mLastTouchX = (viewCursorRingBounds.left + viewCursorRingBounds.right) / 2;
8790 mLastTouchY = (viewCursorRingBounds.top + viewCursorRingBounds.bottom) / 2;
Leon Scrogginscef1c592011-01-26 11:13:24 -05008791 if (mHeightCanMeasure == false) {
8792 return keyHandled;
8793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008794 Rect visRect = new Rect();
8795 calcOurVisibleRect(visRect);
8796 Rect outset = new Rect(visRect);
8797 int maxXScroll = visRect.width() / 2;
8798 int maxYScroll = visRect.height() / 2;
8799 outset.inset(-maxXScroll, -maxYScroll);
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008800 if (Rect.intersects(outset, viewCursorRingBounds) == false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008801 return keyHandled;
8802 }
8803 // FIXME: Necessary because ScrollView/ListView do not scroll left/right
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008804 int maxH = Math.min(viewCursorRingBounds.right - visRect.right,
8805 maxXScroll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008806 if (maxH > 0) {
8807 pinScrollBy(maxH, 0, true, 0);
8808 } else {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008809 maxH = Math.max(viewCursorRingBounds.left - visRect.left,
8810 -maxXScroll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008811 if (maxH < 0) {
8812 pinScrollBy(maxH, 0, true, 0);
8813 }
8814 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008815 if (mLastCursorBounds.isEmpty()) return keyHandled;
8816 if (mLastCursorBounds.equals(contentCursorRingBounds)) {
8817 return keyHandled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008818 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008819 if (DebugFlags.WEB_VIEW) {
8820 Log.v(LOGTAG, "navHandledKey contentCursorRingBounds="
8821 + contentCursorRingBounds);
8822 }
8823 requestRectangleOnScreen(viewCursorRingBounds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008824 return keyHandled;
8825 }
Cary Clarkd6982c92009-05-29 11:02:22 -04008826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008827 /**
Svetoslav Ganov12bed782011-01-03 14:14:50 -08008828 * @return Whether accessibility script has been injected.
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07008829 */
Svetoslav Ganov12bed782011-01-03 14:14:50 -08008830 private boolean accessibilityScriptInjected() {
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07008831 // TODO: Maybe the injected script should announce its presence in
8832 // the page meta-tag so the nativePageShouldHandleShiftAndArrows
8833 // will check that as one of the conditions it looks for
Svetoslav Ganov12bed782011-01-03 14:14:50 -08008834 return mAccessibilityScriptInjected;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07008835 }
8836
8837 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008838 * Set the background color. It's white by default. Pass
8839 * zero to make the view transparent.
8840 * @param color the ARGB color described by Color.java
8841 */
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08008842 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008843 public void setBackgroundColor(int color) {
8844 mBackgroundColor = color;
8845 mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color);
8846 }
8847
Kristian Monsenfc771652011-05-10 16:44:05 +01008848 /**
8849 * @deprecated This method is now obsolete.
8850 */
8851 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008852 public void debugDump() {
Steve Block51b08912011-04-27 15:04:48 +01008853 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008854 nativeDebugDump();
8855 mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
8856 }
Cary Clarkd6982c92009-05-29 11:02:22 -04008857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008858 /**
Mike Reedefe2c722009-10-14 09:42:02 -04008859 * Draw the HTML page into the specified canvas. This call ignores any
8860 * view-specific zoom, scroll offset, or other changes. It does not draw
8861 * any view-specific chrome, such as progress or URL bars.
8862 *
8863 * @hide only needs to be accessible to Browser and testing
8864 */
8865 public void drawPage(Canvas canvas) {
Grace Kloba8abd50b2010-07-08 15:02:14 -07008866 nativeDraw(canvas, 0, 0, false);
Mike Reedefe2c722009-10-14 09:42:02 -04008867 }
8868
8869 /**
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08008870 * Enable the communication b/t the webView and VideoViewProxy
8871 *
8872 * @hide only used by the Browser
8873 */
8874 public void setHTML5VideoViewProxy(HTML5VideoViewProxy proxy) {
8875 mHTML5VideoViewProxy = proxy;
8876 }
8877
8878 /**
Dave Burke84a34052011-02-01 12:57:54 +00008879 * Enable expanded tiles bound for smoother scrolling.
8880 *
8881 * @hide only used by the Browser
8882 */
8883 public void setExpandedTileBounds(boolean enabled) {
Ben Murdochfa148f62011-02-01 20:51:27 +00008884 nativeSetExpandedTileBounds(enabled);
Dave Burke84a34052011-02-01 12:57:54 +00008885 }
8886
8887 /**
Ben Murdochecbc65c2010-01-13 10:54:56 +00008888 * Set the time to wait between passing touches to WebCore. See also the
8889 * TOUCH_SENT_INTERVAL member for further discussion.
8890 *
8891 * @hide This is only used by the DRT test application.
8892 */
8893 public void setTouchInterval(int interval) {
8894 mCurrentTouchInterval = interval;
8895 }
8896
8897 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008898 * Update our cache with updatedText.
8899 * @param updatedText The new text to put in our cache.
8900 */
8901 /* package */ void updateCachedTextfield(String updatedText) {
8902 // Also place our generation number so that when we look at the cache
8903 // we recognize that it is up to date.
8904 nativeUpdateCachedTextfield(updatedText, mTextGeneration);
8905 }
Cary Clarkd6982c92009-05-29 11:02:22 -04008906
Ben Murdoch62275a42010-09-07 11:27:28 +01008907 /*package*/ void autoFillForm(int autoFillQueryId) {
8908 mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM, autoFillQueryId, /* unused */0);
8909 }
8910
Ben Murdoch1708ad52010-11-11 15:56:16 +00008911 /* package */ ViewManager getViewManager() {
8912 return mViewManager;
8913 }
8914
Steve Block51b08912011-04-27 15:04:48 +01008915 private static void checkThread() {
8916 if (!"main".equals(Thread.currentThread().getName())) {
8917 try {
8918 throw new RuntimeException("A WebView method was called on thread '" +
8919 Thread.currentThread().getName() + "'. " +
8920 "All WebView methods must be called on the UI thread. " +
8921 "Future versions of WebView may not support use on other threads.");
8922 } catch (RuntimeException e) {
8923 Log.e(LOGTAG, Log.getStackTraceString(e));
8924 }
8925 }
8926 }
8927
Cary Clark1cb97ee2009-12-11 12:10:36 -05008928 private native int nativeCacheHitFramePointer();
Cary Clarkb2601352011-01-11 11:32:01 -05008929 private native boolean nativeCacheHitIsPlugin();
Cary Clark1cb97ee2009-12-11 12:10:36 -05008930 private native Rect nativeCacheHitNodeBounds();
8931 private native int nativeCacheHitNodePointer();
Leon Scroggins4890feb2009-07-02 10:37:10 -04008932 /* package */ native void nativeClearCursor();
Leon Scrogginscdaff15bd2011-03-04 12:30:03 -05008933 private native void nativeCreate(int ptr, String drawableDir, AssetManager am);
Cary Clarkd6982c92009-05-29 11:02:22 -04008934 private native int nativeCursorFramePointer();
8935 private native Rect nativeCursorNodeBounds();
Cary Clarkaffa5d22010-01-07 12:18:23 -05008936 private native int nativeCursorNodePointer();
Cary Clarkd6982c92009-05-29 11:02:22 -04008937 private native boolean nativeCursorIntersects(Rect visibleRect);
8938 private native boolean nativeCursorIsAnchor();
8939 private native boolean nativeCursorIsTextInput();
Cary Clarked56eda2009-06-18 09:48:47 -04008940 private native Point nativeCursorPosition();
Cary Clarkd6982c92009-05-29 11:02:22 -04008941 private native String nativeCursorText();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008942 /**
8943 * Returns true if the native cursor node says it wants to handle key events
8944 * (ala plugins). This can only be called if mNativeClass is non-zero!
8945 */
Cary Clark2f1d60c2009-06-03 08:05:53 -04008946 private native boolean nativeCursorWantsKeyEvents();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008947 private native void nativeDebugDump();
8948 private native void nativeDestroy();
Grace Kloba8abd50b2010-07-08 15:02:14 -07008949
8950 /**
8951 * Draw the picture set with a background color and extra. If
8952 * "splitIfNeeded" is true and the return value is not 0, the return value
8953 * MUST be passed to WebViewCore with SPLIT_PICTURE_SET message so that the
8954 * native allocation can be freed.
8955 */
8956 private native int nativeDraw(Canvas canvas, int color, int extra,
8957 boolean splitIfNeeded);
Cary Clarkd6982c92009-05-29 11:02:22 -04008958 private native void nativeDumpDisplayTree(String urlOrNull);
Cary Clark924af702010-06-04 16:37:43 -04008959 private native boolean nativeEvaluateLayersAnimations();
Romain Guycabfcc12011-03-07 18:06:46 -08008960 private native int nativeGetDrawGLFunction(Rect rect, Rect viewRect,
8961 float scale, int extras);
8962 private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect);
Cary Clark924af702010-06-04 16:37:43 -04008963 private native void nativeExtendSelection(int x, int y);
Leon Scroggins4f4a5672010-10-19 13:58:11 -04008964 private native int nativeFindAll(String findLower, String findUpper,
8965 boolean sameAsLastSearch);
Cary Clarkd6982c92009-05-29 11:02:22 -04008966 private native void nativeFindNext(boolean forward);
Leon Scroggins3a503392010-01-06 17:04:38 -05008967 /* package */ native int nativeFocusCandidateFramePointer();
Leon Scrogginsf9b1a092010-03-31 15:32:36 -04008968 /* package */ native boolean nativeFocusCandidateHasNextTextfield();
Leon Scroggins69ec5c22010-04-22 16:27:21 -04008969 /* package */ native boolean nativeFocusCandidateIsPassword();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008970 private native boolean nativeFocusCandidateIsRtlText();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008971 private native boolean nativeFocusCandidateIsTextInput();
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05008972 /* package */ native int nativeFocusCandidateMaxLength();
Leon Scrogginsae0238c2011-01-05 15:12:55 -05008973 /* package */ native boolean nativeFocusCandidateIsAutoComplete();
Leon Scroggins0ca70882009-06-26 17:45:29 -04008974 /* package */ native String nativeFocusCandidateName();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008975 private native Rect nativeFocusCandidateNodeBounds();
Leon Scrogginsdfc07272010-10-12 13:40:23 -04008976 /**
8977 * @return A Rect with left, top, right, bottom set to the corresponding
8978 * padding values in the focus candidate, if it is a textfield/textarea with
8979 * a style. Otherwise return null. This is not actually a rectangle; Rect
8980 * is being used to pass four integers.
8981 */
8982 private native Rect nativeFocusCandidatePaddingRect();
Leon Scroggins69ec5c22010-04-22 16:27:21 -04008983 /* package */ native int nativeFocusCandidatePointer();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04008984 private native String nativeFocusCandidateText();
Leon Scroggins56a102c2010-11-12 14:40:07 -05008985 /* package */ native float nativeFocusCandidateTextSize();
Leon Scroggins1ca56262010-11-18 14:03:03 -05008986 /* package */ native int nativeFocusCandidateLineHeight();
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05008987 /**
8988 * Returns an integer corresponding to WebView.cpp::type.
8989 * See WebTextView.setType()
8990 */
8991 private native int nativeFocusCandidateType();
Derek Sollenberger718d69f2009-10-19 15:56:43 -04008992 private native boolean nativeFocusIsPlugin();
Cary Clarke84a0db2010-03-17 15:58:20 -04008993 private native Rect nativeFocusNodeBounds();
Leon Scroggins4890feb2009-07-02 10:37:10 -04008994 /* package */ native int nativeFocusNodePointer();
Cary Clarkd6982c92009-05-29 11:02:22 -04008995 private native Rect nativeGetCursorRingBounds();
Cary Clark57d2c3a2009-12-23 13:57:15 -05008996 private native String nativeGetSelection();
Cary Clarkd6982c92009-05-29 11:02:22 -04008997 private native boolean nativeHasCursorNode();
8998 private native boolean nativeHasFocusNode();
Cary Clarke872f3a2009-06-11 09:51:11 -04008999 private native void nativeHideCursor();
Cary Clark924af702010-06-04 16:37:43 -04009000 private native boolean nativeHitSelection(int x, int y);
Cary Clarkd6982c92009-05-29 11:02:22 -04009001 private native String nativeImageURI(int x, int y);
9002 private native void nativeInstrumentReport();
Cary Clark6f5dfc62010-11-11 13:09:20 -05009003 private native Rect nativeLayerBounds(int layer);
Leon Scroggins1be40982010-03-01 11:20:31 -05009004 /* package */ native boolean nativeMoveCursorToNextTextInput();
Cary Clarkd6982c92009-05-29 11:02:22 -04009005 // return true if the page has been scrolled
9006 private native boolean nativeMotionUp(int x, int y, int slop);
9007 // returns false if it handled the key
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009008 private native boolean nativeMoveCursor(int keyCode, int count,
Cary Clarkd6982c92009-05-29 11:02:22 -04009009 boolean noScroll);
9010 private native int nativeMoveGeneration();
Cary Clark924af702010-06-04 16:37:43 -04009011 private native void nativeMoveSelection(int x, int y);
Leon Scroggins9ab32b62010-05-03 14:19:50 +01009012 /**
9013 * @return true if the page should get the shift and arrow keys, rather
9014 * than select text/navigation.
9015 *
9016 * If the focus is a plugin, or if the focus and cursor match and are
9017 * a contentEditable element, then the page should handle these keys.
9018 */
9019 private native boolean nativePageShouldHandleShiftAndArrows();
Cary Clark1cb97ee2009-12-11 12:10:36 -05009020 private native boolean nativePointInNavCache(int x, int y, int slop);
Cary Clarkd6982c92009-05-29 11:02:22 -04009021 // Like many other of our native methods, you must make sure that
9022 // mNativeClass is not null before calling this method.
9023 private native void nativeRecordButtons(boolean focused,
9024 boolean pressed, boolean invalidate);
Cary Clark924af702010-06-04 16:37:43 -04009025 private native void nativeResetSelection();
Cary Clark2cdee232010-12-29 14:59:24 -05009026 private native Point nativeSelectableText();
Cary Clark924af702010-06-04 16:37:43 -04009027 private native void nativeSelectAll();
Cary Clarkd6982c92009-05-29 11:02:22 -04009028 private native void nativeSelectBestAt(Rect rect);
Svetoslav Ganov9504f572011-01-14 11:38:17 -08009029 private native void nativeSelectAt(int x, int y);
Cary Clark924af702010-06-04 16:37:43 -04009030 private native int nativeSelectionX();
9031 private native int nativeSelectionY();
Leon Scroggins6a367f52010-05-06 17:37:40 -04009032 private native int nativeFindIndex();
Cary Clark924af702010-06-04 16:37:43 -04009033 private native void nativeSetExtendSelection();
Cary Clarkde023c12010-03-03 10:05:16 -05009034 private native void nativeSetFindIsEmpty();
9035 private native void nativeSetFindIsUp(boolean isUp);
Cary Clarkd6982c92009-05-29 11:02:22 -04009036 private native void nativeSetHeightCanMeasure(boolean measure);
Nicolas Roard3cb5ded2011-02-23 18:18:46 -08009037 private native void nativeSetBaseLayer(int layer, Region invalRegion,
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07009038 boolean showVisualIndicator, boolean isPictureAfterFirstLayout);
Cary Clarke60cb7f2010-08-25 14:56:00 -04009039 private native void nativeShowCursorTimed();
Grace Kloba8abd50b2010-07-08 15:02:14 -07009040 private native void nativeReplaceBaseContent(int content);
9041 private native void nativeCopyBaseContentToPicture(Picture pict);
9042 private native boolean nativeHasContent();
Cary Clark2ec30692010-02-23 10:50:38 -05009043 private native void nativeSetSelectionPointer(boolean set,
Cary Clark924af702010-06-04 16:37:43 -04009044 float scale, int x, int y);
9045 private native boolean nativeStartSelection(int x, int y);
Cary Clarkd9fd8572011-02-03 05:25:05 -05009046 private native void nativeStopGL();
Cary Clark31b83672010-03-09 09:20:34 -05009047 private native Rect nativeSubtractLayers(Rect content);
Cary Clarkd6982c92009-05-29 11:02:22 -04009048 private native int nativeTextGeneration();
9049 // Never call this version except by updateCachedTextfield(String) -
9050 // we always want to pass in our generation number.
9051 private native void nativeUpdateCachedTextfield(String updatedText,
9052 int generation);
Cary Clark924af702010-06-04 16:37:43 -04009053 private native boolean nativeWordSelection(int x, int y);
Grace Kloba8b97e4b2009-07-28 13:11:38 -07009054 // return NO_LEFTEDGE means failure.
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04009055 static final int NO_LEFTEDGE = -1;
9056 native int nativeGetBlockLeftEdge(int x, int y, float scale);
Patrick Scotta3ebcc92010-07-16 11:52:22 -04009057
Ben Murdochfa148f62011-02-01 20:51:27 +00009058 private native void nativeSetExpandedTileBounds(boolean enabled);
9059
Patrick Scotta3ebcc92010-07-16 11:52:22 -04009060 // Returns a pointer to the scrollable LayerAndroid at the given point.
Cary Clarkb9aaa772011-01-07 16:14:54 -05009061 private native int nativeScrollableLayer(int x, int y, Rect scrollRect,
9062 Rect scrollBounds);
Leon Scrogginsd5188652011-01-19 17:01:55 -05009063 /**
9064 * Scroll the specified layer.
9065 * @param layer Id of the layer to scroll, as determined by nativeScrollableLayer.
9066 * @param newX Destination x position to which to scroll.
9067 * @param newY Destination y position to which to scroll.
9068 * @return True if the layer is successfully scrolled.
9069 */
9070 private native boolean nativeScrollLayer(int layer, int newX, int newY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071}