blob: fa82c46e2f564e9468aee29d012ea543ca627e3e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
Raphael30df2372010-03-06 10:09:54 -080019import android.annotation.Widget;
John Reck0507ac42011-11-21 13:30:32 -080020import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.AlertDialog;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040022import android.content.BroadcastReceiver;
Dianne Hackborn90d5e8c2010-08-05 13:47:55 -070023import android.content.ClipboardManager;
John Reckfaa42db2011-09-07 11:33:34 -070024import android.content.ComponentCallbacks2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
26import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.DialogInterface.OnCancelListener;
Adam Powell637d3372010-08-25 14:37:03 -070028import android.content.Intent;
29import android.content.IntentFilter;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040030import android.content.pm.PackageInfo;
31import android.content.pm.PackageManager;
Cary Clarkc5cd5e92010-11-22 15:20:02 -050032import android.content.res.Configuration;
Leon Scroggins3667ce42009-05-13 15:58:03 -040033import android.database.DataSetObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.graphics.Bitmap;
Adam Powell637d3372010-08-25 14:37:03 -070035import android.graphics.BitmapFactory;
36import android.graphics.BitmapShader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.graphics.Canvas;
38import android.graphics.Color;
Grace Kloba8abd50b2010-07-08 15:02:14 -070039import android.graphics.DrawFilter;
Grace Kloba178db412010-05-18 22:22:23 -070040import android.graphics.Paint;
Grace Kloba8abd50b2010-07-08 15:02:14 -070041import android.graphics.PaintFlagsDrawFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.graphics.Picture;
43import android.graphics.Point;
44import android.graphics.Rect;
Nicolas Roard46318cf2010-05-10 15:15:51 -070045import android.graphics.RectF;
Grace Kloba178db412010-05-18 22:22:23 -070046import android.graphics.Region;
John Reck335f4542011-08-25 18:25:09 -070047import android.graphics.RegionIterator;
Adam Powell637d3372010-08-25 14:37:03 -070048import android.graphics.Shader;
Mike Reede8853fc2009-09-04 14:01:48 -040049import android.graphics.drawable.Drawable;
Kristian Monsen41e7e6f2010-12-21 12:51:11 +000050import android.net.Proxy;
51import android.net.ProxyProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.net.Uri;
Adam Powell9d32d242010-03-29 16:02:07 -070053import android.net.http.SslCertificate;
Derek Sollenberger41d5e932010-08-23 14:51:41 -040054import android.os.AsyncTask;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.Bundle;
56import android.os.Handler;
Steve Block08d584c2011-05-17 19:05:03 +010057import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Message;
Steve Block08d584c2011-05-17 19:05:03 +010059import android.os.StrictMode;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -070060import android.provider.Settings;
Svetoslav Ganovda355512010-05-12 22:04:44 -070061import android.speech.tts.TextToSpeech;
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -080062import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.util.EventLog;
65import android.util.Log;
John Reck0507ac42011-11-21 13:30:32 -080066import android.view.Display;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.view.Gravity;
Adam Powellad804e32011-09-14 19:11:08 -070068import android.view.HapticFeedbackConstants;
Svetoslav Ganov9504f572011-01-14 11:38:17 -080069import android.view.HardwareCanvas;
Jeff Brown33bbfd22011-02-24 20:55:35 -080070import android.view.InputDevice;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080071import android.view.KeyCharacterMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.view.KeyEvent;
73import android.view.LayoutInflater;
74import android.view.MotionEvent;
Grace Kloba3a0def22010-01-23 21:11:54 -080075import android.view.ScaleGestureDetector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.view.SoundEffectConstants;
77import android.view.VelocityTracker;
78import android.view.View;
79import android.view.ViewConfiguration;
80import android.view.ViewGroup;
Leon Scroggins7f7bd522010-11-05 11:23:31 -040081import android.view.ViewParent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.view.ViewTreeObserver;
John Reck0507ac42011-11-21 13:30:32 -080083import android.view.WindowManager;
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -070084import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganovda355512010-05-12 22:04:44 -070085import android.view.accessibility.AccessibilityManager;
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -070086import android.view.accessibility.AccessibilityNodeInfo;
Derek Sollenberger7cabb032010-01-21 10:37:38 -050087import android.view.inputmethod.EditorInfo;
88import android.view.inputmethod.InputConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.view.inputmethod.InputMethodManager;
Leon Scrogginsd3465f62009-06-02 10:57:54 -040090import android.webkit.WebTextView.AutoCompleteAdapter;
John Reck816c0de2011-06-02 16:04:53 -070091import android.webkit.WebViewCore.DrawData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.webkit.WebViewCore.EventHub;
Grace Klobac2242f22010-03-05 14:00:26 -080093import android.webkit.WebViewCore.TouchEventData;
Grace Kloba178db412010-05-18 22:22:23 -070094import android.webkit.WebViewCore.TouchHighlightData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.widget.AbsoluteLayout;
Leon Scroggins3667ce42009-05-13 15:58:03 -040096import android.widget.Adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.widget.AdapterView;
Michael Kolb73980a92010-08-05 16:32:51 -070098import android.widget.AdapterView.OnItemClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import android.widget.ArrayAdapter;
Leon Scrogginsa8da1732009-10-19 19:04:30 -0400100import android.widget.CheckedTextView;
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -0400101import android.widget.LinearLayout;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import android.widget.ListView;
Adam Powell637d3372010-08-25 14:37:03 -0700103import android.widget.OverScroller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import android.widget.Toast;
Michael Kolb73980a92010-08-05 16:32:51 -0700105
Steve Blockf95d4902011-06-09 11:53:26 +0100106import junit.framework.Assert;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
111import java.io.FileOutputStream;
John Reck816c0de2011-06-02 16:04:53 -0700112import java.io.IOException;
113import java.io.InputStream;
114import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.net.URLDecoder;
116import java.util.ArrayList;
Andrei Popescuf5dba882010-01-12 22:42:41 +0000117import java.util.HashMap;
Derek Sollenberger41d5e932010-08-23 14:51:41 -0400118import java.util.HashSet;
Adam Powell9d32d242010-03-29 16:02:07 -0700119import java.util.List;
Andrei Popescu4950b2b2009-09-03 13:56:07 +0100120import java.util.Map;
Andrei Popescua6d747d2010-02-11 13:19:21 +0000121import java.util.Set;
Leon Scroggins115626a2011-02-17 12:00:48 -0500122import java.util.Vector;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700123import java.util.regex.Matcher;
124import java.util.regex.Pattern;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
Nicolas Roard2bc0b012011-11-16 19:26:25 -0800126import javax.microedition.khronos.egl.EGL10;
127import javax.microedition.khronos.egl.EGLContext;
128import javax.microedition.khronos.egl.EGLDisplay;
129import static javax.microedition.khronos.egl.EGL10.*;
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131/**
Cary Clarkd6982c92009-05-29 11:02:22 -0400132 * <p>A View that displays web pages. This class is the basis upon which you
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 * can roll your own web browser or simply display some online content within your Activity.
134 * It uses the WebKit rendering engine to display
135 * web pages and includes methods to navigate forward and backward
136 * through a history, zoom in and out, perform text searches and more.</p>
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 * <p>To enable the built-in zoom, set
138 * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
139 * (introduced in API version 3).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 * <p>Note that, in order for your Activity to access the Internet and load web pages
Scott Main8b3cea02010-05-14 14:12:43 -0700141 * in a WebView, you must add the {@code INTERNET} permissions to your
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 * Android Manifest file:</p>
143 * <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100144 *
Scott Main8b3cea02010-05-14 14:12:43 -0700145 * <p>This must be a child of the <a
Ben Dodson4e8620f2010-08-25 10:55:47 -0700146 * href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code <manifest>}</a>
Scott Main8b3cea02010-05-14 14:12:43 -0700147 * element.</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100148 *
Scott Main41ec6532010-08-19 16:57:07 -0700149 * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-webview.html">Web View
150 * tutorial</a>.</p>
151 *
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100152 * <h3>Basic usage</h3>
153 *
154 * <p>By default, a WebView provides no browser-like widgets, does not
Scott Main8b3cea02010-05-14 14:12:43 -0700155 * enable JavaScript and web page errors are ignored. If your goal is only
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100156 * to display some HTML as a part of your UI, this is probably fine;
157 * the user won't need to interact with the web page beyond reading
158 * it, and the web page won't need to interact with the user. If you
Scott Main8b3cea02010-05-14 14:12:43 -0700159 * actually want a full-blown web browser, then you probably want to
160 * invoke the Browser application with a URL Intent rather than show it
161 * with a WebView. For example:
162 * <pre>
163 * Uri uri = Uri.parse("http://www.example.com");
164 * Intent intent = new Intent(Intent.ACTION_VIEW, uri);
165 * startActivity(intent);
166 * </pre>
167 * <p>See {@link android.content.Intent} for more information.</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100168 *
Ben Dodson4e8620f2010-08-25 10:55:47 -0700169 * <p>To provide a WebView in your own Activity, include a {@code <WebView>} in your layout,
Scott Main8b3cea02010-05-14 14:12:43 -0700170 * or set the entire Activity window as a WebView during {@link
171 * android.app.Activity#onCreate(Bundle) onCreate()}:</p>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100172 * <pre class="prettyprint">
173 * WebView webview = new WebView(this);
174 * setContentView(webview);
Scott Main8b3cea02010-05-14 14:12:43 -0700175 * </pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100176 *
Scott Main8b3cea02010-05-14 14:12:43 -0700177 * <p>Then load the desired web page:</p>
Scott Maine3b9f8b2010-05-18 08:41:36 -0700178 * <pre>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100179 * // Simplest usage: note that an exception will NOT be thrown
180 * // if there is an error loading this page (see below).
181 * webview.loadUrl("http://slashdot.org/");
182 *
Scott Main8b3cea02010-05-14 14:12:43 -0700183 * // OR, you can also load from an HTML string:
Scott Maine3b9f8b2010-05-18 08:41:36 -0700184 * String summary = "&lt;html>&lt;body>You scored &lt;b>192&lt;/b> points.&lt;/body>&lt;/html>";
Steve Blockf95d4902011-06-09 11:53:26 +0100185 * webview.loadData(summary, "text/html", null);
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100186 * // ... although note that there are restrictions on what this HTML can do.
Scott Main8b3cea02010-05-14 14:12:43 -0700187 * // See the JavaDocs for {@link #loadData(String,String,String) loadData()} and {@link
188 * #loadDataWithBaseURL(String,String,String,String,String) loadDataWithBaseURL()} for more info.
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100189 * </pre>
190 *
191 * <p>A WebView has several customization points where you can add your
192 * own behavior. These are:</p>
193 *
194 * <ul>
195 * <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass.
196 * This class is called when something that might impact a
197 * browser UI happens, for instance, progress updates and
Scott Main8b3cea02010-05-14 14:12:43 -0700198 * JavaScript alerts are sent here (see <a
199 * href="{@docRoot}guide/developing/debug-tasks.html#DebuggingWebPages">Debugging Tasks</a>).
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100200 * </li>
201 * <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
202 * It will be called when things happen that impact the
203 * rendering of the content, eg, errors or form submissions. You
Scott Main8b3cea02010-05-14 14:12:43 -0700204 * can also intercept URL loading here (via {@link
205 * android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String)
206 * shouldOverrideUrlLoading()}).</li>
207 * <li>Modifying the {@link android.webkit.WebSettings}, such as
208 * enabling JavaScript with {@link android.webkit.WebSettings#setJavaScriptEnabled(boolean)
209 * setJavaScriptEnabled()}. </li>
Steve Block4cd73c52011-11-09 13:06:52 +0000210 * <li>Injecting Java objects into the WebView using the
211 * {@link android.webkit.WebView#addJavascriptInterface} method. This
212 * method allows you to inject Java objects into a page's JavaScript
213 * context, so that they can be accessed by JavaScript in the page.</li>
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100214 * </ul>
215 *
216 * <p>Here's a more complicated example, showing error handling,
217 * settings, and progress notification:</p>
218 *
219 * <pre class="prettyprint">
220 * // Let's display the progress in the activity title bar, like the
221 * // browser app does.
222 * getWindow().requestFeature(Window.FEATURE_PROGRESS);
223 *
224 * webview.getSettings().setJavaScriptEnabled(true);
225 *
226 * final Activity activity = this;
227 * webview.setWebChromeClient(new WebChromeClient() {
228 * public void onProgressChanged(WebView view, int progress) {
229 * // Activities and WebViews measure progress with different scales.
230 * // The progress meter will automatically disappear when we reach 100%
231 * activity.setProgress(progress * 1000);
232 * }
233 * });
234 * webview.setWebViewClient(new WebViewClient() {
235 * public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
236 * Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
237 * }
238 * });
239 *
240 * webview.loadUrl("http://slashdot.org/");
241 * </pre>
242 *
243 * <h3>Cookie and window management</h3>
244 *
245 * <p>For obvious security reasons, your application has its own
Scott Main8b3cea02010-05-14 14:12:43 -0700246 * cache, cookie store etc.&mdash;it does not share the Browser
247 * application's data. Cookies are managed on a separate thread, so
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100248 * operations like index building don't block the UI
249 * thread. Follow the instructions in {@link android.webkit.CookieSyncManager}
250 * if you want to use cookies in your application.
251 * </p>
252 *
253 * <p>By default, requests by the HTML to open new windows are
254 * ignored. This is true whether they be opened by JavaScript or by
255 * the target attribute on a link. You can customize your
Scott Main8b3cea02010-05-14 14:12:43 -0700256 * {@link WebChromeClient} to provide your own behaviour for opening multiple windows,
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100257 * and render them in whatever manner you want.</p>
258 *
Scott Main8b3cea02010-05-14 14:12:43 -0700259 * <p>The standard behavior for an Activity is to be destroyed and
260 * recreated when the device orientation or any other configuration changes. This will cause
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100261 * the WebView to reload the current page. If you don't want that, you
Scott Main8b3cea02010-05-14 14:12:43 -0700262 * can set your Activity to handle the {@code orientation} and {@code keyboardHidden}
Mike Hearnadcd2ed2009-01-21 16:44:36 +0100263 * changes, and then just leave the WebView alone. It'll automatically
Scott Main8b3cea02010-05-14 14:12:43 -0700264 * re-orient itself as appropriate. Read <a
265 * href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a> for
266 * more information about how to handle configuration changes during runtime.</p>
267 *
268 *
269 * <h3>Building web pages to support different screen densities</h3>
270 *
271 * <p>The screen density of a device is based on the screen resolution. A screen with low density
272 * has fewer available pixels per inch, where a screen with high density
Brad Fitzpatrick438d0592010-06-10 12:19:19 -0700273 * has more &mdash; sometimes significantly more &mdash; pixels per inch. The density of a
Scott Main8b3cea02010-05-14 14:12:43 -0700274 * screen is important because, other things being equal, a UI element (such as a button) whose
275 * height and width are defined in terms of screen pixels will appear larger on the lower density
276 * screen and smaller on the higher density screen.
277 * For simplicity, Android collapses all actual screen densities into three generalized densities:
278 * high, medium, and low.</p>
279 * <p>By default, WebView scales a web page so that it is drawn at a size that matches the default
280 * appearance on a medium density screen. So, it applies 1.5x scaling on a high density screen
281 * (because its pixels are smaller) and 0.75x scaling on a low density screen (because its pixels
282 * are bigger).
283 * Starting with API Level 5 (Android 2.0), WebView supports DOM, CSS, and meta tag features to help
284 * you (as a web developer) target screens with different screen densities.</p>
285 * <p>Here's a summary of the features you can use to handle different screen densities:</p>
286 * <ul>
287 * <li>The {@code window.devicePixelRatio} DOM property. The value of this property specifies the
288 * default scaling factor used for the current device. For example, if the value of {@code
289 * window.devicePixelRatio} is "1.0", then the device is considered a medium density (mdpi) device
290 * and default scaling is not applied to the web page; if the value is "1.5", then the device is
291 * considered a high density device (hdpi) and the page content is scaled 1.5x; if the
292 * value is "0.75", then the device is considered a low density device (ldpi) and the content is
293 * scaled 0.75x. However, if you specify the {@code "target-densitydpi"} meta property
294 * (discussed below), then you can stop this default scaling behavior.</li>
295 * <li>The {@code -webkit-device-pixel-ratio} CSS media query. Use this to specify the screen
296 * densities for which this style sheet is to be used. The corresponding value should be either
297 * "0.75", "1", or "1.5", to indicate that the styles are for devices with low density, medium
298 * density, or high density screens, respectively. For example:
299 * <pre>
300 * &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" /&gt;</pre>
301 * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5,
302 * which is the high density pixel ratio.</p>
303 * </li>
304 * <li>The {@code target-densitydpi} property for the {@code viewport} meta tag. You can use
305 * this to specify the target density for which the web page is designed, using the following
306 * values:
307 * <ul>
308 * <li>{@code device-dpi} - Use the device's native dpi as the target dpi. Default scaling never
309 * occurs.</li>
310 * <li>{@code high-dpi} - Use hdpi as the target dpi. Medium and low density screens scale down
311 * as appropriate.</li>
312 * <li>{@code medium-dpi} - Use mdpi as the target dpi. High density screens scale up and
313 * low density screens scale down. This is also the default behavior.</li>
314 * <li>{@code low-dpi} - Use ldpi as the target dpi. Medium and high density screens scale up
315 * as appropriate.</li>
Ben Dodson4e8620f2010-08-25 10:55:47 -0700316 * <li><em>{@code <value>}</em> - Specify a dpi value to use as the target dpi (accepted
Scott Main8b3cea02010-05-14 14:12:43 -0700317 * values are 70-400).</li>
318 * </ul>
319 * <p>Here's an example meta tag to specify the target density:</p>
320 * <pre>&lt;meta name="viewport" content="target-densitydpi=device-dpi" /&gt;</pre></li>
321 * </ul>
322 * <p>If you want to modify your web page for different densities, by using the {@code
323 * -webkit-device-pixel-ratio} CSS media query and/or the {@code
324 * window.devicePixelRatio} DOM property, then you should set the {@code target-densitydpi} meta
325 * property to {@code device-dpi}. This stops Android from performing scaling in your web page and
326 * allows you to make the necessary adjustments for each density via CSS and JavaScript.</p>
327 *
Michael Kolb73980a92010-08-05 16:32:51 -0700328 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 */
Raphael30df2372010-03-06 10:09:54 -0800330@Widget
Cary Clarkd6982c92009-05-29 11:02:22 -0400331public class WebView extends AbsoluteLayout
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 implements ViewTreeObserver.OnGlobalFocusChangeListener,
333 ViewGroup.OnHierarchyChangeListener {
334
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800335 private class InnerGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
336 public void onGlobalLayout() {
337 if (isShown()) {
338 setGLRectViewport();
339 }
340 }
341 }
342
Teng-Hui Zhu55133372010-12-07 17:19:16 -0800343 private class InnerScrollChangedListener implements ViewTreeObserver.OnScrollChangedListener {
344 public void onScrollChanged() {
345 if (isShown()) {
346 setGLRectViewport();
347 }
348 }
349 }
350
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800351 // The listener to capture global layout change event.
Teng-Hui Zhu55133372010-12-07 17:19:16 -0800352 private InnerGlobalLayoutListener mGlobalLayoutListener = null;
353
354 // The listener to capture scroll event.
355 private InnerScrollChangedListener mScrollChangedListener = null;
Teng-Hui Zhua7f76872010-11-29 11:15:32 -0800356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 // if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing
358 // the screen all-the-time. Good for profiling our drawing code
359 static private final boolean AUTO_REDRAW_HACK = false;
360 // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
361 private boolean mAutoRedraw;
362
Mattias Falk0ae2ec82010-09-16 16:24:46 +0200363 // Reference to the AlertDialog displayed by InvokeListBox.
364 // It's used to dismiss the dialog in destroy if not done before.
365 private AlertDialog mListBoxDialog = null;
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 static final String LOGTAG = "webview";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368
Derek Sollenberger90b6e482010-05-10 12:38:54 -0400369 private ZoomManager mZoomManager;
Cary Clarkd6982c92009-05-29 11:02:22 -0400370
Romain Guycabfcc12011-03-07 18:06:46 -0800371 private final Rect mGLRectViewport = new Rect();
372 private final Rect mViewRectViewport = new Rect();
George Mount82ed95f2011-11-15 11:27:47 -0800373 private final RectF mVisibleContentRect = new RectF();
Chet Haase91fc3cf2011-01-28 00:20:04 -0800374 private boolean mGLViewportEmpty = false;
Nicolas Roard12c18e62010-10-13 20:14:31 -0700375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 /**
377 * Transportation object for returning WebView across thread boundaries.
378 */
379 public class WebViewTransport {
380 private WebView mWebview;
381
382 /**
383 * Set the WebView to the transportation object.
384 * @param webview The WebView to transport.
385 */
386 public synchronized void setWebView(WebView webview) {
387 mWebview = webview;
388 }
389
390 /**
391 * Return the WebView object.
392 * @return WebView The transported WebView object.
393 */
394 public synchronized WebView getWebView() {
395 return mWebview;
396 }
397 }
398
John Reck34a676b2011-09-07 13:41:17 -0700399 private static class OnTrimMemoryListener implements ComponentCallbacks2 {
400 private static OnTrimMemoryListener sInstance = null;
401
402 static void init(Context c) {
403 if (sInstance == null) {
404 sInstance = new OnTrimMemoryListener(c.getApplicationContext());
405 }
406 }
407
408 private OnTrimMemoryListener(Context c) {
409 c.registerComponentCallbacks(this);
410 }
411
412 @Override
413 public void onConfigurationChanged(Configuration newConfig) {
414 // Ignore
415 }
416
417 @Override
418 public void onLowMemory() {
419 // Ignore
420 }
421
422 @Override
423 public void onTrimMemory(int level) {
424 if (DebugFlags.WEB_VIEW) {
425 Log.d("WebView", "onTrimMemory: " + level);
426 }
427 WebView.nativeOnTrimMemory(level);
428 }
429
430 }
431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 // A final CallbackProxy shared by WebViewCore and BrowserFrame.
433 private final CallbackProxy mCallbackProxy;
434
435 private final WebViewDatabase mDatabase;
436
437 // SSL certificate for the main top-level page (if secure)
438 private SslCertificate mCertificate;
439
440 // Native WebView pointer that is 0 until the native object has been
441 // created.
442 private int mNativeClass;
443 // This would be final but it needs to be set to null when the WebView is
444 // destroyed.
445 private WebViewCore mWebViewCore;
446 // Handler for dispatching UI messages.
447 /* package */ final Handler mPrivateHandler = new PrivateHandler();
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400448 private WebTextView mWebTextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 // Used to ignore changes to webkit text that arrives to the UI side after
450 // more key events.
451 private int mTextGeneration;
452
Leon Scroggins IIIb24e18b2010-04-20 17:07:28 -0400453 /* package */ void incrementTextGeneration() { mTextGeneration++; }
454
Patrick Scott0a5ce012009-07-02 08:56:10 -0400455 // Used by WebViewCore to create child views.
456 /* package */ final ViewManager mViewManager;
457
Grace Kloba11438c32009-12-16 11:39:12 -0800458 // Used to display in full screen mode
459 PluginFullScreenHolder mFullScreenHolder;
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 /**
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -0800462 * Position of the last touch event in pixels.
463 * Use integer to prevent loss of dragging delta calculation accuracy;
464 * which was done in float and converted to integer, and resulted in gradual
465 * and compounding touch position and view dragging mismatch.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 */
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -0800467 private int mLastTouchX;
468 private int mLastTouchY;
John Reck75738722011-06-10 11:28:53 -0700469 private int mStartTouchX;
470 private int mStartTouchY;
471 private float mAverageAngle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472
473 /**
474 * Time of the last touch event.
475 */
476 private long mLastTouchTime;
477
478 /**
479 * Time of the last time sending touch event to WebViewCore
480 */
481 private long mLastSentTouchTime;
482
483 /**
484 * The minimum elapsed time before sending another ACTION_MOVE event to
Grace Kloba53d3c1e2009-06-26 11:36:03 -0700485 * WebViewCore. This really should be tuned for each type of the devices.
486 * For example in Google Map api test case, it takes Dream device at least
487 * 150ms to do a full cycle in the WebViewCore by processing a touch event,
488 * triggering the layout and drawing the picture. While the same process
489 * takes 60+ms on the current high speed device. If we make
490 * TOUCH_SENT_INTERVAL too small, there will be multiple touch events sent
491 * to WebViewCore queue and the real layout and draw events will be pushed
492 * to further, which slows down the refresh rate. Choose 50 to favor the
493 * current high speed devices. For Dream like devices, 100 is a better
494 * choice. Maybe make this in the buildspec later.
Huahui Wue2975f12010-12-14 13:45:28 -0800495 * (Update 12/14/2010: changed to 0 since current device should be able to
496 * handle the raw events and Map team voted to have the raw events too.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 */
Huahui Wue2975f12010-12-14 13:45:28 -0800498 private static final int TOUCH_SENT_INTERVAL = 0;
Ben Murdochecbc65c2010-01-13 10:54:56 +0000499 private int mCurrentTouchInterval = TOUCH_SENT_INTERVAL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500
501 /**
502 * Helper class to get velocity for fling
503 */
504 VelocityTracker mVelocityTracker;
Romain Guy4296fc42009-07-06 11:48:52 -0700505 private int mMaximumFling;
Cary Clark278ce052009-08-31 16:08:42 -0400506 private float mLastVelocity;
507 private float mLastVelX;
508 private float mLastVelY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509
Patrick Scott62310912010-12-06 17:44:50 -0500510 // The id of the native layer being scrolled.
Michael Kolb5da91bd2011-11-29 15:29:03 -0800511 private int mCurrentScrollingLayerId;
Patrick Scott62310912010-12-06 17:44:50 -0500512 private Rect mScrollingLayerRect = new Rect();
Patrick Scotta3ebcc92010-07-16 11:52:22 -0400513
Grace Kloba3c19d992010-05-17 19:19:06 -0700514 // only trigger accelerated fling if the new velocity is at least
515 // MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION times of the previous velocity
516 private static final float MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION = 0.2f;
517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 /**
519 * Touch mode
520 */
521 private int mTouchMode = TOUCH_DONE_MODE;
522 private static final int TOUCH_INIT_MODE = 1;
523 private static final int TOUCH_DRAG_START_MODE = 2;
524 private static final int TOUCH_DRAG_MODE = 3;
525 private static final int TOUCH_SHORTPRESS_START_MODE = 4;
526 private static final int TOUCH_SHORTPRESS_MODE = 5;
Grace Kloba04b28682009-09-14 14:38:37 -0700527 private static final int TOUCH_DOUBLE_TAP_MODE = 6;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 private static final int TOUCH_DONE_MODE = 7;
Cary Clark924af702010-06-04 16:37:43 -0400529 private static final int TOUCH_PINCH_DRAG = 8;
Patrick Scotta3ebcc92010-07-16 11:52:22 -0400530 private static final int TOUCH_DRAG_LAYER_MODE = 9;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531
532 // Whether to forward the touch events to WebCore
Huahui Wu5d4064c2011-01-21 16:10:23 -0800533 // Can only be set by WebKit via JNI.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 private boolean mForwardTouchEvents = false;
535
Grace Klobac2242f22010-03-05 14:00:26 -0800536 // Whether to prevent default during touch. The initial value depends on
537 // mForwardTouchEvents. If WebCore wants all the touch events, it says yes
538 // for touch down. Otherwise UI will wait for the answer of the first
539 // confirmed move before taking over the control.
540 private static final int PREVENT_DEFAULT_NO = 0;
541 private static final int PREVENT_DEFAULT_MAYBE_YES = 1;
542 private static final int PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN = 2;
543 private static final int PREVENT_DEFAULT_YES = 3;
544 private static final int PREVENT_DEFAULT_IGNORE = 4;
545 private int mPreventDefault = PREVENT_DEFAULT_IGNORE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546
Grace Klobac2242f22010-03-05 14:00:26 -0800547 // true when the touch movement exceeds the slop
548 private boolean mConfirmMove;
Grace Kloba5f68d6f2009-12-08 18:42:54 -0800549
Grace Klobac2242f22010-03-05 14:00:26 -0800550 // if true, touch events will be first processed by WebCore, if prevent
551 // default is not set, the UI will continue handle them.
552 private boolean mDeferTouchProcess;
553
554 // to avoid interfering with the current touch events, track them
555 // separately. Currently no snapping or fling in the deferred process mode
556 private int mDeferTouchMode = TOUCH_DONE_MODE;
557 private float mLastDeferTouchX;
558 private float mLastDeferTouchY;
Grace Kloba5f68d6f2009-12-08 18:42:54 -0800559
Leon Scroggins72543e12009-07-23 15:29:45 -0400560 // To keep track of whether the current drag was initiated by a WebTextView,
561 // so that we know not to hide the cursor
562 boolean mDragFromTextInput;
563
Cary Clarkd6982c92009-05-29 11:02:22 -0400564 // Whether or not to draw the cursor ring.
565 private boolean mDrawCursorRing = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566
Mike Reedd205d5b2009-05-27 11:02:29 -0400567 // true if onPause has been called (and not onResume)
568 private boolean mIsPaused;
569
Cary Clarkb8491342010-11-29 16:23:19 -0500570 private HitTestResult mInitialHitTestResult;
571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 /**
573 * Customizable constant
574 */
575 // pre-computed square of ViewConfiguration.getScaledTouchSlop()
576 private int mTouchSlopSquare;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700577 // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
578 private int mDoubleTapSlopSquare;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700579 // pre-computed density adjusted navigation slop
580 private int mNavSlop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 // This should be ViewConfiguration.getTapTimeout()
582 // But system time out is 100ms, which is too short for the browser.
583 // In the browser, if it switches out of tap too soon, jump tap won't work.
Ben Murdochadf096c2011-08-12 12:37:15 +0100584 // In addition, a double tap on a trackpad will always have a duration of
585 // 300ms, so this value must be at least that (otherwise we will timeout the
586 // first tap and convert it to a long press).
587 private static final int TAP_TIMEOUT = 300;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 // This should be ViewConfiguration.getLongPressTimeout()
589 // But system time out is 500ms, which is too short for the browser.
590 // With a short timeout, it's difficult to treat trigger a short press.
591 private static final int LONG_PRESS_TIMEOUT = 1000;
592 // needed to avoid flinging after a pause of no movement
593 private static final int MIN_FLING_TIME = 250;
Cary Clark25415e22009-10-12 13:41:28 -0400594 // draw unfiltered after drag is held without movement
595 private static final int MOTIONLESS_TIME = 100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 // The amount of content to overlap between two screens when going through
597 // pages with the space bar, in pixels.
598 private static final int PAGE_SCROLL_OVERLAP = 24;
599
600 /**
601 * These prevent calling requestLayout if either dimension is fixed. This
602 * depends on the layout parameters and the measure specs.
603 */
604 boolean mWidthCanMeasure;
605 boolean mHeightCanMeasure;
606
607 // Remember the last dimensions we sent to the native side so we can avoid
608 // sending the same dimensions more than once.
609 int mLastWidthSent;
610 int mLastHeightSent;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -0800611 // Since view height sent to webkit could be fixed to avoid relayout, this
612 // value records the last sent actual view height.
613 int mLastActualHeightSent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614
615 private int mContentWidth; // cache of value from WebViewCore
616 private int mContentHeight; // cache of value from WebViewCore
617
Cary Clarkd6982c92009-05-29 11:02:22 -0400618 // Need to have the separate control for horizontal and vertical scrollbar
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 // style than the View's single scrollbar style
620 private boolean mOverlayHorizontalScrollbar = true;
621 private boolean mOverlayVerticalScrollbar = false;
622
623 // our standard speed. this way small distances will be traversed in less
624 // time than large distances, but we cap the duration, so that very large
625 // distances won't take too long to get there.
626 private static final int STD_SPEED = 480; // pixels per second
627 // time for the longest scroll animation
628 private static final int MAX_DURATION = 750; // milliseconds
Leon Scroggins03c87bf2009-09-18 15:05:59 -0400629 private static final int SLIDE_TITLE_DURATION = 500; // milliseconds
Adam Powell637d3372010-08-25 14:37:03 -0700630
631 // Used by OverScrollGlow
632 OverScroller mScroller;
633
634 private boolean mInOverScrollMode = false;
635 private static Paint mOverScrollBackground;
636 private static Paint mOverScrollBorder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637
638 private boolean mWrapContent;
Cary Clark25415e22009-10-12 13:41:28 -0400639 private static final int MOTIONLESS_FALSE = 0;
640 private static final int MOTIONLESS_PENDING = 1;
641 private static final int MOTIONLESS_TRUE = 2;
Grace Kloba9b657802010-04-08 13:46:23 -0700642 private static final int MOTIONLESS_IGNORE = 3;
Cary Clark25415e22009-10-12 13:41:28 -0400643 private int mHeldMotionless;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644
Svetoslav Ganovda355512010-05-12 22:04:44 -0700645 // An instance for injecting accessibility in WebViews with disabled
646 // JavaScript or ones for which no accessibility script exists
647 private AccessibilityInjector mAccessibilityInjector;
648
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700649 // flag indicating if accessibility script is injected so we
650 // know to handle Shift and arrows natively first
651 private boolean mAccessibilityScriptInjected;
652
John Reck086a5142011-08-31 16:59:10 -0700653 static final boolean USE_JAVA_TEXT_SELECTION = true;
John Reckeffabe82011-10-27 09:09:36 -0700654 static final boolean DEBUG_TEXT_HANDLES = false;
John Reck086a5142011-08-31 16:59:10 -0700655 private Region mTextSelectionRegion = new Region();
656 private Paint mTextSelectionPaint;
657 private Drawable mSelectHandleLeft;
658 private Drawable mSelectHandleRight;
659
John Reck0966dd22011-09-18 11:03:00 -0700660 static final boolean USE_WEBKIT_RINGS = false;
Grace Kloba178db412010-05-18 22:22:23 -0700661 // the color used to highlight the touch rectangles
John Reck086a5142011-08-31 16:59:10 -0700662 private static final int HIGHLIGHT_COLOR = 0x6633b5e5;
Grace Kloba178db412010-05-18 22:22:23 -0700663 // the round corner for the highlight path
664 private static final float TOUCH_HIGHLIGHT_ARC = 5.0f;
665 // the region indicating where the user touched on the screen
666 private Region mTouchHighlightRegion = new Region();
667 // the paint for the touch highlight
668 private Paint mTouchHightlightPaint;
669 // debug only
670 private static final boolean DEBUG_TOUCH_HIGHLIGHT = true;
671 private static final int TOUCH_HIGHLIGHT_ELAPSE_TIME = 2000;
672 private Paint mTouchCrossHairColor;
673 private int mTouchHighlightX;
674 private int mTouchHighlightY;
John Reck335f4542011-08-25 18:25:09 -0700675 private long mTouchHighlightRequested;
Grace Kloba178db412010-05-18 22:22:23 -0700676
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -0800677 // Basically this proxy is used to tell the Video to update layer tree at
678 // SetBaseLayer time and to pause when WebView paused.
679 private HTML5VideoViewProxy mHTML5VideoViewProxy;
680
John Reck95b7d6f2011-06-03 15:23:43 -0700681 // If we are using a set picture, don't send view updates to webkit
682 private boolean mBlockWebkitViewMessages = false;
683
Derek Sollenberger1d335f32011-07-08 11:28:23 -0400684 // cached value used to determine if we need to switch drawing models
685 private boolean mHardwareAccelSkia = false;
686
Grace Klobac2242f22010-03-05 14:00:26 -0800687 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 * Private message ids
689 */
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400690 private static final int REMEMBER_PASSWORD = 1;
691 private static final int NEVER_REMEMBER_PASSWORD = 2;
692 private static final int SWITCH_TO_SHORTPRESS = 3;
693 private static final int SWITCH_TO_LONGPRESS = 4;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700694 private static final int RELEASE_SINGLE_TAP = 5;
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400695 private static final int REQUEST_FORM_DATA = 6;
Cary Clark25415e22009-10-12 13:41:28 -0400696 private static final int DRAG_HELD_MOTIONLESS = 8;
697 private static final int AWAKEN_SCROLL_BARS = 9;
Grace Klobac2242f22010-03-05 14:00:26 -0800698 private static final int PREVENT_DEFAULT_TIMEOUT = 10;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500699 private static final int SCROLL_SELECT_TEXT = 11;
700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701
Grace Klobac2242f22010-03-05 14:00:26 -0800702 private static final int FIRST_PRIVATE_MSG_ID = REMEMBER_PASSWORD;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500703 private static final int LAST_PRIVATE_MSG_ID = SCROLL_SELECT_TEXT;
Grace Klobac2242f22010-03-05 14:00:26 -0800704
705 /*
706 * Package message ids
707 */
Grace Klobac2242f22010-03-05 14:00:26 -0800708 static final int SCROLL_TO_MSG_ID = 101;
Grace Klobac2242f22010-03-05 14:00:26 -0800709 static final int NEW_PICTURE_MSG_ID = 105;
710 static final int UPDATE_TEXT_ENTRY_MSG_ID = 106;
711 static final int WEBCORE_INITIALIZED_MSG_ID = 107;
712 static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 108;
713 static final int UPDATE_ZOOM_RANGE = 109;
Leon Scroggins9ab32b62010-05-03 14:19:50 +0100714 static final int UNHANDLED_NAV_KEY = 110;
Grace Klobac2242f22010-03-05 14:00:26 -0800715 static final int CLEAR_TEXT_ENTRY = 111;
716 static final int UPDATE_TEXT_SELECTION_MSG_ID = 112;
717 static final int SHOW_RECT_MSG_ID = 113;
718 static final int LONG_PRESS_CENTER = 114;
719 static final int PREVENT_TOUCH_ID = 115;
720 static final int WEBCORE_NEED_TOUCH_EVENTS = 116;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 // obj=Rect in doc coordinates
Grace Klobac2242f22010-03-05 14:00:26 -0800722 static final int INVAL_RECT_MSG_ID = 117;
723 static final int REQUEST_KEYBOARD = 118;
724 static final int DO_MOTION_UP = 119;
725 static final int SHOW_FULLSCREEN = 120;
726 static final int HIDE_FULLSCREEN = 121;
727 static final int DOM_FOCUS_CHANGED = 122;
Grace Kloba8abd50b2010-07-08 15:02:14 -0700728 static final int REPLACE_BASE_CONTENT = 123;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -0400729 static final int FORM_DID_BLUR = 124;
Grace Klobac2242f22010-03-05 14:00:26 -0800730 static final int RETURN_LABEL = 125;
731 static final int FIND_AGAIN = 126;
Grace Klobae8300a12010-03-12 13:32:55 -0800732 static final int CENTER_FIT_RECT = 127;
Leon Scrogginsb4157792010-03-18 12:42:33 -0400733 static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128;
Grace Kloba50004bc2010-04-13 22:58:51 -0700734 static final int SET_SCROLLBAR_MODES = 129;
Svetoslav Ganovda355512010-05-12 22:04:44 -0700735 static final int SELECTION_STRING_CHANGED = 130;
Grace Kloba178db412010-05-18 22:22:23 -0700736 static final int SET_TOUCH_HIGHLIGHT_RECTS = 131;
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -0700737 static final int SAVE_WEBARCHIVE_FINISHED = 132;
Cary Clarkd6982c92009-05-29 11:02:22 -0400738
Ben Murdoch62275a42010-09-07 11:27:28 +0100739 static final int SET_AUTOFILLABLE = 133;
Ben Murdoch961d55f2010-12-02 13:58:24 +0000740 static final int AUTOFILL_COMPLETE = 134;
Ben Murdoch62275a42010-09-07 11:27:28 +0100741
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800742 static final int SELECT_AT = 135;
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -0500743 static final int SCREEN_ON = 136;
Nicolas Roard0e778a12011-03-11 14:29:05 -0800744 static final int ENTER_FULLSCREEN_VIDEO = 137;
John Reck0966dd22011-09-18 11:03:00 -0700745 static final int UPDATE_SELECTION = 138;
Mangesh Ghiware31f263d2011-11-21 16:54:20 -0800746 static final int UPDATE_ZOOM_DENSITY = 139;
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800747
Grace Klobac2242f22010-03-05 14:00:26 -0800748 private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
Grace Kloba178db412010-05-18 22:22:23 -0700749 private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
Grace Klobac2242f22010-03-05 14:00:26 -0800750
751 static final String[] HandlerPrivateDebugString = {
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400752 "REMEMBER_PASSWORD", // = 1;
753 "NEVER_REMEMBER_PASSWORD", // = 2;
754 "SWITCH_TO_SHORTPRESS", // = 3;
755 "SWITCH_TO_LONGPRESS", // = 4;
Grace Kloba8b97e4b2009-07-28 13:11:38 -0700756 "RELEASE_SINGLE_TAP", // = 5;
Leon Scrogginsd3465f62009-06-02 10:57:54 -0400757 "REQUEST_FORM_DATA", // = 6;
Grace Kloba96949ef2010-01-25 09:53:01 -0800758 "RESUME_WEBCORE_PRIORITY", // = 7;
Cary Clark25415e22009-10-12 13:41:28 -0400759 "DRAG_HELD_MOTIONLESS", // = 8;
760 "AWAKEN_SCROLL_BARS", // = 9;
Cary Clark6f5dfc62010-11-11 13:09:20 -0500761 "PREVENT_DEFAULT_TIMEOUT", // = 10;
762 "SCROLL_SELECT_TEXT" // = 11;
Grace Klobac2242f22010-03-05 14:00:26 -0800763 };
764
765 static final String[] HandlerPackageDebugString = {
766 "SCROLL_TO_MSG_ID", // = 101;
Patrick Scottfa8be1c2011-02-02 14:09:34 -0500767 "102", // = 102;
768 "103", // = 103;
769 "104", // = 104;
Grace Klobac2242f22010-03-05 14:00:26 -0800770 "NEW_PICTURE_MSG_ID", // = 105;
771 "UPDATE_TEXT_ENTRY_MSG_ID", // = 106;
772 "WEBCORE_INITIALIZED_MSG_ID", // = 107;
773 "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 108;
774 "UPDATE_ZOOM_RANGE", // = 109;
Leon Scroggins9ab32b62010-05-03 14:19:50 +0100775 "UNHANDLED_NAV_KEY", // = 110;
Grace Klobac2242f22010-03-05 14:00:26 -0800776 "CLEAR_TEXT_ENTRY", // = 111;
777 "UPDATE_TEXT_SELECTION_MSG_ID", // = 112;
778 "SHOW_RECT_MSG_ID", // = 113;
779 "LONG_PRESS_CENTER", // = 114;
780 "PREVENT_TOUCH_ID", // = 115;
781 "WEBCORE_NEED_TOUCH_EVENTS", // = 116;
782 "INVAL_RECT_MSG_ID", // = 117;
783 "REQUEST_KEYBOARD", // = 118;
784 "DO_MOTION_UP", // = 119;
785 "SHOW_FULLSCREEN", // = 120;
786 "HIDE_FULLSCREEN", // = 121;
787 "DOM_FOCUS_CHANGED", // = 122;
Grace Kloba8abd50b2010-07-08 15:02:14 -0700788 "REPLACE_BASE_CONTENT", // = 123;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -0400789 "FORM_DID_BLUR", // = 124;
Grace Klobac2242f22010-03-05 14:00:26 -0800790 "RETURN_LABEL", // = 125;
Grace Klobae8300a12010-03-12 13:32:55 -0800791 "FIND_AGAIN", // = 126;
Leon Scrogginsb4157792010-03-18 12:42:33 -0400792 "CENTER_FIT_RECT", // = 127;
Grace Kloba50004bc2010-04-13 22:58:51 -0700793 "REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128;
Grace Kloba178db412010-05-18 22:22:23 -0700794 "SET_SCROLLBAR_MODES", // = 129;
795 "SELECTION_STRING_CHANGED", // = 130;
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -0700796 "SET_TOUCH_HIGHLIGHT_RECTS", // = 131;
Ben Murdoch62275a42010-09-07 11:27:28 +0100797 "SAVE_WEBARCHIVE_FINISHED", // = 132;
Ben Murdoch961d55f2010-12-02 13:58:24 +0000798 "SET_AUTOFILLABLE", // = 133;
Svetoslav Ganov9504f572011-01-14 11:38:17 -0800799 "AUTOFILL_COMPLETE", // = 134;
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -0500800 "SELECT_AT", // = 135;
Nicolas Roard0e778a12011-03-11 14:29:05 -0800801 "SCREEN_ON", // = 136;
Mangesh Ghiware31f263d2011-11-21 16:54:20 -0800802 "ENTER_FULLSCREEN_VIDEO", // = 137;
803 "UPDATE_SELECTION", // = 138;
804 "UPDATE_ZOOM_DENSITY" // = 139;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 };
806
Grace Klobaa4fa1072009-11-09 12:01:50 -0800807 // If the site doesn't use the viewport meta tag to specify the viewport,
808 // use DEFAULT_VIEWPORT_WIDTH as the default viewport width
Shimeng (Simon) Wang14bcc0e2010-09-17 10:12:05 -0700809 static final int DEFAULT_VIEWPORT_WIDTH = 980;
Grace Klobaa4fa1072009-11-09 12:01:50 -0800810
811 // normally we try to fit the content to the minimum preferred width
812 // calculated by the Webkit. To avoid the bad behavior when some site's
813 // minimum preferred width keeps growing when changing the viewport width or
814 // the minimum preferred width is huge, an upper limit is needed.
815 static int sMaxViewportWidth = DEFAULT_VIEWPORT_WIDTH;
816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 // initial scale in percent. 0 means using default.
Grace Kloba16efce72009-11-10 15:49:03 -0800818 private int mInitialScaleInPercent = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819
Patrick Scottfa8be1c2011-02-02 14:09:34 -0500820 // Whether or not a scroll event should be sent to webkit. This is only set
821 // to false when restoring the scroll position.
822 private boolean mSendScrollEvent = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823
824 private int mSnapScrollMode = SNAP_NONE;
Cary Clarkac492e12009-10-14 14:53:37 -0400825 private static final int SNAP_NONE = 0;
826 private static final int SNAP_LOCK = 1; // not a separate state
827 private static final int SNAP_X = 2; // may be combined with SNAP_LOCK
828 private static final int SNAP_Y = 4; // may be combined with SNAP_LOCK
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 private boolean mSnapPositive;
Cary Clarkd6982c92009-05-29 11:02:22 -0400830
Cary Clark2ec30692010-02-23 10:50:38 -0500831 // keep these in sync with their counterparts in WebView.cpp
832 private static final int DRAW_EXTRAS_NONE = 0;
833 private static final int DRAW_EXTRAS_FIND = 1;
834 private static final int DRAW_EXTRAS_SELECTION = 2;
835 private static final int DRAW_EXTRAS_CURSOR_RING = 3;
836
Grace Kloba50004bc2010-04-13 22:58:51 -0700837 // keep this in sync with WebCore:ScrollbarMode in WebKit
838 private static final int SCROLLBAR_AUTO = 0;
839 private static final int SCROLLBAR_ALWAYSOFF = 1;
840 // as we auto fade scrollbar, this is ignored.
841 private static final int SCROLLBAR_ALWAYSON = 2;
842 private int mHorizontalScrollBarMode = SCROLLBAR_AUTO;
843 private int mVerticalScrollBarMode = SCROLLBAR_AUTO;
844
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700845 // constants for determining script injection strategy
846 private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1;
847 private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0;
848 private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1;
849
Svetoslav Ganovda355512010-05-12 22:04:44 -0700850 // the alias via which accessibility JavaScript interface is exposed
851 private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
852
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -0800853 // Template for JavaScript that injects a screen-reader.
854 private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
Svetoslav Ganovda355512010-05-12 22:04:44 -0700855 "javascript:(function() {" +
856 " var chooser = document.createElement('script');" +
857 " chooser.type = 'text/javascript';" +
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -0800858 " chooser.src = '%1s';" +
Svetoslav Ganovda355512010-05-12 22:04:44 -0700859 " document.getElementsByTagName('head')[0].appendChild(chooser);" +
860 " })();";
861
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700862 // Regular expression that matches the "axs" URL parameter.
863 // The value of 0 means the accessibility script is opted out
864 // The value of 1 means the accessibility script is already injected
865 private static final String PATTERN_MATCH_AXS_URL_PARAMETER = "(\\?axs=(0|1))|(&axs=(0|1))";
866
Svetoslav Ganov4acac232011-02-02 15:22:24 -0800867 // TextToSpeech instance exposed to JavaScript to the injected screenreader.
868 private TextToSpeech mTextToSpeech;
869
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -0700870 // variable to cache the above pattern in case accessibility is enabled.
871 private Pattern mMatchAxsUrlParameterPattern;
872
Adam Powell637d3372010-08-25 14:37:03 -0700873 /**
874 * Max distance to overscroll by in pixels.
875 * This how far content can be pulled beyond its normal bounds by the user.
876 */
877 private int mOverscrollDistance;
878
879 /**
880 * Max distance to overfling by in pixels.
881 * This is how far flinged content can move beyond the end of its normal bounds.
882 */
883 private int mOverflingDistance;
884
885 private OverScrollGlow mOverScrollGlow;
886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 // Used to match key downs and key ups
Leon Scroggins115626a2011-02-17 12:00:48 -0500888 private Vector<Integer> mKeysPressed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889
890 /* package */ static boolean mLogEvent = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891
892 // for event log
893 private long mLastTouchUpTime = 0;
894
Ben Murdochdb8d19c2010-10-29 11:44:17 +0100895 private WebViewCore.AutoFillData mAutoFillData;
Ben Murdoch62275a42010-09-07 11:27:28 +0100896
Kristian Monsencbb59db2011-05-09 16:04:34 +0100897 private static boolean sNotificationsEnabled = true;
898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 /**
900 * URI scheme for telephone number
901 */
902 public static final String SCHEME_TEL = "tel:";
903 /**
904 * URI scheme for email address
905 */
906 public static final String SCHEME_MAILTO = "mailto:";
907 /**
908 * URI scheme for map address
909 */
910 public static final String SCHEME_GEO = "geo:0,0?q=";
Cary Clarkd6982c92009-05-29 11:02:22 -0400911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 private int mBackgroundColor = Color.WHITE;
913
Cary Clark6f5dfc62010-11-11 13:09:20 -0500914 private static final long SELECT_SCROLL_INTERVAL = 1000 / 60; // 60 / second
915 private int mAutoScrollX = 0;
916 private int mAutoScrollY = 0;
Cary Clarkb9aaa772011-01-07 16:14:54 -0500917 private int mMinAutoScrollX = 0;
918 private int mMaxAutoScrollX = 0;
919 private int mMinAutoScrollY = 0;
920 private int mMaxAutoScrollY = 0;
921 private Rect mScrollingLayerBounds = new Rect();
Cary Clark6f5dfc62010-11-11 13:09:20 -0500922 private boolean mSentAutoScrollMessage = false;
923
Nicolas Roard2bc0b012011-11-16 19:26:25 -0800924 // Temporary hack to work around the context removal upon memory pressure
925 private static boolean mIncrementEGLContextHack = false;
926
Adam Powell4fb35d42011-03-03 17:54:55 -0800927 // used for serializing asynchronously handled touch events.
928 private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
929
Adam Powelle00e8a782011-09-11 17:48:42 -0700930 // Used to track whether picture updating was paused due to a window focus change.
931 private boolean mPictureUpdatePausedForFocusChange = false;
932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 // Used to notify listeners of a new picture.
934 private PictureListener mPictureListener;
935 /**
936 * Interface to listen for new pictures as they change.
Kristian Monsenfc771652011-05-10 16:44:05 +0100937 * @deprecated This interface is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 */
Kristian Monsenfc771652011-05-10 16:44:05 +0100939 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 public interface PictureListener {
941 /**
942 * Notify the listener that the picture has changed.
943 * @param view The WebView that owns the picture.
944 * @param picture The new picture.
Kristian Monsen4aad1022011-11-17 13:28:02 +0000945 * @deprecated Due to internal changes, the picture does not include
946 * composited layers such as fixed position elements or scrollable divs.
947 * While the PictureListener API can still be used to detect changes in
948 * the WebView content, you are advised against its usage until a replacement
949 * is provided in a future Android release
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 */
Kristian Monsenfc771652011-05-10 16:44:05 +0100951 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 public void onNewPicture(WebView view, Picture picture);
953 }
954
Leon Scroggins3246c222009-05-26 09:51:23 -0400955 // FIXME: Want to make this public, but need to change the API file.
956 public /*static*/ class HitTestResult {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 /**
958 * Default HitTestResult, where the target is unknown
959 */
960 public static final int UNKNOWN_TYPE = 0;
961 /**
Steve Block1854ddb2011-04-19 12:18:19 +0100962 * @deprecated This type is no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 */
Steve Block1854ddb2011-04-19 12:18:19 +0100964 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 public static final int ANCHOR_TYPE = 1;
966 /**
967 * HitTestResult for hitting a phone number
968 */
969 public static final int PHONE_TYPE = 2;
970 /**
971 * HitTestResult for hitting a map address
972 */
973 public static final int GEO_TYPE = 3;
974 /**
975 * HitTestResult for hitting an email address
976 */
977 public static final int EMAIL_TYPE = 4;
978 /**
979 * HitTestResult for hitting an HTML::img tag
980 */
981 public static final int IMAGE_TYPE = 5;
982 /**
Steve Block1854ddb2011-04-19 12:18:19 +0100983 * @deprecated This type is no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 */
Steve Block1854ddb2011-04-19 12:18:19 +0100985 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 public static final int IMAGE_ANCHOR_TYPE = 6;
987 /**
988 * HitTestResult for hitting a HTML::a tag with src=http
989 */
990 public static final int SRC_ANCHOR_TYPE = 7;
991 /**
992 * HitTestResult for hitting a HTML::a tag with src=http + HTML::img
993 */
994 public static final int SRC_IMAGE_ANCHOR_TYPE = 8;
995 /**
996 * HitTestResult for hitting an edit text area
997 */
998 public static final int EDIT_TEXT_TYPE = 9;
999
1000 private int mType;
1001 private String mExtra;
1002
1003 HitTestResult() {
1004 mType = UNKNOWN_TYPE;
1005 }
1006
1007 private void setType(int type) {
1008 mType = type;
1009 }
1010
1011 private void setExtra(String extra) {
1012 mExtra = extra;
1013 }
1014
Jonathan Dixone230e542011-12-21 10:57:00 +00001015 /**
1016 * Gets the type of the hit test result.
1017 * @return See the XXX_TYPE constants defined in this class.
1018 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 public int getType() {
1020 return mType;
1021 }
1022
Jonathan Dixone230e542011-12-21 10:57:00 +00001023 /**
1024 * Gets additional type-dependant information about the result, see
1025 * {@link WebView#getHitTestResult()} for details.
1026 * @return may either be null or contain extra information about this result.
1027 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 public String getExtra() {
1029 return mExtra;
1030 }
1031 }
1032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 /**
1034 * Construct a new WebView with a Context object.
1035 * @param context A Context object used to access application assets.
1036 */
1037 public WebView(Context context) {
1038 this(context, null);
1039 }
1040
1041 /**
1042 * Construct a new WebView with layout parameters.
1043 * @param context A Context object used to access application assets.
1044 * @param attrs An AttributeSet passed to our parent.
1045 */
1046 public WebView(Context context, AttributeSet attrs) {
1047 this(context, attrs, com.android.internal.R.attr.webViewStyle);
1048 }
1049
1050 /**
1051 * Construct a new WebView with layout parameters and a default style.
1052 * @param context A Context object used to access application assets.
1053 * @param attrs An AttributeSet passed to our parent.
1054 * @param defStyle The default style resource ID.
1055 */
1056 public WebView(Context context, AttributeSet attrs, int defStyle) {
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07001057 this(context, attrs, defStyle, false);
1058 }
1059
1060 /**
1061 * Construct a new WebView with layout parameters and a default style.
1062 * @param context A Context object used to access application assets.
1063 * @param attrs An AttributeSet passed to our parent.
1064 * @param defStyle The default style resource ID.
Jonathan Dixone230e542011-12-21 10:57:00 +00001065 * @param privateBrowsing If true the web view will be initialized in private mode.
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07001066 */
1067 public WebView(Context context, AttributeSet attrs, int defStyle,
1068 boolean privateBrowsing) {
1069 this(context, attrs, defStyle, null, privateBrowsing);
Andrei Popescu4950b2b2009-09-03 13:56:07 +01001070 }
1071
1072 /**
1073 * Construct a new WebView with layout parameters, a default style and a set
1074 * of custom Javscript interfaces to be added to the WebView at initialization
Romain Guy01d0fbf2009-12-01 14:52:19 -08001075 * time. This guarantees that these interfaces will be available when the JS
Andrei Popescu4950b2b2009-09-03 13:56:07 +01001076 * context is initialized.
1077 * @param context A Context object used to access application assets.
1078 * @param attrs An AttributeSet passed to our parent.
1079 * @param defStyle The default style resource ID.
Steve Block81f19ff2010-11-01 13:23:24 +00001080 * @param javaScriptInterfaces is a Map of interface names, as keys, and
Andrei Popescu4950b2b2009-09-03 13:56:07 +01001081 * object implementing those interfaces, as values.
Jonathan Dixone230e542011-12-21 10:57:00 +00001082 * @param privateBrowsing If true the web view will be initialized in private mode.
Jonathan Dixon02630bf2011-12-21 18:47:52 +00001083 * @hide This is an implementation detail.
Andrei Popescu4950b2b2009-09-03 13:56:07 +01001084 */
1085 protected WebView(Context context, AttributeSet attrs, int defStyle,
Steve Block81f19ff2010-11-01 13:23:24 +00001086 Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 super(context, attrs, defStyle);
Steve Block51b08912011-04-27 15:04:48 +01001088 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089
Kristian Monsen87af7312011-09-09 02:12:51 +01001090 if (context == null) {
1091 throw new IllegalArgumentException("Invalid context argument");
1092 }
1093
Kristian Monsend89a30a2010-11-16 18:11:59 +00001094 // Used by the chrome stack to find application paths
1095 JniUtil.setContext(context);
1096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 mCallbackProxy = new CallbackProxy(context, this);
Grace Kloba9a67c822009-12-20 11:33:58 -08001098 mViewManager = new ViewManager(this);
Ben Murdochd2e91d12011-02-25 17:11:02 +00001099 L10nUtils.setApplicationContext(context.getApplicationContext());
Steve Block81f19ff2010-11-01 13:23:24 +00001100 mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 mDatabase = WebViewDatabase.getInstance(context);
Adam Powell637d3372010-08-25 14:37:03 -07001102 mScroller = new OverScroller(context, null, 0, 0, false); //TODO Use OverScroller's flywheel
Derek Sollenberger03e48912010-05-18 17:03:42 -04001103 mZoomManager = new ZoomManager(this, mCallbackProxy);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001104
Derek Sollenberger90b6e482010-05-10 12:38:54 -04001105 /* The init method must follow the creation of certain member variables,
1106 * such as the mZoomManager.
1107 */
1108 init();
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001109 setupPackageListener(context);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001110 setupProxyListener(context);
Grace Kloba3a0def22010-01-23 21:11:54 -08001111 updateMultiTouchSupport(context);
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07001112
1113 if (privateBrowsing) {
1114 startPrivateBrowsing();
1115 }
Ben Murdochffcc49e2010-10-28 18:24:57 +01001116
Ben Murdoch01b04e12010-11-08 10:49:16 +00001117 mAutoFillData = new WebViewCore.AutoFillData();
Grace Kloba3a0def22010-01-23 21:11:54 -08001118 }
1119
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001120 private static class ProxyReceiver extends BroadcastReceiver {
1121 @Override
1122 public void onReceive(Context context, Intent intent) {
1123 if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) {
1124 handleProxyBroadcast(intent);
1125 }
1126 }
1127 }
1128
Kristian Monsen9437d912010-12-23 15:39:31 +00001129 /*
Kristian Monsencbb59db2011-05-09 16:04:34 +01001130 * Receiver for PROXY_CHANGE_ACTION, will be null when it is not added handling broadcasts.
Kristian Monsen9437d912010-12-23 15:39:31 +00001131 */
Kristian Monsencbb59db2011-05-09 16:04:34 +01001132 private static ProxyReceiver sProxyReceiver;
Kristian Monsen9437d912010-12-23 15:39:31 +00001133
Kristian Monsencbb59db2011-05-09 16:04:34 +01001134 /*
1135 * @param context This method expects this to be a valid context
1136 */
Kristian Monsen9437d912010-12-23 15:39:31 +00001137 private static synchronized void setupProxyListener(Context context) {
Kristian Monsencbb59db2011-05-09 16:04:34 +01001138 if (sProxyReceiver != null || sNotificationsEnabled == false) {
Kristian Monsen9437d912010-12-23 15:39:31 +00001139 return;
1140 }
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001141 IntentFilter filter = new IntentFilter();
1142 filter.addAction(Proxy.PROXY_CHANGE_ACTION);
Kristian Monsencbb59db2011-05-09 16:04:34 +01001143 sProxyReceiver = new ProxyReceiver();
Kristian Monsen9437d912010-12-23 15:39:31 +00001144 Intent currentProxy = context.getApplicationContext().registerReceiver(
Kristian Monsencbb59db2011-05-09 16:04:34 +01001145 sProxyReceiver, filter);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001146 if (currentProxy != null) {
1147 handleProxyBroadcast(currentProxy);
1148 }
1149 }
1150
Kristian Monsencbb59db2011-05-09 16:04:34 +01001151 /*
1152 * @param context This method expects this to be a valid context
1153 */
1154 private static synchronized void disableProxyListener(Context context) {
1155 if (sProxyReceiver == null)
1156 return;
1157
1158 context.getApplicationContext().unregisterReceiver(sProxyReceiver);
1159 sProxyReceiver = null;
1160 }
1161
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001162 private static void handleProxyBroadcast(Intent intent) {
1163 ProxyProperties proxyProperties = (ProxyProperties)intent.getExtra(Proxy.EXTRA_PROXY_INFO);
1164 if (proxyProperties == null || proxyProperties.getHost() == null) {
Kristian Monsen2032eee2011-05-23 14:25:27 +01001165 WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, null);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001166 return;
1167 }
Kristian Monsen2032eee2011-05-23 14:25:27 +01001168 WebViewCore.sendStaticMessage(EventHub.PROXY_CHANGED, proxyProperties);
Kristian Monsen41e7e6f2010-12-21 12:51:11 +00001169 }
1170
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001171 /*
Kristian Monsen4190aab2010-12-16 18:39:21 +00001172 * A variable to track if there is a receiver added for ACTION_PACKAGE_ADDED
1173 * or ACTION_PACKAGE_REMOVED.
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001174 */
Kristian Monsen4190aab2010-12-16 18:39:21 +00001175 private static boolean sPackageInstallationReceiverAdded = false;
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001176
1177 /*
1178 * A set of Google packages we monitor for the
1179 * navigator.isApplicationInstalled() API. Add additional packages as
1180 * needed.
1181 */
1182 private static Set<String> sGoogleApps;
1183 static {
1184 sGoogleApps = new HashSet<String>();
1185 sGoogleApps.add("com.google.android.youtube");
1186 }
1187
Kristian Monsen4190aab2010-12-16 18:39:21 +00001188 private static class PackageListener extends BroadcastReceiver {
1189 @Override
1190 public void onReceive(Context context, Intent intent) {
1191 final String action = intent.getAction();
1192 final String packageName = intent.getData().getSchemeSpecificPart();
1193 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1194 if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) {
1195 // if it is replacing, refreshPlugins() when adding
1196 return;
1197 }
1198
1199 if (sGoogleApps.contains(packageName)) {
1200 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
1201 WebViewCore.sendStaticMessage(EventHub.ADD_PACKAGE_NAME, packageName);
1202 } else {
1203 WebViewCore.sendStaticMessage(EventHub.REMOVE_PACKAGE_NAME, packageName);
1204 }
1205 }
1206
1207 PluginManager pm = PluginManager.getInstance(context);
1208 if (pm.containsPluginPermissionAndSignatures(packageName)) {
1209 pm.refreshPlugins(Intent.ACTION_PACKAGE_ADDED.equals(action));
1210 }
1211 }
1212 }
1213
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001214 private void setupPackageListener(Context context) {
1215
1216 /*
1217 * we must synchronize the instance check and the creation of the
1218 * receiver to ensure that only ONE receiver exists for all WebView
1219 * instances.
1220 */
1221 synchronized (WebView.class) {
1222
1223 // if the receiver already exists then we do not need to register it
1224 // again
Kristian Monsen4190aab2010-12-16 18:39:21 +00001225 if (sPackageInstallationReceiverAdded) {
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001226 return;
1227 }
1228
1229 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
1230 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1231 filter.addDataScheme("package");
Kristian Monsen4190aab2010-12-16 18:39:21 +00001232 BroadcastReceiver packageListener = new PackageListener();
1233 context.getApplicationContext().registerReceiver(packageListener, filter);
1234 sPackageInstallationReceiverAdded = true;
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001235 }
1236
1237 // check if any of the monitored apps are already installed
1238 AsyncTask<Void, Void, Set<String>> task = new AsyncTask<Void, Void, Set<String>>() {
1239
1240 @Override
1241 protected Set<String> doInBackground(Void... unused) {
1242 Set<String> installedPackages = new HashSet<String>();
1243 PackageManager pm = mContext.getPackageManager();
Kristian Monsen63a1b0c2011-03-09 13:54:54 +00001244 for (String name : sGoogleApps) {
1245 try {
1246 PackageInfo pInfo = pm.getPackageInfo(name,
1247 PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
1248 installedPackages.add(name);
Steve Block51b08912011-04-27 15:04:48 +01001249 } catch (PackageManager.NameNotFoundException e) {
Kristian Monsen63a1b0c2011-03-09 13:54:54 +00001250 // package not found
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001251 }
1252 }
1253 return installedPackages;
1254 }
1255
1256 // Executes on the UI thread
1257 @Override
1258 protected void onPostExecute(Set<String> installedPackages) {
Derek Sollenbergerc92de672010-09-01 08:55:22 -04001259 if (mWebViewCore != null) {
1260 mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, installedPackages);
1261 }
Derek Sollenberger41d5e932010-08-23 14:51:41 -04001262 }
1263 };
1264 task.execute();
1265 }
1266
Grace Kloba3a0def22010-01-23 21:11:54 -08001267 void updateMultiTouchSupport(Context context) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04001268 mZoomManager.updateMultiTouchSupport(context);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001269 }
1270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 private void init() {
John Reck34a676b2011-09-07 13:41:17 -07001272 OnTrimMemoryListener.init(getContext());
1273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 setWillNotDraw(false);
1275 setFocusable(true);
1276 setFocusableInTouchMode(true);
1277 setClickable(true);
1278 setLongClickable(true);
1279
Romain Guy4296fc42009-07-06 11:48:52 -07001280 final ViewConfiguration configuration = ViewConfiguration.get(getContext());
Grace Kloba8b97e4b2009-07-28 13:11:38 -07001281 int slop = configuration.getScaledTouchSlop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 mTouchSlopSquare = slop * slop;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07001283 slop = configuration.getScaledDoubleTapSlop();
1284 mDoubleTapSlopSquare = slop * slop;
Grace Kloba25737912009-06-19 12:42:47 -07001285 final float density = getContext().getResources().getDisplayMetrics().density;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001286 // use one line height, 16 based on our current default font, for how
1287 // far we allow a touch be away from the edge of a link
Grace Kloba25737912009-06-19 12:42:47 -07001288 mNavSlop = (int) (16 * density);
Derek Sollenberger90b6e482010-05-10 12:38:54 -04001289 mZoomManager.init(density);
Romain Guy4296fc42009-07-06 11:48:52 -07001290 mMaximumFling = configuration.getScaledMaximumFlingVelocity();
Patrick Scotta3ebcc92010-07-16 11:52:22 -04001291
1292 // Compute the inverse of the density squared.
1293 DRAG_LAYER_INVERSE_DENSITY_SQUARED = 1 / (density * density);
Adam Powell637d3372010-08-25 14:37:03 -07001294
1295 mOverscrollDistance = configuration.getScaledOverscrollDistance();
1296 mOverflingDistance = configuration.getScaledOverflingDistance();
Teng-Hui Zhu15bfa532011-02-14 17:01:16 -08001297
1298 setScrollBarStyle(super.getScrollBarStyle());
Leon Scroggins115626a2011-02-17 12:00:48 -05001299 // Initially use a size of two, since the user is likely to only hold
1300 // down two keys at a time (shift + another key)
1301 mKeysPressed = new Vector<Integer>(2);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08001302 mHTML5VideoViewProxy = null ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 }
1304
Patrick Dubroye0a799a2011-05-04 16:19:22 -07001305 @Override
1306 public boolean shouldDelayChildPressedState() {
1307 return true;
1308 }
1309
Svetoslav Ganovda355512010-05-12 22:04:44 -07001310 /**
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001311 * Adds accessibility APIs to JavaScript.
Svetoslav Ganovda355512010-05-12 22:04:44 -07001312 *
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001313 * Note: This method is responsible to performing the necessary
1314 * check if the accessibility APIs should be exposed.
Svetoslav Ganovda355512010-05-12 22:04:44 -07001315 */
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001316 private void addAccessibilityApisToJavaScript() {
1317 if (AccessibilityManager.getInstance(mContext).isEnabled()
1318 && getSettings().getJavaScriptEnabled()) {
1319 // exposing the TTS for now ...
Narayan Kamath68e2af52011-11-28 17:10:04 +00001320 final Context ctx = getContext();
1321 if (ctx != null) {
1322 final String packageName = ctx.getPackageName();
1323 if (packageName != null) {
1324 mTextToSpeech = new TextToSpeech(getContext(), null, null,
1325 packageName + ".**webview**");
1326 addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
1327 }
1328 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001329 }
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001330 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001331
Svetoslav Ganov4acac232011-02-02 15:22:24 -08001332 /**
1333 * Removes accessibility APIs from JavaScript.
1334 */
1335 private void removeAccessibilityApisFromJavaScript() {
1336 // exposing the TTS for now ...
1337 if (mTextToSpeech != null) {
1338 removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE);
1339 mTextToSpeech.shutdown();
1340 mTextToSpeech = null;
1341 }
Svetoslav Ganovda355512010-05-12 22:04:44 -07001342 }
1343
Adam Powell637d3372010-08-25 14:37:03 -07001344 @Override
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -07001345 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1346 super.onInitializeAccessibilityNodeInfo(info);
1347 info.setScrollable(isScrollableForAccessibility());
1348 }
1349
1350 @Override
1351 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1352 super.onInitializeAccessibilityEvent(event);
1353 event.setScrollable(isScrollableForAccessibility());
1354 event.setScrollX(mScrollX);
1355 event.setScrollY(mScrollY);
1356 final int convertedContentWidth = contentToViewX(getContentWidth());
1357 final int adjustedViewWidth = getWidth() - mPaddingLeft - mPaddingRight;
1358 event.setMaxScrollX(Math.max(convertedContentWidth - adjustedViewWidth, 0));
1359 final int convertedContentHeight = contentToViewY(getContentHeight());
1360 final int adjustedViewHeight = getHeight() - mPaddingTop - mPaddingBottom;
1361 event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
1362 }
1363
1364 private boolean isScrollableForAccessibility() {
1365 return (contentToViewX(getContentWidth()) > getWidth() - mPaddingLeft - mPaddingRight
1366 || contentToViewY(getContentHeight()) > getHeight() - mPaddingTop - mPaddingBottom);
1367 }
1368
1369 @Override
Adam Powell637d3372010-08-25 14:37:03 -07001370 public void setOverScrollMode(int mode) {
1371 super.setOverScrollMode(mode);
1372 if (mode != OVER_SCROLL_NEVER) {
1373 if (mOverScrollGlow == null) {
1374 mOverScrollGlow = new OverScrollGlow(this);
1375 }
1376 } else {
1377 mOverScrollGlow = null;
1378 }
1379 }
1380
Mangesh Ghiwaree832b632011-11-16 11:46:39 -08001381 /* package */ void adjustDefaultZoomDensity(int zoomDensity) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04001382 final float density = mContext.getResources().getDisplayMetrics().density
Grace Kloba0d8b77c2009-06-25 11:20:51 -07001383 * 100 / zoomDensity;
Mangesh Ghiwaree832b632011-11-16 11:46:39 -08001384 updateDefaultZoomDensity(density);
1385 }
1386
1387 /* package */ void updateDefaultZoomDensity(float density) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04001388 mNavSlop = (int) (16 * density);
1389 mZoomManager.updateDefaultZoomDensity(density);
Grace Kloba0d8b77c2009-06-25 11:20:51 -07001390 }
1391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 /* package */ boolean onSavePassword(String schemePlusHost, String username,
1393 String password, final Message resumeMsg) {
1394 boolean rVal = false;
1395 if (resumeMsg == null) {
1396 // null resumeMsg implies saving password silently
1397 mDatabase.setUsernamePassword(schemePlusHost, username, password);
1398 } else {
1399 final Message remember = mPrivateHandler.obtainMessage(
1400 REMEMBER_PASSWORD);
1401 remember.getData().putString("host", schemePlusHost);
1402 remember.getData().putString("username", username);
1403 remember.getData().putString("password", password);
1404 remember.obj = resumeMsg;
1405
1406 final Message neverRemember = mPrivateHandler.obtainMessage(
1407 NEVER_REMEMBER_PASSWORD);
1408 neverRemember.getData().putString("host", schemePlusHost);
1409 neverRemember.getData().putString("username", username);
1410 neverRemember.getData().putString("password", password);
1411 neverRemember.obj = resumeMsg;
1412
1413 new AlertDialog.Builder(getContext())
1414 .setTitle(com.android.internal.R.string.save_password_label)
1415 .setMessage(com.android.internal.R.string.save_password_message)
1416 .setPositiveButton(com.android.internal.R.string.save_password_notnow,
1417 new DialogInterface.OnClickListener() {
1418 public void onClick(DialogInterface dialog, int which) {
1419 resumeMsg.sendToTarget();
1420 }
1421 })
1422 .setNeutralButton(com.android.internal.R.string.save_password_remember,
1423 new DialogInterface.OnClickListener() {
1424 public void onClick(DialogInterface dialog, int which) {
1425 remember.sendToTarget();
1426 }
1427 })
1428 .setNegativeButton(com.android.internal.R.string.save_password_never,
1429 new DialogInterface.OnClickListener() {
1430 public void onClick(DialogInterface dialog, int which) {
1431 neverRemember.sendToTarget();
1432 }
1433 })
1434 .setOnCancelListener(new OnCancelListener() {
1435 public void onCancel(DialogInterface dialog) {
1436 resumeMsg.sendToTarget();
1437 }
1438 }).show();
1439 // Return true so that WebViewCore will pause while the dialog is
1440 // up.
1441 rVal = true;
1442 }
1443 return rVal;
1444 }
1445
1446 @Override
1447 public void setScrollBarStyle(int style) {
1448 if (style == View.SCROLLBARS_INSIDE_INSET
1449 || style == View.SCROLLBARS_OUTSIDE_INSET) {
1450 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
1451 } else {
1452 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
1453 }
1454 super.setScrollBarStyle(style);
1455 }
1456
1457 /**
1458 * Specify whether the horizontal scrollbar has overlay style.
1459 * @param overlay TRUE if horizontal scrollbar should have overlay style.
1460 */
1461 public void setHorizontalScrollbarOverlay(boolean overlay) {
Steve Block51b08912011-04-27 15:04:48 +01001462 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 mOverlayHorizontalScrollbar = overlay;
1464 }
1465
1466 /**
1467 * Specify whether the vertical scrollbar has overlay style.
1468 * @param overlay TRUE if vertical scrollbar should have overlay style.
1469 */
1470 public void setVerticalScrollbarOverlay(boolean overlay) {
Steve Block51b08912011-04-27 15:04:48 +01001471 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 mOverlayVerticalScrollbar = overlay;
1473 }
1474
1475 /**
1476 * Return whether horizontal scrollbar has overlay style
1477 * @return TRUE if horizontal scrollbar has overlay style.
1478 */
1479 public boolean overlayHorizontalScrollbar() {
Steve Block51b08912011-04-27 15:04:48 +01001480 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 return mOverlayHorizontalScrollbar;
1482 }
1483
1484 /**
1485 * Return whether vertical scrollbar has overlay style
1486 * @return TRUE if vertical scrollbar has overlay style.
1487 */
1488 public boolean overlayVerticalScrollbar() {
Steve Block51b08912011-04-27 15:04:48 +01001489 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 return mOverlayVerticalScrollbar;
1491 }
1492
1493 /*
1494 * Return the width of the view where the content of WebView should render
1495 * to.
Grace Kloba6ed525e2009-09-17 15:31:12 -07001496 * Note: this can be called from WebCoreThread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 */
Grace Kloba6ed525e2009-09-17 15:31:12 -07001498 /* package */ int getViewWidth() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) {
1500 return getWidth();
1501 } else {
Shimeng (Simon) Wang37127542010-12-03 16:34:00 -08001502 return Math.max(0, getWidth() - getVerticalScrollbarWidth());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 }
1504 }
1505
Michael Kolb601e7792011-02-23 17:43:16 -08001506 /**
Mike Reede8853fc2009-09-04 14:01:48 -04001507 * returns the height of the titlebarview (if any). Does not care about
1508 * scrolling
Michael Kolb75a03f92011-02-23 16:12:13 -08001509 * @hide
Mike Reede8853fc2009-09-04 14:01:48 -04001510 */
Michael Kolb75a03f92011-02-23 16:12:13 -08001511 protected int getTitleHeight() {
Mike Reede8853fc2009-09-04 14:01:48 -04001512 return mTitleBar != null ? mTitleBar.getHeight() : 0;
1513 }
1514
Michael Kolbe54f6652011-03-16 09:11:51 -07001515 /**
Mike Reede8853fc2009-09-04 14:01:48 -04001516 * Return the amount of the titlebarview (if any) that is visible
Michael Kolb73980a92010-08-05 16:32:51 -07001517 *
Michael Kolb24e53b02011-03-16 12:52:04 -07001518 * @deprecated This method is now obsolete.
Mike Reede8853fc2009-09-04 14:01:48 -04001519 */
Michael Kolb73980a92010-08-05 16:32:51 -07001520 public int getVisibleTitleHeight() {
Steve Block51b08912011-04-27 15:04:48 +01001521 checkThread();
Steve Block92c99162011-05-23 17:36:01 +01001522 return getVisibleTitleHeightImpl();
1523 }
1524
1525 private int getVisibleTitleHeightImpl() {
Adam Powell637d3372010-08-25 14:37:03 -07001526 // need to restrict mScrollY due to over scroll
John Reckfffce6f2011-10-06 20:37:01 -07001527 return Math.max(getTitleHeight() - Math.max(0, mScrollY),
John Reckd6ac7272011-11-08 15:00:17 -08001528 getOverlappingActionModeHeight());
1529 }
1530
1531 private int mCachedOverlappingActionModeHeight = -1;
1532
1533 private int getOverlappingActionModeHeight() {
1534 if (mFindCallback == null) {
1535 return 0;
1536 }
1537 if (mCachedOverlappingActionModeHeight < 0) {
1538 getGlobalVisibleRect(mGlobalVisibleRect, mGlobalVisibleOffset);
1539 mCachedOverlappingActionModeHeight = Math.max(0,
1540 mFindCallback.getActionModeGlobalBottom() - mGlobalVisibleRect.top);
1541 }
1542 return mCachedOverlappingActionModeHeight;
Mike Reede8853fc2009-09-04 14:01:48 -04001543 }
1544
1545 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 * Return the height of the view where the content of WebView should render
Leon Scroggins0236e672009-09-02 21:12:08 -04001547 * to. Note that this excludes mTitleBar, if there is one.
Grace Kloba6ed525e2009-09-17 15:31:12 -07001548 * Note: this can be called from WebCoreThread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 */
Grace Kloba6ed525e2009-09-17 15:31:12 -07001550 /* package */ int getViewHeight() {
Steve Block92c99162011-05-23 17:36:01 +01001551 return getViewHeightWithTitle() - getVisibleTitleHeightImpl();
Grace Kloba8eff73f2009-09-24 09:34:32 -07001552 }
1553
John Reck816c0de2011-06-02 16:04:53 -07001554 int getViewHeightWithTitle() {
Leon Scroggins0236e672009-09-02 21:12:08 -04001555 int height = getHeight();
Mike Reede8853fc2009-09-04 14:01:48 -04001556 if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) {
Leon Scroggins0236e672009-09-02 21:12:08 -04001557 height -= getHorizontalScrollbarHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 }
Grace Kloba8eff73f2009-09-24 09:34:32 -07001559 return height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 }
1561
1562 /**
1563 * @return The SSL certificate for the main top-level page or null if
1564 * there is no certificate (the site is not secure).
1565 */
1566 public SslCertificate getCertificate() {
Steve Block51b08912011-04-27 15:04:48 +01001567 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 return mCertificate;
1569 }
1570
1571 /**
1572 * Sets the SSL certificate for the main top-level page.
1573 */
1574 public void setCertificate(SslCertificate certificate) {
Steve Block51b08912011-04-27 15:04:48 +01001575 checkThread();
Brian Carlstromdba8cb72010-03-18 16:56:41 -07001576 if (DebugFlags.WEB_VIEW) {
1577 Log.v(LOGTAG, "setCertificate=" + certificate);
1578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 // here, the certificate can be null (if the site is not secure)
1580 mCertificate = certificate;
1581 }
1582
1583 //-------------------------------------------------------------------------
1584 // Methods called by activity
1585 //-------------------------------------------------------------------------
1586
1587 /**
1588 * Save the username and password for a particular host in the WebView's
1589 * internal database.
1590 * @param host The host that required the credentials.
1591 * @param username The username for the given host.
1592 * @param password The password for the given host.
1593 */
1594 public void savePassword(String host, String username, String password) {
Steve Block51b08912011-04-27 15:04:48 +01001595 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596 mDatabase.setUsernamePassword(host, username, password);
1597 }
1598
1599 /**
1600 * Set the HTTP authentication credentials for a given host and realm.
1601 *
1602 * @param host The host for the credentials.
1603 * @param realm The realm for the credentials.
1604 * @param username The username for the password. If it is null, it means
1605 * password can't be saved.
1606 * @param password The password
1607 */
1608 public void setHttpAuthUsernamePassword(String host, String realm,
1609 String username, String password) {
Steve Block51b08912011-04-27 15:04:48 +01001610 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
1612 }
1613
1614 /**
1615 * Retrieve the HTTP authentication username and password for a given
1616 * host & realm pair
1617 *
1618 * @param host The host for which the credentials apply.
1619 * @param realm The realm for which the credentials apply.
1620 * @return String[] if found, String[0] is username, which can be null and
1621 * String[1] is password. Return null if it can't find anything.
1622 */
1623 public String[] getHttpAuthUsernamePassword(String host, String realm) {
Steve Block51b08912011-04-27 15:04:48 +01001624 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 return mDatabase.getHttpAuthUsernamePassword(host, realm);
1626 }
1627
1628 /**
Leon Scroggins05919f22010-09-14 17:22:36 -04001629 * Remove Find or Select ActionModes, if active.
1630 */
1631 private void clearActionModes() {
1632 if (mSelectCallback != null) {
1633 mSelectCallback.finish();
1634 }
1635 if (mFindCallback != null) {
1636 mFindCallback.finish();
1637 }
1638 }
1639
1640 /**
1641 * Called to clear state when moving from one page to another, or changing
1642 * in some other way that makes elements associated with the current page
1643 * (such as WebTextView or ActionModes) no longer relevant.
1644 */
1645 private void clearHelpers() {
1646 clearTextEntry();
1647 clearActionModes();
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04001648 dismissFullScreenMode();
Ben Murdoch2ffc9ec2011-11-28 15:41:31 +00001649 cancelSelectDialog();
1650 }
1651
1652 private void cancelSelectDialog() {
1653 if (mListBoxDialog != null) {
1654 mListBoxDialog.cancel();
1655 mListBoxDialog = null;
1656 }
Leon Scroggins05919f22010-09-14 17:22:36 -04001657 }
1658
1659 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 * Destroy the internal state of the WebView. This method should be called
1661 * after the WebView has been removed from the view system. No other
1662 * methods may be called on a WebView after destroy.
1663 */
1664 public void destroy() {
Steve Block51b08912011-04-27 15:04:48 +01001665 checkThread();
1666 destroyImpl();
1667 }
1668
1669 private void destroyImpl() {
Leon Scroggins05919f22010-09-14 17:22:36 -04001670 clearHelpers();
Mattias Falk0ae2ec82010-09-16 16:24:46 +02001671 if (mListBoxDialog != null) {
1672 mListBoxDialog.dismiss();
1673 mListBoxDialog = null;
1674 }
George Mount1fa26cb2011-10-03 10:56:28 -07001675 // remove so that it doesn't cause events
1676 if (mWebTextView != null) {
1677 mWebTextView.remove();
1678 mWebTextView = null;
1679 }
Cary Clarkd9fd8572011-02-03 05:25:05 -05001680 if (mNativeClass != 0) nativeStopGL();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 if (mWebViewCore != null) {
1682 // Set the handlers to null before destroying WebViewCore so no
Cary Clarkd6982c92009-05-29 11:02:22 -04001683 // more messages will be posted.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 mCallbackProxy.setWebViewClient(null);
1685 mCallbackProxy.setWebChromeClient(null);
1686 // Tell WebViewCore to destroy itself
Andrei Popescu04098572010-03-09 12:23:19 +00001687 synchronized (this) {
1688 WebViewCore webViewCore = mWebViewCore;
1689 mWebViewCore = null; // prevent using partial webViewCore
1690 webViewCore.destroy();
1691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 // Remove any pending messages that might not be serviced yet.
1693 mPrivateHandler.removeCallbacksAndMessages(null);
1694 mCallbackProxy.removeCallbacksAndMessages(null);
1695 // Wake up the WebCore thread just in case it is waiting for a
Steve Block81f19ff2010-11-01 13:23:24 +00001696 // JavaScript dialog.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 synchronized (mCallbackProxy) {
1698 mCallbackProxy.notify();
1699 }
1700 }
1701 if (mNativeClass != 0) {
1702 nativeDestroy();
1703 mNativeClass = 0;
1704 }
1705 }
1706
1707 /**
1708 * Enables platform notifications of data state and proxy changes.
Kristian Monsencbb59db2011-05-09 16:04:34 +01001709 * Notifications are enabled by default.
Kristian Monsenfc771652011-05-10 16:44:05 +01001710 *
1711 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001713 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 public static void enablePlatformNotifications() {
Steve Block51b08912011-04-27 15:04:48 +01001715 checkThread();
Kristian Monsencbb59db2011-05-09 16:04:34 +01001716 synchronized (WebView.class) {
1717 Network.enablePlatformNotifications();
1718 sNotificationsEnabled = true;
1719 Context context = JniUtil.getContext();
1720 if (context != null)
1721 setupProxyListener(context);
1722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 }
1724
1725 /**
Kristian Monsencbb59db2011-05-09 16:04:34 +01001726 * Disables platform notifications of data state and proxy changes.
1727 * Notifications are enabled by default.
Kristian Monsenfc771652011-05-10 16:44:05 +01001728 *
1729 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001731 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 public static void disablePlatformNotifications() {
Steve Block51b08912011-04-27 15:04:48 +01001733 checkThread();
Kristian Monsencbb59db2011-05-09 16:04:34 +01001734 synchronized (WebView.class) {
1735 Network.disablePlatformNotifications();
1736 sNotificationsEnabled = false;
1737 Context context = JniUtil.getContext();
1738 if (context != null)
1739 disableProxyListener(context);
1740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 }
Cary Clarkd6982c92009-05-29 11:02:22 -04001742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 /**
Feng Qianb3081372009-06-29 15:55:18 -07001744 * Sets JavaScript engine flags.
1745 *
1746 * @param flags JS engine flags in a String
1747 *
Jonathan Dixon4cde13a2011-12-16 18:36:20 +00001748 * @hide This is an implementation detail.
Feng Qianb3081372009-06-29 15:55:18 -07001749 */
1750 public void setJsFlags(String flags) {
Steve Block51b08912011-04-27 15:04:48 +01001751 checkThread();
Feng Qianb3081372009-06-29 15:55:18 -07001752 mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
1753 }
1754
1755 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 * Inform WebView of the network state. This is used to set
Steve Block81f19ff2010-11-01 13:23:24 +00001757 * the JavaScript property window.navigator.isOnline and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 * generates the online/offline event as specified in HTML5, sec. 5.7.7
1759 * @param networkUp boolean indicating if network is available
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 */
1761 public void setNetworkAvailable(boolean networkUp) {
Steve Block51b08912011-04-27 15:04:48 +01001762 checkThread();
Grace Klobaa72cc092009-04-02 08:50:17 -07001763 mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE,
1764 networkUp ? 1 : 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 }
1766
1767 /**
Andrei Popescuf5dba882010-01-12 22:42:41 +00001768 * Inform WebView about the current network type.
1769 * {@hide}
1770 */
1771 public void setNetworkType(String type, String subtype) {
Steve Block51b08912011-04-27 15:04:48 +01001772 checkThread();
Andrei Popescuf5dba882010-01-12 22:42:41 +00001773 Map<String, String> map = new HashMap<String, String>();
1774 map.put("type", type);
1775 map.put("subtype", subtype);
1776 mWebViewCore.sendMessage(EventHub.SET_NETWORK_TYPE, map);
1777 }
1778 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04001779 * Save the state of this WebView used in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 * {@link android.app.Activity#onSaveInstanceState}. Please note that this
1781 * method no longer stores the display data for this WebView. The previous
1782 * behavior could potentially leak files if {@link #restoreState} was never
1783 * called. See {@link #savePicture} and {@link #restorePicture} for saving
1784 * and restoring the display data.
1785 * @param outState The Bundle to store the WebView state.
1786 * @return The same copy of the back/forward list used to save the state. If
1787 * saveState fails, the returned list will be null.
1788 * @see #savePicture
1789 * @see #restorePicture
1790 */
1791 public WebBackForwardList saveState(Bundle outState) {
Steve Block51b08912011-04-27 15:04:48 +01001792 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 if (outState == null) {
1794 return null;
1795 }
1796 // We grab a copy of the back/forward list because a client of WebView
1797 // may have invalidated the history list by calling clearHistory.
1798 WebBackForwardList list = copyBackForwardList();
1799 final int currentIndex = list.getCurrentIndex();
1800 final int size = list.getSize();
1801 // We should fail saving the state if the list is empty or the index is
1802 // not in a valid range.
1803 if (currentIndex < 0 || currentIndex >= size || size == 0) {
1804 return null;
1805 }
1806 outState.putInt("index", currentIndex);
1807 // FIXME: This should just be a byte[][] instead of ArrayList but
1808 // Parcel.java does not have the code to handle multi-dimensional
1809 // arrays.
1810 ArrayList<byte[]> history = new ArrayList<byte[]>(size);
1811 for (int i = 0; i < size; i++) {
1812 WebHistoryItem item = list.getItemAtIndex(i);
Cary Clark4fbf81b2009-09-29 16:07:56 -04001813 if (null == item) {
1814 // FIXME: this shouldn't happen
1815 // need to determine how item got set to null
1816 Log.w(LOGTAG, "saveState: Unexpected null history item.");
1817 return null;
1818 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 byte[] data = item.getFlattenedData();
1820 if (data == null) {
1821 // It would be very odd to not have any data for a given history
1822 // item. And we will fail to rebuild the history list without
1823 // flattened data.
1824 return null;
1825 }
1826 history.add(data);
1827 }
1828 outState.putSerializable("history", history);
1829 if (mCertificate != null) {
1830 outState.putBundle("certificate",
1831 SslCertificate.saveState(mCertificate));
1832 }
Elliott Slaughterd6284792010-08-18 18:17:52 -07001833 outState.putBoolean("privateBrowsingEnabled", isPrivateBrowsingEnabled());
Shimeng (Simon) Wang4ae1f6f2010-08-26 10:58:38 -07001834 mZoomManager.saveZoomState(outState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 return list;
1836 }
1837
1838 /**
1839 * Save the current display data to the Bundle given. Used in conjunction
1840 * with {@link #saveState}.
1841 * @param b A Bundle to store the display data.
1842 * @param dest The file to store the serialized picture data. Will be
1843 * overwritten with this WebView's picture data.
1844 * @return True if the picture was successfully saved.
Kristian Monsenfc771652011-05-10 16:44:05 +01001845 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001847 @Deprecated
Patrick Scottda9a22b2010-04-08 08:32:52 -04001848 public boolean savePicture(Bundle b, final File dest) {
Steve Block51b08912011-04-27 15:04:48 +01001849 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 if (dest == null || b == null) {
1851 return false;
1852 }
1853 final Picture p = capturePicture();
Patrick Scottda9a22b2010-04-08 08:32:52 -04001854 // Use a temporary file while writing to ensure the destination file
1855 // contains valid data.
1856 final File temp = new File(dest.getPath() + ".writing");
1857 new Thread(new Runnable() {
1858 public void run() {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001859 FileOutputStream out = null;
Patrick Scottda9a22b2010-04-08 08:32:52 -04001860 try {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001861 out = new FileOutputStream(temp);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001862 p.writeToStream(out);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001863 // Writing the picture succeeded, rename the temporary file
1864 // to the destination.
1865 temp.renameTo(dest);
1866 } catch (Exception e) {
1867 // too late to do anything about it.
1868 } finally {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001869 if (out != null) {
1870 try {
1871 out.close();
1872 } catch (Exception e) {
1873 // Can't do anything about that
1874 }
1875 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001876 temp.delete();
1877 }
1878 }
1879 }).start();
1880 // now update the bundle
1881 b.putInt("scrollX", mScrollX);
1882 b.putInt("scrollY", mScrollY);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001883 mZoomManager.saveZoomState(b);
Patrick Scottda9a22b2010-04-08 08:32:52 -04001884 return true;
1885 }
1886
1887 private void restoreHistoryPictureFields(Picture p, Bundle b) {
1888 int sx = b.getInt("scrollX", 0);
1889 int sy = b.getInt("scrollY", 0);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001890
Patrick Scottda9a22b2010-04-08 08:32:52 -04001891 mDrawHistory = true;
1892 mHistoryPicture = p;
Huahui Wu88b869a2011-03-17 17:42:12 -07001893
Patrick Scottda9a22b2010-04-08 08:32:52 -04001894 mScrollX = sx;
1895 mScrollY = sy;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001896 mZoomManager.restoreZoomState(b);
1897 final float scale = mZoomManager.getScale();
Patrick Scottda9a22b2010-04-08 08:32:52 -04001898 mHistoryWidth = Math.round(p.getWidth() * scale);
1899 mHistoryHeight = Math.round(p.getHeight() * scale);
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04001900
Patrick Scottda9a22b2010-04-08 08:32:52 -04001901 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 }
1903
1904 /**
1905 * Restore the display data that was save in {@link #savePicture}. Used in
1906 * conjunction with {@link #restoreState}.
John Reck2df8f422011-09-22 19:50:41 -07001907 *
1908 * Note that this will not work if the WebView is hardware accelerated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 * @param b A Bundle containing the saved display data.
1910 * @param src The file where the picture data was stored.
1911 * @return True if the picture was successfully restored.
Kristian Monsenfc771652011-05-10 16:44:05 +01001912 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 */
Kristian Monsenfc771652011-05-10 16:44:05 +01001914 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 public boolean restorePicture(Bundle b, File src) {
Steve Block51b08912011-04-27 15:04:48 +01001916 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 if (src == null || b == null) {
1918 return false;
1919 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001920 if (!src.exists()) {
1921 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001923 try {
1924 final FileInputStream in = new FileInputStream(src);
1925 final Bundle copy = new Bundle(b);
1926 new Thread(new Runnable() {
1927 public void run() {
Patrick Scottda9a22b2010-04-08 08:32:52 -04001928 try {
The Android Open Source Project2d743fe2010-06-04 11:07:49 -07001929 final Picture p = Picture.createFromStream(in);
1930 if (p != null) {
1931 // Post a runnable on the main thread to update the
1932 // history picture fields.
1933 mPrivateHandler.post(new Runnable() {
1934 public void run() {
1935 restoreHistoryPictureFields(p, copy);
1936 }
1937 });
1938 }
1939 } finally {
1940 try {
1941 in.close();
1942 } catch (Exception e) {
1943 // Nothing we can do now.
1944 }
Patrick Scottda9a22b2010-04-08 08:32:52 -04001945 }
1946 }
1947 }).start();
1948 } catch (FileNotFoundException e){
1949 e.printStackTrace();
1950 }
1951 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 }
1953
1954 /**
John Reck816c0de2011-06-02 16:04:53 -07001955 * Saves the view data to the output stream. The output is highly
1956 * version specific, and may not be able to be loaded by newer versions
1957 * of WebView.
1958 * @param stream The {@link OutputStream} to save to
1959 * @return True if saved successfully
1960 * @hide
1961 */
1962 public boolean saveViewState(OutputStream stream) {
1963 try {
1964 return ViewStateSerializer.serializeViewState(stream, this);
1965 } catch (IOException e) {
1966 Log.w(LOGTAG, "Failed to saveViewState", e);
1967 }
1968 return false;
1969 }
1970
1971 /**
1972 * Loads the view data from the input stream. See
1973 * {@link #saveViewState(OutputStream)} for more information.
1974 * @param stream The {@link InputStream} to load from
1975 * @return True if loaded successfully
1976 * @hide
1977 */
1978 public boolean loadViewState(InputStream stream) {
1979 try {
John Reck60c84d62011-06-08 18:00:02 -07001980 mLoadedPicture = ViewStateSerializer.deserializeViewState(stream, this);
John Reck95b7d6f2011-06-03 15:23:43 -07001981 mBlockWebkitViewMessages = true;
John Reck60c84d62011-06-08 18:00:02 -07001982 setNewPicture(mLoadedPicture, true);
John Reck23a446c2011-10-17 17:06:09 -07001983 mLoadedPicture.mViewState = null;
John Reck816c0de2011-06-02 16:04:53 -07001984 return true;
1985 } catch (IOException e) {
1986 Log.w(LOGTAG, "Failed to loadViewState", e);
1987 }
1988 return false;
1989 }
1990
1991 /**
John Reck95b7d6f2011-06-03 15:23:43 -07001992 * Clears the view state set with {@link #loadViewState(InputStream)}.
1993 * This WebView will then switch to showing the content from webkit
1994 * @hide
1995 */
1996 public void clearViewState() {
1997 mBlockWebkitViewMessages = false;
John Reck60c84d62011-06-08 18:00:02 -07001998 mLoadedPicture = null;
John Reck95b7d6f2011-06-03 15:23:43 -07001999 invalidate();
2000 }
2001
2002 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002003 * Restore the state of this WebView from the given map used in
Cary Clarkd6982c92009-05-29 11:02:22 -04002004 * {@link android.app.Activity#onRestoreInstanceState}. This method should
2005 * be called to restore the state of the WebView before using the object. If
2006 * it is called after the WebView has had a chance to build state (load
2007 * pages, create a back/forward list, etc.) there may be undesirable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 * side-effects. Please note that this method no longer restores the
2009 * display data for this WebView. See {@link #savePicture} and {@link
2010 * #restorePicture} for saving and restoring the display data.
2011 * @param inState The incoming Bundle of state.
2012 * @return The restored back/forward list or null if restoreState failed.
2013 * @see #savePicture
2014 * @see #restorePicture
2015 */
2016 public WebBackForwardList restoreState(Bundle inState) {
Steve Block51b08912011-04-27 15:04:48 +01002017 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 WebBackForwardList returnList = null;
2019 if (inState == null) {
2020 return returnList;
2021 }
2022 if (inState.containsKey("index") && inState.containsKey("history")) {
2023 mCertificate = SslCertificate.restoreState(
2024 inState.getBundle("certificate"));
2025
2026 final WebBackForwardList list = mCallbackProxy.getBackForwardList();
2027 final int index = inState.getInt("index");
2028 // We can't use a clone of the list because we need to modify the
2029 // shared copy, so synchronize instead to prevent concurrent
2030 // modifications.
2031 synchronized (list) {
2032 final List<byte[]> history =
2033 (List<byte[]>) inState.getSerializable("history");
2034 final int size = history.size();
2035 // Check the index bounds so we don't crash in native code while
2036 // restoring the history index.
2037 if (index < 0 || index >= size) {
2038 return null;
2039 }
2040 for (int i = 0; i < size; i++) {
2041 byte[] data = history.remove(0);
2042 if (data == null) {
2043 // If we somehow have null data, we cannot reconstruct
2044 // the item and thus our history list cannot be rebuilt.
2045 return null;
2046 }
2047 WebHistoryItem item = new WebHistoryItem(data);
2048 list.addHistoryItem(item);
2049 }
2050 // Grab the most recent copy to return to the caller.
2051 returnList = copyBackForwardList();
2052 // Update the copy to have the correct index.
2053 returnList.setCurrentIndex(index);
2054 }
Elliott Slaughterd6284792010-08-18 18:17:52 -07002055 // Restore private browsing setting.
2056 if (inState.getBoolean("privateBrowsingEnabled")) {
2057 getSettings().setPrivateBrowsingEnabled(true);
2058 }
Shimeng (Simon) Wang4ae1f6f2010-08-26 10:58:38 -07002059 mZoomManager.restoreZoomState(inState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 // Remove all pending messages because we are restoring previous
2061 // state.
2062 mWebViewCore.removeMessages();
2063 // Send a restore state message.
2064 mWebViewCore.sendMessage(EventHub.RESTORE_STATE, index);
2065 }
2066 return returnList;
2067 }
2068
2069 /**
Steve Blockf71dea02011-08-01 12:29:14 +01002070 * Load the given URL with the specified additional HTTP headers.
2071 * @param url The URL of the resource to load.
2072 * @param additionalHttpHeaders The additional headers to be used in the
2073 * HTTP request for this URL, specified as a map from name to
2074 * value. Note that if this map contains any of the headers
2075 * that are set by default by the WebView, such as those
2076 * controlling caching, accept types or the User-Agent, their
2077 * values may be overriden by the WebView's defaults.
Grace Klobad0d9bc22010-01-26 18:08:28 -08002078 */
Steve Blockf71dea02011-08-01 12:29:14 +01002079 public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
Steve Block51b08912011-04-27 15:04:48 +01002080 checkThread();
Steve Blockf71dea02011-08-01 12:29:14 +01002081 loadUrlImpl(url, additionalHttpHeaders);
Steve Block51b08912011-04-27 15:04:48 +01002082 }
2083
2084 private void loadUrlImpl(String url, Map<String, String> extraHeaders) {
Grace Klobad0d9bc22010-01-26 18:08:28 -08002085 switchOutDrawHistory();
2086 WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
2087 arg.mUrl = url;
2088 arg.mExtraHeaders = extraHeaders;
2089 mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04002090 clearHelpers();
Grace Klobad0d9bc22010-01-26 18:08:28 -08002091 }
2092
2093 /**
Steve Blockf71dea02011-08-01 12:29:14 +01002094 * Load the given URL.
2095 * @param url The URL of the resource to load.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 */
2097 public void loadUrl(String url) {
Steve Block51b08912011-04-27 15:04:48 +01002098 checkThread();
2099 loadUrlImpl(url);
2100 }
2101
2102 private void loadUrlImpl(String url) {
Patrick Scott4c3ca702009-07-15 15:41:05 -04002103 if (url == null) {
2104 return;
2105 }
Steve Block51b08912011-04-27 15:04:48 +01002106 loadUrlImpl(url, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 }
2108
2109 /**
Grace Kloba57534302009-05-22 18:55:02 -07002110 * Load the url with postData using "POST" method into the WebView. If url
2111 * is not a network url, it will be loaded with {link
2112 * {@link #loadUrl(String)} instead.
Cary Clarkd6982c92009-05-29 11:02:22 -04002113 *
Grace Kloba57534302009-05-22 18:55:02 -07002114 * @param url The url of the resource to load.
2115 * @param postData The data will be passed to "POST" request.
Grace Kloba57534302009-05-22 18:55:02 -07002116 */
2117 public void postUrl(String url, byte[] postData) {
Steve Block51b08912011-04-27 15:04:48 +01002118 checkThread();
Grace Kloba57534302009-05-22 18:55:02 -07002119 if (URLUtil.isNetworkUrl(url)) {
2120 switchOutDrawHistory();
Cary Clarkded054c2009-06-15 10:26:08 -04002121 WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
2122 arg.mUrl = url;
2123 arg.mPostData = postData;
Grace Kloba57534302009-05-22 18:55:02 -07002124 mWebViewCore.sendMessage(EventHub.POST_URL, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04002125 clearHelpers();
Grace Kloba57534302009-05-22 18:55:02 -07002126 } else {
Steve Block51b08912011-04-27 15:04:48 +01002127 loadUrlImpl(url);
Grace Kloba57534302009-05-22 18:55:02 -07002128 }
2129 }
2130
2131 /**
Steve Blockb28b22a2011-07-04 13:01:25 +01002132 * Load the given data into the WebView using a 'data' scheme URL.
2133 * <p>
2134 * Note that JavaScript's same origin policy means that script running in a
2135 * page loaded using this method will be unable to access content loaded
2136 * using any scheme other than 'data', including 'http(s)'. To avoid this
2137 * restriction, use {@link
2138 * #loadDataWithBaseURL(String,String,String,String,String)
2139 * loadDataWithBaseURL()} with an appropriate base URL.
Steve Blockf95d4902011-06-09 11:53:26 +01002140 * <p>
2141 * If the value of the encoding parameter is 'base64', then the data must
2142 * be encoded as base64. Otherwise, the data must use ASCII encoding for
2143 * octets inside the range of safe URL characters and use the standard %xx
John Reckcca606d2011-10-07 12:31:26 -07002144 * hex encoding of URLs for octets outside that range. For example,
2145 * '#', '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively.
Steve Blockb19c7872011-10-10 14:09:44 +01002146 * <p>
2147 * The 'data' scheme URL formed by this method uses the default US-ASCII
2148 * charset. If you need need to set a different charset, you should form a
Steve Block33f962b2011-10-11 14:49:47 +01002149 * 'data' scheme URL which explicitly specifies a charset parameter in the
2150 * mediatype portion of the URL and call {@link #loadUrl(String)} instead.
2151 * Note that the charset obtained from the mediatype portion of a data URL
2152 * always overrides that specified in the HTML or XML document itself.
Steve Blockf95d4902011-06-09 11:53:26 +01002153 * @param data A String of data in the given encoding.
Steve Block33f962b2011-10-11 14:49:47 +01002154 * @param mimeType The MIME type of the data, e.g. 'text/html'.
Steve Blockf95d4902011-06-09 11:53:26 +01002155 * @param encoding The encoding of the data.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 */
2157 public void loadData(String data, String mimeType, String encoding) {
Steve Block51b08912011-04-27 15:04:48 +01002158 checkThread();
2159 loadDataImpl(data, mimeType, encoding);
2160 }
2161
2162 private void loadDataImpl(String data, String mimeType, String encoding) {
Steve Blockf95d4902011-06-09 11:53:26 +01002163 StringBuilder dataUrl = new StringBuilder("data:");
2164 dataUrl.append(mimeType);
2165 if ("base64".equals(encoding)) {
2166 dataUrl.append(";base64");
2167 }
2168 dataUrl.append(",");
2169 dataUrl.append(data);
2170 loadUrlImpl(dataUrl.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 }
2172
2173 /**
Steve Blockb28b22a2011-07-04 13:01:25 +01002174 * Load the given data into the WebView, using baseUrl as the base URL for
2175 * the content. The base URL is used both to resolve relative URLs and when
2176 * applying JavaScript's same origin policy. The historyUrl is used for the
2177 * history entry.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 * <p>
Steve Blockae328572011-06-08 18:58:51 +01002179 * Note that content specified in this way can access local device files
2180 * (via 'file' scheme URLs) only if baseUrl specifies a scheme other than
2181 * 'http', 'https', 'ftp', 'ftps', 'about' or 'javascript'.
Steve Blocke482d892011-07-01 13:57:32 +01002182 * <p>
2183 * If the base URL uses the data scheme, this method is equivalent to
2184 * calling {@link #loadData(String,String,String) loadData()} and the
2185 * historyUrl is ignored.
Steve Blockb28b22a2011-07-04 13:01:25 +01002186 * @param baseUrl URL to use as the page's base URL. If null defaults to
Steve Blocke482d892011-07-01 13:57:32 +01002187 * 'about:blank'
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 * @param data A String of data in the given encoding.
Steve Blocke482d892011-07-01 13:57:32 +01002189 * @param mimeType The MIMEType of the data, e.g. 'text/html'. If null,
2190 * defaults to 'text/html'.
2191 * @param encoding The encoding of the data.
2192 * @param historyUrl URL to use as the history entry, if null defaults to
2193 * 'about:blank'.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 */
2195 public void loadDataWithBaseURL(String baseUrl, String data,
Leon Scroggins1bb1a912010-03-23 15:39:46 -04002196 String mimeType, String encoding, String historyUrl) {
Steve Block51b08912011-04-27 15:04:48 +01002197 checkThread();
Cary Clarkd6982c92009-05-29 11:02:22 -04002198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
Steve Block51b08912011-04-27 15:04:48 +01002200 loadDataImpl(data, mimeType, encoding);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002201 return;
2202 }
2203 switchOutDrawHistory();
Cary Clarkded054c2009-06-15 10:26:08 -04002204 WebViewCore.BaseUrlData arg = new WebViewCore.BaseUrlData();
2205 arg.mBaseUrl = baseUrl;
2206 arg.mData = data;
2207 arg.mMimeType = mimeType;
2208 arg.mEncoding = encoding;
Leon Scroggins1bb1a912010-03-23 15:39:46 -04002209 arg.mHistoryUrl = historyUrl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
Leon Scroggins05919f22010-09-14 17:22:36 -04002211 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 }
2213
2214 /**
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07002215 * Saves the current view as a web archive.
2216 *
2217 * @param filename The filename where the archive should be placed.
2218 */
2219 public void saveWebArchive(String filename) {
Steve Block51b08912011-04-27 15:04:48 +01002220 checkThread();
2221 saveWebArchiveImpl(filename, false, null);
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07002222 }
2223
2224 /* package */ static class SaveWebArchiveMessage {
2225 SaveWebArchiveMessage (String basename, boolean autoname, ValueCallback<String> callback) {
2226 mBasename = basename;
2227 mAutoname = autoname;
2228 mCallback = callback;
2229 }
2230
2231 /* package */ final String mBasename;
2232 /* package */ final boolean mAutoname;
2233 /* package */ final ValueCallback<String> mCallback;
2234 /* package */ String mResultFile;
2235 }
2236
2237 /**
2238 * Saves the current view as a web archive.
2239 *
2240 * @param basename The filename where the archive should be placed.
2241 * @param autoname If false, takes basename to be a file. If true, basename
2242 * is assumed to be a directory in which a filename will be
2243 * chosen according to the url of the current page.
2244 * @param callback Called after the web archive has been saved. The
2245 * parameter for onReceiveValue will either be the filename
2246 * under which the file was saved, or null if saving the
2247 * file failed.
2248 */
2249 public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
Steve Block51b08912011-04-27 15:04:48 +01002250 checkThread();
2251 saveWebArchiveImpl(basename, autoname, callback);
2252 }
2253
2254 private void saveWebArchiveImpl(String basename, boolean autoname,
2255 ValueCallback<String> callback) {
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07002256 mWebViewCore.sendMessage(EventHub.SAVE_WEBARCHIVE,
2257 new SaveWebArchiveMessage(basename, autoname, callback));
2258 }
2259
2260 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002261 * Stop the current load.
2262 */
2263 public void stopLoading() {
Steve Block51b08912011-04-27 15:04:48 +01002264 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002265 // TODO: should we clear all the messages in the queue before sending
2266 // STOP_LOADING?
2267 switchOutDrawHistory();
2268 mWebViewCore.sendMessage(EventHub.STOP_LOADING);
2269 }
2270
2271 /**
2272 * Reload the current url.
2273 */
2274 public void reload() {
Steve Block51b08912011-04-27 15:04:48 +01002275 checkThread();
Leon Scroggins05919f22010-09-14 17:22:36 -04002276 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 switchOutDrawHistory();
2278 mWebViewCore.sendMessage(EventHub.RELOAD);
2279 }
2280
2281 /**
2282 * Return true if this WebView has a back history item.
2283 * @return True iff this WebView has a back history item.
2284 */
2285 public boolean canGoBack() {
Steve Block51b08912011-04-27 15:04:48 +01002286 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002287 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2288 synchronized (l) {
2289 if (l.getClearPending()) {
2290 return false;
2291 } else {
2292 return l.getCurrentIndex() > 0;
2293 }
2294 }
2295 }
2296
2297 /**
2298 * Go back in the history of this WebView.
2299 */
2300 public void goBack() {
Steve Block51b08912011-04-27 15:04:48 +01002301 checkThread();
2302 goBackOrForwardImpl(-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 }
2304
2305 /**
2306 * Return true if this WebView has a forward history item.
2307 * @return True iff this Webview has a forward history item.
2308 */
2309 public boolean canGoForward() {
Steve Block51b08912011-04-27 15:04:48 +01002310 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2312 synchronized (l) {
2313 if (l.getClearPending()) {
2314 return false;
2315 } else {
2316 return l.getCurrentIndex() < l.getSize() - 1;
2317 }
2318 }
2319 }
2320
2321 /**
2322 * Go forward in the history of this WebView.
2323 */
2324 public void goForward() {
Steve Block51b08912011-04-27 15:04:48 +01002325 checkThread();
2326 goBackOrForwardImpl(1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 }
2328
2329 /**
2330 * Return true if the page can go back or forward the given
2331 * number of steps.
2332 * @param steps The negative or positive number of steps to move the
2333 * history.
2334 */
2335 public boolean canGoBackOrForward(int steps) {
Steve Block51b08912011-04-27 15:04:48 +01002336 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002337 WebBackForwardList l = mCallbackProxy.getBackForwardList();
2338 synchronized (l) {
2339 if (l.getClearPending()) {
2340 return false;
2341 } else {
2342 int newIndex = l.getCurrentIndex() + steps;
2343 return newIndex >= 0 && newIndex < l.getSize();
2344 }
2345 }
2346 }
2347
2348 /**
2349 * Go to the history item that is the number of steps away from
2350 * the current item. Steps is negative if backward and positive
2351 * if forward.
2352 * @param steps The number of steps to take back or forward in the back
2353 * forward list.
2354 */
2355 public void goBackOrForward(int steps) {
Steve Block51b08912011-04-27 15:04:48 +01002356 checkThread();
2357 goBackOrForwardImpl(steps);
2358 }
2359
2360 private void goBackOrForwardImpl(int steps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 goBackOrForward(steps, false);
2362 }
2363
2364 private void goBackOrForward(int steps, boolean ignoreSnapshot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 if (steps != 0) {
Leon Scroggins05919f22010-09-14 17:22:36 -04002366 clearHelpers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002367 mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps,
2368 ignoreSnapshot ? 1 : 0);
2369 }
2370 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002371
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002372 /**
2373 * Returns true if private browsing is enabled in this WebView.
2374 */
Elliott Slaughter7c2d1352010-08-20 15:57:18 -07002375 public boolean isPrivateBrowsingEnabled() {
Steve Block51b08912011-04-27 15:04:48 +01002376 checkThread();
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002377 return getSettings().isPrivateBrowsingEnabled();
2378 }
2379
Elliott Slaughter7c2d1352010-08-20 15:57:18 -07002380 private void startPrivateBrowsing() {
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002381 getSettings().setPrivateBrowsingEnabled(true);
Elliott Slaughterf21d2e32010-07-14 18:08:54 -07002382 }
2383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 private boolean extendScroll(int y) {
2385 int finalY = mScroller.getFinalY();
2386 int newY = pinLocY(finalY + y);
2387 if (newY == finalY) return false;
2388 mScroller.setFinalY(newY);
2389 mScroller.extendDuration(computeDuration(0, y));
2390 return true;
2391 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002393 /**
2394 * Scroll the contents of the view up by half the view size
2395 * @param top true to jump to the top of the page
2396 * @return true if the page was scrolled
2397 */
2398 public boolean pageUp(boolean top) {
Steve Block51b08912011-04-27 15:04:48 +01002399 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002400 if (mNativeClass == 0) {
2401 return false;
2402 }
Cary Clarke872f3a2009-06-11 09:51:11 -04002403 nativeClearCursor(); // start next trackball movement from page edge
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002404 if (top) {
2405 // go to the top of the document
2406 return pinScrollTo(mScrollX, 0, true, 0);
2407 }
2408 // Page up
2409 int h = getHeight();
2410 int y;
2411 if (h > 2 * PAGE_SCROLL_OVERLAP) {
2412 y = -h + PAGE_SCROLL_OVERLAP;
2413 } else {
2414 y = -h / 2;
2415 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002416 return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002417 : extendScroll(y);
2418 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002420 /**
2421 * Scroll the contents of the view down by half the page size
2422 * @param bottom true to jump to bottom of page
2423 * @return true if the page was scrolled
2424 */
2425 public boolean pageDown(boolean bottom) {
Steve Block51b08912011-04-27 15:04:48 +01002426 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427 if (mNativeClass == 0) {
2428 return false;
2429 }
Cary Clarke872f3a2009-06-11 09:51:11 -04002430 nativeClearCursor(); // start next trackball movement from page edge
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002431 if (bottom) {
Adam Powell637d3372010-08-25 14:37:03 -07002432 return pinScrollTo(mScrollX, computeRealVerticalScrollRange(), true, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002433 }
2434 // Page down.
2435 int h = getHeight();
2436 int y;
2437 if (h > 2 * PAGE_SCROLL_OVERLAP) {
2438 y = h - PAGE_SCROLL_OVERLAP;
2439 } else {
2440 y = h / 2;
2441 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002442 return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002443 : extendScroll(y);
2444 }
2445
2446 /**
2447 * Clear the view so that onDraw() will draw nothing but white background,
2448 * and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY
2449 */
2450 public void clearView() {
Steve Block51b08912011-04-27 15:04:48 +01002451 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002452 mContentWidth = 0;
2453 mContentHeight = 0;
Chris Craik5cf78f72011-07-28 11:34:31 -07002454 setBaseLayer(0, null, false, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002455 mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
2456 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002458 /**
2459 * Return a new picture that captures the current display of the webview.
2460 * This is a copy of the display, and will be unaffected if the webview
2461 * later loads a different URL.
2462 *
2463 * @return a picture containing the current contents of the view. Note this
2464 * picture is of the entire document, and is not restricted to the
2465 * bounds of the view.
2466 */
2467 public Picture capturePicture() {
Steve Block51b08912011-04-27 15:04:48 +01002468 checkThread();
Cary Clark5ffbb812010-10-08 15:38:39 -04002469 if (mNativeClass == 0) return null;
Grace Kloba8abd50b2010-07-08 15:02:14 -07002470 Picture result = new Picture();
2471 nativeCopyBaseContentToPicture(result);
2472 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473 }
2474
2475 /**
2476 * Return true if the browser is displaying a TextView for text input.
2477 */
2478 private boolean inEditingMode() {
Leon Scroggins63284ed2010-04-09 14:54:46 -04002479 return mWebTextView != null && mWebTextView.getParent() != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002480 }
2481
Leon Scroggins6088e832010-02-17 13:17:32 -05002482 /**
2483 * Remove the WebTextView.
Leon Scroggins6088e832010-02-17 13:17:32 -05002484 */
Leon Scroggins2aed7762010-08-13 17:11:42 -04002485 private void clearTextEntry() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002486 if (inEditingMode()) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04002487 mWebTextView.remove();
Leon Scroggins III6f992702010-08-12 14:24:00 -04002488 } else {
2489 // The keyboard may be open with the WebView as the served view
2490 hideSoftKeyboard();
2491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002492 }
2493
Cary Clarkd6982c92009-05-29 11:02:22 -04002494 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002495 * Return the current scale of the WebView
2496 * @return The current scale.
2497 */
2498 public float getScale() {
Steve Block51b08912011-04-27 15:04:48 +01002499 checkThread();
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002500 return mZoomManager.getScale();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002501 }
2502
John Reck1cfe8dd2011-09-27 20:14:39 -07002503 // Called by JNI. Returns the scale to apply to the text selection handles
2504 /* package */ float getTextHandleScale() {
2505 float density = mContext.getResources().getDisplayMetrics().density;
2506 return density / getScale();
2507 }
2508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002509 /**
Mangesh Ghiware66b2ff82011-12-08 13:43:55 -08002510 * Compute the reading level scale of the WebView
2511 * @param scale The current scale.
Mangesh Ghiwareb5f9fc32011-08-31 17:49:07 -07002512 * @return The reading level scale.
2513 */
Mangesh Ghiware66b2ff82011-12-08 13:43:55 -08002514 /*package*/ float computeReadingLevelScale(float scale) {
2515 return mZoomManager.computeReadingLevelScale(scale);
Mangesh Ghiwareb5f9fc32011-08-31 17:49:07 -07002516 }
2517
2518 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002519 * Set the initial scale for the WebView. 0 means default. If
2520 * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
2521 * way. Otherwise it starts with 100%. If initial scale is greater than 0,
Mangesh Ghiwaree832b632011-11-16 11:46:39 -08002522 * WebView starts with this value as initial scale.
2523 * Please note that unlike the scale properties in the viewport meta tag,
2524 * this method doesn't take the screen density into account.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 *
2526 * @param scaleInPercent The initial scale in percent.
2527 */
2528 public void setInitialScale(int scaleInPercent) {
Steve Block51b08912011-04-27 15:04:48 +01002529 checkThread();
Derek Sollenberger341e22f2010-06-02 12:34:34 -04002530 mZoomManager.setInitialScaleInPercent(scaleInPercent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002531 }
2532
2533 /**
2534 * Invoke the graphical zoom picker widget for this WebView. This will
2535 * result in the zoom widget appearing on the screen to control the zoom
2536 * level of this WebView.
2537 */
2538 public void invokeZoomPicker() {
Steve Block51b08912011-04-27 15:04:48 +01002539 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 if (!getSettings().supportZoom()) {
2541 Log.w(LOGTAG, "This WebView doesn't support zoom.");
2542 return;
2543 }
Leon Scroggins05919f22010-09-14 17:22:36 -04002544 clearHelpers();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04002545 mZoomManager.invokeZoomPicker();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 }
2547
2548 /**
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04002549 * Return a HitTestResult based on the current cursor node. If a HTML::a tag
Steve Block81f19ff2010-11-01 13:23:24 +00002550 * is found and the anchor has a non-JavaScript url, the HitTestResult type
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002551 * is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
Steve Block81f19ff2010-11-01 13:23:24 +00002552 * 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 -08002553 * be UNKNOWN_TYPE and the url has to be retrieved through
2554 * {@link #requestFocusNodeHref} asynchronously. If a HTML::img tag is
2555 * found, the HitTestResult type is set to IMAGE_TYPE and the url is set in
2556 * the "extra" field. A type of
2557 * SRC_IMAGE_ANCHOR_TYPE indicates an anchor with a url that has an image as
2558 * a child node. If a phone number is found, the HitTestResult type is set
2559 * to PHONE_TYPE and the phone number is set in the "extra" field of
2560 * HitTestResult. If a map address is found, the HitTestResult type is set
2561 * to GEO_TYPE and the address is set in the "extra" field of HitTestResult.
2562 * If an email address is found, the HitTestResult type is set to EMAIL_TYPE
2563 * and the email is set in the "extra" field of HitTestResult. Otherwise,
2564 * HitTestResult type is set to UNKNOWN_TYPE.
2565 */
2566 public HitTestResult getHitTestResult() {
Steve Block51b08912011-04-27 15:04:48 +01002567 checkThread();
Cary Clarkb8491342010-11-29 16:23:19 -05002568 return hitTestResult(mInitialHitTestResult);
2569 }
2570
2571 private HitTestResult hitTestResult(HitTestResult fallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 if (mNativeClass == 0) {
2573 return null;
2574 }
2575
2576 HitTestResult result = new HitTestResult();
Cary Clarkd6982c92009-05-29 11:02:22 -04002577 if (nativeHasCursorNode()) {
2578 if (nativeCursorIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 result.setType(HitTestResult.EDIT_TEXT_TYPE);
Cary Clarkd6982c92009-05-29 11:02:22 -04002580 } else {
2581 String text = nativeCursorText();
2582 if (text != null) {
2583 if (text.startsWith(SCHEME_TEL)) {
2584 result.setType(HitTestResult.PHONE_TYPE);
Victoria Lease4d8ea3b2011-12-14 17:13:47 -08002585 result.setExtra(URLDecoder.decode(text
2586 .substring(SCHEME_TEL.length())));
Cary Clarkd6982c92009-05-29 11:02:22 -04002587 } else if (text.startsWith(SCHEME_MAILTO)) {
2588 result.setType(HitTestResult.EMAIL_TYPE);
2589 result.setExtra(text.substring(SCHEME_MAILTO.length()));
2590 } else if (text.startsWith(SCHEME_GEO)) {
2591 result.setType(HitTestResult.GEO_TYPE);
2592 result.setExtra(URLDecoder.decode(text
2593 .substring(SCHEME_GEO.length())));
2594 } else if (nativeCursorIsAnchor()) {
2595 result.setType(HitTestResult.SRC_ANCHOR_TYPE);
2596 result.setExtra(text);
2597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002598 }
2599 }
Cary Clarkb8491342010-11-29 16:23:19 -05002600 } else if (fallback != null) {
2601 /* If webkit causes a rebuild while the long press is in progress,
2602 * the cursor node may be reset, even if it is still around. This
2603 * uses the cursor node saved when the touch began. Since the
2604 * nativeImageURI below only changes the result if it is successful,
2605 * this uses the data beneath the touch if available or the original
2606 * tap data otherwise.
2607 */
2608 Log.v(LOGTAG, "hitTestResult use fallback");
2609 result = fallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 }
2611 int type = result.getType();
2612 if (type == HitTestResult.UNKNOWN_TYPE
2613 || type == HitTestResult.SRC_ANCHOR_TYPE) {
2614 // Now check to see if it is an image.
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002615 int contentX = viewToContentX(mLastTouchX + mScrollX);
2616 int contentY = viewToContentY(mLastTouchY + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002617 String text = nativeImageURI(contentX, contentY);
2618 if (text != null) {
Cary Clarkd6982c92009-05-29 11:02:22 -04002619 result.setType(type == HitTestResult.UNKNOWN_TYPE ?
2620 HitTestResult.IMAGE_TYPE :
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002621 HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
2622 result.setExtra(text);
2623 }
2624 }
2625 return result;
2626 }
2627
Leon Scrogginse26efa32009-12-15 16:38:45 -05002628 // Called by JNI when the DOM has changed the focus. Clear the focus so
2629 // that new keys will go to the newly focused field
2630 private void domChangedFocus() {
2631 if (inEditingMode()) {
2632 mPrivateHandler.obtainMessage(DOM_FOCUS_CHANGED).sendToTarget();
2633 }
2634 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 /**
Cary Clark861368a2010-12-15 11:24:37 -05002636 * Request the anchor or image element URL at the last tapped point.
2637 * If hrefMsg is null, this method returns immediately and does not
2638 * dispatch hrefMsg to its target. If the tapped point hits an image,
2639 * an anchor, or an image in an anchor, the message associates
2640 * strings in named keys in its data. The value paired with the key
2641 * may be an empty string.
Cary Clarkd6982c92009-05-29 11:02:22 -04002642 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 * @param hrefMsg This message will be dispatched with the result of the
Cary Clark861368a2010-12-15 11:24:37 -05002644 * request. The message data contains three keys:
2645 * - "url" returns the anchor's href attribute.
2646 * - "title" returns the anchor's text.
2647 * - "src" returns the image's src attribute.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002648 */
2649 public void requestFocusNodeHref(Message hrefMsg) {
Steve Block51b08912011-04-27 15:04:48 +01002650 checkThread();
Cary Clarke41bb532010-11-30 15:59:59 -05002651 if (hrefMsg == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 return;
2653 }
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002654 int contentX = viewToContentX(mLastTouchX + mScrollX);
2655 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clark3ecd7db2011-02-24 14:58:23 -05002656 if (nativeHasCursorNode()) {
2657 Rect cursorBounds = nativeGetCursorRingBounds();
2658 if (!cursorBounds.contains(contentX, contentY)) {
2659 int slop = viewToContentDimension(mNavSlop);
2660 cursorBounds.inset(-slop, -slop);
2661 if (cursorBounds.contains(contentX, contentY)) {
2662 contentX = (int) cursorBounds.centerX();
2663 contentY = (int) cursorBounds.centerY();
2664 }
2665 }
2666 }
Cary Clarke41bb532010-11-30 15:59:59 -05002667 mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
2668 contentX, contentY, hrefMsg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002669 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 /**
2672 * Request the url of the image last touched by the user. msg will be sent
2673 * to its target with a String representing the url as its object.
Cary Clarkd6982c92009-05-29 11:02:22 -04002674 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 * @param msg This message will be dispatched with the result of the request
2676 * as the data member with "url" as key. The result can be null.
2677 */
2678 public void requestImageRef(Message msg) {
Steve Block51b08912011-04-27 15:04:48 +01002679 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04002680 if (0 == mNativeClass) return; // client isn't initialized
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08002681 int contentX = viewToContentX(mLastTouchX + mScrollX);
2682 int contentY = viewToContentY(mLastTouchY + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 String ref = nativeImageURI(contentX, contentY);
2684 Bundle data = msg.getData();
2685 data.putString("url", ref);
2686 msg.setData(data);
2687 msg.sendToTarget();
2688 }
2689
Derek Sollenberger87b17be52010-06-01 11:49:31 -04002690 static int pinLoc(int x, int viewMax, int docMax) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax);
2692 if (docMax < viewMax) { // the doc has room on the sides for "blank"
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002693 // pin the short document to the top/left of the screen
2694 x = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695// Log.d(LOGTAG, "--- center " + x);
2696 } else if (x < 0) {
2697 x = 0;
2698// Log.d(LOGTAG, "--- zero");
2699 } else if (x + viewMax > docMax) {
2700 x = docMax - viewMax;
2701// Log.d(LOGTAG, "--- pin " + x);
2702 }
2703 return x;
2704 }
2705
2706 // Expects x in view coordinates
Derek Sollenberger03e48912010-05-18 17:03:42 -04002707 int pinLocX(int x) {
Adam Powell637d3372010-08-25 14:37:03 -07002708 if (mInOverScrollMode) return x;
2709 return pinLoc(x, getViewWidth(), computeRealHorizontalScrollRange());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 }
2711
2712 // Expects y in view coordinates
Derek Sollenberger03e48912010-05-18 17:03:42 -04002713 int pinLocY(int y) {
Adam Powell637d3372010-08-25 14:37:03 -07002714 if (mInOverScrollMode) return y;
Mike Reede5e63f42010-03-19 14:38:23 -04002715 return pinLoc(y, getViewHeightWithTitle(),
Adam Powell637d3372010-08-25 14:37:03 -07002716 computeRealVerticalScrollRange() + getTitleHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 }
2718
Leon Scroggins0236e672009-09-02 21:12:08 -04002719 /**
2720 * A title bar which is embedded in this WebView, and scrolls along with it
2721 * vertically, but not horizontally.
2722 */
2723 private View mTitleBar;
2724
2725 /**
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002726 * the title bar rendering gravity
2727 */
2728 private int mTitleGravity;
2729
2730 /**
Leon Scroggins0236e672009-09-02 21:12:08 -04002731 * Add or remove a title bar to be embedded into the WebView, and scroll
2732 * along with it vertically, while remaining in view horizontally. Pass
2733 * null to remove the title bar from the WebView, and return to drawing
2734 * the WebView normally without translating to account for the title bar.
2735 * @hide
2736 */
Leon Scroggins078c52c2009-09-04 16:58:09 -04002737 public void setEmbeddedTitleBar(View v) {
2738 if (mTitleBar == v) return;
2739 if (mTitleBar != null) {
Leon Scroggins0236e672009-09-02 21:12:08 -04002740 removeView(mTitleBar);
Leon Scroggins078c52c2009-09-04 16:58:09 -04002741 }
2742 if (null != v) {
Leon Scroggins0236e672009-09-02 21:12:08 -04002743 addView(v, new AbsoluteLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08002744 ViewGroup.LayoutParams.MATCH_PARENT,
Leon Scroggins078c52c2009-09-04 16:58:09 -04002745 ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0));
Leon Scroggins0236e672009-09-02 21:12:08 -04002746 }
2747 mTitleBar = v;
2748 }
2749
2750 /**
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002751 * Set where to render the embedded title bar
2752 * NO_GRAVITY at the top of the page
2753 * TOP at the top of the screen
2754 * @hide
2755 */
2756 public void setTitleBarGravity(int gravity) {
2757 mTitleGravity = gravity;
Michael Kolb63052ac2011-04-06 16:32:38 -07002758 // force refresh
2759 invalidate();
Michael Kolbc4ca53f2011-02-05 13:53:14 -08002760 }
2761
2762 /**
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002763 * Given a distance in view space, convert it to content space. Note: this
2764 * does not reflect translation, just scaling, so this should not be called
2765 * with coordinates, but should be called for dimensions like width or
2766 * height.
2767 */
2768 private int viewToContentDimension(int d) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002769 return Math.round(d * mZoomManager.getInvScale());
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002770 }
2771
2772 /**
Leon Scroggins0236e672009-09-02 21:12:08 -04002773 * Given an x coordinate in view space, convert it to content space. Also
2774 * may be used for absolute heights (such as for the WebTextView's
2775 * textSize, which is unaffected by the height of the title bar).
2776 */
2777 /*package*/ int viewToContentX(int x) {
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002778 return viewToContentDimension(x);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779 }
2780
Leon Scroggins0236e672009-09-02 21:12:08 -04002781 /**
2782 * Given a y coordinate in view space, convert it to content space.
2783 * Takes into account the height of the title bar if there is one
2784 * embedded into the WebView.
2785 */
2786 /*package*/ int viewToContentY(int y) {
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002787 return viewToContentDimension(y - getTitleHeight());
Mike Reede8853fc2009-09-04 14:01:48 -04002788 }
2789
2790 /**
Nicolas Roard46318cf2010-05-10 15:15:51 -07002791 * Given a x coordinate in view space, convert it to content space.
2792 * Returns the result as a float.
2793 */
2794 private float viewToContentXf(int x) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002795 return x * mZoomManager.getInvScale();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002796 }
2797
2798 /**
2799 * Given a y coordinate in view space, convert it to content space.
2800 * Takes into account the height of the title bar if there is one
2801 * embedded into the WebView. Returns the result as a float.
2802 */
2803 private float viewToContentYf(int y) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002804 return (y - getTitleHeight()) * mZoomManager.getInvScale();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002805 }
2806
2807 /**
Mike Reede8853fc2009-09-04 14:01:48 -04002808 * Given a distance in content space, convert it to view space. Note: this
2809 * does not reflect translation, just scaling, so this should not be called
2810 * with coordinates, but should be called for dimensions like width or
2811 * height.
2812 */
2813 /*package*/ int contentToViewDimension(int d) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002814 return Math.round(d * mZoomManager.getScale());
Leon Scroggins0236e672009-09-02 21:12:08 -04002815 }
2816
2817 /**
2818 * Given an x coordinate in content space, convert it to view
Leon Scrogginsd3997e52009-09-21 14:15:18 -04002819 * space.
Leon Scroggins0236e672009-09-02 21:12:08 -04002820 */
2821 /*package*/ int contentToViewX(int x) {
Mike Reede8853fc2009-09-04 14:01:48 -04002822 return contentToViewDimension(x);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823 }
2824
Leon Scroggins0236e672009-09-02 21:12:08 -04002825 /**
2826 * Given a y coordinate in content space, convert it to view
2827 * space. Takes into account the height of the title bar.
2828 */
2829 /*package*/ int contentToViewY(int y) {
Mike Reede8853fc2009-09-04 14:01:48 -04002830 return contentToViewDimension(y) + getTitleHeight();
Leon Scroggins0236e672009-09-02 21:12:08 -04002831 }
2832
Mike Reede9e86b82009-09-15 11:26:53 -04002833 private Rect contentToViewRect(Rect x) {
2834 return new Rect(contentToViewX(x.left), contentToViewY(x.top),
2835 contentToViewX(x.right), contentToViewY(x.bottom));
2836 }
2837
2838 /* To invalidate a rectangle in content coordinates, we need to transform
2839 the rect into view coordinates, so we can then call invalidate(...).
2840
2841 Normally, we would just call contentToView[XY](...), which eventually
2842 calls Math.round(coordinate * mActualScale). However, for invalidates,
2843 we need to account for the slop that occurs with antialiasing. To
2844 address that, we are a little more liberal in the size of the rect that
2845 we invalidate.
2846
2847 This liberal calculation calls floor() for the top/left, and ceil() for
2848 the bottom/right coordinates. This catches the possible extra pixels of
2849 antialiasing that we might have missed with just round().
2850 */
2851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002852 // Called by JNI to invalidate the View, given rectangle coordinates in
2853 // content space
2854 private void viewInvalidate(int l, int t, int r, int b) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002855 final float scale = mZoomManager.getScale();
Mike Reede9e86b82009-09-15 11:26:53 -04002856 final int dy = getTitleHeight();
2857 invalidate((int)Math.floor(l * scale),
2858 (int)Math.floor(t * scale) + dy,
2859 (int)Math.ceil(r * scale),
2860 (int)Math.ceil(b * scale) + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 }
2862
2863 // Called by JNI to invalidate the View after a delay, given rectangle
2864 // coordinates in content space
2865 private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04002866 final float scale = mZoomManager.getScale();
Mike Reede9e86b82009-09-15 11:26:53 -04002867 final int dy = getTitleHeight();
2868 postInvalidateDelayed(delay,
2869 (int)Math.floor(l * scale),
2870 (int)Math.floor(t * scale) + dy,
2871 (int)Math.ceil(r * scale),
2872 (int)Math.ceil(b * scale) + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002873 }
2874
Mike Reede9e86b82009-09-15 11:26:53 -04002875 private void invalidateContentRect(Rect r) {
2876 viewInvalidate(r.left, r.top, r.right, r.bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 }
2878
Cary Clark278ce052009-08-31 16:08:42 -04002879 // stop the scroll animation, and don't let a subsequent fling add
2880 // to the existing velocity
2881 private void abortAnimation() {
2882 mScroller.abortAnimation();
2883 mLastVelocity = 0;
2884 }
2885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 /* call from webcoreview.draw(), so we're still executing in the UI thread
2887 */
2888 private void recordNewContentSize(int w, int h, boolean updateLayout) {
2889
2890 // premature data from webkit, ignore
2891 if ((w | h) == 0) {
2892 return;
2893 }
Cary Clarkd6982c92009-05-29 11:02:22 -04002894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002895 // don't abort a scroll animation if we didn't change anything
2896 if (mContentWidth != w || mContentHeight != h) {
2897 // record new dimensions
2898 mContentWidth = w;
2899 mContentHeight = h;
2900 // If history Picture is drawn, don't update scroll. They will be
2901 // updated when we get out of that mode.
2902 if (!mDrawHistory) {
2903 // repin our scroll, taking into account the new content size
Derek Sollenberger03e48912010-05-18 17:03:42 -04002904 updateScrollCoordinates(pinLocX(mScrollX), pinLocY(mScrollY));
Leon Scrogginsd84e7d52009-09-29 11:11:45 -04002905 if (!mScroller.isFinished()) {
2906 // We are in the middle of a scroll. Repin the final scroll
2907 // position.
2908 mScroller.setFinalX(pinLocX(mScroller.getFinalX()));
2909 mScroller.setFinalY(pinLocY(mScroller.getFinalY()));
2910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 }
2912 }
2913 contentSizeChanged(updateLayout);
2914 }
2915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002916 // Used to avoid sending many visible rect messages.
John Reck9f9fac02011-11-10 17:33:24 -08002917 private Rect mLastVisibleRectSent = new Rect();
2918 private Rect mLastGlobalRect = new Rect();
John Reckaefc28a2011-11-07 17:42:06 -08002919 private Rect mVisibleRect = new Rect();
2920 private Rect mGlobalVisibleRect = new Rect();
2921 private Point mScrollOffset = new Point();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002922
Derek Sollenberger03e48912010-05-18 17:03:42 -04002923 Rect sendOurVisibleRect() {
Derek Sollenberger293c3602010-06-04 10:44:48 -04002924 if (mZoomManager.isPreventingWebkitUpdates()) return mLastVisibleRectSent;
John Reckaefc28a2011-11-07 17:42:06 -08002925 calcOurContentVisibleRect(mVisibleRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 // Rect.equals() checks for null input.
John Reckaefc28a2011-11-07 17:42:06 -08002927 if (!mVisibleRect.equals(mLastVisibleRectSent)) {
John Reck95b7d6f2011-06-03 15:23:43 -07002928 if (!mBlockWebkitViewMessages) {
John Reckaefc28a2011-11-07 17:42:06 -08002929 mScrollOffset.set(mVisibleRect.left, mVisibleRect.top);
John Reck95b7d6f2011-06-03 15:23:43 -07002930 mWebViewCore.removeMessages(EventHub.SET_SCROLL_OFFSET);
2931 mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
John Reckaefc28a2011-11-07 17:42:06 -08002932 nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, mScrollOffset);
John Reck95b7d6f2011-06-03 15:23:43 -07002933 }
John Reck9f9fac02011-11-10 17:33:24 -08002934 mLastVisibleRectSent.set(mVisibleRect);
Cary Clark32820242010-12-03 10:27:20 -05002935 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002936 }
John Reckaefc28a2011-11-07 17:42:06 -08002937 if (getGlobalVisibleRect(mGlobalVisibleRect)
2938 && !mGlobalVisibleRect.equals(mLastGlobalRect)) {
Cary Clark3524be92009-06-22 13:09:11 -04002939 if (DebugFlags.WEB_VIEW) {
John Reckaefc28a2011-11-07 17:42:06 -08002940 Log.v(LOGTAG, "sendOurVisibleRect=(" + mGlobalVisibleRect.left + ","
2941 + mGlobalVisibleRect.top + ",r=" + mGlobalVisibleRect.right + ",b="
2942 + mGlobalVisibleRect.bottom);
Cary Clark3524be92009-06-22 13:09:11 -04002943 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002944 // TODO: the global offset is only used by windowRect()
2945 // in ChromeClientAndroid ; other clients such as touch
2946 // and mouse events could return view + screen relative points.
John Reck95b7d6f2011-06-03 15:23:43 -07002947 if (!mBlockWebkitViewMessages) {
John Reckaefc28a2011-11-07 17:42:06 -08002948 mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, mGlobalVisibleRect);
John Reck95b7d6f2011-06-03 15:23:43 -07002949 }
John Reck9f9fac02011-11-10 17:33:24 -08002950 mLastGlobalRect.set(mGlobalVisibleRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002951 }
John Reckaefc28a2011-11-07 17:42:06 -08002952 return mVisibleRect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953 }
2954
John Reckaefc28a2011-11-07 17:42:06 -08002955 private Point mGlobalVisibleOffset = new Point();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002956 // Sets r to be the visible rectangle of our webview in view coordinates
2957 private void calcOurVisibleRect(Rect r) {
John Reckaefc28a2011-11-07 17:42:06 -08002958 getGlobalVisibleRect(r, mGlobalVisibleOffset);
2959 r.offset(-mGlobalVisibleOffset.x, -mGlobalVisibleOffset.y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002960 }
2961
2962 // Sets r to be our visible rectangle in content coordinates
2963 private void calcOurContentVisibleRect(Rect r) {
2964 calcOurVisibleRect(r);
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002965 r.left = viewToContentX(r.left);
Leon Scroggins37df6a82009-09-23 10:31:23 -04002966 // viewToContentY will remove the total height of the title bar. Add
2967 // the visible height back in to account for the fact that if the title
2968 // bar is partially visible, the part of the visible rect which is
2969 // displaying our content is displaced by that amount.
Steve Block92c99162011-05-23 17:36:01 +01002970 r.top = viewToContentY(r.top + getVisibleTitleHeightImpl());
Teng-Hui Zhuc99821d2010-12-02 15:44:29 -08002971 r.right = viewToContentX(r.right);
2972 r.bottom = viewToContentY(r.bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002973 }
2974
John Reckaefc28a2011-11-07 17:42:06 -08002975 private Rect mContentVisibleRect = new Rect();
Nicolas Roard46318cf2010-05-10 15:15:51 -07002976 // Sets r to be our visible rectangle in content coordinates. We use this
2977 // method on the native side to compute the position of the fixed layers.
2978 // Uses floating coordinates (necessary to correctly place elements when
2979 // the scale factor is not 1)
2980 private void calcOurContentVisibleRectF(RectF r) {
John Reckaefc28a2011-11-07 17:42:06 -08002981 calcOurVisibleRect(mContentVisibleRect);
2982 r.left = viewToContentXf(mContentVisibleRect.left);
Nicolas Roard46318cf2010-05-10 15:15:51 -07002983 // viewToContentY will remove the total height of the title bar. Add
2984 // the visible height back in to account for the fact that if the title
2985 // bar is partially visible, the part of the visible rect which is
2986 // displaying our content is displaced by that amount.
John Reckaefc28a2011-11-07 17:42:06 -08002987 r.top = viewToContentYf(mContentVisibleRect.top + getVisibleTitleHeightImpl());
2988 r.right = viewToContentXf(mContentVisibleRect.right);
2989 r.bottom = viewToContentYf(mContentVisibleRect.bottom);
Nicolas Roard46318cf2010-05-10 15:15:51 -07002990 }
2991
Grace Klobaef347ef2009-07-30 11:20:32 -07002992 static class ViewSizeData {
2993 int mWidth;
2994 int mHeight;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08002995 float mHeightWidthRatio;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08002996 int mActualViewHeight;
Grace Klobaef347ef2009-07-30 11:20:32 -07002997 int mTextWrapWidth;
Grace Kloba3a0def22010-01-23 21:11:54 -08002998 int mAnchorX;
2999 int mAnchorY;
Grace Klobaef347ef2009-07-30 11:20:32 -07003000 float mScale;
Cary Clark6d45acc2009-08-27 15:42:57 -04003001 boolean mIgnoreHeight;
Grace Klobaef347ef2009-07-30 11:20:32 -07003002 }
3003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003004 /**
3005 * Compute unzoomed width and height, and if they differ from the last
Derek Sollenberger03e48912010-05-18 17:03:42 -04003006 * values we sent, send them to webkit (to be used as new viewport)
3007 *
3008 * @param force ensures that the message is sent to webkit even if the width
3009 * or height has not changed since the last message
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 *
3011 * @return true if new values were sent
3012 */
Derek Sollenberger03e48912010-05-18 17:03:42 -04003013 boolean sendViewSizeZoom(boolean force) {
John Reck95b7d6f2011-06-03 15:23:43 -07003014 if (mBlockWebkitViewMessages) return false;
Derek Sollenberger293c3602010-06-04 10:44:48 -04003015 if (mZoomManager.isPreventingWebkitUpdates()) return false;
Grace Kloba3a0def22010-01-23 21:11:54 -08003016
Grace Klobaef347ef2009-07-30 11:20:32 -07003017 int viewWidth = getViewWidth();
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003018 int newWidth = Math.round(viewWidth * mZoomManager.getInvScale());
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003019 // This height could be fixed and be different from actual visible height.
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08003020 int viewHeight = getViewHeightWithTitle() - getTitleHeight();
3021 int newHeight = Math.round(viewHeight * mZoomManager.getInvScale());
3022 // Make the ratio more accurate than (newHeight / newWidth), since the
3023 // latter both are calculated and rounded.
3024 float heightWidthRatio = (float) viewHeight / viewWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003025 /*
3026 * Because the native side may have already done a layout before the
3027 * View system was able to measure us, we have to send a height of 0 to
3028 * remove excess whitespace when we grow our width. This will trigger a
3029 * layout and a change in content size. This content size change will
3030 * mean that contentSizeChanged will either call this method directly or
3031 * indirectly from onSizeChanged.
3032 */
3033 if (newWidth > mLastWidthSent && mWrapContent) {
3034 newHeight = 0;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08003035 heightWidthRatio = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 }
Shimeng (Simon) Wang6a0b5ca2011-02-08 09:49:35 -08003037 // Actual visible content height.
3038 int actualViewHeight = Math.round(getViewHeight() * mZoomManager.getInvScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003039 // Avoid sending another message if the dimensions have not changed.
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003040 if (newWidth != mLastWidthSent || newHeight != mLastHeightSent || force ||
3041 actualViewHeight != mLastActualHeightSent) {
Grace Klobaef347ef2009-07-30 11:20:32 -07003042 ViewSizeData data = new ViewSizeData();
3043 data.mWidth = newWidth;
3044 data.mHeight = newHeight;
Shimeng (Simon) Wanga0cc8642011-02-03 10:24:03 -08003045 data.mHeightWidthRatio = heightWidthRatio;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003046 data.mActualViewHeight = actualViewHeight;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003047 data.mTextWrapWidth = Math.round(viewWidth / mZoomManager.getTextWrapScale());
3048 data.mScale = mZoomManager.getScale();
Derek Sollenberger293c3602010-06-04 10:44:48 -04003049 data.mIgnoreHeight = mZoomManager.isFixedLengthAnimationInProgress()
3050 && !mHeightCanMeasure;
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04003051 data.mAnchorX = mZoomManager.getDocumentAnchorX();
3052 data.mAnchorY = mZoomManager.getDocumentAnchorY();
Grace Klobaef347ef2009-07-30 11:20:32 -07003053 mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003054 mLastWidthSent = newWidth;
3055 mLastHeightSent = newHeight;
Shimeng (Simon) Wang48fc9092011-02-03 14:29:54 -08003056 mLastActualHeightSent = actualViewHeight;
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04003057 mZoomManager.clearDocumentAnchor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003058 return true;
3059 }
3060 return false;
3061 }
3062
Mangesh Ghiwareedb528e2011-10-12 14:25:41 -07003063 /**
3064 * Update the double-tap zoom.
3065 */
Mangesh Ghiwarebb99e282011-10-21 10:53:29 -07003066 /* package */ void updateDoubleTapZoom(int doubleTapZoom) {
3067 mZoomManager.updateDoubleTapZoom(doubleTapZoom);
Mangesh Ghiwareedb528e2011-10-12 14:25:41 -07003068 }
3069
Adam Powell637d3372010-08-25 14:37:03 -07003070 private int computeRealHorizontalScrollRange() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003071 if (mDrawHistory) {
3072 return mHistoryWidth;
3073 } else {
Grace Klobae621d6f2009-09-11 13:20:39 -07003074 // to avoid rounding error caused unnecessary scrollbar, use floor
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003075 return (int) Math.floor(mContentWidth * mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 }
3077 }
3078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003079 @Override
Adam Powell637d3372010-08-25 14:37:03 -07003080 protected int computeHorizontalScrollRange() {
3081 int range = computeRealHorizontalScrollRange();
3082
3083 // Adjust reported range if overscrolled to compress the scroll bars
3084 final int scrollX = mScrollX;
3085 final int overscrollRight = computeMaxScrollX();
3086 if (scrollX < 0) {
3087 range -= scrollX;
3088 } else if (scrollX > overscrollRight) {
3089 range += scrollX - overscrollRight;
3090 }
3091
3092 return range;
3093 }
3094
3095 @Override
3096 protected int computeHorizontalScrollOffset() {
3097 return Math.max(mScrollX, 0);
3098 }
3099
3100 private int computeRealVerticalScrollRange() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 if (mDrawHistory) {
3102 return mHistoryHeight;
3103 } else {
Grace Klobae621d6f2009-09-11 13:20:39 -07003104 // to avoid rounding error caused unnecessary scrollbar, use floor
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04003105 return (int) Math.floor(mContentHeight * mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003106 }
3107 }
3108
Leon Scroggins0236e672009-09-02 21:12:08 -04003109 @Override
Adam Powell637d3372010-08-25 14:37:03 -07003110 protected int computeVerticalScrollRange() {
3111 int range = computeRealVerticalScrollRange();
3112
3113 // Adjust reported range if overscrolled to compress the scroll bars
3114 final int scrollY = mScrollY;
3115 final int overscrollBottom = computeMaxScrollY();
3116 if (scrollY < 0) {
3117 range -= scrollY;
3118 } else if (scrollY > overscrollBottom) {
3119 range += scrollY - overscrollBottom;
3120 }
3121
3122 return range;
3123 }
3124
3125 @Override
Leon Scroggins0236e672009-09-02 21:12:08 -04003126 protected int computeVerticalScrollOffset() {
Mike Reede8853fc2009-09-04 14:01:48 -04003127 return Math.max(mScrollY - getTitleHeight(), 0);
Leon Scroggins0236e672009-09-02 21:12:08 -04003128 }
3129
3130 @Override
3131 protected int computeVerticalScrollExtent() {
3132 return getViewHeight();
3133 }
3134
Mike Reede8853fc2009-09-04 14:01:48 -04003135 /** @hide */
3136 @Override
3137 protected void onDrawVerticalScrollBar(Canvas canvas,
3138 Drawable scrollBar,
3139 int l, int t, int r, int b) {
Adam Powell637d3372010-08-25 14:37:03 -07003140 if (mScrollY < 0) {
3141 t -= mScrollY;
3142 }
Steve Block92c99162011-05-23 17:36:01 +01003143 scrollBar.setBounds(l, t + getVisibleTitleHeightImpl(), r, b);
Mike Reede8853fc2009-09-04 14:01:48 -04003144 scrollBar.draw(canvas);
3145 }
3146
Adam Powell637d3372010-08-25 14:37:03 -07003147 @Override
3148 protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
3149 boolean clampedY) {
Patrick Scott62310912010-12-06 17:44:50 -05003150 // Special-case layer scrolling so that we do not trigger normal scroll
3151 // updating.
3152 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
John Reck83b9e1d2011-11-02 10:18:12 -07003153 scrollLayerTo(scrollX, scrollY);
Patrick Scott62310912010-12-06 17:44:50 -05003154 return;
3155 }
Adam Powell637d3372010-08-25 14:37:03 -07003156 mInOverScrollMode = false;
3157 int maxX = computeMaxScrollX();
3158 int maxY = computeMaxScrollY();
3159 if (maxX == 0) {
3160 // do not over scroll x if the page just fits the screen
3161 scrollX = pinLocX(scrollX);
3162 } else if (scrollX < 0 || scrollX > maxX) {
3163 mInOverScrollMode = true;
3164 }
3165 if (scrollY < 0 || scrollY > maxY) {
3166 mInOverScrollMode = true;
3167 }
3168
3169 int oldX = mScrollX;
3170 int oldY = mScrollY;
3171
3172 super.scrollTo(scrollX, scrollY);
3173
3174 if (mOverScrollGlow != null) {
3175 mOverScrollGlow.pullGlow(mScrollX, mScrollY, oldX, oldY, maxX, maxY);
3176 }
3177 }
3178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 /**
3180 * Get the url for the current page. This is not always the same as the url
3181 * passed to WebViewClient.onPageStarted because although the load for
3182 * that url has begun, the current page may not have changed.
3183 * @return The url for the current page.
3184 */
3185 public String getUrl() {
Steve Block51b08912011-04-27 15:04:48 +01003186 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3188 return h != null ? h.getUrl() : null;
3189 }
Cary Clarkd6982c92009-05-29 11:02:22 -04003190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003191 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04003192 * Get the original url for the current page. This is not always the same
3193 * as the url passed to WebViewClient.onPageStarted because although the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 * load for that url has begun, the current page may not have changed.
3195 * Also, there may have been redirects resulting in a different url to that
3196 * originally requested.
3197 * @return The url that was originally requested for the current page.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003198 */
3199 public String getOriginalUrl() {
Steve Block51b08912011-04-27 15:04:48 +01003200 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3202 return h != null ? h.getOriginalUrl() : null;
3203 }
3204
3205 /**
3206 * Get the title for the current page. This is the title of the current page
3207 * until WebViewClient.onReceivedTitle is called.
3208 * @return The title for the current page.
3209 */
3210 public String getTitle() {
Steve Block51b08912011-04-27 15:04:48 +01003211 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3213 return h != null ? h.getTitle() : null;
3214 }
3215
3216 /**
3217 * Get the favicon for the current page. This is the favicon of the current
3218 * page until WebViewClient.onReceivedIcon is called.
3219 * @return The favicon for the current page.
3220 */
3221 public Bitmap getFavicon() {
Steve Block51b08912011-04-27 15:04:48 +01003222 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3224 return h != null ? h.getFavicon() : null;
3225 }
3226
3227 /**
Ben Murdoch372dfc82010-07-01 15:56:01 +01003228 * Get the touch icon url for the apple-touch-icon <link> element, or
3229 * a URL on this site's server pointing to the standard location of a
3230 * touch icon.
Patrick Scott2ba12622009-08-04 13:20:05 -04003231 * @hide
3232 */
3233 public String getTouchIconUrl() {
3234 WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
3235 return h != null ? h.getTouchIconUrl() : null;
3236 }
3237
3238 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 * Get the progress for the current page.
3240 * @return The progress for the current page between 0 and 100.
3241 */
3242 public int getProgress() {
Steve Block51b08912011-04-27 15:04:48 +01003243 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244 return mCallbackProxy.getProgress();
3245 }
Cary Clarkd6982c92009-05-29 11:02:22 -04003246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247 /**
3248 * @return the height of the HTML content.
3249 */
3250 public int getContentHeight() {
Steve Block51b08912011-04-27 15:04:48 +01003251 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 return mContentHeight;
3253 }
3254
3255 /**
Leon Scrogginsea96d1e2009-09-23 13:41:01 -04003256 * @return the width of the HTML content.
3257 * @hide
3258 */
3259 public int getContentWidth() {
3260 return mContentWidth;
3261 }
3262
3263 /**
John Reck9b90d552011-06-14 15:19:17 -07003264 * @hide
3265 */
3266 public int getPageBackgroundColor() {
3267 return nativeGetBackgroundColor();
3268 }
3269
3270 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003271 * Pause all layout, parsing, and JavaScript timers for all webviews. This
Mike Reedd205d5b2009-05-27 11:02:29 -04003272 * is a global requests, not restricted to just this webview. This can be
3273 * useful if the application has been paused.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 */
3275 public void pauseTimers() {
Steve Block51b08912011-04-27 15:04:48 +01003276 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
3278 }
3279
3280 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003281 * Resume all layout, parsing, and JavaScript timers for all webviews.
Mike Reedd205d5b2009-05-27 11:02:29 -04003282 * This will resume dispatching all timers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 */
3284 public void resumeTimers() {
Steve Block51b08912011-04-27 15:04:48 +01003285 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
3287 }
3288
3289 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003290 * Call this to pause any extra processing associated with this WebView and
3291 * its associated DOM, plugins, JavaScript etc. For example, if the WebView
3292 * is taken offscreen, this could be called to reduce unnecessary CPU or
3293 * network traffic. When the WebView is again "active", call onResume().
Mike Reedd205d5b2009-05-27 11:02:29 -04003294 *
Steve Block81f19ff2010-11-01 13:23:24 +00003295 * Note that this differs from pauseTimers(), which affects all WebViews.
Mike Reedd205d5b2009-05-27 11:02:29 -04003296 */
3297 public void onPause() {
Steve Block51b08912011-04-27 15:04:48 +01003298 checkThread();
Mike Reedd205d5b2009-05-27 11:02:29 -04003299 if (!mIsPaused) {
3300 mIsPaused = true;
3301 mWebViewCore.sendMessage(EventHub.ON_PAUSE);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08003302 // We want to pause the current playing video when switching out
3303 // from the current WebView/tab.
3304 if (mHTML5VideoViewProxy != null) {
3305 mHTML5VideoViewProxy.pauseAndDispatch();
3306 }
John Reck5f1c5492011-11-09 16:23:07 -08003307 if (mNativeClass != 0) {
3308 nativeSetPauseDrawing(mNativeClass, true);
3309 }
Ben Murdoch2ffc9ec2011-11-28 15:41:31 +00003310
3311 cancelSelectDialog();
John Reck5f1c5492011-11-09 16:23:07 -08003312 }
3313 }
3314
3315 @Override
3316 protected void onWindowVisibilityChanged(int visibility) {
3317 super.onWindowVisibilityChanged(visibility);
3318 updateDrawingState();
3319 }
3320
3321 void updateDrawingState() {
3322 if (mNativeClass == 0 || mIsPaused) return;
3323 if (getWindowVisibility() != VISIBLE) {
3324 nativeSetPauseDrawing(mNativeClass, true);
3325 } else if (getVisibility() != VISIBLE) {
3326 nativeSetPauseDrawing(mNativeClass, true);
3327 } else {
3328 nativeSetPauseDrawing(mNativeClass, false);
Mike Reedd205d5b2009-05-27 11:02:29 -04003329 }
3330 }
3331
3332 /**
Steve Block81f19ff2010-11-01 13:23:24 +00003333 * Call this to resume a WebView after a previous call to onPause().
Mike Reedd205d5b2009-05-27 11:02:29 -04003334 */
3335 public void onResume() {
Steve Block51b08912011-04-27 15:04:48 +01003336 checkThread();
Mike Reedd205d5b2009-05-27 11:02:29 -04003337 if (mIsPaused) {
3338 mIsPaused = false;
3339 mWebViewCore.sendMessage(EventHub.ON_RESUME);
John Reck5f1c5492011-11-09 16:23:07 -08003340 if (mNativeClass != 0) {
3341 nativeSetPauseDrawing(mNativeClass, false);
3342 }
Mike Reedd205d5b2009-05-27 11:02:29 -04003343 }
3344 }
3345
3346 /**
3347 * Returns true if the view is paused, meaning onPause() was called. Calling
3348 * onResume() sets the paused state back to false.
3349 * @hide
3350 */
3351 public boolean isPaused() {
3352 return mIsPaused;
3353 }
3354
3355 /**
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003356 * Call this to inform the view that memory is low so that it can
3357 * free any available memory.
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003358 */
3359 public void freeMemory() {
Steve Block51b08912011-04-27 15:04:48 +01003360 checkThread();
Derek Sollenbergere0155e92009-06-10 15:35:45 -04003361 mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
3362 }
3363
3364 /**
Mike Hearnadcd2ed2009-01-21 16:44:36 +01003365 * Clear the resource cache. Note that the cache is per-application, so
3366 * this will clear the cache for all WebViews used.
3367 *
3368 * @param includeDiskFiles If false, only the RAM cache is cleared.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 */
3370 public void clearCache(boolean includeDiskFiles) {
Steve Block51b08912011-04-27 15:04:48 +01003371 checkThread();
Mike Hearnadcd2ed2009-01-21 16:44:36 +01003372 // Note: this really needs to be a static method as it clears cache for all
3373 // WebView. But we need mWebViewCore to send message to WebCore thread, so
3374 // we can't make this static.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
3376 includeDiskFiles ? 1 : 0, 0);
3377 }
3378
3379 /**
3380 * Make sure that clearing the form data removes the adapter from the
3381 * currently focused textfield if there is one.
3382 */
3383 public void clearFormData() {
Steve Block51b08912011-04-27 15:04:48 +01003384 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 if (inEditingMode()) {
John Recka6070602011-10-05 18:26:57 -07003386 mWebTextView.setAdapterCustom(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003387 }
3388 }
3389
3390 /**
3391 * Tell the WebView to clear its internal back/forward list.
3392 */
3393 public void clearHistory() {
Steve Block51b08912011-04-27 15:04:48 +01003394 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 mCallbackProxy.getBackForwardList().setClearPending();
3396 mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
3397 }
3398
3399 /**
3400 * Clear the SSL preferences table stored in response to proceeding with SSL
3401 * certificate errors.
3402 */
3403 public void clearSslPreferences() {
Steve Block51b08912011-04-27 15:04:48 +01003404 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
3406 }
3407
3408 /**
3409 * Return the WebBackForwardList for this WebView. This contains the
3410 * back/forward list for use in querying each item in the history stack.
3411 * This is a copy of the private WebBackForwardList so it contains only a
3412 * snapshot of the current state. Multiple calls to this method may return
3413 * different objects. The object returned from this method will not be
3414 * updated to reflect any new state.
3415 */
3416 public WebBackForwardList copyBackForwardList() {
Steve Block51b08912011-04-27 15:04:48 +01003417 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 return mCallbackProxy.getBackForwardList().clone();
3419 }
3420
3421 /*
3422 * Highlight and scroll to the next occurance of String in findAll.
Cary Clarkd6982c92009-05-29 11:02:22 -04003423 * Wraps the page infinitely, and scrolls. Must be called after
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 * calling findAll.
3425 *
3426 * @param forward Direction to search.
3427 */
3428 public void findNext(boolean forward) {
Steve Block51b08912011-04-27 15:04:48 +01003429 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04003430 if (0 == mNativeClass) return; // client isn't initialized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 nativeFindNext(forward);
3432 }
3433
3434 /*
3435 * Find all instances of find on the page and highlight them.
3436 * @param find String to find.
3437 * @return int The number of occurances of the String "find"
3438 * that were found.
3439 */
3440 public int findAll(String find) {
Steve Block51b08912011-04-27 15:04:48 +01003441 checkThread();
Cary Clark7f970112009-10-15 15:29:08 -04003442 if (0 == mNativeClass) return 0; // client isn't initialized
Cary Clarkde023c12010-03-03 10:05:16 -05003443 int result = find != null ? nativeFindAll(find.toLowerCase(),
Leon Scroggins4f4a5672010-10-19 13:58:11 -04003444 find.toUpperCase(), find.equalsIgnoreCase(mLastFind)) : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003445 invalidate();
Leon Scroggins5de63892009-10-29 09:48:43 -04003446 mLastFind = find;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003447 return result;
3448 }
3449
Cary Clark3403eb32010-03-03 10:05:16 -05003450 /**
Leon Scroggins93553d72011-03-08 11:43:40 -05003451 * Start an ActionMode for finding text in this WebView. Only works if this
3452 * WebView is attached to the view system.
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003453 * @param text If non-null, will be the initial text to search for.
3454 * Otherwise, the last String searched for in this WebView will
3455 * be used to start.
Leon Scroggins571354f2011-01-04 10:12:41 -05003456 * @param showIme If true, show the IME, assuming the user will begin typing.
3457 * If false and text is non-null, perform a find all.
3458 * @return boolean True if the find dialog is shown, false otherwise.
Cary Clarkde023c12010-03-03 10:05:16 -05003459 */
Leon Scroggins571354f2011-01-04 10:12:41 -05003460 public boolean showFindDialog(String text, boolean showIme) {
Steve Block51b08912011-04-27 15:04:48 +01003461 checkThread();
Leon Scroggins19abf2d2011-01-10 14:50:04 -05003462 FindActionModeCallback callback = new FindActionModeCallback(mContext);
Leon Scroggins93553d72011-03-08 11:43:40 -05003463 if (getParent() == null || startActionMode(callback) == null) {
Leon Scroggins571354f2011-01-04 10:12:41 -05003464 // Could not start the action mode, so end Find on page
Leon Scroggins571354f2011-01-04 10:12:41 -05003465 return false;
3466 }
John Reckd6ac7272011-11-08 15:00:17 -08003467 mCachedOverlappingActionModeHeight = -1;
Leon Scroggins19abf2d2011-01-10 14:50:04 -05003468 mFindCallback = callback;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003469 setFindIsUp(true);
3470 mFindCallback.setWebView(this);
Leon Scroggins571354f2011-01-04 10:12:41 -05003471 if (showIme) {
3472 mFindCallback.showSoftInput();
3473 } else if (text != null) {
3474 mFindCallback.setText(text);
3475 mFindCallback.findAll();
3476 return true;
3477 }
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003478 if (text == null) {
3479 text = mLastFind;
3480 }
3481 if (text != null) {
3482 mFindCallback.setText(text);
3483 }
Leon Scroggins571354f2011-01-04 10:12:41 -05003484 return true;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003485 }
3486
3487 /**
3488 * Keep track of the find callback so that we can remove its titlebar if
3489 * necessary.
3490 */
3491 private FindActionModeCallback mFindCallback;
3492
3493 /**
3494 * Toggle whether the find dialog is showing, for both native and Java.
3495 */
3496 private void setFindIsUp(boolean isUp) {
Cary Clarkde023c12010-03-03 10:05:16 -05003497 mFindIsUp = isUp;
Cary Clarkde023c12010-03-03 10:05:16 -05003498 if (0 == mNativeClass) return; // client isn't initialized
3499 nativeSetFindIsUp(isUp);
3500 }
3501
Leon Scroggins III26723fc2010-04-19 13:21:42 -04003502 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003503 * Return the index of the currently highlighted match.
Leon Scroggins III26723fc2010-04-19 13:21:42 -04003504 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003505 int findIndex() {
Leon Scroggins6a367f52010-05-06 17:37:40 -04003506 if (0 == mNativeClass) return -1;
3507 return nativeFindIndex();
3508 }
3509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003510 // Used to know whether the find dialog is open. Affects whether
3511 // or not we draw the highlights for matches.
3512 private boolean mFindIsUp;
Cary Clarkde023c12010-03-03 10:05:16 -05003513
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003514 // Keep track of the last string sent, so we can search again when find is
3515 // reopened.
Leon Scroggins5de63892009-10-29 09:48:43 -04003516 private String mLastFind;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04003519 * Return the first substring consisting of the address of a physical
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 * location. Currently, only addresses in the United States are detected,
3521 * and consist of:
3522 * - a house number
3523 * - a street name
3524 * - a street type (Road, Circle, etc), either spelled out or abbreviated
3525 * - a city name
3526 * - a state or territory, either spelled out or two-letter abbr.
3527 * - an optional 5 digit or 9 digit zip code.
3528 *
3529 * All names must be correctly capitalized, and the zip code, if present,
3530 * must be valid for the state. The street type must be a standard USPS
3531 * spelling or abbreviation. The state or territory must also be spelled
Cary Clarkd6982c92009-05-29 11:02:22 -04003532 * or abbreviated using USPS standards. The house number may not exceed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003533 * five digits.
3534 * @param addr The string to search for addresses.
3535 *
3536 * @return the address, or if no address is found, return null.
3537 */
3538 public static String findAddress(String addr) {
Steve Block51b08912011-04-27 15:04:48 +01003539 checkThread();
Cary Clark3e399de2009-06-17 10:00:57 -04003540 return findAddress(addr, false);
3541 }
3542
3543 /**
3544 * @hide
3545 * Return the first substring consisting of the address of a physical
3546 * location. Currently, only addresses in the United States are detected,
3547 * and consist of:
3548 * - a house number
3549 * - a street name
3550 * - a street type (Road, Circle, etc), either spelled out or abbreviated
3551 * - a city name
3552 * - a state or territory, either spelled out or two-letter abbr.
3553 * - an optional 5 digit or 9 digit zip code.
3554 *
3555 * Names are optionally capitalized, and the zip code, if present,
3556 * must be valid for the state. The street type must be a standard USPS
3557 * spelling or abbreviation. The state or territory must also be spelled
3558 * or abbreviated using USPS standards. The house number may not exceed
3559 * five digits.
3560 * @param addr The string to search for addresses.
3561 * @param caseInsensitive addr Set to true to make search ignore case.
3562 *
3563 * @return the address, or if no address is found, return null.
3564 */
3565 public static String findAddress(String addr, boolean caseInsensitive) {
3566 return WebViewCore.nativeFindAddress(addr, caseInsensitive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567 }
3568
3569 /*
3570 * Clear the highlighting surrounding text matches created by findAll.
3571 */
3572 public void clearMatches() {
Steve Block51b08912011-04-27 15:04:48 +01003573 checkThread();
Cary Clark32847a92009-11-17 16:04:18 -05003574 if (mNativeClass == 0)
3575 return;
Cary Clarkde023c12010-03-03 10:05:16 -05003576 nativeSetFindIsEmpty();
3577 invalidate();
3578 }
3579
3580 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003581 * Called when the find ActionMode ends.
Cary Clarkde023c12010-03-03 10:05:16 -05003582 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04003583 void notifyFindDialogDismissed() {
3584 mFindCallback = null;
John Reckd6ac7272011-11-08 15:00:17 -08003585 mCachedOverlappingActionModeHeight = -1;
Shimeng (Simon) Wang4d8ef422010-03-22 17:06:17 -07003586 if (mWebViewCore == null) {
3587 return;
3588 }
Cary Clarkde023c12010-03-03 10:05:16 -05003589 clearMatches();
3590 setFindIsUp(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 // Now that the dialog has been removed, ensure that we scroll to a
3592 // location that is not beyond the end of the page.
3593 pinScrollTo(mScrollX, mScrollY, false, 0);
3594 invalidate();
3595 }
3596
3597 /**
3598 * Query the document to see if it contains any image references. The
3599 * message object will be dispatched with arg1 being set to 1 if images
3600 * were found and 0 if the document does not reference any images.
3601 * @param response The message that will be dispatched with the result.
3602 */
3603 public void documentHasImages(Message response) {
Steve Block51b08912011-04-27 15:04:48 +01003604 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003605 if (response == null) {
3606 return;
3607 }
3608 mWebViewCore.sendMessage(EventHub.DOC_HAS_IMAGES, response);
3609 }
3610
Michael Kolb73980a92010-08-05 16:32:51 -07003611 /**
3612 * Request the scroller to abort any ongoing animation
3613 *
3614 * @hide
3615 */
3616 public void stopScroll() {
3617 mScroller.forceFinished(true);
3618 mLastVelocity = 0;
3619 }
3620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003621 @Override
3622 public void computeScroll() {
3623 if (mScroller.computeScrollOffset()) {
3624 int oldX = mScrollX;
3625 int oldY = mScrollY;
Adam Powell637d3372010-08-25 14:37:03 -07003626 int x = mScroller.getCurrX();
3627 int y = mScroller.getCurrY();
3628 invalidate(); // So we draw again
3629
3630 if (!mScroller.isFinished()) {
Patrick Scott62310912010-12-06 17:44:50 -05003631 int rangeX = computeMaxScrollX();
3632 int rangeY = computeMaxScrollY();
3633 int overflingDistance = mOverflingDistance;
3634
3635 // Use the layer's scroll data if needed.
3636 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
3637 oldX = mScrollingLayerRect.left;
3638 oldY = mScrollingLayerRect.top;
3639 rangeX = mScrollingLayerRect.right;
3640 rangeY = mScrollingLayerRect.bottom;
3641 // No overscrolling for layers.
3642 overflingDistance = 0;
3643 }
3644
Adam Powell637d3372010-08-25 14:37:03 -07003645 overScrollBy(x - oldX, y - oldY, oldX, oldY,
3646 rangeX, rangeY,
Patrick Scott62310912010-12-06 17:44:50 -05003647 overflingDistance, overflingDistance, false);
Adam Powell637d3372010-08-25 14:37:03 -07003648
3649 if (mOverScrollGlow != null) {
3650 mOverScrollGlow.absorbGlow(x, y, oldX, oldY, rangeX, rangeY);
3651 }
3652 } else {
Patrick Scott62310912010-12-06 17:44:50 -05003653 if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
3654 mScrollX = x;
3655 mScrollY = y;
3656 } else {
3657 // Update the layer position instead of WebView.
John Reck83b9e1d2011-11-02 10:18:12 -07003658 scrollLayerTo(x, y);
Patrick Scott62310912010-12-06 17:44:50 -05003659 }
Adam Powell4c3ce842010-11-23 17:39:56 -08003660 abortAnimation();
Chris Craik58d94af2011-08-18 11:42:13 -07003661 nativeSetIsScrolling(false);
John Reck95b7d6f2011-06-03 15:23:43 -07003662 if (!mBlockWebkitViewMessages) {
3663 WebViewCore.resumePriority();
3664 if (!mSelectingText) {
3665 WebViewCore.resumeUpdatePicture(mWebViewCore);
3666 }
Cary Clark0df02692010-11-24 11:01:37 -05003667 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05003668 if (oldX != mScrollX || oldY != mScrollY) {
3669 sendOurVisibleRect();
3670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003671 }
3672 } else {
3673 super.computeScroll();
3674 }
3675 }
3676
John Reck83b9e1d2011-11-02 10:18:12 -07003677 private void scrollLayerTo(int x, int y) {
3678 if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
3679 return;
3680 }
Michael Kolb5da91bd2011-11-29 15:29:03 -08003681 nativeScrollLayer(mCurrentScrollingLayerId, x, y);
John Reck83b9e1d2011-11-02 10:18:12 -07003682 mScrollingLayerRect.left = x;
3683 mScrollingLayerRect.top = y;
3684 onScrollChanged(mScrollX, mScrollY, mScrollX, mScrollY);
3685 invalidate();
3686 }
3687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688 private static int computeDuration(int dx, int dy) {
3689 int distance = Math.max(Math.abs(dx), Math.abs(dy));
3690 int duration = distance * 1000 / STD_SPEED;
3691 return Math.min(duration, MAX_DURATION);
3692 }
3693
3694 // helper to pin the scrollBy parameters (already in view coordinates)
3695 // returns true if the scroll was changed
3696 private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) {
3697 return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
3698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003699 // helper to pin the scrollTo parameters (already in view coordinates)
3700 // returns true if the scroll was changed
3701 private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) {
3702 x = pinLocX(x);
3703 y = pinLocY(y);
3704 int dx = x - mScrollX;
3705 int dy = y - mScrollY;
3706
3707 if ((dx | dy) == 0) {
3708 return false;
3709 }
Cary Clark21a97ef2010-11-16 09:59:40 -05003710 abortAnimation();
Leon Scrogginsd55de402009-09-17 14:19:49 -04003711 if (animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003712 // Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 mScroller.startScroll(mScrollX, mScrollY, dx, dy,
3714 animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
Mike Cleronf116bf82009-09-27 19:14:12 -07003715 awakenScrollBars(mScroller.getDuration());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003716 invalidate();
3717 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003718 scrollTo(x, y);
3719 }
3720 return true;
3721 }
3722
3723 // Scale from content to view coordinates, and pin.
3724 // Also called by jni webview.cpp
Leon Scroggins4c943042009-07-31 15:05:42 -04003725 private boolean setContentScrollBy(int cx, int cy, boolean animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003726 if (mDrawHistory) {
3727 // disallow WebView to change the scroll position as History Picture
3728 // is used in the view system.
3729 // TODO: as we switchOutDrawHistory when trackball or navigation
3730 // keys are hit, this should be safe. Right?
Leon Scroggins4c943042009-07-31 15:05:42 -04003731 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732 }
Mike Reede8853fc2009-09-04 14:01:48 -04003733 cx = contentToViewDimension(cx);
3734 cy = contentToViewDimension(cy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003735 if (mHeightCanMeasure) {
3736 // move our visible rect according to scroll request
3737 if (cy != 0) {
3738 Rect tempRect = new Rect();
3739 calcOurVisibleRect(tempRect);
3740 tempRect.offset(cx, cy);
3741 requestRectangleOnScreen(tempRect);
3742 }
3743 // FIXME: We scroll horizontally no matter what because currently
3744 // ScrollView and ListView will not scroll horizontally.
3745 // FIXME: Why do we only scroll horizontally if there is no
3746 // vertical scroll?
3747// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
Leon Scroggins4c943042009-07-31 15:05:42 -04003748 return cy == 0 && cx != 0 && pinScrollBy(cx, 0, animate, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003749 } else {
Leon Scroggins4c943042009-07-31 15:05:42 -04003750 return pinScrollBy(cx, cy, animate, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 }
3752 }
3753
Leon Scroggins405d7852009-11-02 14:50:54 -08003754 /**
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003755 * Called by CallbackProxy when the page starts loading.
3756 * @param url The URL of the page which has started loading.
3757 */
3758 /* package */ void onPageStarted(String url) {
3759 // every time we start a new page, we want to reset the
3760 // WebView certificate: if the new site is secure, we
3761 // will reload it and get a new certificate set;
3762 // if the new site is not secure, the certificate must be
3763 // null, and that will be the case
3764 setCertificate(null);
3765
3766 // reset the flag since we set to true in if need after
3767 // loading is see onPageFinished(Url)
3768 mAccessibilityScriptInjected = false;
3769 }
3770
3771 /**
Leon Scroggins405d7852009-11-02 14:50:54 -08003772 * Called by CallbackProxy when the page finishes loading.
3773 * @param url The URL of the page which has finished loading.
3774 */
3775 /* package */ void onPageFinished(String url) {
3776 if (mPageThatNeedsToSlideTitleBarOffScreen != null) {
3777 // If the user is now on a different page, or has scrolled the page
3778 // past the point where the title bar is offscreen, ignore the
3779 // scroll request.
3780 if (mPageThatNeedsToSlideTitleBarOffScreen.equals(url)
3781 && mScrollX == 0 && mScrollY == 0) {
3782 pinScrollTo(0, mYDistanceToSlideTitleOffScreen, true,
3783 SLIDE_TITLE_DURATION);
3784 }
3785 mPageThatNeedsToSlideTitleBarOffScreen = null;
3786 }
Shimeng (Simon) Wangd75fd492011-02-16 14:52:13 -08003787 mZoomManager.onPageFinished(url);
Svetoslav Ganovda355512010-05-12 22:04:44 -07003788 injectAccessibilityForUrl(url);
3789 }
3790
3791 /**
3792 * This method injects accessibility in the loaded document if accessibility
3793 * is enabled. If JavaScript is enabled we try to inject a URL specific script.
3794 * If no URL specific script is found or JavaScript is disabled we fallback to
3795 * the default {@link AccessibilityInjector} implementation.
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003796 * </p>
3797 * If the URL has the "axs" paramter set to 1 it has already done the
3798 * script injection so we do nothing. If the parameter is set to 0
3799 * the URL opts out accessibility script injection so we fall back to
3800 * the default {@link AccessibilityInjector}.
3801 * </p>
3802 * Note: If the user has not opted-in the accessibility script injection no scripts
3803 * are injected rather the default {@link AccessibilityInjector} implementation
3804 * is used.
Svetoslav Ganovda355512010-05-12 22:04:44 -07003805 *
3806 * @param url The URL loaded by this {@link WebView}.
3807 */
3808 private void injectAccessibilityForUrl(String url) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08003809 if (mWebViewCore == null) {
3810 return;
3811 }
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003812 AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
3813
3814 if (!accessibilityManager.isEnabled()) {
Svetoslav Ganovda355512010-05-12 22:04:44 -07003815 // it is possible that accessibility was turned off between reloads
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003816 ensureAccessibilityScriptInjectorInstance(false);
3817 return;
3818 }
3819
3820 if (!getSettings().getJavaScriptEnabled()) {
3821 // no JS so we fallback to the basic buil-in support
3822 ensureAccessibilityScriptInjectorInstance(true);
3823 return;
3824 }
3825
3826 // check the URL "axs" parameter to choose appropriate action
3827 int axsParameterValue = getAxsUrlParameterValue(url);
3828 if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED) {
3829 boolean onDeviceScriptInjectionEnabled = (Settings.Secure.getInt(mContext
3830 .getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
3831 if (onDeviceScriptInjectionEnabled) {
3832 ensureAccessibilityScriptInjectorInstance(false);
3833 // neither script injected nor script injection opted out => we inject
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -08003834 loadUrl(getScreenReaderInjectingJs());
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003835 // TODO: Set this flag after successfull script injection. Maybe upon injection
3836 // the chooser should update the meta tag and we check it to declare success
3837 mAccessibilityScriptInjected = true;
3838 } else {
3839 // injection disabled so we fallback to the basic built-in support
3840 ensureAccessibilityScriptInjectorInstance(true);
3841 }
3842 } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) {
3843 // injection opted out so we fallback to the basic buil-in support
3844 ensureAccessibilityScriptInjectorInstance(true);
3845 } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
3846 ensureAccessibilityScriptInjectorInstance(false);
3847 // the URL provides accessibility but we still need to add our generic script
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -08003848 loadUrl(getScreenReaderInjectingJs());
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003849 } else {
3850 Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
3851 }
3852 }
3853
3854 /**
3855 * Ensures the instance of the {@link AccessibilityInjector} to be present ot not.
3856 *
3857 * @param present True to ensure an insance, false to ensure no instance.
3858 */
3859 private void ensureAccessibilityScriptInjectorInstance(boolean present) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08003860 if (present) {
3861 if (mAccessibilityInjector == null) {
3862 mAccessibilityInjector = new AccessibilityInjector(this);
3863 }
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003864 } else {
Svetoslav Ganovda355512010-05-12 22:04:44 -07003865 mAccessibilityInjector = null;
3866 }
Leon Scroggins405d7852009-11-02 14:50:54 -08003867 }
3868
3869 /**
Svetoslav Ganov3ca5a742011-12-06 15:24:37 -08003870 * Gets JavaScript that injects a screen-reader.
3871 *
3872 * @return The JavaScript snippet.
3873 */
3874 private String getScreenReaderInjectingJs() {
3875 String screenReaderUrl = Settings.Secure.getString(mContext.getContentResolver(),
3876 Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
3877 return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
3878 }
3879
3880 /**
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07003881 * Gets the "axs" URL parameter value.
3882 *
3883 * @param url A url to fetch the paramter from.
3884 * @return The parameter value if such, -1 otherwise.
3885 */
3886 private int getAxsUrlParameterValue(String url) {
3887 if (mMatchAxsUrlParameterPattern == null) {
3888 mMatchAxsUrlParameterPattern = Pattern.compile(PATTERN_MATCH_AXS_URL_PARAMETER);
3889 }
3890 Matcher matcher = mMatchAxsUrlParameterPattern.matcher(url);
3891 if (matcher.find()) {
3892 String keyValuePair = url.substring(matcher.start(), matcher.end());
3893 return Integer.parseInt(keyValuePair.split("=")[1]);
3894 }
3895 return -1;
3896 }
3897
3898 /**
Leon Scroggins405d7852009-11-02 14:50:54 -08003899 * The URL of a page that sent a message to scroll the title bar off screen.
3900 *
3901 * Many mobile sites tell the page to scroll to (0,1) in order to scroll the
3902 * title bar off the screen. Sometimes, the scroll position is set before
3903 * the page finishes loading. Rather than scrolling while the page is still
3904 * loading, keep track of the URL and new scroll position so we can perform
3905 * the scroll once the page finishes loading.
3906 */
3907 private String mPageThatNeedsToSlideTitleBarOffScreen;
3908
3909 /**
3910 * The destination Y scroll position to be used when the page finishes
3911 * loading. See mPageThatNeedsToSlideTitleBarOffScreen.
3912 */
3913 private int mYDistanceToSlideTitleOffScreen;
3914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003915 // scale from content to view coordinates, and pin
Leon Scroggins83d4ba82009-09-17 17:27:13 -04003916 // return true if pin caused the final x/y different than the request cx/cy,
3917 // and a future scroll may reach the request cx/cy after our size has
3918 // changed
3919 // return false if the view scroll to the exact position as it is requested,
3920 // where negative numbers are taken to mean 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003921 private boolean setContentScrollTo(int cx, int cy) {
3922 if (mDrawHistory) {
3923 // disallow WebView to change the scroll position as History Picture
3924 // is used in the view system.
3925 // One known case where this is called is that WebCore tries to
3926 // restore the scroll position. As history Picture already uses the
3927 // saved scroll position, it is ok to skip this.
3928 return false;
3929 }
Leon Scrogginsd7b95aa2009-09-21 13:27:02 -04003930 int vx;
3931 int vy;
3932 if ((cx | cy) == 0) {
3933 // If the page is being scrolled to (0,0), do not add in the title
3934 // bar's height, and simply scroll to (0,0). (The only other work
3935 // in contentToView_ is to multiply, so this would not change 0.)
3936 vx = 0;
3937 vy = 0;
3938 } else {
3939 vx = contentToViewX(cx);
3940 vy = contentToViewY(cy);
3941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003942// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
3943// vx + " " + vy + "]");
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003944 // Some mobile sites attempt to scroll the title bar off the page by
Leon Scrogginsd7b95aa2009-09-21 13:27:02 -04003945 // scrolling to (0,1). If we are at the top left corner of the
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003946 // page, assume this is an attempt to scroll off the title bar, and
3947 // animate the title bar off screen slowly enough that the user can see
3948 // it.
Leon Scroggins405d7852009-11-02 14:50:54 -08003949 if (cx == 0 && cy == 1 && mScrollX == 0 && mScrollY == 0
3950 && mTitleBar != null) {
3951 // FIXME: 100 should be defined somewhere as our max progress.
3952 if (getProgress() < 100) {
3953 // Wait to scroll the title bar off screen until the page has
3954 // finished loading. Keep track of the URL and the destination
3955 // Y position
3956 mPageThatNeedsToSlideTitleBarOffScreen = getUrl();
3957 mYDistanceToSlideTitleOffScreen = vy;
3958 } else {
3959 pinScrollTo(vx, vy, true, SLIDE_TITLE_DURATION);
3960 }
Leon Scroggins03c87bf2009-09-18 15:05:59 -04003961 // Since we are animating, we have not yet reached the desired
3962 // scroll position. Do not return true to request another attempt
3963 return false;
3964 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003965 pinScrollTo(vx, vy, false, 0);
Leon Scroggins83d4ba82009-09-17 17:27:13 -04003966 // If the request was to scroll to a negative coordinate, treat it as if
3967 // it was a request to scroll to 0
3968 if ((mScrollX != vx && cx >= 0) || (mScrollY != vy && cy >= 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003969 return true;
3970 } else {
3971 return false;
3972 }
3973 }
3974
3975 // scale from content to view coordinates, and pin
3976 private void spawnContentScrollTo(int cx, int cy) {
3977 if (mDrawHistory) {
3978 // disallow WebView to change the scroll position as History Picture
3979 // is used in the view system.
3980 return;
3981 }
Leon Scroggins0236e672009-09-02 21:12:08 -04003982 int vx = contentToViewX(cx);
3983 int vy = contentToViewY(cy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003984 pinScrollTo(vx, vy, true, 0);
3985 }
3986
3987 /**
3988 * These are from webkit, and are in content coordinate system (unzoomed)
3989 */
3990 private void contentSizeChanged(boolean updateLayout) {
3991 // suppress 0,0 since we usually see real dimensions soon after
3992 // this avoids drawing the prev content in a funny place. If we find a
3993 // way to consolidate these notifications, this check may become
3994 // obsolete
3995 if ((mContentWidth | mContentHeight) == 0) {
3996 return;
3997 }
3998
3999 if (mHeightCanMeasure) {
Mike Reede8853fc2009-09-04 14:01:48 -04004000 if (getMeasuredHeight() != contentToViewDimension(mContentHeight)
Grace Kloba3f9faf42009-10-13 14:13:54 -07004001 || updateLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002 requestLayout();
4003 }
4004 } else if (mWidthCanMeasure) {
Mike Reede8853fc2009-09-04 14:01:48 -04004005 if (getMeasuredWidth() != contentToViewDimension(mContentWidth)
Grace Kloba3f9faf42009-10-13 14:13:54 -07004006 || updateLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004007 requestLayout();
4008 }
4009 } else {
4010 // If we don't request a layout, try to send our view size to the
4011 // native side to ensure that WebCore has the correct dimensions.
Derek Sollenberger03e48912010-05-18 17:03:42 -04004012 sendViewSizeZoom(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004013 }
4014 }
4015
4016 /**
4017 * Set the WebViewClient that will receive various notifications and
4018 * requests. This will replace the current handler.
4019 * @param client An implementation of WebViewClient.
4020 */
4021 public void setWebViewClient(WebViewClient client) {
Steve Block51b08912011-04-27 15:04:48 +01004022 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004023 mCallbackProxy.setWebViewClient(client);
4024 }
4025
4026 /**
Grace Kloba94ab3b62009-10-07 18:00:19 -07004027 * Gets the WebViewClient
4028 * @return the current WebViewClient instance.
4029 *
Jonathan Dixon4cde13a2011-12-16 18:36:20 +00004030 * @hide This is an implementation detail.
Grace Kloba94ab3b62009-10-07 18:00:19 -07004031 */
4032 public WebViewClient getWebViewClient() {
4033 return mCallbackProxy.getWebViewClient();
4034 }
4035
4036 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004037 * Register the interface to be used when content can not be handled by
4038 * the rendering engine, and should be downloaded instead. This will replace
4039 * the current handler.
4040 * @param listener An implementation of DownloadListener.
4041 */
4042 public void setDownloadListener(DownloadListener listener) {
Steve Block51b08912011-04-27 15:04:48 +01004043 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004044 mCallbackProxy.setDownloadListener(listener);
4045 }
4046
4047 /**
4048 * Set the chrome handler. This is an implementation of WebChromeClient for
Steve Block81f19ff2010-11-01 13:23:24 +00004049 * use in handling JavaScript dialogs, favicons, titles, and the progress.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004050 * This will replace the current handler.
4051 * @param client An implementation of WebChromeClient.
4052 */
4053 public void setWebChromeClient(WebChromeClient client) {
Steve Block51b08912011-04-27 15:04:48 +01004054 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004055 mCallbackProxy.setWebChromeClient(client);
4056 }
4057
4058 /**
Andrei Popescu6fa29582009-06-19 14:54:09 +01004059 * Gets the chrome handler.
4060 * @return the current WebChromeClient instance.
4061 *
Jonathan Dixon4cde13a2011-12-16 18:36:20 +00004062 * @hide This is an implementation detail.
Andrei Popescu6fa29582009-06-19 14:54:09 +01004063 */
4064 public WebChromeClient getWebChromeClient() {
4065 return mCallbackProxy.getWebChromeClient();
4066 }
4067
4068 /**
Patrick Scott0b2e84b2010-03-02 08:58:44 -05004069 * Set the back/forward list client. This is an implementation of
4070 * WebBackForwardListClient for handling new items and changes in the
4071 * history index.
4072 * @param client An implementation of WebBackForwardListClient.
4073 * {@hide}
4074 */
4075 public void setWebBackForwardListClient(WebBackForwardListClient client) {
4076 mCallbackProxy.setWebBackForwardListClient(client);
4077 }
4078
4079 /**
4080 * Gets the WebBackForwardListClient.
4081 * {@hide}
4082 */
4083 public WebBackForwardListClient getWebBackForwardListClient() {
4084 return mCallbackProxy.getWebBackForwardListClient();
4085 }
4086
4087 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088 * Set the Picture listener. This is an interface used to receive
4089 * notifications of a new Picture.
4090 * @param listener An implementation of WebView.PictureListener.
Kristian Monsenfc771652011-05-10 16:44:05 +01004091 * @deprecated This method is now obsolete.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004092 */
Kristian Monsenfc771652011-05-10 16:44:05 +01004093 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004094 public void setPictureListener(PictureListener listener) {
Steve Block51b08912011-04-27 15:04:48 +01004095 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004096 mPictureListener = listener;
4097 }
4098
4099 /**
4100 * {@hide}
4101 */
4102 /* FIXME: Debug only! Remove for SDK! */
4103 public void externalRepresentation(Message callback) {
4104 mWebViewCore.sendMessage(EventHub.REQUEST_EXT_REPRESENTATION, callback);
4105 }
4106
4107 /**
4108 * {@hide}
4109 */
4110 /* FIXME: Debug only! Remove for SDK! */
4111 public void documentAsText(Message callback) {
4112 mWebViewCore.sendMessage(EventHub.REQUEST_DOC_AS_TEXT, callback);
4113 }
4114
4115 /**
Steve Block4cd73c52011-11-09 13:06:52 +00004116 * This method injects the supplied Java object into the WebView. The
4117 * object is injected into the JavaScript context of the main frame, using
4118 * the supplied name. This allows the Java object to be accessed from
4119 * JavaScript. Note that that injected objects will not appear in
4120 * JavaScript until the page is next (re)loaded. For example:
4121 * <pre> webView.addJavascriptInterface(new Object(), "injectedObject");
4122 * webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
4123 * webView.loadUrl("javascript:alert(injectedObject.toString())");</pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004124 * <p><strong>IMPORTANT:</strong>
4125 * <ul>
Steve Block4cd73c52011-11-09 13:06:52 +00004126 * <li> addJavascriptInterface() can be used to allow JavaScript to control
4127 * the host application. This is a powerful feature, but also presents a
4128 * security risk. Use of this method in a WebView containing untrusted
4129 * content could allow an attacker to manipulate the host application in
4130 * unintended ways, executing Java code with the permissions of the host
4131 * application. Use extreme care when using this method in a WebView which
4132 * could contain untrusted content.
4133 * <li> JavaScript interacts with Java object on a private, background
4134 * thread of the WebView. Care is therefore required to maintain thread
4135 * safety.</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004136 * </ul></p>
Steve Block4cd73c52011-11-09 13:06:52 +00004137 * @param object The Java object to inject into the WebView's JavaScript
4138 * context. Null values are ignored.
4139 * @param name The name used to expose the instance in JavaScript.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004140 */
Steve Block4cd73c52011-11-09 13:06:52 +00004141 public void addJavascriptInterface(Object object, String name) {
Steve Block51b08912011-04-27 15:04:48 +01004142 checkThread();
Steve Block4cd73c52011-11-09 13:06:52 +00004143 if (object == null) {
Steve Block544295e2010-12-02 18:40:06 +00004144 return;
4145 }
Cary Clarkded054c2009-06-15 10:26:08 -04004146 WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
Steve Block4cd73c52011-11-09 13:06:52 +00004147 arg.mObject = object;
4148 arg.mInterfaceName = name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149 mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
4150 }
4151
4152 /**
Steve Block689a3422010-12-07 18:18:26 +00004153 * Removes a previously added JavaScript interface with the given name.
4154 * @param interfaceName The name of the interface to remove.
4155 */
4156 public void removeJavascriptInterface(String interfaceName) {
Steve Block51b08912011-04-27 15:04:48 +01004157 checkThread();
Svetoslav Ganovfa443142011-03-02 14:54:03 -08004158 if (mWebViewCore != null) {
4159 WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
4160 arg.mInterfaceName = interfaceName;
4161 mWebViewCore.sendMessage(EventHub.REMOVE_JS_INTERFACE, arg);
4162 }
Steve Block689a3422010-12-07 18:18:26 +00004163 }
4164
4165 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004166 * Return the WebSettings object used to control the settings for this
4167 * WebView.
4168 * @return A WebSettings object that can be used to control this WebView's
4169 * settings.
4170 */
4171 public WebSettings getSettings() {
Steve Block51b08912011-04-27 15:04:48 +01004172 checkThread();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04004173 return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004174 }
4175
4176 /**
4177 * Return the list of currently loaded plugins.
4178 * @return The list of currently loaded plugins.
Andrei Popescu385df692009-08-13 11:59:57 +01004179 *
Kristian Monsenf0d97312011-01-12 19:15:35 +00004180 * @hide
Andrei Popescu385df692009-08-13 11:59:57 +01004181 * @deprecated This was used for Gears, which has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004182 */
Andrei Popescu385df692009-08-13 11:59:57 +01004183 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004184 public static synchronized PluginList getPluginList() {
Steve Block51b08912011-04-27 15:04:48 +01004185 checkThread();
Grace Klobabb245ea2009-11-10 13:13:24 -08004186 return new PluginList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004187 }
4188
4189 /**
Kristian Monsenf0d97312011-01-12 19:15:35 +00004190 * @hide
Andrei Popescu385df692009-08-13 11:59:57 +01004191 * @deprecated This was used for Gears, which has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004192 */
Andrei Popescu385df692009-08-13 11:59:57 +01004193 @Deprecated
Steve Block51b08912011-04-27 15:04:48 +01004194 public void refreshPlugins(boolean reloadOpenPages) {
4195 checkThread();
4196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004197
4198 //-------------------------------------------------------------------------
4199 // Override View methods
4200 //-------------------------------------------------------------------------
4201
4202 @Override
4203 protected void finalize() throws Throwable {
Cary Clark9a4c0632009-08-10 16:40:08 -04004204 try {
John Reckb9376462011-09-13 14:34:52 -07004205 if (mNativeClass != 0) {
John Reck5540abc2011-09-15 11:08:00 -07004206 mPrivateHandler.post(new Runnable() {
John Reckb9376462011-09-13 14:34:52 -07004207 @Override
4208 public void run() {
4209 destroy();
4210 }
4211 });
4212 }
Cary Clark9a4c0632009-08-10 16:40:08 -04004213 } finally {
4214 super.finalize();
4215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004216 }
Cary Clarkd6982c92009-05-29 11:02:22 -04004217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004218 @Override
Leon Scroggins0236e672009-09-02 21:12:08 -04004219 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
4220 if (child == mTitleBar) {
4221 // When drawing the title bar, move it horizontally to always show
Adam Powell9d32d242010-03-29 16:02:07 -07004222 // at the top of the WebView.
Leon Scroggins0236e672009-09-02 21:12:08 -04004223 mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft());
Michael Kolbc4ca53f2011-02-05 13:53:14 -08004224 int newTop = 0;
4225 if (mTitleGravity == Gravity.NO_GRAVITY) {
4226 newTop = Math.min(0, mScrollY);
4227 } else if (mTitleGravity == Gravity.TOP) {
4228 newTop = mScrollY;
4229 }
Michael Kolb75a03f92011-02-23 16:12:13 -08004230 mTitleBar.setBottom(newTop + mTitleBar.getHeight());
Mindy Pereira3331f2b2010-12-03 09:58:37 -08004231 mTitleBar.setTop(newTop);
Leon Scroggins0236e672009-09-02 21:12:08 -04004232 }
4233 return super.drawChild(canvas, child, drawingTime);
4234 }
4235
John Reck335f4542011-08-25 18:25:09 -07004236 private void drawContent(Canvas canvas, boolean drawRings) {
John Reck335f4542011-08-25 18:25:09 -07004237 drawCoreAndCursorRing(canvas, mBackgroundColor,
4238 mDrawCursorRing && drawRings);
Mike Reed19f3f0e2009-11-12 12:50:20 -05004239 }
4240
Adam Powell637d3372010-08-25 14:37:03 -07004241 /**
4242 * Draw the background when beyond bounds
4243 * @param canvas Canvas to draw into
4244 */
4245 private void drawOverScrollBackground(Canvas canvas) {
4246 if (mOverScrollBackground == null) {
4247 mOverScrollBackground = new Paint();
4248 Bitmap bm = BitmapFactory.decodeResource(
4249 mContext.getResources(),
4250 com.android.internal.R.drawable.status_bar_background);
4251 mOverScrollBackground.setShader(new BitmapShader(bm,
4252 Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
4253 mOverScrollBorder = new Paint();
4254 mOverScrollBorder.setStyle(Paint.Style.STROKE);
4255 mOverScrollBorder.setStrokeWidth(0);
4256 mOverScrollBorder.setColor(0xffbbbbbb);
4257 }
4258
4259 int top = 0;
4260 int right = computeRealHorizontalScrollRange();
4261 int bottom = top + computeRealVerticalScrollRange();
4262 // first draw the background and anchor to the top of the view
4263 canvas.save();
4264 canvas.translate(mScrollX, mScrollY);
4265 canvas.clipRect(-mScrollX, top - mScrollY, right - mScrollX, bottom
4266 - mScrollY, Region.Op.DIFFERENCE);
4267 canvas.drawPaint(mOverScrollBackground);
4268 canvas.restore();
4269 // then draw the border
4270 canvas.drawRect(-1, top - 1, right, bottom, mOverScrollBorder);
4271 // next clip the region for the content
4272 canvas.clipRect(0, top, right, bottom);
4273 }
4274
Mike Reed19f3f0e2009-11-12 12:50:20 -05004275 @Override
4276 protected void onDraw(Canvas canvas) {
George Mount5d3f6e62011-12-05 15:19:00 -08004277 if (inFullScreenMode()) {
4278 return; // no need to draw anything if we aren't visible.
4279 }
John Reck086a5142011-08-31 16:59:10 -07004280 // if mNativeClass is 0, the WebView is either destroyed or not
4281 // initialized. In either case, just draw the background color and return
Mike Reed19f3f0e2009-11-12 12:50:20 -05004282 if (mNativeClass == 0) {
John Reck086a5142011-08-31 16:59:10 -07004283 canvas.drawColor(mBackgroundColor);
Mike Reed19f3f0e2009-11-12 12:50:20 -05004284 return;
4285 }
4286
Grace Klobae47ac472010-03-11 14:53:07 -08004287 // if both mContentWidth and mContentHeight are 0, it means there is no
4288 // valid Picture passed to WebView yet. This can happen when WebView
4289 // just starts. Draw the background and return.
4290 if ((mContentWidth | mContentHeight) == 0 && mHistoryPicture == null) {
4291 canvas.drawColor(mBackgroundColor);
4292 return;
4293 }
4294
Ben Murdoch811ba6c2011-01-26 10:19:39 +00004295 if (canvas.isHardwareAccelerated()) {
Nicolas Roard2bc0b012011-11-16 19:26:25 -08004296 if (mIncrementEGLContextHack == false) {
4297 mIncrementEGLContextHack = true;
4298 EGL10 egl = (EGL10) EGLContext.getEGL();
4299 EGLDisplay eglDisplay = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
4300 int[] version = new int[2];
4301 egl.eglInitialize(eglDisplay, version);
4302 }
Ben Murdoch811ba6c2011-01-26 10:19:39 +00004303 mZoomManager.setHardwareAccelerated();
4304 }
4305
Mike Reed19f3f0e2009-11-12 12:50:20 -05004306 int saveCount = canvas.save();
Adam Powell637d3372010-08-25 14:37:03 -07004307 if (mInOverScrollMode && !getSettings()
4308 .getUseWebViewBackgroundForOverscrollBackground()) {
4309 drawOverScrollBackground(canvas);
4310 }
Mike Reed19f3f0e2009-11-12 12:50:20 -05004311 if (mTitleBar != null) {
Michael Kolb75a03f92011-02-23 16:12:13 -08004312 canvas.translate(0, getTitleHeight());
Mike Reed19f3f0e2009-11-12 12:50:20 -05004313 }
John Reck335f4542011-08-25 18:25:09 -07004314 boolean drawJavaRings = !mTouchHighlightRegion.isEmpty()
4315 && (mTouchMode == TOUCH_INIT_MODE
4316 || mTouchMode == TOUCH_SHORTPRESS_START_MODE
John Reck0ba72ad2011-08-29 10:19:02 -07004317 || mTouchMode == TOUCH_SHORTPRESS_MODE
4318 || mTouchMode == TOUCH_DONE_MODE);
John Reck335f4542011-08-25 18:25:09 -07004319 boolean drawNativeRings = !drawJavaRings;
4320 if (USE_WEBKIT_RINGS) {
4321 drawNativeRings = !drawJavaRings && !isInTouchMode();
4322 }
4323 drawContent(canvas, drawNativeRings);
Leon Scroggins0236e672009-09-02 21:12:08 -04004324 canvas.restoreToCount(saveCount);
Cary Clarkd6982c92009-05-29 11:02:22 -04004325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004326 if (AUTO_REDRAW_HACK && mAutoRedraw) {
4327 invalidate();
4328 }
Nicolas Roard38863332010-01-04 19:30:55 +00004329 mWebViewCore.signalRepaintDone();
Grace Kloba178db412010-05-18 22:22:23 -07004330
Adam Powell637d3372010-08-25 14:37:03 -07004331 if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas)) {
4332 invalidate();
4333 }
4334
Grace Kloba178db412010-05-18 22:22:23 -07004335 // paint the highlight in the end
John Reck335f4542011-08-25 18:25:09 -07004336 if (drawJavaRings) {
4337 long delay = System.currentTimeMillis() - mTouchHighlightRequested;
4338 if (delay < ViewConfiguration.getTapTimeout()) {
4339 Rect r = mTouchHighlightRegion.getBounds();
4340 postInvalidateDelayed(delay, r.left, r.top, r.right, r.bottom);
4341 } else {
4342 if (mTouchHightlightPaint == null) {
4343 mTouchHightlightPaint = new Paint();
John Reck086a5142011-08-31 16:59:10 -07004344 mTouchHightlightPaint.setColor(HIGHLIGHT_COLOR);
John Reck335f4542011-08-25 18:25:09 -07004345 }
4346 RegionIterator iter = new RegionIterator(mTouchHighlightRegion);
4347 Rect r = new Rect();
4348 while (iter.next(r)) {
4349 canvas.drawRect(r, mTouchHightlightPaint);
4350 }
Grace Kloba178db412010-05-18 22:22:23 -07004351 }
Grace Kloba178db412010-05-18 22:22:23 -07004352 }
4353 if (DEBUG_TOUCH_HIGHLIGHT) {
4354 if (getSettings().getNavDump()) {
4355 if ((mTouchHighlightX | mTouchHighlightY) != 0) {
4356 if (mTouchCrossHairColor == null) {
4357 mTouchCrossHairColor = new Paint();
4358 mTouchCrossHairColor.setColor(Color.RED);
4359 }
4360 canvas.drawLine(mTouchHighlightX - mNavSlop,
4361 mTouchHighlightY - mNavSlop, mTouchHighlightX
4362 + mNavSlop + 1, mTouchHighlightY + mNavSlop
4363 + 1, mTouchCrossHairColor);
4364 canvas.drawLine(mTouchHighlightX + mNavSlop + 1,
4365 mTouchHighlightY - mNavSlop, mTouchHighlightX
4366 - mNavSlop,
4367 mTouchHighlightY + mNavSlop + 1,
4368 mTouchCrossHairColor);
4369 }
4370 }
4371 }
4372 }
4373
John Reck335f4542011-08-25 18:25:09 -07004374 private void removeTouchHighlight() {
4375 mWebViewCore.removeMessages(EventHub.GET_TOUCH_HIGHLIGHT_RECTS);
4376 mPrivateHandler.removeMessages(SET_TOUCH_HIGHLIGHT_RECTS);
4377 setTouchHighlightRects(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004378 }
4379
4380 @Override
4381 public void setLayoutParams(ViewGroup.LayoutParams params) {
4382 if (params.height == LayoutParams.WRAP_CONTENT) {
4383 mWrapContent = true;
4384 }
4385 super.setLayoutParams(params);
4386 }
4387
4388 @Override
4389 public boolean performLongClick() {
Grace Kloba98e6fcf2010-01-27 15:20:30 -08004390 // performLongClick() is the result of a delayed message. If we switch
4391 // to windows overview, the WebView will be temporarily removed from the
4392 // view system. In that case, do nothing.
4393 if (getParent() == null) return false;
Adam Powellbe366682010-09-12 12:47:04 -07004394
4395 // A multi-finger gesture can look like a long press; make sure we don't take
4396 // long press actions if we're scaling.
4397 final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
4398 if (detector != null && detector.isInProgress()) {
4399 return false;
4400 }
Michael Kolbc4ca53f2011-02-05 13:53:14 -08004401
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004402 if (mNativeClass != 0 && nativeCursorIsTextInput()) {
4403 // Send the click so that the textfield is in focus
Leon Scroggins1d96ca02009-10-23 11:49:03 -04004404 centerKeyPressOnTextField();
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004405 rebuildWebTextView();
Leon Scroggins2c8e0512010-05-11 15:50:27 -04004406 } else {
Leon Scroggins2aed7762010-08-13 17:11:42 -04004407 clearTextEntry();
Leon Scroggins3ccd3652009-06-26 17:22:50 -04004408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004409 if (inEditingMode()) {
Leon Scrogginsfcf57762010-12-14 18:09:23 -05004410 // Since we just called rebuildWebTextView, the layout is not set
4411 // properly. Update it so it can correctly find the word to select.
4412 mWebTextView.ensureLayout();
4413 // Provide a touch down event to WebTextView, which will allow it
4414 // to store the location to use in performLongClick.
4415 AbsoluteLayout.LayoutParams params
4416 = (AbsoluteLayout.LayoutParams) mWebTextView.getLayoutParams();
4417 MotionEvent fake = MotionEvent.obtain(mLastTouchTime,
4418 mLastTouchTime, MotionEvent.ACTION_DOWN,
4419 mLastTouchX - params.x + mScrollX,
4420 mLastTouchY - params.y + mScrollY, 0);
4421 mWebTextView.dispatchTouchEvent(fake);
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004422 return mWebTextView.performLongClick();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004423 }
Cary Clark1e8e10d2010-11-17 13:49:25 -05004424 if (mSelectingText) return false; // long click does nothing on selection
Cary Clark924af702010-06-04 16:37:43 -04004425 /* if long click brings up a context menu, the super function
4426 * returns true and we're done. Otherwise, nothing happened when
4427 * the user clicked. */
4428 if (super.performLongClick()) {
4429 return true;
4430 }
4431 /* In the case where the application hasn't already handled the long
4432 * click action, look for a word under the click. If one is found,
4433 * animate the text selection into view.
4434 * FIXME: no animation code yet */
Adam Powellad804e32011-09-14 19:11:08 -07004435 final boolean isSelecting = selectText();
4436 if (isSelecting) {
4437 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
4438 }
4439 return isSelecting;
Cary Clarkfc8bf742010-11-22 11:02:29 -05004440 }
4441
4442 /**
4443 * Select the word at the last click point.
4444 *
Jonathan Dixon4cde13a2011-12-16 18:36:20 +00004445 * @hide This is an implementation detail.
Cary Clarkfc8bf742010-11-22 11:02:29 -05004446 */
4447 public boolean selectText() {
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08004448 int x = viewToContentX(mLastTouchX + mScrollX);
4449 int y = viewToContentY(mLastTouchY + mScrollY);
Cary Clark2cdee232010-12-29 14:59:24 -05004450 return selectText(x, y);
4451 }
4452
4453 /**
4454 * Select the word at the indicated content coordinates.
4455 */
4456 boolean selectText(int x, int y) {
Cary Clark03f00222011-02-10 19:37:15 -05004457 if (!setUpSelect(true, x, y)) {
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05004458 return false;
4459 }
Cary Clark03f00222011-02-10 19:37:15 -05004460 nativeSetExtendSelection();
4461 mDrawSelectionPointer = false;
Cary Clark03f00222011-02-10 19:37:15 -05004462 mTouchMode = TOUCH_DRAG_MODE;
4463 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464 }
4465
Cary Clarkc5cd5e92010-11-22 15:20:02 -05004466 private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
4467
4468 @Override
4469 protected void onConfigurationChanged(Configuration newConfig) {
John Reckd6ac7272011-11-08 15:00:17 -08004470 mCachedOverlappingActionModeHeight = -1;
Cary Clarkc5cd5e92010-11-22 15:20:02 -05004471 if (mSelectingText && mOrientation != newConfig.orientation) {
4472 selectionDone();
4473 }
4474 mOrientation = newConfig.orientation;
John Reck23a446c2011-10-17 17:06:09 -07004475 if (mWebViewCore != null && !mBlockWebkitViewMessages) {
4476 mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
4477 }
Cary Clarkc5cd5e92010-11-22 15:20:02 -05004478 }
4479
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04004480 /**
4481 * Keep track of the Callback so we can end its ActionMode or remove its
4482 * titlebar.
4483 */
4484 private SelectActionModeCallback mSelectCallback;
4485
Leon Scroggins63356742010-12-15 17:37:08 -05004486 // These values are possible options for didUpdateWebTextViewDimensions.
4487 private static final int FULLY_ON_SCREEN = 0;
4488 private static final int INTERSECTS_SCREEN = 1;
4489 private static final int ANYWHERE = 2;
4490
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004491 /**
4492 * Check to see if the focused textfield/textarea is still on screen. If it
4493 * is, update the the dimensions and location of WebTextView. Otherwise,
4494 * remove the WebTextView. Should be called when the zoom level changes.
Leon Scroggins63356742010-12-15 17:37:08 -05004495 * @param intersection How to determine whether the textfield/textarea is
4496 * still on screen.
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004497 * @return boolean True if the textfield/textarea is still on screen and the
4498 * dimensions/location of WebTextView have been updated.
4499 */
Leon Scroggins63356742010-12-15 17:37:08 -05004500 private boolean didUpdateWebTextViewDimensions(int intersection) {
Cary Clark5da9aeb2009-10-06 17:40:53 -04004501 Rect contentBounds = nativeFocusCandidateNodeBounds();
4502 Rect vBox = contentToViewRect(contentBounds);
4503 Rect visibleRect = new Rect();
4504 calcOurVisibleRect(visibleRect);
Michael Kolb5da91bd2011-11-29 15:29:03 -08004505 offsetByLayerScrollPosition(vBox);
Leon Scrogginsbcbf5642010-02-17 17:56:51 -05004506 // If the textfield is on screen, place the WebTextView in
4507 // its new place, accounting for our new scroll/zoom values,
4508 // and adjust its textsize.
Leon Scroggins63356742010-12-15 17:37:08 -05004509 boolean onScreen;
4510 switch (intersection) {
4511 case FULLY_ON_SCREEN:
4512 onScreen = visibleRect.contains(vBox);
4513 break;
4514 case INTERSECTS_SCREEN:
4515 onScreen = Rect.intersects(visibleRect, vBox);
4516 break;
4517 case ANYWHERE:
4518 onScreen = true;
4519 break;
4520 default:
4521 throw new AssertionError(
4522 "invalid parameter passed to didUpdateWebTextViewDimensions");
4523 }
4524 if (onScreen) {
Cary Clark5da9aeb2009-10-06 17:40:53 -04004525 mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
4526 vBox.height());
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004527 mWebTextView.updateTextSize();
4528 updateWebTextViewPadding();
Cary Clark5da9aeb2009-10-06 17:40:53 -04004529 return true;
4530 } else {
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004531 // The textfield is now off screen. The user probably
4532 // was not zooming to see the textfield better. Remove
4533 // the WebTextView. If the user types a key, and the
4534 // textfield is still in focus, we will reconstruct
4535 // the WebTextView and scroll it back on screen.
4536 mWebTextView.remove();
Cary Clark5da9aeb2009-10-06 17:40:53 -04004537 return false;
4538 }
4539 }
4540
Michael Kolb5da91bd2011-11-29 15:29:03 -08004541 private void offsetByLayerScrollPosition(Rect box) {
4542 if ((mCurrentScrollingLayerId != 0)
4543 && (mCurrentScrollingLayerId == nativeFocusCandidateLayerId())) {
4544 box.offsetTo(box.left - mScrollingLayerRect.left,
4545 box.top - mScrollingLayerRect.top);
4546 }
4547 }
4548
Shimeng (Simon) Wang464b6902011-03-16 11:27:44 -07004549 void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator,
Chris Craik5cf78f72011-07-28 11:34:31 -07004550 boolean isPictureAfterFirstLayout, boolean registerPageSwapCallback) {
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004551 if (mNativeClass == 0)
4552 return;
Chris Craik09a71e02011-12-12 18:03:29 -08004553 nativeSetBaseLayer(mNativeClass, layer, invalRegion, showVisualIndicator,
Chris Craik5cf78f72011-07-28 11:34:31 -07004554 isPictureAfterFirstLayout, registerPageSwapCallback);
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08004555 if (mHTML5VideoViewProxy != null) {
4556 mHTML5VideoViewProxy.setBaseLayer(layer);
4557 }
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004558 }
4559
John Reck816c0de2011-06-02 16:04:53 -07004560 int getBaseLayer() {
John Reck90afe212011-09-01 11:39:37 -07004561 if (mNativeClass == 0) {
4562 return 0;
4563 }
John Reck816c0de2011-06-02 16:04:53 -07004564 return nativeGetBaseLayer();
4565 }
4566
Derek Sollenberger293c3602010-06-04 10:44:48 -04004567 private void onZoomAnimationStart() {
4568 // If it is in password mode, turn it off so it does not draw misplaced.
Chris Craike3e7a882011-07-25 14:35:22 -07004569 if (inEditingMode()) {
4570 mWebTextView.setVisibility(INVISIBLE);
Derek Sollenberger293c3602010-06-04 10:44:48 -04004571 }
4572 }
4573
4574 private void onZoomAnimationEnd() {
4575 // adjust the edit text view if needed
Chris Craike3e7a882011-07-25 14:35:22 -07004576 if (inEditingMode()
4577 && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04004578 // If it is a password field, start drawing the WebTextView once
4579 // again.
Chris Craike3e7a882011-07-25 14:35:22 -07004580 mWebTextView.setVisibility(VISIBLE);
Derek Sollenberger293c3602010-06-04 10:44:48 -04004581 }
4582 }
4583
4584 void onFixedLengthZoomAnimationStart() {
4585 WebViewCore.pauseUpdatePicture(getWebViewCore());
4586 onZoomAnimationStart();
4587 }
4588
4589 void onFixedLengthZoomAnimationEnd() {
John Reck95b7d6f2011-06-03 15:23:43 -07004590 if (!mBlockWebkitViewMessages && !mSelectingText) {
Cary Clark0df02692010-11-24 11:01:37 -05004591 WebViewCore.resumeUpdatePicture(mWebViewCore);
4592 }
Derek Sollenberger293c3602010-06-04 10:44:48 -04004593 onZoomAnimationEnd();
4594 }
4595
Grace Kloba8abd50b2010-07-08 15:02:14 -07004596 private static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG |
4597 Paint.DITHER_FLAG |
4598 Paint.SUBPIXEL_TEXT_FLAG;
4599 private static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG |
4600 Paint.DITHER_FLAG;
4601
4602 private final DrawFilter mZoomFilter =
4603 new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
4604 // If we need to trade better quality for speed, set mScrollFilter to null
4605 private final DrawFilter mScrollFilter =
4606 new PaintFlagsDrawFilter(SCROLL_BITS, 0);
4607
Cary Clarkd6982c92009-05-29 11:02:22 -04004608 private void drawCoreAndCursorRing(Canvas canvas, int color,
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004609 boolean drawCursorRing) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004610 if (mDrawHistory) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04004611 canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004612 canvas.drawPicture(mHistoryPicture);
4613 return;
4614 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004615 if (mNativeClass == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004616
Derek Sollenberger293c3602010-06-04 10:44:48 -04004617 boolean animateZoom = mZoomManager.isFixedLengthAnimationInProgress();
Grace Klobac2242f22010-03-05 14:00:26 -08004618 boolean animateScroll = ((!mScroller.isFinished()
Cary Clark25415e22009-10-12 13:41:28 -04004619 || mVelocityTracker != null)
4620 && (mTouchMode != TOUCH_DRAG_MODE ||
Grace Klobac2242f22010-03-05 14:00:26 -08004621 mHeldMotionless != MOTIONLESS_TRUE))
4622 || mDeferTouchMode == TOUCH_DRAG_MODE;
Cary Clark25415e22009-10-12 13:41:28 -04004623 if (mTouchMode == TOUCH_DRAG_MODE) {
4624 if (mHeldMotionless == MOTIONLESS_PENDING) {
4625 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
4626 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
4627 mHeldMotionless = MOTIONLESS_FALSE;
4628 }
4629 if (mHeldMotionless == MOTIONLESS_FALSE) {
4630 mPrivateHandler.sendMessageDelayed(mPrivateHandler
4631 .obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
Ben Murdochfd8d3de2011-10-13 13:23:29 +01004632 mPrivateHandler.sendMessageDelayed(mPrivateHandler
4633 .obtainMessage(AWAKEN_SCROLL_BARS),
4634 ViewConfiguration.getScrollDefaultDelay());
Cary Clark25415e22009-10-12 13:41:28 -04004635 mHeldMotionless = MOTIONLESS_PENDING;
4636 }
4637 }
John Reck57efcff2011-09-15 13:51:52 -07004638 int saveCount = canvas.save();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 if (animateZoom) {
Derek Sollenberger293c3602010-06-04 10:44:48 -04004640 mZoomManager.animateZoom(canvas);
Romain Guyd6cf4772011-03-04 17:10:54 -08004641 } else if (!canvas.isHardwareAccelerated()) {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04004642 canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643 }
4644
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004645 boolean UIAnimationsRunning = false;
4646 // Currently for each draw we compute the animation values;
4647 // We may in the future decide to do that independently.
Chris Craikd0051c02011-11-29 10:26:10 -08004648 if (mNativeClass != 0 && !canvas.isHardwareAccelerated()
4649 && nativeEvaluateLayersAnimations(mNativeClass)) {
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004650 UIAnimationsRunning = true;
4651 // If we have unfinished (or unstarted) animations,
Nicolas Roardf2674c12011-03-16 16:04:57 -07004652 // we ask for a repaint. We only need to do this in software
4653 // rendering (with hardware rendering we already have a different
4654 // method of requesting a repaint)
Chris Craikd0051c02011-11-29 10:26:10 -08004655 mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
4656 invalidate();
Nicolas Roardcc2c8422010-04-19 19:08:55 -07004657 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004658
Cary Clark2ec30692010-02-23 10:50:38 -05004659 // decide which adornments to draw
4660 int extras = DRAW_EXTRAS_NONE;
4661 if (mFindIsUp) {
Cary Clark924af702010-06-04 16:37:43 -04004662 extras = DRAW_EXTRAS_FIND;
John Reckeffabe82011-10-27 09:09:36 -07004663 } else if (mSelectingText && (!USE_JAVA_TEXT_SELECTION || DEBUG_TEXT_HANDLES)) {
Cary Clark924af702010-06-04 16:37:43 -04004664 extras = DRAW_EXTRAS_SELECTION;
John Reckb61bfed2011-10-13 19:07:50 -07004665 nativeSetSelectionPointer(mNativeClass,
4666 mDrawSelectionPointer,
4667 mZoomManager.getInvScale(), mSelectX, mSelectY - getTitleHeight());
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004668 } else if (drawCursorRing) {
Cary Clark2ec30692010-02-23 10:50:38 -05004669 extras = DRAW_EXTRAS_CURSOR_RING;
4670 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05004671 if (DebugFlags.WEB_VIEW) {
4672 Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp
4673 + " mSelectingText=" + mSelectingText
4674 + " nativePageShouldHandleShiftAndArrows()="
4675 + nativePageShouldHandleShiftAndArrows()
4676 + " animateZoom=" + animateZoom
4677 + " extras=" + extras);
4678 }
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004679
George Mount82ed95f2011-11-15 11:27:47 -08004680 calcOurContentVisibleRectF(mVisibleContentRect);
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004681 if (canvas.isHardwareAccelerated()) {
George Mount82ed95f2011-11-15 11:27:47 -08004682 Rect glRectViewport = mGLViewportEmpty ? null : mGLRectViewport;
4683 Rect viewRectViewport = mGLViewportEmpty ? null : mViewRectViewport;
Derek Sollenberger1d335f32011-07-08 11:28:23 -04004684
George Mount82ed95f2011-11-15 11:27:47 -08004685 int functor = nativeGetDrawGLFunction(mNativeClass, glRectViewport,
4686 viewRectViewport, mVisibleContentRect, getScale(), extras);
4687 ((HardwareCanvas) canvas).callDrawGLFunction(functor);
Derek Sollenberger1d335f32011-07-08 11:28:23 -04004688 if (mHardwareAccelSkia != getSettings().getHardwareAccelSkiaEnabled()) {
4689 mHardwareAccelSkia = getSettings().getHardwareAccelSkiaEnabled();
4690 nativeUseHardwareAccelSkia(mHardwareAccelSkia);
4691 }
4692
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004693 } else {
4694 DrawFilter df = null;
4695 if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) {
4696 df = mZoomFilter;
4697 } else if (animateScroll) {
4698 df = mScrollFilter;
4699 }
4700 canvas.setDrawFilter(df);
Patrick Scott85b69e02011-01-25 15:19:45 -05004701 // XXX: Revisit splitting content. Right now it causes a
4702 // synchronization problem with layers.
George Mount82ed95f2011-11-15 11:27:47 -08004703 int content = nativeDraw(canvas, mVisibleContentRect, color,
4704 extras, false);
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004705 canvas.setDrawFilter(null);
John Reck95b7d6f2011-06-03 15:23:43 -07004706 if (!mBlockWebkitViewMessages && content != 0) {
Nicolas Roard67a9f2a2010-09-07 14:49:06 -07004707 mWebViewCore.sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0);
4708 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07004709 }
Cary Clark2ec30692010-02-23 10:50:38 -05004710
John Reck57efcff2011-09-15 13:51:52 -07004711 canvas.restoreToCount(saveCount);
4712 if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
4713 drawTextSelectionHandles(canvas);
4714 }
4715
Cary Clark2ec30692010-02-23 10:50:38 -05004716 if (extras == DRAW_EXTRAS_CURSOR_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004717 if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
4718 mTouchMode = TOUCH_SHORTPRESS_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004720 }
Cary Clark5da9aeb2009-10-06 17:40:53 -04004721 if (mFocusSizeChanged) {
4722 mFocusSizeChanged = false;
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004723 // If we are zooming, this will get handled above, when the zoom
4724 // finishes. We also do not need to do this unless the WebTextView
Chris Craik5cf78f72011-07-28 11:34:31 -07004725 // is showing. With hardware acceleration, the pageSwapCallback()
4726 // updates the WebTextView position in sync with page swapping
4727 if (!canvas.isHardwareAccelerated() && !animateZoom && inEditingMode()) {
Leon Scroggins63356742010-12-15 17:37:08 -05004728 didUpdateWebTextViewDimensions(ANYWHERE);
Leon Scrogginsecfc0eb2009-11-19 13:47:46 -05004729 }
Cary Clark5da9aeb2009-10-06 17:40:53 -04004730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004731 }
4732
John Reck086a5142011-08-31 16:59:10 -07004733 private void drawTextSelectionHandles(Canvas canvas) {
4734 if (mTextSelectionPaint == null) {
4735 mTextSelectionPaint = new Paint();
4736 mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
4737 }
4738 mTextSelectionRegion.setEmpty();
John Reckeffabe82011-10-27 09:09:36 -07004739 nativeGetTextSelectionRegion(mNativeClass, mTextSelectionRegion);
John Reck086a5142011-08-31 16:59:10 -07004740 Rect r = new Rect();
4741 RegionIterator iter = new RegionIterator(mTextSelectionRegion);
John Reckeffabe82011-10-27 09:09:36 -07004742 Rect clip = canvas.getClipBounds();
John Reck086a5142011-08-31 16:59:10 -07004743 while (iter.next(r)) {
John Reckeffabe82011-10-27 09:09:36 -07004744 r.set(contentToViewDimension(r.left),
John Reck086a5142011-08-31 16:59:10 -07004745 contentToViewDimension(r.top),
4746 contentToViewDimension(r.right),
4747 contentToViewDimension(r.bottom));
John Reckeffabe82011-10-27 09:09:36 -07004748 if (r.intersect(clip)) {
4749 canvas.drawRect(r, mTextSelectionPaint);
John Reck086a5142011-08-31 16:59:10 -07004750 }
John Reck086a5142011-08-31 16:59:10 -07004751 }
4752 if (mSelectHandleLeft == null) {
4753 mSelectHandleLeft = mContext.getResources().getDrawable(
4754 com.android.internal.R.drawable.text_select_handle_left);
4755 }
John Reckeffabe82011-10-27 09:09:36 -07004756 int[] handles = new int[4];
4757 nativeGetSelectionHandles(mNativeClass, handles);
4758 int start_x = contentToViewDimension(handles[0]);
4759 int start_y = contentToViewDimension(handles[1]);
4760 int end_x = contentToViewDimension(handles[2]);
4761 int end_y = contentToViewDimension(handles[3]);
John Reck086a5142011-08-31 16:59:10 -07004762 // Magic formula copied from TextView
4763 start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4;
4764 mSelectHandleLeft.setBounds(start_x, start_y,
4765 start_x + mSelectHandleLeft.getIntrinsicWidth(),
4766 start_y + mSelectHandleLeft.getIntrinsicHeight());
4767 if (mSelectHandleRight == null) {
4768 mSelectHandleRight = mContext.getResources().getDrawable(
4769 com.android.internal.R.drawable.text_select_handle_right);
4770 }
4771 end_x -= mSelectHandleRight.getIntrinsicWidth() / 4;
4772 mSelectHandleRight.setBounds(end_x, end_y,
4773 end_x + mSelectHandleRight.getIntrinsicWidth(),
4774 end_y + mSelectHandleRight.getIntrinsicHeight());
John Reckeffabe82011-10-27 09:09:36 -07004775 if (DEBUG_TEXT_HANDLES) {
4776 mSelectHandleLeft.setAlpha(125);
4777 mSelectHandleRight.setAlpha(125);
4778 }
John Reck086a5142011-08-31 16:59:10 -07004779 mSelectHandleLeft.draw(canvas);
4780 mSelectHandleRight.draw(canvas);
4781 }
4782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004783 // draw history
4784 private boolean mDrawHistory = false;
4785 private Picture mHistoryPicture = null;
4786 private int mHistoryWidth = 0;
4787 private int mHistoryHeight = 0;
4788
4789 // Only check the flag, can be called from WebCore thread
4790 boolean drawHistory() {
4791 return mDrawHistory;
4792 }
4793
Derek Sollenberger341e22f2010-06-02 12:34:34 -04004794 int getHistoryPictureWidth() {
4795 return (mHistoryPicture != null) ? mHistoryPicture.getWidth() : 0;
4796 }
4797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004798 // Should only be called in UI thread
4799 void switchOutDrawHistory() {
4800 if (null == mWebViewCore) return; // CallbackProxy may trigger this
Grace Kloba8abd50b2010-07-08 15:02:14 -07004801 if (mDrawHistory && (getProgress() == 100 || nativeHasContent())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004802 mDrawHistory = false;
Patrick Scottda9a22b2010-04-08 08:32:52 -04004803 mHistoryPicture = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004804 invalidate();
4805 int oldScrollX = mScrollX;
4806 int oldScrollY = mScrollY;
4807 mScrollX = pinLocX(mScrollX);
4808 mScrollY = pinLocY(mScrollY);
4809 if (oldScrollX != mScrollX || oldScrollY != mScrollY) {
Grace Kloba327dce92010-04-02 15:38:55 -07004810 onScrollChanged(mScrollX, mScrollY, oldScrollX, oldScrollY);
4811 } else {
4812 sendOurVisibleRect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004814 }
4815 }
4816
Cary Clarkd6982c92009-05-29 11:02:22 -04004817 WebViewCore.CursorData cursorData() {
Svetoslav Ganov7882a782011-05-11 17:53:01 -07004818 WebViewCore.CursorData result = cursorDataNoPosition();
Cary Clarked56eda2009-06-18 09:48:47 -04004819 Point position = nativeCursorPosition();
4820 result.mX = position.x;
4821 result.mY = position.y;
Cary Clarkd6982c92009-05-29 11:02:22 -04004822 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004823 }
Cary Clarkd6982c92009-05-29 11:02:22 -04004824
Svetoslav Ganov7882a782011-05-11 17:53:01 -07004825 WebViewCore.CursorData cursorDataNoPosition() {
4826 WebViewCore.CursorData result = new WebViewCore.CursorData();
4827 result.mMoveGeneration = nativeMoveGeneration();
4828 result.mFrame = nativeCursorFramePointer();
4829 return result;
4830 }
4831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004832 /**
4833 * Delete text from start to end in the focused textfield. If there is no
Cary Clarkd6982c92009-05-29 11:02:22 -04004834 * focus, or if start == end, silently fail. If start and end are out of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004835 * order, swap them.
4836 * @param start Beginning of selection to delete.
4837 * @param end End of selection to delete.
4838 */
4839 /* package */ void deleteSelection(int start, int end) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004840 mTextGeneration++;
Leon Scroggins6679f2f2009-08-12 18:48:10 -04004841 WebViewCore.TextSelectionData data
4842 = new WebViewCore.TextSelectionData(start, end);
4843 mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
4844 data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004845 }
4846
4847 /**
4848 * Set the selection to (start, end) in the focused textfield. If start and
4849 * end are out of order, swap them.
4850 * @param start Beginning of selection.
4851 * @param end End of selection.
4852 */
4853 /* package */ void setSelection(int start, int end) {
Leon Scrogginsacea08d2010-05-27 15:09:32 -04004854 if (mWebViewCore != null) {
4855 mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end);
4856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004857 }
4858
Derek Sollenberger7cabb032010-01-21 10:37:38 -05004859 @Override
4860 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
4861 InputConnection connection = super.onCreateInputConnection(outAttrs);
4862 outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_FULLSCREEN;
4863 return connection;
4864 }
4865
Leon Scroggins04e0a102010-01-08 16:19:27 -05004866 /**
4867 * Called in response to a message from webkit telling us that the soft
4868 * keyboard should be launched.
4869 */
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004870 private void displaySoftKeyboard(boolean isTextView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004871 InputMethodManager imm = (InputMethodManager)
4872 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004873
Shimeng (Simon) Wang7924a4a2010-09-14 13:20:46 -07004874 // bring it back to the default level scale so that user can enter text
Shimeng (Simon) Wang6c09ef02010-09-09 13:56:34 -07004875 boolean zoom = mZoomManager.getScale() < mZoomManager.getDefaultScale();
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004876 if (zoom) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04004877 mZoomManager.setZoomCenter(mLastTouchX, mLastTouchY);
Shimeng (Simon) Wang6c09ef02010-09-09 13:56:34 -07004878 mZoomManager.setZoomScale(mZoomManager.getDefaultScale(), false);
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004879 }
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004880 if (isTextView) {
Leon Scroggins04e0a102010-01-08 16:19:27 -05004881 rebuildWebTextView();
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004882 if (inEditingMode()) {
Leon Scrogginsd69b7012011-03-09 16:18:28 -05004883 imm.showSoftInput(mWebTextView, 0, mWebTextView.getResultReceiver());
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004884 if (zoom) {
Leon Scroggins63356742010-12-15 17:37:08 -05004885 didUpdateWebTextViewDimensions(INTERSECTS_SCREEN);
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004886 }
4887 return;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07004888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004889 }
Leon Scroggins200c13d2010-05-14 15:35:42 -04004890 // Used by plugins and contentEditable.
Leon Scrogginse3844ee2010-02-23 15:15:16 -05004891 // Also used if the navigation cache is out of date, and
4892 // does not recognize that a textfield is in focus. In that
4893 // case, use WebView as the targeted view.
4894 // see http://b/issue?id=2457459
4895 imm.showSoftInput(this, 0);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04004896 }
4897
4898 // Called by WebKit to instruct the UI to hide the keyboard
4899 private void hideSoftKeyboard() {
Leon Scrogginsf2e17a82010-09-24 15:58:50 -04004900 InputMethodManager imm = InputMethodManager.peekInstance();
4901 if (imm != null && (imm.isActive(this)
4902 || (inEditingMode() && imm.isActive(mWebTextView)))) {
Leon Scroggins III71d17e42010-09-02 12:53:08 -04004903 imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
4904 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004905 }
4906
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004907 /*
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004908 * This method checks the current focus and cursor and potentially rebuilds
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004909 * mWebTextView to have the appropriate properties, such as password,
4910 * multiline, and what text it contains. It also removes it if necessary.
4911 */
Leon Scroggins01058282009-07-30 16:33:56 -04004912 /* package */ void rebuildWebTextView() {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004913 // If the WebView does not have focus, do nothing until it gains focus.
Grace Kloba04b28682009-09-14 14:38:37 -07004914 if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004915 return;
4916 }
4917 boolean alreadyThere = inEditingMode();
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004918 // inEditingMode can only return true if mWebTextView is non-null,
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004919 // so we can safely call remove() if (alreadyThere)
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004920 if (0 == mNativeClass || !nativeFocusCandidateIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004921 if (alreadyThere) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004922 mWebTextView.remove();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004923 }
4924 return;
4925 }
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004926 // At this point, we know we have found an input field, so go ahead
Leon Scrogginsd3465f62009-06-02 10:57:54 -04004927 // and create the WebTextView if necessary.
4928 if (mWebTextView == null) {
Ben Murdochdb8d19c2010-10-29 11:44:17 +01004929 mWebTextView = new WebTextView(mContext, WebView.this, mAutoFillData.getQueryId());
Leon Scroggins2ca912e2009-04-28 16:51:55 -04004930 // Initialize our generation number.
4931 mTextGeneration = 0;
4932 }
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004933 mWebTextView.updateTextSize();
John Reckc0e9fb92011-10-21 12:39:43 -07004934 updateWebTextViewPosition();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04004935 String text = nativeFocusCandidateText();
4936 int nodePointer = nativeFocusCandidatePointer();
Chris Craike3e7a882011-07-25 14:35:22 -07004937 // This needs to be called before setType, which may call
4938 // requestFormData, and it needs to have the correct nodePointer.
4939 mWebTextView.setNodePointer(nodePointer);
4940 mWebTextView.setType(nativeFocusCandidateType());
Russell Brennerb76b3b12011-09-28 18:00:02 -07004941 // Gravity needs to be set after setType
4942 mWebTextView.setGravityForRtl(nativeFocusCandidateIsRtlText());
Chris Craike3e7a882011-07-25 14:35:22 -07004943 if (null == text) {
4944 if (DebugFlags.WEB_VIEW) {
4945 Log.v(LOGTAG, "rebuildWebTextView null == text");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004946 }
Chris Craike3e7a882011-07-25 14:35:22 -07004947 text = "";
4948 }
4949 mWebTextView.setTextAndKeepSelection(text);
4950 InputMethodManager imm = InputMethodManager.peekInstance();
4951 if (imm != null && imm.isActive(mWebTextView)) {
4952 imm.restartInput(mWebTextView);
John Reckc0e9fb92011-10-21 12:39:43 -07004953 mWebTextView.clearComposingText();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004954 }
Leon Scrogginsf8ca2d72010-10-21 17:14:42 -04004955 if (isFocused()) {
4956 mWebTextView.requestFocus();
4957 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004958 }
4959
John Reckc0e9fb92011-10-21 12:39:43 -07004960 private void updateWebTextViewPosition() {
4961 Rect visibleRect = new Rect();
4962 calcOurContentVisibleRect(visibleRect);
4963 // Note that sendOurVisibleRect calls viewToContent, so the coordinates
4964 // should be in content coordinates.
4965 Rect bounds = nativeFocusCandidateNodeBounds();
4966 Rect vBox = contentToViewRect(bounds);
Michael Kolb5da91bd2011-11-29 15:29:03 -08004967 offsetByLayerScrollPosition(vBox);
John Reckc0e9fb92011-10-21 12:39:43 -07004968 mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
4969 if (!Rect.intersects(bounds, visibleRect)) {
4970 revealSelection();
4971 }
4972 updateWebTextViewPadding();
4973 }
4974
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05004975 /**
Leon Scrogginsc35f4ac2010-11-10 08:59:05 -05004976 * Update the padding of mWebTextView based on the native textfield/textarea
4977 */
4978 void updateWebTextViewPadding() {
4979 Rect paddingRect = nativeFocusCandidatePaddingRect();
4980 if (paddingRect != null) {
4981 // Use contentToViewDimension since these are the dimensions of
4982 // the padding.
4983 mWebTextView.setPadding(
4984 contentToViewDimension(paddingRect.left),
4985 contentToViewDimension(paddingRect.top),
4986 contentToViewDimension(paddingRect.right),
4987 contentToViewDimension(paddingRect.bottom));
4988 }
4989 }
4990
4991 /**
Leon Scroggins200c13d2010-05-14 15:35:42 -04004992 * Tell webkit to put the cursor on screen.
4993 */
4994 /* package */ void revealSelection() {
4995 if (mWebViewCore != null) {
4996 mWebViewCore.sendMessage(EventHub.REVEAL_SELECTION);
4997 }
4998 }
4999
5000 /**
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05005001 * Called by WebTextView to find saved form data associated with the
5002 * textfield
5003 * @param name Name of the textfield.
5004 * @param nodePointer Pointer to the node of the textfield, so it can be
5005 * compared to the currently focused textfield when the data is
5006 * retrieved.
Ben Murdoch62275a42010-09-07 11:27:28 +01005007 * @param autoFillable true if WebKit has determined this field is part of
5008 * a form that can be auto filled.
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005009 * @param autoComplete true if the attribute "autocomplete" is set to true
5010 * on the textfield.
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05005011 */
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005012 /* package */ void requestFormData(String name, int nodePointer,
5013 boolean autoFillable, boolean autoComplete) {
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05005014 if (mWebViewCore.getSettings().getSaveFormData()) {
5015 Message update = mPrivateHandler.obtainMessage(REQUEST_FORM_DATA);
5016 update.arg1 = nodePointer;
5017 RequestFormData updater = new RequestFormData(name, getUrl(),
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005018 update, autoFillable, autoComplete);
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05005019 Thread t = new Thread(updater);
5020 t.start();
5021 }
5022 }
5023
Leon Scroggins3a503392010-01-06 17:04:38 -05005024 /**
5025 * Pass a message to find out the <label> associated with the <input>
5026 * identified by nodePointer
5027 * @param framePointer Pointer to the frame containing the <input> node
5028 * @param nodePointer Pointer to the node for which a <label> is desired.
5029 */
5030 /* package */ void requestLabel(int framePointer, int nodePointer) {
5031 mWebViewCore.sendMessage(EventHub.REQUEST_LABEL, framePointer,
5032 nodePointer);
5033 }
5034
Leon Scrogginsd3465f62009-06-02 10:57:54 -04005035 /*
5036 * This class requests an Adapter for the WebTextView which shows past
5037 * entries stored in the database. It is a Runnable so that it can be done
5038 * in its own thread, without slowing down the UI.
5039 */
5040 private class RequestFormData implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005041 private String mName;
5042 private String mUrl;
5043 private Message mUpdateMessage;
Ben Murdoch62275a42010-09-07 11:27:28 +01005044 private boolean mAutoFillable;
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005045 private boolean mAutoComplete;
Ben Murdoch50799a92011-07-25 11:35:45 +01005046 private WebSettings mWebSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005047
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005048 public RequestFormData(String name, String url, Message msg,
5049 boolean autoFillable, boolean autoComplete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005050 mName = name;
Ben Murdoch2376f822011-09-09 16:49:44 +01005051 mUrl = WebTextView.urlForAutoCompleteData(url);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005052 mUpdateMessage = msg;
Ben Murdoch62275a42010-09-07 11:27:28 +01005053 mAutoFillable = autoFillable;
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005054 mAutoComplete = autoComplete;
Ben Murdoch50799a92011-07-25 11:35:45 +01005055 mWebSettings = getSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005056 }
5057
5058 public void run() {
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005059 ArrayList<String> pastEntries = new ArrayList<String>();
Ben Murdoch62275a42010-09-07 11:27:28 +01005060
5061 if (mAutoFillable) {
5062 // Note that code inside the adapter click handler in WebTextView depends
5063 // on the AutoFill item being at the top of the drop down list. If you change
5064 // the order, make sure to do it there too!
Ben Murdoch50799a92011-07-25 11:35:45 +01005065 if (mWebSettings != null && mWebSettings.getAutoFillProfile() != null) {
Ben Murdoch57914382010-11-16 11:50:39 +00005066 pastEntries.add(getResources().getText(
5067 com.android.internal.R.string.autofill_this_form).toString() +
5068 " " +
5069 mAutoFillData.getPreviewString());
5070 mWebTextView.setAutoFillProfileIsSet(true);
5071 } else {
5072 // There is no autofill profile set up yet, so add an option that
5073 // will invite the user to set their profile up.
5074 pastEntries.add(getResources().getText(
5075 com.android.internal.R.string.setup_autofill).toString());
5076 mWebTextView.setAutoFillProfileIsSet(false);
5077 }
Ben Murdoch62275a42010-09-07 11:27:28 +01005078 }
5079
Leon Scrogginsae0238c2011-01-05 15:12:55 -05005080 if (mAutoComplete) {
5081 pastEntries.addAll(mDatabase.getFormData(mUrl, mName));
5082 }
Ben Murdoch62275a42010-09-07 11:27:28 +01005083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005084 if (pastEntries.size() > 0) {
5085 AutoCompleteAdapter adapter = new
5086 AutoCompleteAdapter(mContext, pastEntries);
Cary Clarkded054c2009-06-15 10:26:08 -04005087 mUpdateMessage.obj = adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005088 mUpdateMessage.sendToTarget();
5089 }
5090 }
5091 }
5092
Grace Kloba8ae1b412009-11-23 10:35:34 -08005093 /**
5094 * Dump the display tree to "/sdcard/displayTree.txt"
5095 *
5096 * @hide debug only
5097 */
5098 public void dumpDisplayTree() {
5099 nativeDumpDisplayTree(getUrl());
5100 }
5101
5102 /**
5103 * Dump the dom tree to adb shell if "toFile" is False, otherwise dump it to
5104 * "/sdcard/domTree.txt"
5105 *
5106 * @hide debug only
5107 */
5108 public void dumpDomTree(boolean toFile) {
5109 mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE, toFile ? 1 : 0, 0);
5110 }
5111
5112 /**
5113 * Dump the render tree to adb shell if "toFile" is False, otherwise dump it
5114 * to "/sdcard/renderTree.txt"
5115 *
5116 * @hide debug only
5117 */
5118 public void dumpRenderTree(boolean toFile) {
5119 mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE, toFile ? 1 : 0, 0);
5120 }
5121
Andrei Popescu5e7bb0a2010-02-01 22:32:16 +00005122 /**
Steve Block68dede32010-08-04 10:28:46 +01005123 * Called by DRT on UI thread, need to proxy to WebCore thread.
5124 *
5125 * @hide debug only
5126 */
5127 public void useMockDeviceOrientation() {
5128 mWebViewCore.sendMessage(EventHub.USE_MOCK_DEVICE_ORIENTATION);
5129 }
5130
5131 /**
5132 * Called by DRT on WebCore thread.
5133 *
5134 * @hide debug only
5135 */
5136 public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
5137 boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
Steve Blockf4a705f2010-08-11 13:08:24 +01005138 mWebViewCore.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta,
5139 canProvideGamma, gamma);
Steve Block68dede32010-08-04 10:28:46 +01005140 }
5141
Leon Scrogginse3225672009-06-03 15:53:13 -04005142 // This is used to determine long press with the center key. Does not
5143 // affect long press with the trackball/touch.
5144 private boolean mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005145
5146 @Override
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04005147 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
John Reck95b7d6f2011-06-03 15:23:43 -07005148 if (mBlockWebkitViewMessages) {
5149 return false;
5150 }
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04005151 // send complex characters to webkit for use by JS and plugins
5152 if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getCharacters() != null) {
5153 // pass the key to DOM
5154 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
5155 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
5156 // return true as DOM handles the key
5157 return true;
5158 }
5159 return false;
5160 }
5161
Cary Clarkaa86ac82010-12-28 11:30:18 -05005162 private boolean isEnterActionKey(int keyCode) {
5163 return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
5164 || keyCode == KeyEvent.KEYCODE_ENTER
5165 || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
5166 }
5167
Derek Sollenbergerff0f9732010-08-06 11:50:49 -04005168 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005169 public boolean onKeyDown(int keyCode, KeyEvent event) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005170 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005171 Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
Cary Clarkaa86ac82010-12-28 11:30:18 -05005172 + "keyCode=" + keyCode
Cary Clark215b72c2009-06-26 14:38:43 -04005173 + ", " + event + ", unicode=" + event.getUnicodeChar());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005174 }
John Reck95b7d6f2011-06-03 15:23:43 -07005175 if (mBlockWebkitViewMessages) {
5176 return false;
5177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005178
Cary Clark122da932010-12-28 15:58:08 -05005179 // don't implement accelerator keys here; defer to host application
5180 if (event.isCtrlPressed()) {
5181 return false;
5182 }
5183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005184 if (mNativeClass == 0) {
5185 return false;
5186 }
5187
5188 // do this hack up front, so it always works, regardless of touch-mode
5189 if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) {
5190 mAutoRedraw = !mAutoRedraw;
5191 if (mAutoRedraw) {
5192 invalidate();
5193 }
5194 return true;
5195 }
5196
5197 // Bubble up the key event if
5198 // 1. it is a system key; or
Grace Kloba04b28682009-09-14 14:38:37 -07005199 // 2. the host application wants to handle it;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005200 if (event.isSystem()
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005201 || mCallbackProxy.uiOverrideKeyEvent(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005202 return false;
5203 }
5204
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005205 // accessibility support
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005206 if (accessibilityScriptInjected()) {
Svetoslav Ganovb01c3d22011-01-11 14:19:17 -08005207 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5208 // if an accessibility script is injected we delegate to it the key handling.
5209 // this script is a screen reader which is a fully fledged solution for blind
5210 // users to navigate in and interact with web pages.
5211 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
5212 return true;
5213 } else {
5214 // Clean up if accessibility was disabled after loading the current URL.
5215 mAccessibilityScriptInjected = false;
5216 }
5217 } else if (mAccessibilityInjector != null) {
5218 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5219 if (mAccessibilityInjector.onKeyEvent(event)) {
5220 // if an accessibility injector is present (no JavaScript enabled or the site
5221 // opts out injecting our JavaScript screen reader) we let it decide whether
5222 // to act on and consume the event.
5223 return true;
5224 }
5225 } else {
5226 // Clean up if accessibility was disabled after loading the current URL.
5227 mAccessibilityInjector = null;
5228 }
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005229 }
5230
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08005231 if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
Cary Clarka3ee56f2011-01-10 11:20:56 -05005232 if (event.hasNoModifiers()) {
5233 pageUp(false);
5234 return true;
5235 } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
5236 pageUp(true);
5237 return true;
5238 }
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08005239 }
5240
5241 if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
Cary Clarka3ee56f2011-01-10 11:20:56 -05005242 if (event.hasNoModifiers()) {
5243 pageDown(false);
5244 return true;
5245 } else if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
5246 pageDown(true);
5247 return true;
5248 }
5249 }
5250
5251 if (keyCode == KeyEvent.KEYCODE_MOVE_HOME && event.hasNoModifiers()) {
5252 pageUp(true);
5253 return true;
5254 }
5255
5256 if (keyCode == KeyEvent.KEYCODE_MOVE_END && event.hasNoModifiers()) {
5257 pageDown(true);
Chih-Wei Huang4e916ad2010-06-10 09:56:47 +08005258 return true;
5259 }
5260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005261 if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
5262 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005263 switchOutDrawHistory();
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005264 if (nativePageShouldHandleShiftAndArrows()) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07005265 letPageHandleNavKey(keyCode, event.getEventTime(), true, event.getMetaState());
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05005266 return true;
5267 }
Cary Clarka3ee56f2011-01-10 11:20:56 -05005268 if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
5269 switch (keyCode) {
5270 case KeyEvent.KEYCODE_DPAD_UP:
5271 pageUp(true);
5272 return true;
5273 case KeyEvent.KEYCODE_DPAD_DOWN:
5274 pageDown(true);
5275 return true;
5276 case KeyEvent.KEYCODE_DPAD_LEFT:
5277 nativeClearCursor(); // start next trackball movement from page edge
5278 return pinScrollTo(0, mScrollY, true, 0);
5279 case KeyEvent.KEYCODE_DPAD_RIGHT:
5280 nativeClearCursor(); // start next trackball movement from page edge
5281 return pinScrollTo(mContentWidth, mScrollY, true, 0);
5282 }
5283 }
Cary Clark924af702010-06-04 16:37:43 -04005284 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04005285 int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
5286 ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
5287 int yRate = keyCode == KeyEvent.KEYCODE_DPAD_UP ?
5288 -1 : keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : 0;
5289 int multiplier = event.getRepeatCount() + 1;
5290 moveSelection(xRate * multiplier, yRate * multiplier);
5291 return true;
5292 }
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05005293 if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005294 playSoundEffect(keyCodeToSoundsEffect(keyCode));
5295 return true;
5296 }
5297 // Bubble up the key event as WebView doesn't handle it
5298 return false;
5299 }
5300
Cary Clark1477b8f2011-02-09 19:33:00 -05005301 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005302 switchOutDrawHistory();
Cary Clarkddbda002011-01-06 13:40:15 -05005303 boolean wantsKeyEvents = nativeCursorNodePointer() == 0
5304 || nativeCursorWantsKeyEvents();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005305 if (event.getRepeatCount() == 0) {
Cary Clark924af702010-06-04 16:37:43 -04005306 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04005307 return true; // discard press if copy in progress
5308 }
Leon Scrogginse3225672009-06-03 15:53:13 -04005309 mGotCenterDown = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 mPrivateHandler.sendMessageDelayed(mPrivateHandler
Leon Scrogginse3225672009-06-03 15:53:13 -04005311 .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT);
Cary Clarkddbda002011-01-06 13:40:15 -05005312 if (!wantsKeyEvents) return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005313 }
5314 // Bubble up the key event as WebView doesn't handle it
Cary Clarkddbda002011-01-06 13:40:15 -05005315 if (!wantsKeyEvents) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005316 }
5317
5318 if (getSettings().getNavDump()) {
5319 switch (keyCode) {
5320 case KeyEvent.KEYCODE_4:
Grace Kloba8ae1b412009-11-23 10:35:34 -08005321 dumpDisplayTree();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005322 break;
5323 case KeyEvent.KEYCODE_5:
5324 case KeyEvent.KEYCODE_6:
Grace Kloba8ae1b412009-11-23 10:35:34 -08005325 dumpDomTree(keyCode == KeyEvent.KEYCODE_5);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005326 break;
5327 case KeyEvent.KEYCODE_7:
5328 case KeyEvent.KEYCODE_8:
Grace Kloba8ae1b412009-11-23 10:35:34 -08005329 dumpRenderTree(keyCode == KeyEvent.KEYCODE_7);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005330 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005331 }
5332 }
5333
Derek Sollenberger718d69f2009-10-19 15:56:43 -04005334 if (nativeCursorIsTextInput()) {
Leon Scroggins1cc24202009-06-16 10:10:28 -04005335 // This message will put the node in focus, for the DOM's notion
Leon Scrogginsb45a2632011-01-12 14:11:24 -05005336 // of focus.
5337 mWebViewCore.sendMessage(EventHub.FAKE_CLICK, nativeCursorFramePointer(),
Leon Scroggins01058282009-07-30 16:33:56 -04005338 nativeCursorNodePointer());
Leon Scroggins0658e8f2009-06-26 14:09:09 -04005339 // This will bring up the WebTextView and put it in focus, for
5340 // our view system's notion of focus
5341 rebuildWebTextView();
5342 // Now we need to pass the event to it
Leon Scrogginsc66f68a2009-10-02 15:12:30 -04005343 if (inEditingMode()) {
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005344 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005345 return mWebTextView.dispatchKeyEvent(event);
Leon Scrogginsc66f68a2009-10-02 15:12:30 -04005346 }
Leon Scroggins40981262009-07-01 10:57:47 -04005347 } else if (nativeHasFocusNode()) {
5348 // In this case, the cursor is not on a text input, but the focus
5349 // might be. Check it, and if so, hand over to the WebTextView.
5350 rebuildWebTextView();
5351 if (inEditingMode()) {
Leon Scroggins0aa341f2010-02-24 16:49:35 -05005352 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005353 return mWebTextView.dispatchKeyEvent(event);
Leon Scroggins40981262009-07-01 10:57:47 -04005354 }
Cary Clark19436562009-06-04 16:25:07 -04005355 }
5356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005357 // TODO: should we pass all the keys to DOM or check the meta tag
Cary Clark2f1d60c2009-06-03 08:05:53 -04005358 if (nativeCursorWantsKeyEvents() || true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005359 // pass the key to DOM
5360 mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
5361 // return true as DOM handles the key
5362 return true;
5363 }
5364
5365 // Bubble up the key event as WebView doesn't handle it
5366 return false;
5367 }
5368
5369 @Override
5370 public boolean onKeyUp(int keyCode, KeyEvent event) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005371 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005372 Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
Cary Clark215b72c2009-06-26 14:38:43 -04005373 + ", " + event + ", unicode=" + event.getUnicodeChar());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005374 }
John Reck95b7d6f2011-06-03 15:23:43 -07005375 if (mBlockWebkitViewMessages) {
5376 return false;
5377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005378
5379 if (mNativeClass == 0) {
5380 return false;
5381 }
5382
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04005383 // special CALL handling when cursor node's href is "tel:XXX"
Cary Clarkd6982c92009-05-29 11:02:22 -04005384 if (keyCode == KeyEvent.KEYCODE_CALL && nativeHasCursorNode()) {
5385 String text = nativeCursorText();
5386 if (!nativeCursorIsTextInput() && text != null
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005387 && text.startsWith(SCHEME_TEL)) {
5388 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
5389 getContext().startActivity(intent);
5390 return true;
5391 }
5392 }
5393
5394 // Bubble up the key event if
5395 // 1. it is a system key; or
5396 // 2. the host application wants to handle it;
Svetoslav Ganovda355512010-05-12 22:04:44 -07005397 if (event.isSystem()
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005398 || mCallbackProxy.uiOverrideKeyEvent(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005399 return false;
5400 }
5401
Svetoslav Ganovc93fb652011-01-05 18:52:05 -08005402 // accessibility support
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005403 if (accessibilityScriptInjected()) {
Svetoslav Ganovb01c3d22011-01-11 14:19:17 -08005404 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5405 // if an accessibility script is injected we delegate to it the key handling.
5406 // this script is a screen reader which is a fully fledged solution for blind
5407 // users to navigate in and interact with web pages.
5408 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
5409 return true;
5410 } else {
5411 // Clean up if accessibility was disabled after loading the current URL.
5412 mAccessibilityScriptInjected = false;
5413 }
5414 } else if (mAccessibilityInjector != null) {
5415 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5416 if (mAccessibilityInjector.onKeyEvent(event)) {
5417 // if an accessibility injector is present (no JavaScript enabled or the site
5418 // opts out injecting our JavaScript screen reader) we let it decide whether to
5419 // act on and consume the event.
5420 return true;
5421 }
5422 } else {
5423 // Clean up if accessibility was disabled after loading the current URL.
5424 mAccessibilityInjector = null;
5425 }
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005426 }
5427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005428 if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
5429 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
Svetoslav Ganov12bed782011-01-03 14:14:50 -08005430 if (nativePageShouldHandleShiftAndArrows()) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07005431 letPageHandleNavKey(keyCode, event.getEventTime(), false, event.getMetaState());
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05005432 return true;
5433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005434 // always handle the navigation keys in the UI thread
5435 // Bubble up the key event as WebView doesn't handle it
5436 return false;
5437 }
5438
Cary Clarkaa86ac82010-12-28 11:30:18 -05005439 if (isEnterActionKey(keyCode)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005440 // remove the long press message first
Leon Scrogginse3225672009-06-03 15:53:13 -04005441 mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
5442 mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005443
Cary Clark924af702010-06-04 16:37:43 -04005444 if (mSelectingText) {
Cary Clarkc05af372009-10-16 10:52:27 -04005445 if (mExtendSelection) {
Cary Clark924af702010-06-04 16:37:43 -04005446 copySelection();
5447 selectionDone();
Cary Clarkc05af372009-10-16 10:52:27 -04005448 } else {
5449 mExtendSelection = true;
Cary Clark924af702010-06-04 16:37:43 -04005450 nativeSetExtendSelection();
Cary Clark09e383c2009-10-26 16:43:58 -04005451 invalidate(); // draw the i-beam instead of the arrow
Cary Clarkc05af372009-10-16 10:52:27 -04005452 }
5453 return true; // discard press if copy in progress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005454 }
Grace Klobadd817492009-09-14 10:17:06 -07005455
5456 // perform the single click
5457 Rect visibleRect = sendOurVisibleRect();
5458 // Note that sendOurVisibleRect calls viewToContent, so the
5459 // coordinates should be in content coordinates.
5460 if (!nativeCursorIntersects(visibleRect)) {
5461 return false;
5462 }
Grace Klobadd817492009-09-14 10:17:06 -07005463 WebViewCore.CursorData data = cursorData();
5464 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
5465 playSoundEffect(SoundEffectConstants.CLICK);
Leon Scroggins1d60c5c2009-10-23 10:16:51 -04005466 if (nativeCursorIsTextInput()) {
5467 rebuildWebTextView();
Leon Scroggins1d96ca02009-10-23 11:49:03 -04005468 centerKeyPressOnTextField();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005469 if (inEditingMode()) {
5470 mWebTextView.setDefaultSelection();
Leon Scrogginsbb107bd2009-10-23 16:18:42 -04005471 }
Leon Scroggins1d60c5c2009-10-23 10:16:51 -04005472 return true;
5473 }
Leon Scroggins2aed7762010-08-13 17:11:42 -04005474 clearTextEntry();
Cary Clarke60cb7f2010-08-25 14:56:00 -04005475 nativeShowCursorTimed();
Cary Clarkddbda002011-01-06 13:40:15 -05005476 if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
5477 return true;
5478 }
5479 if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) {
Grace Klobadd817492009-09-14 10:17:06 -07005480 mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
5481 nativeCursorNodePointer());
Cary Clarkddbda002011-01-06 13:40:15 -05005482 return true;
Grace Klobadd817492009-09-14 10:17:06 -07005483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005484 }
5485
5486 // TODO: should we pass all the keys to DOM or check the meta tag
Cary Clark2f1d60c2009-06-03 08:05:53 -04005487 if (nativeCursorWantsKeyEvents() || true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005488 // pass the key to DOM
5489 mWebViewCore.sendMessage(EventHub.KEY_UP, event);
5490 // return true as DOM handles the key
5491 return true;
5492 }
5493
5494 // Bubble up the key event as WebView doesn't handle it
5495 return false;
5496 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005497
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005498 /*
Cary Clark03f00222011-02-10 19:37:15 -05005499 * Enter selecting text mode, and see if CAB should be shown.
5500 * Returns true if the WebView is now in
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005501 * selecting text mode (including if it was already in that mode, and this
5502 * method did nothing).
5503 */
Cary Clark03f00222011-02-10 19:37:15 -05005504 private boolean setUpSelect(boolean selectWord, int x, int y) {
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005505 if (0 == mNativeClass) return false; // client isn't initialized
5506 if (inFullScreenMode()) return false;
5507 if (mSelectingText) return true;
Cary Clark03f00222011-02-10 19:37:15 -05005508 nativeResetSelection();
5509 if (selectWord && !nativeWordSelection(x, y)) {
5510 selectionDone();
5511 return false;
5512 }
5513 mSelectCallback = new SelectActionModeCallback();
5514 mSelectCallback.setWebView(this);
5515 if (startActionMode(mSelectCallback) == null) {
5516 // There is no ActionMode, so do not allow the user to modify a
5517 // selection.
5518 selectionDone();
5519 return false;
5520 }
Cary Clark09e383c2009-10-26 16:43:58 -04005521 mExtendSelection = false;
Cary Clark924af702010-06-04 16:37:43 -04005522 mSelectingText = mDrawSelectionPointer = true;
John Reckeffabe82011-10-27 09:09:36 -07005523 if (DEBUG_TEXT_HANDLES) {
5524 // Debugging text handles requires running in software mode
5525 setLayerType(LAYER_TYPE_SOFTWARE, null);
5526 }
Cary Clark924af702010-06-04 16:37:43 -04005527 // don't let the picture change during text selection
5528 WebViewCore.pauseUpdatePicture(mWebViewCore);
Cary Clark09e383c2009-10-26 16:43:58 -04005529 if (nativeHasCursorNode()) {
5530 Rect rect = nativeCursorNodeBounds();
5531 mSelectX = contentToViewX(rect.left);
5532 mSelectY = contentToViewY(rect.top);
Steve Block92c99162011-05-23 17:36:01 +01005533 } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08005534 mSelectX = mScrollX + mLastTouchX;
5535 mSelectY = mScrollY + mLastTouchY;
Cary Clark09e383c2009-10-26 16:43:58 -04005536 } else {
5537 mSelectX = mScrollX + getViewWidth() / 2;
5538 mSelectY = mScrollY + getViewHeightWithTitle() / 2;
5539 }
5540 nativeHideCursor();
Cary Clarkb9aaa772011-01-07 16:14:54 -05005541 mMinAutoScrollX = 0;
5542 mMaxAutoScrollX = getViewWidth();
5543 mMinAutoScrollY = 0;
5544 mMaxAutoScrollY = getViewHeightWithTitle();
Michael Kolb5da91bd2011-11-29 15:29:03 -08005545 mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX),
Cary Clarkb9aaa772011-01-07 16:14:54 -05005546 viewToContentY(mSelectY), mScrollingLayerRect,
5547 mScrollingLayerBounds);
Michael Kolb5da91bd2011-11-29 15:29:03 -08005548 if (mCurrentScrollingLayerId != 0) {
Cary Clarkb9aaa772011-01-07 16:14:54 -05005549 if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
5550 mMinAutoScrollX = Math.max(mMinAutoScrollX,
5551 contentToViewX(mScrollingLayerBounds.left));
5552 mMaxAutoScrollX = Math.min(mMaxAutoScrollX,
5553 contentToViewX(mScrollingLayerBounds.right));
5554 }
5555 if (mScrollingLayerRect.top != mScrollingLayerRect.bottom) {
5556 mMinAutoScrollY = Math.max(mMinAutoScrollY,
5557 contentToViewY(mScrollingLayerBounds.top));
5558 mMaxAutoScrollY = Math.min(mMaxAutoScrollY,
5559 contentToViewY(mScrollingLayerBounds.bottom));
5560 }
5561 }
5562 mMinAutoScrollX += SELECT_SCROLL;
5563 mMaxAutoScrollX -= SELECT_SCROLL;
5564 mMinAutoScrollY += SELECT_SCROLL;
5565 mMaxAutoScrollY -= SELECT_SCROLL;
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005566 return true;
Cary Clark09e383c2009-10-26 16:43:58 -04005567 }
5568
Cary Clark966641a2010-03-04 08:41:56 -05005569 /**
5570 * Use this method to put the WebView into text selection mode.
5571 * Do not rely on this functionality; it will be deprecated in the future.
Kristian Monsenfc771652011-05-10 16:44:05 +01005572 * @deprecated This method is now obsolete.
Cary Clark966641a2010-03-04 08:41:56 -05005573 */
Kristian Monsenfc771652011-05-10 16:44:05 +01005574 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005575 public void emulateShiftHeld() {
Steve Block51b08912011-04-27 15:04:48 +01005576 checkThread();
Cary Clark03f00222011-02-10 19:37:15 -05005577 setUpSelect(false, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005578 }
5579
Cary Clark924af702010-06-04 16:37:43 -04005580 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005581 * Select all of the text in this WebView.
Cary Clark2cdee232010-12-29 14:59:24 -05005582 *
Jonathan Dixon4cde13a2011-12-16 18:36:20 +00005583 * @hide This is an implementation detail.
Cary Clark924af702010-06-04 16:37:43 -04005584 */
Cary Clark2cdee232010-12-29 14:59:24 -05005585 public void selectAll() {
Cary Clark924af702010-06-04 16:37:43 -04005586 if (0 == mNativeClass) return; // client isn't initialized
5587 if (inFullScreenMode()) return;
Cary Clark2cdee232010-12-29 14:59:24 -05005588 if (!mSelectingText) {
5589 // retrieve a point somewhere within the text
5590 Point select = nativeSelectableText();
5591 if (!selectText(select.x, select.y)) return;
Leon Scroggins8a4fd2f2010-12-16 18:17:23 -05005592 }
Cary Clark924af702010-06-04 16:37:43 -04005593 nativeSelectAll();
5594 mDrawSelectionPointer = false;
5595 mExtendSelection = true;
5596 invalidate();
5597 }
5598
5599 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005600 * Called when the selection has been removed.
Cary Clark924af702010-06-04 16:37:43 -04005601 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005602 void selectionDone() {
Cary Clark924af702010-06-04 16:37:43 -04005603 if (mSelectingText) {
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005604 mSelectingText = false;
John Reckeffabe82011-10-27 09:09:36 -07005605 if (DEBUG_TEXT_HANDLES) {
5606 // Debugging text handles required running in software mode, set
5607 // back to default now
5608 setLayerType(LAYER_TYPE_NONE, null);
5609 }
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005610 // finish is idempotent, so this is fine even if selectionDone was
5611 // called by mSelectCallback.onDestroyActionMode
5612 mSelectCallback.finish();
5613 mSelectCallback = null;
Cary Clark0df02692010-11-24 11:01:37 -05005614 WebViewCore.resumePriority();
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005615 WebViewCore.resumeUpdatePicture(mWebViewCore);
Cary Clark924af702010-06-04 16:37:43 -04005616 invalidate(); // redraw without selection
Cary Clark6f5dfc62010-11-11 13:09:20 -05005617 mAutoScrollX = 0;
5618 mAutoScrollY = 0;
5619 mSentAutoScrollMessage = false;
Cary Clark924af702010-06-04 16:37:43 -04005620 }
5621 }
5622
5623 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005624 * Copy the selection to the clipboard
Cary Clark2cdee232010-12-29 14:59:24 -05005625 *
Jonathan Dixon4cde13a2011-12-16 18:36:20 +00005626 * @hide This is an implementation detail.
Cary Clark924af702010-06-04 16:37:43 -04005627 */
Cary Clark2cdee232010-12-29 14:59:24 -05005628 public boolean copySelection() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005629 boolean copiedSomething = false;
Cary Clark924af702010-06-04 16:37:43 -04005630 String selection = getSelection();
Cary Clark7170bb62011-01-12 10:12:15 -05005631 if (selection != null && selection != "") {
Cary Clark924af702010-06-04 16:37:43 -04005632 if (DebugFlags.WEB_VIEW) {
5633 Log.v(LOGTAG, "copySelection \"" + selection + "\"");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005634 }
Cary Clark924af702010-06-04 16:37:43 -04005635 Toast.makeText(mContext
5636 , com.android.internal.R.string.text_copied
5637 , Toast.LENGTH_SHORT).show();
5638 copiedSomething = true;
Dianne Hackborn90d5e8c2010-08-05 13:47:55 -07005639 ClipboardManager cm = (ClipboardManager)getContext()
5640 .getSystemService(Context.CLIPBOARD_SERVICE);
5641 cm.setText(selection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005642 }
Cary Clark09e383c2009-10-26 16:43:58 -04005643 invalidate(); // remove selection region and pointer
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005644 return copiedSomething;
5645 }
5646
Cary Clark924af702010-06-04 16:37:43 -04005647 /**
Jonathan Dixon4cde13a2011-12-16 18:36:20 +00005648 * @hide This is an implementation detail.
Narayan Kamath9497c5f2011-02-22 12:05:34 +00005649 */
5650 public SearchBox getSearchBox() {
Michael Kolbb7481862011-03-03 17:09:19 -08005651 if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
5652 return null;
5653 }
Narayan Kamath9497c5f2011-02-22 12:05:34 +00005654 return mWebViewCore.getBrowserFrame().getSearchBox();
5655 }
5656
5657 /**
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005658 * Returns the currently highlighted text as a string.
Cary Clark924af702010-06-04 16:37:43 -04005659 */
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04005660 String getSelection() {
Cary Clark924af702010-06-04 16:37:43 -04005661 if (mNativeClass == 0) return "";
5662 return nativeGetSelection();
5663 }
5664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005665 @Override
5666 protected void onAttachedToWindow() {
5667 super.onAttachedToWindow();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005668 if (hasWindowFocus()) setActive(true);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005669 final ViewTreeObserver treeObserver = getViewTreeObserver();
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005670 if (mGlobalLayoutListener == null) {
5671 mGlobalLayoutListener = new InnerGlobalLayoutListener();
5672 treeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener);
5673 }
5674 if (mScrollChangedListener == null) {
5675 mScrollChangedListener = new InnerScrollChangedListener();
5676 treeObserver.addOnScrollChangedListener(mScrollChangedListener);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005677 }
Svetoslav Ganov4acac232011-02-02 15:22:24 -08005678
5679 addAccessibilityApisToJavaScript();
Adam Powell4fb35d42011-03-03 17:54:55 -08005680
5681 mTouchEventQueue.reset();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005682 }
5683
5684 @Override
5685 protected void onDetachedFromWindow() {
Leon Scroggins05919f22010-09-14 17:22:36 -04005686 clearHelpers();
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005687 mZoomManager.dismissZoomPicker();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005688 if (hasWindowFocus()) setActive(false);
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005689
5690 final ViewTreeObserver treeObserver = getViewTreeObserver();
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005691 if (mGlobalLayoutListener != null) {
5692 treeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
5693 mGlobalLayoutListener = null;
5694 }
5695 if (mScrollChangedListener != null) {
5696 treeObserver.removeOnScrollChangedListener(mScrollChangedListener);
5697 mScrollChangedListener = null;
Teng-Hui Zhua7f76872010-11-29 11:15:32 -08005698 }
5699
Svetoslav Ganov4acac232011-02-02 15:22:24 -08005700 removeAccessibilityApisFromJavaScript();
5701
Grace Kloba378f0282010-03-26 15:01:30 -07005702 super.onDetachedFromWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005703 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005704
Steve Howard16bd9372010-04-12 14:46:09 -07005705 @Override
5706 protected void onVisibilityChanged(View changedView, int visibility) {
5707 super.onVisibilityChanged(changedView, visibility);
Derek Sollenbergerf39d2662010-06-24 16:41:04 -04005708 // The zoomManager may be null if the webview is created from XML that
5709 // specifies the view's visibility param as not visible (see http://b/2794841)
5710 if (visibility != View.VISIBLE && mZoomManager != null) {
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005711 mZoomManager.dismissZoomPicker();
Steve Howard16bd9372010-04-12 14:46:09 -07005712 }
John Reck5f1c5492011-11-09 16:23:07 -08005713 updateDrawingState();
Steve Howard16bd9372010-04-12 14:46:09 -07005714 }
5715
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005716 /**
5717 * @deprecated WebView no longer needs to implement
5718 * ViewGroup.OnHierarchyChangeListener. This method does nothing now.
5719 */
Jonathan Dixone230e542011-12-21 10:57:00 +00005720 // Cannot add @hide as this can always be accessed via the interface.
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005721 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005722 public void onChildViewAdded(View parent, View child) {}
Cary Clarkd6982c92009-05-29 11:02:22 -04005723
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005724 /**
5725 * @deprecated WebView no longer needs to implement
5726 * ViewGroup.OnHierarchyChangeListener. This method does nothing now.
5727 */
Jonathan Dixone230e542011-12-21 10:57:00 +00005728 // Cannot add @hide as this can always be accessed via the interface.
Leon Scrogginsa57632f2009-11-16 10:51:12 -05005729 @Deprecated
5730 public void onChildViewRemoved(View p, View child) {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005731
5732 /**
5733 * @deprecated WebView should not have implemented
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08005734 * ViewTreeObserver.OnGlobalFocusChangeListener. This method does nothing now.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005735 */
Jonathan Dixone230e542011-12-21 10:57:00 +00005736 // Cannot add @hide as this can always be accessed via the interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005737 @Deprecated
5738 public void onGlobalFocusChanged(View oldFocus, View newFocus) {
5739 }
5740
Leon Scroggins40777232011-01-18 16:49:20 -05005741 void setActive(boolean active) {
Grace Kloba9b95ab12010-04-01 16:07:30 -07005742 if (active) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005743 if (hasFocus()) {
5744 // If our window regained focus, and we have focus, then begin
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005745 // drawing the cursor ring
Michael Kolbedb39ce2011-11-17 10:17:28 -08005746 mDrawCursorRing = !inEditingMode();
Leon Scroggins2aed7762010-08-13 17:11:42 -04005747 setFocusControllerActive(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005748 } else {
Michael Kolbedb39ce2011-11-17 10:17:28 -08005749 mDrawCursorRing = false;
Leon Scroggins2aed7762010-08-13 17:11:42 -04005750 if (!inEditingMode()) {
5751 // If our window gained focus, but we do not have it, do not
5752 // draw the cursor ring.
Leon Scroggins2aed7762010-08-13 17:11:42 -04005753 setFocusControllerActive(false);
5754 }
John Reckbdfb3c52011-09-21 18:20:30 -07005755 // We do not call recordButtons here because we assume
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005756 // that when we lost focus, or window focus, it got called with
5757 // false for the first parameter
5758 }
5759 } else {
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005760 if (!mZoomManager.isZoomPickerVisible()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005761 /*
Derek Sollenberger90b6e482010-05-10 12:38:54 -04005762 * The external zoom controls come in their own window, so our
5763 * window loses focus. Our policy is to not draw the cursor ring
5764 * if our window is not focused, but this is an exception since
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005765 * the user can still navigate the web page with the zoom
5766 * controls showing.
5767 */
Cary Clarkd6982c92009-05-29 11:02:22 -04005768 mDrawCursorRing = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005769 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005770 mKeysPressed.clear();
Grace Kloba378f0282010-03-26 15:01:30 -07005771 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
5772 mTouchMode = TOUCH_DONE_MODE;
Leon Scroggins2aed7762010-08-13 17:11:42 -04005773 setFocusControllerActive(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005774 }
5775 invalidate();
Grace Kloba9b95ab12010-04-01 16:07:30 -07005776 }
5777
5778 // To avoid drawing the cursor ring, and remove the TextView when our window
5779 // loses focus.
5780 @Override
5781 public void onWindowFocusChanged(boolean hasWindowFocus) {
5782 setActive(hasWindowFocus);
5783 if (hasWindowFocus) {
Patrick Scott8a5d3352010-08-18 11:00:42 -04005784 JWebCoreJavaBridge.setActiveWebView(this);
Adam Powellf4f520a2011-09-13 20:16:32 -07005785 if (mPictureUpdatePausedForFocusChange) {
Adam Powelle00e8a782011-09-11 17:48:42 -07005786 WebViewCore.resumeUpdatePicture(mWebViewCore);
Adam Powelle00e8a782011-09-11 17:48:42 -07005787 mPictureUpdatePausedForFocusChange = false;
5788 }
Grace Kloba9b95ab12010-04-01 16:07:30 -07005789 } else {
Patrick Scott8a5d3352010-08-18 11:00:42 -04005790 JWebCoreJavaBridge.removeActiveWebView(this);
Adam Powelle00e8a782011-09-11 17:48:42 -07005791 final WebSettings settings = getSettings();
Adam Powellf4f520a2011-09-13 20:16:32 -07005792 if (settings != null && settings.enableSmoothTransition() &&
Adam Powelle00e8a782011-09-11 17:48:42 -07005793 mWebViewCore != null && !WebViewCore.isUpdatePicturePaused(mWebViewCore)) {
5794 WebViewCore.pauseUpdatePicture(mWebViewCore);
Adam Powelle00e8a782011-09-11 17:48:42 -07005795 mPictureUpdatePausedForFocusChange = true;
5796 }
Grace Kloba9b95ab12010-04-01 16:07:30 -07005797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005798 super.onWindowFocusChanged(hasWindowFocus);
5799 }
5800
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005801 /*
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005802 * Pass a message to WebCore Thread, telling the WebCore::Page's
5803 * FocusController to be "inactive" so that it will
5804 * not draw the blinking cursor. It gets set to "active" to draw the cursor
5805 * in WebViewCore.cpp, when the WebCore thread receives key events/clicks.
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005806 */
Leon Scroggins2aed7762010-08-13 17:11:42 -04005807 /* package */ void setFocusControllerActive(boolean active) {
5808 if (mWebViewCore == null) return;
5809 mWebViewCore.sendMessage(EventHub.SET_ACTIVE, active ? 1 : 0, 0);
Leon Scroggins244d2d42010-12-06 16:29:38 -05005810 // Need to send this message after the document regains focus.
5811 if (active && mListBoxMessage != null) {
5812 mWebViewCore.sendMessage(mListBoxMessage);
5813 mListBoxMessage = null;
5814 }
Leon Scroggins63dda1c2009-04-15 13:25:00 -04005815 }
5816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005817 @Override
5818 protected void onFocusChanged(boolean focused, int direction,
5819 Rect previouslyFocusedRect) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04005820 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005821 Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction);
5822 }
5823 if (focused) {
5824 // When we regain focus, if we have window focus, resume drawing
Leon Scrogginsfa03cde2009-06-15 15:48:46 -04005825 // the cursor ring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005826 if (hasWindowFocus()) {
Michael Kolbedb39ce2011-11-17 10:17:28 -08005827 mDrawCursorRing = !inEditingMode();
Leon Scroggins2aed7762010-08-13 17:11:42 -04005828 setFocusControllerActive(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005829 //} else {
5830 // The WebView has gained focus while we do not have
5831 // windowfocus. When our window lost focus, we should have
John Reckbdfb3c52011-09-21 18:20:30 -07005832 // called recordButtons(false...)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005833 }
5834 } else {
5835 // When we lost focus, unless focus went to the TextView (which is
Cary Clarkd6982c92009-05-29 11:02:22 -04005836 // true if we are in editing mode), stop drawing the cursor ring.
Michael Kolbedb39ce2011-11-17 10:17:28 -08005837 mDrawCursorRing = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005838 if (!inEditingMode()) {
Leon Scrogginsb4ffd112011-01-24 17:43:47 -05005839 setFocusControllerActive(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005840 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005841 mKeysPressed.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005842 }
5843
5844 super.onFocusChanged(focused, direction, previouslyFocusedRect);
5845 }
5846
Nicolas Roard12c18e62010-10-13 20:14:31 -07005847 void setGLRectViewport() {
Teng-Hui Zhue6fb0f12010-11-23 16:37:45 -08005848 // Use the getGlobalVisibleRect() to get the intersection among the parents
Chet Haase91fc3cf2011-01-28 00:20:04 -08005849 // visible == false means we're clipped - send a null rect down to indicate that
5850 // we should not draw
5851 boolean visible = getGlobalVisibleRect(mGLRectViewport);
5852 if (visible) {
5853 // Then need to invert the Y axis, just for GL
5854 View rootView = getRootView();
5855 int rootViewHeight = rootView.getHeight();
Romain Guycabfcc12011-03-07 18:06:46 -08005856 mViewRectViewport.set(mGLRectViewport);
Chet Haase91fc3cf2011-01-28 00:20:04 -08005857 int savedWebViewBottom = mGLRectViewport.bottom;
Steve Block92c99162011-05-23 17:36:01 +01005858 mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeightImpl();
Chet Haase91fc3cf2011-01-28 00:20:04 -08005859 mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
5860 mGLViewportEmpty = false;
5861 } else {
5862 mGLViewportEmpty = true;
5863 }
George Mount82ed95f2011-11-15 11:27:47 -08005864 calcOurContentVisibleRectF(mVisibleContentRect);
Romain Guycabfcc12011-03-07 18:06:46 -08005865 nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
George Mount5d3f6e62011-12-05 15:19:00 -08005866 mGLViewportEmpty ? null : mViewRectViewport,
5867 mVisibleContentRect);
Nicolas Roard12c18e62010-10-13 20:14:31 -07005868 }
5869
Grace Kloba3f9faf42009-10-13 14:13:54 -07005870 /**
5871 * @hide
5872 */
5873 @Override
5874 protected boolean setFrame(int left, int top, int right, int bottom) {
5875 boolean changed = super.setFrame(left, top, right, bottom);
5876 if (!changed && mHeightCanMeasure) {
5877 // When mHeightCanMeasure is true, we will set mLastHeightSent to 0
5878 // in WebViewCore after we get the first layout. We do call
5879 // requestLayout() when we get contentSizeChanged(). But the View
5880 // system won't call onSizeChanged if the dimension is not changed.
5881 // In this case, we need to call sendViewSizeZoom() explicitly to
5882 // notify the WebKit about the new dimensions.
Derek Sollenberger03e48912010-05-18 17:03:42 -04005883 sendViewSizeZoom(false);
Grace Kloba3f9faf42009-10-13 14:13:54 -07005884 }
Nicolas Roard12c18e62010-10-13 20:14:31 -07005885 setGLRectViewport();
Grace Kloba3f9faf42009-10-13 14:13:54 -07005886 return changed;
5887 }
5888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005889 @Override
5890 protected void onSizeChanged(int w, int h, int ow, int oh) {
5891 super.onSizeChanged(w, h, ow, oh);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005892
Grace Klobaa4fa1072009-11-09 12:01:50 -08005893 // adjust the max viewport width depending on the view dimensions. This
5894 // is to ensure the scaling is not going insane. So do not shrink it if
5895 // the view size is temporarily smaller, e.g. when soft keyboard is up.
Derek Sollenberger4aef6972010-06-24 15:03:43 -04005896 int newMaxViewportWidth = (int) (Math.max(w, h) / mZoomManager.getDefaultMinZoomScale());
Grace Klobaa4fa1072009-11-09 12:01:50 -08005897 if (newMaxViewportWidth > sMaxViewportWidth) {
5898 sMaxViewportWidth = newMaxViewportWidth;
5899 }
5900
Derek Sollenberger341e22f2010-06-02 12:34:34 -04005901 mZoomManager.onSizeChanged(w, h, ow, oh);
John Reck60c84d62011-06-08 18:00:02 -07005902
5903 if (mLoadedPicture != null && mDelaySetPicture == null) {
5904 // Size changes normally result in a new picture
5905 // Re-set the loaded picture to simulate that
5906 // However, do not update the base layer as that hasn't changed
5907 setNewPicture(mLoadedPicture, false);
5908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005909 }
5910
5911 @Override
5912 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
5913 super.onScrollChanged(l, t, oldl, oldt);
Adam Powell637d3372010-08-25 14:37:03 -07005914 if (!mInOverScrollMode) {
5915 sendOurVisibleRect();
5916 // update WebKit if visible title bar height changed. The logic is same
Steve Block92c99162011-05-23 17:36:01 +01005917 // as getVisibleTitleHeightImpl.
Adam Powell637d3372010-08-25 14:37:03 -07005918 int titleHeight = getTitleHeight();
5919 if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
5920 sendViewSizeZoom(false);
5921 }
Mike Reedb64f6f82010-03-23 10:29:37 -04005922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005923 }
Cary Clarkd6982c92009-05-29 11:02:22 -04005924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005925 @Override
5926 public boolean dispatchKeyEvent(KeyEvent event) {
Leon Scroggins115626a2011-02-17 12:00:48 -05005927 switch (event.getAction()) {
5928 case KeyEvent.ACTION_DOWN:
5929 mKeysPressed.add(Integer.valueOf(event.getKeyCode()));
5930 break;
5931 case KeyEvent.ACTION_MULTIPLE:
5932 // Always accept the action.
5933 break;
5934 case KeyEvent.ACTION_UP:
5935 int location = mKeysPressed.indexOf(Integer.valueOf(event.getKeyCode()));
5936 if (location == -1) {
5937 // We did not receive the key down for this key, so do not
5938 // handle the key up.
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005939 return false;
Leon Scroggins115626a2011-02-17 12:00:48 -05005940 } else {
5941 // We did receive the key down. Handle the key up, and
5942 // remove it from our pressed keys.
5943 mKeysPressed.remove(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005944 }
Leon Scroggins115626a2011-02-17 12:00:48 -05005945 break;
5946 default:
5947 // Accept the action. This should not happen, unless a new
5948 // action is added to KeyEvent.
5949 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005950 }
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005951 if (inEditingMode() && mWebTextView.isFocused()) {
5952 // Ensure that the WebTextView gets the event, even if it does
5953 // not currently have a bounds.
5954 return mWebTextView.dispatchKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005955 } else {
Leon Scrogginsdefba0c2011-02-17 13:51:50 -05005956 return super.dispatchKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005957 }
5958 }
5959
John Reck75738722011-06-10 11:28:53 -07005960 /*
5961 * Here is the snap align logic:
5962 * 1. If it starts nearly horizontally or vertically, snap align;
5963 * 2. If there is a dramitic direction change, let it go;
5964 *
5965 * Adjustable parameters. Angle is the radians on a unit circle, limited
5966 * to quadrant 1. Values range from 0f (horizontal) to PI/2 (vertical)
5967 */
John Reck2664d852011-06-13 10:37:15 -07005968 private static final float HSLOPE_TO_START_SNAP = .25f;
5969 private static final float HSLOPE_TO_BREAK_SNAP = .4f;
John Reck75738722011-06-10 11:28:53 -07005970 private static final float VSLOPE_TO_START_SNAP = 1.25f;
5971 private static final float VSLOPE_TO_BREAK_SNAP = .95f;
5972 /*
5973 * These values are used to influence the average angle when entering
5974 * snap mode. If is is the first movement entering snap, we set the average
5975 * to the appropriate ideal. If the user is entering into snap after the
5976 * first movement, then we average the average angle with these values.
5977 */
5978 private static final float ANGLE_VERT = 2f;
5979 private static final float ANGLE_HORIZ = 0f;
John Reck2664d852011-06-13 10:37:15 -07005980 /*
5981 * The modified moving average weight.
5982 * Formula: MAV[t]=MAV[t-1] + (P[t]-MAV[t-1])/n
5983 */
5984 private static final float MMA_WEIGHT_N = 5;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005985
Grace Klobac2242f22010-03-05 14:00:26 -08005986 private boolean hitFocusedPlugin(int contentX, int contentY) {
Cary Clarke84a0db2010-03-17 15:58:20 -04005987 if (DebugFlags.WEB_VIEW) {
5988 Log.v(LOGTAG, "nativeFocusIsPlugin()=" + nativeFocusIsPlugin());
5989 Rect r = nativeFocusNodeBounds();
5990 Log.v(LOGTAG, "nativeFocusNodeBounds()=(" + r.left + ", " + r.top
5991 + ", " + r.right + ", " + r.bottom + ")");
5992 }
Grace Klobac2242f22010-03-05 14:00:26 -08005993 return nativeFocusIsPlugin()
Cary Clarke84a0db2010-03-17 15:58:20 -04005994 && nativeFocusNodeBounds().contains(contentX, contentY);
Grace Klobac2242f22010-03-05 14:00:26 -08005995 }
5996
5997 private boolean shouldForwardTouchEvent() {
John Reck95b7d6f2011-06-03 15:23:43 -07005998 if (mFullScreenHolder != null) return true;
5999 if (mBlockWebkitViewMessages) return false;
6000 return mForwardTouchEvents
Cary Clark924af702010-06-04 16:37:43 -04006001 && !mSelectingText
Adam Powella0def722011-03-14 17:54:10 -07006002 && mPreventDefault != PREVENT_DEFAULT_IGNORE
John Reck95b7d6f2011-06-03 15:23:43 -07006003 && mPreventDefault != PREVENT_DEFAULT_NO;
Grace Klobac2242f22010-03-05 14:00:26 -08006004 }
6005
6006 private boolean inFullScreenMode() {
6007 return mFullScreenHolder != null;
6008 }
6009
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04006010 private void dismissFullScreenMode() {
6011 if (inFullScreenMode()) {
Derek Sollenberger7ab3d672011-06-01 14:45:05 -04006012 mFullScreenHolder.hide();
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04006013 mFullScreenHolder = null;
George Mount5d3f6e62011-12-05 15:19:00 -08006014 invalidate();
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04006015 }
6016 }
6017
Derek Sollenberger293c3602010-06-04 10:44:48 -04006018 void onPinchToZoomAnimationStart() {
6019 // cancel the single touch handling
6020 cancelTouch();
6021 onZoomAnimationStart();
6022 }
6023
6024 void onPinchToZoomAnimationEnd(ScaleGestureDetector detector) {
6025 onZoomAnimationEnd();
6026 // start a drag, TOUCH_PINCH_DRAG, can't use TOUCH_INIT_MODE as
6027 // it may trigger the unwanted click, can't use TOUCH_DRAG_MODE
6028 // as it may trigger the unwanted fling.
6029 mTouchMode = TOUCH_PINCH_DRAG;
6030 mConfirmMove = true;
6031 startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime);
6032 }
6033
Patrick Scott62310912010-12-06 17:44:50 -05006034 // See if there is a layer at x, y and switch to TOUCH_DRAG_LAYER_MODE if a
6035 // layer is found.
Patrick Scott4b903782010-11-30 08:14:05 -05006036 private void startScrollingLayer(float x, float y) {
Patrick Scott62310912010-12-06 17:44:50 -05006037 int contentX = viewToContentX((int) x + mScrollX);
6038 int contentY = viewToContentY((int) y + mScrollY);
Michael Kolb5da91bd2011-11-29 15:29:03 -08006039 mCurrentScrollingLayerId = nativeScrollableLayer(contentX, contentY,
Cary Clarkb9aaa772011-01-07 16:14:54 -05006040 mScrollingLayerRect, mScrollingLayerBounds);
Michael Kolb5da91bd2011-11-29 15:29:03 -08006041 if (mCurrentScrollingLayerId != 0) {
Patrick Scott62310912010-12-06 17:44:50 -05006042 mTouchMode = TOUCH_DRAG_LAYER_MODE;
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006043 }
6044 }
6045
6046 // 1/(density * density) used to compute the distance between points.
6047 // Computed in init().
6048 private float DRAG_LAYER_INVERSE_DENSITY_SQUARED;
6049
6050 // The distance between two points reported in onTouchEvent scaled by the
6051 // density of the screen.
6052 private static final int DRAG_LAYER_FINGER_DISTANCE = 20000;
6053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006054 @Override
Svetoslav Ganov7882a782011-05-11 17:53:01 -07006055 public boolean onHoverEvent(MotionEvent event) {
6056 if (mNativeClass == 0) {
6057 return false;
6058 }
6059 WebViewCore.CursorData data = cursorDataNoPosition();
Svetoslav Ganovfbb15602011-06-21 17:51:36 -07006060 data.mX = viewToContentX((int) event.getX() + mScrollX);
6061 data.mY = viewToContentY((int) event.getY() + mScrollY);
Svetoslav Ganov7882a782011-05-11 17:53:01 -07006062 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
6063 return true;
6064 }
6065
6066 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006067 public boolean onTouchEvent(MotionEvent ev) {
Andy Stadlerb34fd1ff2010-09-27 15:51:09 -07006068 if (mNativeClass == 0 || (!isClickable() && !isLongClickable())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006069 return false;
6070 }
6071
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006072 if (DebugFlags.WEB_VIEW) {
Huahui Wu41865f42010-09-02 13:41:41 -07006073 Log.v(LOGTAG, ev + " at " + ev.getEventTime()
6074 + " mTouchMode=" + mTouchMode
6075 + " numPointers=" + ev.getPointerCount());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006076 }
6077
Adam Powell4fb35d42011-03-03 17:54:55 -08006078 // If WebKit wasn't interested in this multitouch gesture, enqueue
6079 // the event for handling directly rather than making the round trip
6080 // to WebKit and back.
6081 if (ev.getPointerCount() > 1 && mPreventDefault != PREVENT_DEFAULT_NO) {
6082 passMultiTouchToWebKit(ev, mTouchEventQueue.nextTouchSequence());
Adam Powelle33cef82011-02-23 16:51:20 -08006083 } else {
Adam Powell4fb35d42011-03-03 17:54:55 -08006084 mTouchEventQueue.enqueueTouchEvent(ev);
Huahui Wu41865f42010-09-02 13:41:41 -07006085 }
6086
Adam Powell4fb35d42011-03-03 17:54:55 -08006087 // Since all events are handled asynchronously, we always want the gesture stream.
6088 return true;
Huahui Wu0904c0d2011-01-07 17:30:53 -08006089 }
Patrick Scott4b903782010-11-30 08:14:05 -05006090
John Reck75738722011-06-10 11:28:53 -07006091 private float calculateDragAngle(int dx, int dy) {
6092 dx = Math.abs(dx);
6093 dy = Math.abs(dy);
6094 return (float) Math.atan2(dy, dx);
6095 }
6096
Huahui Wuf147d452011-01-12 14:02:36 -08006097 /*
6098 * Common code for single touch and multi-touch.
6099 * (x, y) denotes current focus point, which is the touch point for single touch
6100 * and the middle point for multi-touch.
6101 */
Huahui Wu1f301252011-01-19 17:32:32 -08006102 private boolean handleTouchEventCommon(MotionEvent ev, int action, int x, int y) {
Huahui Wu0904c0d2011-01-07 17:30:53 -08006103 long eventTime = ev.getEventTime();
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006105 // Due to the touch screen edge effect, a touch closer to the edge
6106 // always snapped to the edge. As getViewWidth() can be different from
6107 // getWidth() due to the scrollbar, adjusting the point to match
6108 // getViewWidth(). Same applied to the height.
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006109 x = Math.min(x, getViewWidth() - 1);
6110 y = Math.min(y, getViewHeightWithTitle() - 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006111
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006112 int deltaX = mLastTouchX - x;
6113 int deltaY = mLastTouchY - y;
6114 int contentX = viewToContentX(x + mScrollX);
6115 int contentY = viewToContentY(y + mScrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006116
6117 switch (action) {
6118 case MotionEvent.ACTION_DOWN: {
Grace Klobac2242f22010-03-05 14:00:26 -08006119 mPreventDefault = PREVENT_DEFAULT_NO;
6120 mConfirmMove = false;
Cary Clarkb8491342010-11-29 16:23:19 -05006121 mInitialHitTestResult = null;
Grace Kloba04b28682009-09-14 14:38:37 -07006122 if (!mScroller.isFinished()) {
Cary Clark278ce052009-08-31 16:08:42 -04006123 // stop the current scroll animation, but if this is
6124 // the start of a fling, allow it to add to the current
6125 // fling's velocity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006126 mScroller.abortAnimation();
6127 mTouchMode = TOUCH_DRAG_START_MODE;
Grace Klobac2242f22010-03-05 14:00:26 -08006128 mConfirmMove = true;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006129 nativeSetIsScrolling(false);
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006130 } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
6131 mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
John Reck335f4542011-08-25 18:25:09 -07006132 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
6133 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07006134 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006135 if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
6136 mTouchMode = TOUCH_DOUBLE_TAP_MODE;
6137 } else {
6138 // commit the short press action for the previous tap
6139 doShortPress();
Grace Klobac2242f22010-03-05 14:00:26 -08006140 mTouchMode = TOUCH_INIT_MODE;
John Reck95b7d6f2011-06-03 15:23:43 -07006141 mDeferTouchProcess = !mBlockWebkitViewMessages
6142 && (!inFullScreenMode() && mForwardTouchEvents)
6143 ? hitFocusedPlugin(contentX, contentY)
6144 : false;
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006145 }
Grace Klobac2242f22010-03-05 14:00:26 -08006146 } else { // the normal case
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006147 mTouchMode = TOUCH_INIT_MODE;
John Reck95b7d6f2011-06-03 15:23:43 -07006148 mDeferTouchProcess = !mBlockWebkitViewMessages
6149 && (!inFullScreenMode() && mForwardTouchEvents)
6150 ? hitFocusedPlugin(contentX, contentY)
6151 : false;
6152 if (!mBlockWebkitViewMessages) {
6153 mWebViewCore.sendMessage(
6154 EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
6155 }
John Reck335f4542011-08-25 18:25:09 -07006156 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
Grace Kloba178db412010-05-18 22:22:23 -07006157 TouchHighlightData data = new TouchHighlightData();
6158 data.mX = contentX;
6159 data.mY = contentY;
John Reck335f4542011-08-25 18:25:09 -07006160 data.mNativeLayerRect = new Rect();
6161 data.mNativeLayer = nativeScrollableLayer(
6162 contentX, contentY, data.mNativeLayerRect, null);
Grace Kloba178db412010-05-18 22:22:23 -07006163 data.mSlop = viewToContentDimension(mNavSlop);
John Reck335f4542011-08-25 18:25:09 -07006164 mTouchHighlightRegion.setEmpty();
John Reck95b7d6f2011-06-03 15:23:43 -07006165 if (!mBlockWebkitViewMessages) {
John Reck335f4542011-08-25 18:25:09 -07006166 mTouchHighlightRequested = System.currentTimeMillis();
6167 mWebViewCore.sendMessageAtFrontOfQueue(
6168 EventHub.GET_TOUCH_HIGHLIGHT_RECTS, data);
John Reck95b7d6f2011-06-03 15:23:43 -07006169 }
Grace Kloba178db412010-05-18 22:22:23 -07006170 if (DEBUG_TOUCH_HIGHLIGHT) {
6171 if (getSettings().getNavDump()) {
6172 mTouchHighlightX = (int) x + mScrollX;
6173 mTouchHighlightY = (int) y + mScrollY;
6174 mPrivateHandler.postDelayed(new Runnable() {
6175 public void run() {
6176 mTouchHighlightX = mTouchHighlightY = 0;
6177 invalidate();
6178 }
6179 }, TOUCH_HIGHLIGHT_ELAPSE_TIME);
6180 }
6181 }
6182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006183 if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
Dan Egnor18e93962010-02-10 19:27:58 -08006184 EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006185 (eventTime - mLastTouchUpTime), eventTime);
6186 }
Cary Clark924af702010-06-04 16:37:43 -04006187 if (mSelectingText) {
6188 mDrawSelectionPointer = false;
6189 mSelectionStarted = nativeStartSelection(contentX, contentY);
6190 if (DebugFlags.WEB_VIEW) {
6191 Log.v(LOGTAG, "select=" + contentX + "," + contentY);
6192 }
6193 invalidate();
6194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006195 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07006196 // Trigger the link
Cary Clark43f608f2011-02-18 11:30:12 -05006197 if (!mSelectingText && (mTouchMode == TOUCH_INIT_MODE
6198 || mTouchMode == TOUCH_DOUBLE_TAP_MODE)) {
Grace Klobac2242f22010-03-05 14:00:26 -08006199 mPrivateHandler.sendEmptyMessageDelayed(
6200 SWITCH_TO_SHORTPRESS, TAP_TIMEOUT);
6201 mPrivateHandler.sendEmptyMessageDelayed(
6202 SWITCH_TO_LONGPRESS, LONG_PRESS_TIMEOUT);
6203 if (inFullScreenMode() || mDeferTouchProcess) {
6204 mPreventDefault = PREVENT_DEFAULT_YES;
John Reck95b7d6f2011-06-03 15:23:43 -07006205 } else if (!mBlockWebkitViewMessages && mForwardTouchEvents) {
Grace Klobac2242f22010-03-05 14:00:26 -08006206 mPreventDefault = PREVENT_DEFAULT_MAYBE_YES;
6207 } else {
6208 mPreventDefault = PREVENT_DEFAULT_NO;
6209 }
6210 // pass the touch events from UI thread to WebCore thread
6211 if (shouldForwardTouchEvent()) {
Huahui Wu98933f32011-07-07 14:27:44 -07006212 TouchEventData ted = new TouchEventData();
Grace Klobac2242f22010-03-05 14:00:26 -08006213 ted.mAction = action;
Huahui Wu98933f32011-07-07 14:27:44 -07006214 ted.mIds = new int[1];
6215 ted.mIds[0] = ev.getPointerId(0);
6216 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006217 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006218 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006219 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006220 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006221 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006222 ted.mNativeLayer = nativeScrollableLayer(
6223 contentX, contentY, ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08006224 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006225 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006226 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6227 if (mDeferTouchProcess) {
6228 // still needs to set them for compute deltaX/Y
6229 mLastTouchX = x;
6230 mLastTouchY = y;
6231 break;
6232 }
6233 if (!inFullScreenMode()) {
Ben Murdocha3f055e2010-05-26 18:46:56 +01006234 mPrivateHandler.removeMessages(PREVENT_DEFAULT_TIMEOUT);
Grace Klobac2242f22010-03-05 14:00:26 -08006235 mPrivateHandler.sendMessageDelayed(mPrivateHandler
6236 .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
6237 action, 0), TAP_TIMEOUT);
6238 }
6239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006240 }
Grace Kloba3a0def22010-01-23 21:11:54 -08006241 startTouch(x, y, eventTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006242 break;
6243 }
6244 case MotionEvent.ACTION_MOVE: {
Grace Klobac2242f22010-03-05 14:00:26 -08006245 boolean firstMove = false;
6246 if (!mConfirmMove && (deltaX * deltaX + deltaY * deltaY)
6247 >= mTouchSlopSquare) {
6248 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
6249 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6250 mConfirmMove = true;
6251 firstMove = true;
6252 if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
6253 mTouchMode = TOUCH_INIT_MODE;
6254 }
John Reck335f4542011-08-25 18:25:09 -07006255 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
6256 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07006257 }
Grace Klobac2242f22010-03-05 14:00:26 -08006258 }
6259 // pass the touch events from UI thread to WebCore thread
6260 if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
6261 || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
Huahui Wu98933f32011-07-07 14:27:44 -07006262 TouchEventData ted = new TouchEventData();
Grace Klobac2242f22010-03-05 14:00:26 -08006263 ted.mAction = action;
Huahui Wu98933f32011-07-07 14:27:44 -07006264 ted.mIds = new int[1];
6265 ted.mIds[0] = ev.getPointerId(0);
6266 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006267 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006268 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006269 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006270 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006271 ted.mReprocess = mDeferTouchProcess;
Michael Kolb5da91bd2011-11-29 15:29:03 -08006272 ted.mNativeLayer = mCurrentScrollingLayerId;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006273 ted.mNativeLayerRect.set(mScrollingLayerRect);
Adam Powellae9d2642011-03-08 16:00:30 -08006274 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006275 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006276 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6277 mLastSentTouchTime = eventTime;
6278 if (mDeferTouchProcess) {
6279 break;
6280 }
6281 if (firstMove && !inFullScreenMode()) {
6282 mPrivateHandler.sendMessageDelayed(mPrivateHandler
6283 .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
6284 action, 0), TAP_TIMEOUT);
6285 }
6286 }
6287 if (mTouchMode == TOUCH_DONE_MODE
6288 || mPreventDefault == PREVENT_DEFAULT_YES) {
6289 // no dragging during scroll zoom animation, or when prevent
6290 // default is yes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006291 break;
6292 }
Grace Klobac2242f22010-03-05 14:00:26 -08006293 if (mVelocityTracker == null) {
6294 Log.e(LOGTAG, "Got null mVelocityTracker when "
6295 + "mPreventDefault = " + mPreventDefault
6296 + " mDeferTouchProcess = " + mDeferTouchProcess
6297 + " mTouchMode = " + mTouchMode);
Huahui Wu8465cc92011-01-12 10:17:19 -08006298 } else {
6299 mVelocityTracker.addMovement(ev);
Grace Klobac2242f22010-03-05 14:00:26 -08006300 }
Cary Clark924af702010-06-04 16:37:43 -04006301 if (mSelectingText && mSelectionStarted) {
6302 if (DebugFlags.WEB_VIEW) {
6303 Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006304 }
Leon Scroggins7f7bd522010-11-05 11:23:31 -04006305 ViewParent parent = getParent();
6306 if (parent != null) {
6307 parent.requestDisallowInterceptTouchEvent(true);
6308 }
Cary Clarkb9aaa772011-01-07 16:14:54 -05006309 mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL
6310 : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
6311 mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL
6312 : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
6313 if ((mAutoScrollX != 0 || mAutoScrollY != 0)
6314 && !mSentAutoScrollMessage) {
6315 mSentAutoScrollMessage = true;
6316 mPrivateHandler.sendEmptyMessageDelayed(
6317 SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
Cary Clark6f5dfc62010-11-11 13:09:20 -05006318 }
Cary Clarkaa86ac82010-12-28 11:30:18 -05006319 if (deltaX != 0 || deltaY != 0) {
6320 nativeExtendSelection(contentX, contentY);
6321 invalidate();
6322 }
Cary Clark924af702010-06-04 16:37:43 -04006323 break;
6324 }
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006325
6326 if (mTouchMode != TOUCH_DRAG_MODE &&
6327 mTouchMode != TOUCH_DRAG_LAYER_MODE) {
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07006328
Grace Klobac2242f22010-03-05 14:00:26 -08006329 if (!mConfirmMove) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006330 break;
6331 }
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07006332
Grace Klobac2242f22010-03-05 14:00:26 -08006333 if (mPreventDefault == PREVENT_DEFAULT_MAYBE_YES
6334 || mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
Grace Klobaf58af622009-09-24 17:41:23 -07006335 // track mLastTouchTime as we may need to do fling at
6336 // ACTION_UP
6337 mLastTouchTime = eventTime;
6338 break;
6339 }
Adam Powell048a3a52010-09-08 23:59:37 -07006340
Huahui Wuc0109242011-01-14 12:51:12 -08006341 // Only lock dragging to one axis if we don't have a scale in progress.
6342 // Scaling implies free-roaming movement. Note this is only ever a question
6343 // if mZoomManager.supportsPanDuringZoom() is true.
6344 final ScaleGestureDetector detector =
6345 mZoomManager.getMultiTouchGestureDetector();
John Reck75738722011-06-10 11:28:53 -07006346 mAverageAngle = calculateDragAngle(deltaX, deltaY);
Huahui Wuc0109242011-01-14 12:51:12 -08006347 if (detector == null || !detector.isInProgress()) {
6348 // if it starts nearly horizontal or vertical, enforce it
John Reck75738722011-06-10 11:28:53 -07006349 if (mAverageAngle < HSLOPE_TO_START_SNAP) {
Huahui Wuc0109242011-01-14 12:51:12 -08006350 mSnapScrollMode = SNAP_X;
6351 mSnapPositive = deltaX > 0;
John Reck75738722011-06-10 11:28:53 -07006352 mAverageAngle = ANGLE_HORIZ;
6353 } else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
Huahui Wuc0109242011-01-14 12:51:12 -08006354 mSnapScrollMode = SNAP_Y;
6355 mSnapPositive = deltaY > 0;
John Reck75738722011-06-10 11:28:53 -07006356 mAverageAngle = ANGLE_VERT;
Huahui Wuc0109242011-01-14 12:51:12 -08006357 }
6358 }
6359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006360 mTouchMode = TOUCH_DRAG_MODE;
Romain Guyf7b4acc2009-12-01 16:24:45 -08006361 mLastTouchX = x;
6362 mLastTouchY = y;
Romain Guyf7b4acc2009-12-01 16:24:45 -08006363 deltaX = 0;
6364 deltaY = 0;
6365
Patrick Scott62310912010-12-06 17:44:50 -05006366 startScrollingLayer(x, y);
Grace Klobac2242f22010-03-05 14:00:26 -08006367 startDrag();
6368 }
6369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006370 // do pan
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006371 boolean done = false;
Cary Clark25415e22009-10-12 13:41:28 -04006372 boolean keepScrollBarsVisible = false;
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006373 if (deltaX == 0 && deltaY == 0) {
Cary Clark25415e22009-10-12 13:41:28 -04006374 keepScrollBarsVisible = done = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006375 } else {
John Reck2664d852011-06-13 10:37:15 -07006376 mAverageAngle +=
6377 (calculateDragAngle(deltaX, deltaY) - mAverageAngle)
6378 / MMA_WEIGHT_N;
John Reck75738722011-06-10 11:28:53 -07006379 if (mSnapScrollMode != SNAP_NONE) {
6380 if (mSnapScrollMode == SNAP_Y) {
6381 // radical change means getting out of snap mode
6382 if (mAverageAngle < VSLOPE_TO_BREAK_SNAP) {
6383 mSnapScrollMode = SNAP_NONE;
6384 }
6385 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006386 if (mSnapScrollMode == SNAP_X) {
6387 // radical change means getting out of snap mode
John Reck75738722011-06-10 11:28:53 -07006388 if (mAverageAngle > HSLOPE_TO_BREAK_SNAP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006389 mSnapScrollMode = SNAP_NONE;
6390 }
John Reck75738722011-06-10 11:28:53 -07006391 }
6392 } else {
6393 if (mAverageAngle < HSLOPE_TO_START_SNAP) {
6394 mSnapScrollMode = SNAP_X;
6395 mSnapPositive = deltaX > 0;
6396 mAverageAngle = (mAverageAngle + ANGLE_HORIZ) / 2;
6397 } else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
6398 mSnapScrollMode = SNAP_Y;
6399 mSnapPositive = deltaY > 0;
6400 mAverageAngle = (mAverageAngle + ANGLE_VERT) / 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006401 }
6402 }
Cary Clarkac492e12009-10-14 14:53:37 -04006403 if (mSnapScrollMode != SNAP_NONE) {
6404 if ((mSnapScrollMode & SNAP_X) == SNAP_X) {
6405 deltaY = 0;
Grace Kloba5b2c0562009-09-30 10:17:13 -07006406 } else {
Cary Clarkac492e12009-10-14 14:53:37 -04006407 deltaX = 0;
Grace Kloba5b2c0562009-09-30 10:17:13 -07006408 }
Cary Clarkac492e12009-10-14 14:53:37 -04006409 }
John Reck75738722011-06-10 11:28:53 -07006410 mLastTouchX = x;
6411 mLastTouchY = y;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006412
6413 if (deltaX * deltaX + deltaY * deltaY > mTouchSlopSquare) {
Cary Clarkac492e12009-10-14 14:53:37 -04006414 mHeldMotionless = MOTIONLESS_FALSE;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006415 nativeSetIsScrolling(true);
6416 } else {
6417 mHeldMotionless = MOTIONLESS_TRUE;
6418 nativeSetIsScrolling(false);
6419 keepScrollBarsVisible = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006420 }
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006422 mLastTouchTime = eventTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006423 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006424
Grace Klobac2242f22010-03-05 14:00:26 -08006425 doDrag(deltaX, deltaY);
Mike Reed19f3f0e2009-11-12 12:50:20 -05006426
Patrick Scotta3ebcc92010-07-16 11:52:22 -04006427 // Turn off scrollbars when dragging a layer.
6428 if (keepScrollBarsVisible &&
6429 mTouchMode != TOUCH_DRAG_LAYER_MODE) {
Cary Clark25415e22009-10-12 13:41:28 -04006430 if (mHeldMotionless != MOTIONLESS_TRUE) {
6431 mHeldMotionless = MOTIONLESS_TRUE;
6432 invalidate();
6433 }
Grace Kloba5b2c0562009-09-30 10:17:13 -07006434 // keep the scrollbar on the screen even there is no scroll
6435 awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
6436 false);
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006437 // Post a message so that we'll keep them alive while we're not scrolling.
6438 mPrivateHandler.sendMessageDelayed(mPrivateHandler
6439 .obtainMessage(AWAKEN_SCROLL_BARS),
6440 ViewConfiguration.getScrollDefaultDelay());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006441 // return false to indicate that we can't pan out of the
6442 // view space
Cary Clark25415e22009-10-12 13:41:28 -04006443 return !done;
Ben Murdochfd8d3de2011-10-13 13:23:29 +01006444 } else {
6445 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006446 }
6447 break;
6448 }
6449 case MotionEvent.ACTION_UP: {
Leon Scroggins IIIae9f8e42010-04-14 16:06:06 -04006450 if (!isFocused()) requestFocus();
Grace Klobac2242f22010-03-05 14:00:26 -08006451 // pass the touch events from UI thread to WebCore thread
6452 if (shouldForwardTouchEvent()) {
Huahui Wu98933f32011-07-07 14:27:44 -07006453 TouchEventData ted = new TouchEventData();
6454 ted.mIds = new int[1];
6455 ted.mIds[0] = ev.getPointerId(0);
Grace Klobac2242f22010-03-05 14:00:26 -08006456 ted.mAction = action;
Huahui Wu98933f32011-07-07 14:27:44 -07006457 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006458 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006459 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006460 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006461 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006462 ted.mReprocess = mDeferTouchProcess;
Michael Kolb5da91bd2011-11-29 15:29:03 -08006463 ted.mNativeLayer = mCurrentScrollingLayerId;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006464 ted.mNativeLayerRect.set(mScrollingLayerRect);
Adam Powellae9d2642011-03-08 16:00:30 -08006465 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006466 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006467 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Mike Reed19f3f0e2009-11-12 12:50:20 -05006468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006469 mLastTouchUpTime = eventTime;
Cary Clarkb9aaa772011-01-07 16:14:54 -05006470 if (mSentAutoScrollMessage) {
6471 mAutoScrollX = mAutoScrollY = 0;
6472 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006473 switch (mTouchMode) {
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006474 case TOUCH_DOUBLE_TAP_MODE: // double tap
6475 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
Grace Klobac2242f22010-03-05 14:00:26 -08006476 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6477 if (inFullScreenMode() || mDeferTouchProcess) {
Huahui Wu98933f32011-07-07 14:27:44 -07006478 TouchEventData ted = new TouchEventData();
6479 ted.mIds = new int[1];
6480 ted.mIds[0] = ev.getPointerId(0);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08006481 ted.mAction = WebViewCore.ACTION_DOUBLETAP;
Huahui Wu98933f32011-07-07 14:27:44 -07006482 ted.mPoints = new Point[1];
Huahui Wu41865f42010-09-02 13:41:41 -07006483 ted.mPoints[0] = new Point(contentX, contentY);
Huahui Wu98933f32011-07-07 14:27:44 -07006484 ted.mPointsInView = new Point[1];
Huahui Wu88b869a2011-03-17 17:42:12 -07006485 ted.mPointsInView[0] = new Point(x, y);
Huahui Wu98933f32011-07-07 14:27:44 -07006486 ted.mMetaState = ev.getMetaState();
Grace Klobac2242f22010-03-05 14:00:26 -08006487 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006488 ted.mNativeLayer = nativeScrollableLayer(
6489 contentX, contentY,
6490 ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08006491 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07006492 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08006493 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Grace Klobac2242f22010-03-05 14:00:26 -08006494 } else if (mPreventDefault != PREVENT_DEFAULT_YES){
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04006495 mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
Grace Klobac2242f22010-03-05 14:00:26 -08006496 mTouchMode = TOUCH_DONE_MODE;
Grace Kloba5f68d6f2009-12-08 18:42:54 -08006497 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07006498 break;
Grace Klobaf58af622009-09-24 17:41:23 -07006499 case TOUCH_INIT_MODE: // tap
Grace Klobad66d84f2009-09-27 14:48:07 -07006500 case TOUCH_SHORTPRESS_START_MODE:
6501 case TOUCH_SHORTPRESS_MODE:
Grace Klobaf58af622009-09-24 17:41:23 -07006502 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
Grace Klobad66d84f2009-09-27 14:48:07 -07006503 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
Grace Klobac2242f22010-03-05 14:00:26 -08006504 if (mConfirmMove) {
Grace Klobaf58af622009-09-24 17:41:23 -07006505 Log.w(LOGTAG, "Miss a drag as we are waiting for" +
6506 " WebCore's response for touch down.");
Grace Klobac2242f22010-03-05 14:00:26 -08006507 if (mPreventDefault != PREVENT_DEFAULT_YES
Grace Klobad7625dd2010-03-04 11:46:12 -08006508 && (computeMaxScrollX() > 0
6509 || computeMaxScrollY() > 0)) {
Ben Murdochfc0bcdd2010-04-23 10:55:29 -07006510 // If the user has performed a very quick touch
6511 // sequence it is possible that we may get here
6512 // before WebCore has had a chance to process the events.
6513 // In this case, any call to preventDefault in the
6514 // JS touch handler will not have been executed yet.
6515 // Hence we will see both the UI (now) and WebCore
6516 // (when context switches) handling the event,
6517 // regardless of whether the web developer actually
6518 // doeses preventDefault in their touch handler. This
6519 // is the nature of our asynchronous touch model.
6520
Grace Klobaf58af622009-09-24 17:41:23 -07006521 // we will not rewrite drag code here, but we
6522 // will try fling if it applies.
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006523 WebViewCore.reducePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006524 // to get better performance, pause updating the
6525 // picture
6526 WebViewCore.pauseUpdatePicture(mWebViewCore);
Grace Klobaf58af622009-09-24 17:41:23 -07006527 // fall through to TOUCH_DRAG_MODE
6528 } else {
Grace Klobac36862d52010-04-19 10:16:42 -07006529 // WebKit may consume the touch event and modify
6530 // DOM. drawContentPicture() will be called with
6531 // animateSroll as true for better performance.
6532 // Force redraw in high-quality.
6533 invalidate();
Grace Klobaf58af622009-09-24 17:41:23 -07006534 break;
6535 }
6536 } else {
Cary Clark924af702010-06-04 16:37:43 -04006537 if (mSelectingText) {
6538 // tapping on selection or controls does nothing
6539 if (!nativeHitSelection(contentX, contentY)) {
6540 selectionDone();
6541 }
6542 break;
6543 }
Grace Klobaec9a1042010-06-01 19:00:23 -07006544 // only trigger double tap if the WebView is
6545 // scalable
6546 if (mTouchMode == TOUCH_INIT_MODE
6547 && (canZoomIn() || canZoomOut())) {
Grace Klobac2242f22010-03-05 14:00:26 -08006548 mPrivateHandler.sendEmptyMessageDelayed(
6549 RELEASE_SINGLE_TAP, ViewConfiguration
6550 .getDoubleTapTimeout());
6551 } else {
6552 doShortPress();
Grace Klobaf58af622009-09-24 17:41:23 -07006553 }
6554 break;
6555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006556 case TOUCH_DRAG_MODE:
Patrick Scott2f492272010-12-03 09:52:35 -05006557 case TOUCH_DRAG_LAYER_MODE:
Cary Clark25415e22009-10-12 13:41:28 -04006558 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
6559 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006560 // if the user waits a while w/o moving before the
6561 // up, we don't want to do a fling
6562 if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
Grace Klobac2242f22010-03-05 14:00:26 -08006563 if (mVelocityTracker == null) {
6564 Log.e(LOGTAG, "Got null mVelocityTracker when "
6565 + "mPreventDefault = "
6566 + mPreventDefault
6567 + " mDeferTouchProcess = "
6568 + mDeferTouchProcess);
Huahui Wu8465cc92011-01-12 10:17:19 -08006569 } else {
6570 mVelocityTracker.addMovement(ev);
Grace Klobac2242f22010-03-05 14:00:26 -08006571 }
Grace Kloba9b657802010-04-08 13:46:23 -07006572 // set to MOTIONLESS_IGNORE so that it won't keep
6573 // removing and sending message in
6574 // drawCoreAndCursorRing()
6575 mHeldMotionless = MOTIONLESS_IGNORE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006576 doFling();
6577 break;
Adam Powell637d3372010-08-25 14:37:03 -07006578 } else {
6579 if (mScroller.springBack(mScrollX, mScrollY, 0,
6580 computeMaxScrollX(), 0,
6581 computeMaxScrollY())) {
6582 invalidate();
6583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006584 }
Grace Kloba9b657802010-04-08 13:46:23 -07006585 // redraw in high-quality, as we're done dragging
6586 mHeldMotionless = MOTIONLESS_TRUE;
6587 invalidate();
Grace Kloba524aab572010-04-07 11:12:52 -07006588 // fall through
6589 case TOUCH_DRAG_START_MODE:
6590 // TOUCH_DRAG_START_MODE should not happen for the real
6591 // device as we almost certain will get a MOVE. But this
6592 // is possible on emulator.
Cary Clark278ce052009-08-31 16:08:42 -04006593 mLastVelocity = 0;
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006594 WebViewCore.resumePriority();
Cary Clark0df02692010-11-24 11:01:37 -05006595 if (!mSelectingText) {
6596 WebViewCore.resumeUpdatePicture(mWebViewCore);
6597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006598 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006599 }
Grace Klobac2242f22010-03-05 14:00:26 -08006600 stopTouch();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006601 break;
6602 }
6603 case MotionEvent.ACTION_CANCEL: {
Grace Klobad7625dd2010-03-04 11:46:12 -08006604 if (mTouchMode == TOUCH_DRAG_MODE) {
Adam Powell637d3372010-08-25 14:37:03 -07006605 mScroller.springBack(mScrollX, mScrollY, 0,
6606 computeMaxScrollX(), 0, computeMaxScrollY());
Grace Klobac2242f22010-03-05 14:00:26 -08006607 invalidate();
Grace Klobad7625dd2010-03-04 11:46:12 -08006608 }
Grace Klobac2242f22010-03-05 14:00:26 -08006609 cancelWebCoreTouchEvent(contentX, contentY, false);
6610 cancelTouch();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006611 break;
6612 }
6613 }
6614 return true;
6615 }
Cary Clarkd6982c92009-05-29 11:02:22 -04006616
Adam Powell4fb35d42011-03-03 17:54:55 -08006617 private void passMultiTouchToWebKit(MotionEvent ev, long sequence) {
Huahui Wu98933f32011-07-07 14:27:44 -07006618 TouchEventData ted = new TouchEventData();
6619 ted.mAction = ev.getActionMasked();
6620 final int count = ev.getPointerCount();
6621 ted.mIds = new int[count];
6622 ted.mPoints = new Point[count];
6623 ted.mPointsInView = new Point[count];
6624 for (int c = 0; c < count; c++) {
Huahui Wue838a422011-01-13 16:03:43 -08006625 ted.mIds[c] = ev.getPointerId(c);
Huahui Wu41865f42010-09-02 13:41:41 -07006626 int x = viewToContentX((int) ev.getX(c) + mScrollX);
6627 int y = viewToContentY((int) ev.getY(c) + mScrollY);
6628 ted.mPoints[c] = new Point(x, y);
Huahui Wu88b869a2011-03-17 17:42:12 -07006629 ted.mPointsInView[c] = new Point((int) ev.getX(c), (int) ev.getY(c));
Huahui Wu41865f42010-09-02 13:41:41 -07006630 }
Huahui Wu98933f32011-07-07 14:27:44 -07006631 if (ted.mAction == MotionEvent.ACTION_POINTER_DOWN
6632 || ted.mAction == MotionEvent.ACTION_POINTER_UP) {
6633 ted.mActionIndex = ev.getActionIndex();
6634 }
6635 ted.mMetaState = ev.getMetaState();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006636 ted.mReprocess = true;
6637 ted.mMotionEvent = MotionEvent.obtain(ev);
Adam Powell4fb35d42011-03-03 17:54:55 -08006638 ted.mSequence = sequence;
Adam Powell3c534772011-04-04 14:27:12 -07006639 mTouchEventQueue.preQueueTouchEventData(ted);
Huahui Wu41865f42010-09-02 13:41:41 -07006640 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6641 cancelLongPress();
6642 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
Huahui Wu41865f42010-09-02 13:41:41 -07006643 }
6644
Adam Powell8f626a12011-03-10 19:27:15 -08006645 void handleMultiTouchInWebView(MotionEvent ev) {
Huahui Wu0904c0d2011-01-07 17:30:53 -08006646 if (DebugFlags.WEB_VIEW) {
6647 Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime()
6648 + " mTouchMode=" + mTouchMode
6649 + " numPointers=" + ev.getPointerCount()
6650 + " scrolloffset=(" + mScrollX + "," + mScrollY + ")");
6651 }
6652
6653 final ScaleGestureDetector detector =
6654 mZoomManager.getMultiTouchGestureDetector();
Huahui Wu8465cc92011-01-12 10:17:19 -08006655
6656 // A few apps use WebView but don't instantiate gesture detector.
6657 // We don't need to support multi touch for them.
Huahui Wu1f301252011-01-19 17:32:32 -08006658 if (detector == null) return;
Huahui Wu8465cc92011-01-12 10:17:19 -08006659
Huahui Wu0904c0d2011-01-07 17:30:53 -08006660 float x = ev.getX();
6661 float y = ev.getY();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006662
Adam Powell8f626a12011-03-10 19:27:15 -08006663 if (mPreventDefault != PREVENT_DEFAULT_YES) {
6664 detector.onTouchEvent(ev);
Huahui Wu0904c0d2011-01-07 17:30:53 -08006665
Adam Powell8f626a12011-03-10 19:27:15 -08006666 if (detector.isInProgress()) {
6667 if (DebugFlags.WEB_VIEW) {
6668 Log.v(LOGTAG, "detector is in progress");
6669 }
6670 mLastTouchTime = ev.getEventTime();
6671 x = detector.getFocusX();
6672 y = detector.getFocusY();
Huahui Wuf147d452011-01-12 14:02:36 -08006673
Adam Powell8f626a12011-03-10 19:27:15 -08006674 cancelLongPress();
6675 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6676 if (!mZoomManager.supportsPanDuringZoom()) {
6677 return;
6678 }
6679 mTouchMode = TOUCH_DRAG_MODE;
6680 if (mVelocityTracker == null) {
6681 mVelocityTracker = VelocityTracker.obtain();
6682 }
Huahui Wu0904c0d2011-01-07 17:30:53 -08006683 }
6684 }
6685
Huahui Wuf147d452011-01-12 14:02:36 -08006686 int action = ev.getActionMasked();
Huahui Wu0904c0d2011-01-07 17:30:53 -08006687 if (action == MotionEvent.ACTION_POINTER_DOWN) {
6688 cancelTouch();
6689 action = MotionEvent.ACTION_DOWN;
Huahui Wu5f4835a2011-07-20 16:50:19 -07006690 } else if (action == MotionEvent.ACTION_POINTER_UP && ev.getPointerCount() >= 2) {
6691 // set mLastTouchX/Y to the remaining points for multi-touch.
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08006692 mLastTouchX = Math.round(x);
6693 mLastTouchY = Math.round(y);
Huahui Wu0904c0d2011-01-07 17:30:53 -08006694 } else if (action == MotionEvent.ACTION_MOVE) {
6695 // negative x or y indicate it is on the edge, skip it.
6696 if (x < 0 || y < 0) {
Huahui Wu1f301252011-01-19 17:32:32 -08006697 return;
Huahui Wu0904c0d2011-01-07 17:30:53 -08006698 }
6699 }
6700
Huahui Wu1f301252011-01-19 17:32:32 -08006701 handleTouchEventCommon(ev, action, Math.round(x), Math.round(y));
Huahui Wu0904c0d2011-01-07 17:30:53 -08006702 }
6703
Grace Klobac2242f22010-03-05 14:00:26 -08006704 private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
6705 if (shouldForwardTouchEvent()) {
6706 if (removeEvents) {
6707 mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
6708 }
6709 TouchEventData ted = new TouchEventData();
Huahui Wue838a422011-01-13 16:03:43 -08006710 ted.mIds = new int[1];
6711 ted.mIds[0] = 0;
Huahui Wu41865f42010-09-02 13:41:41 -07006712 ted.mPoints = new Point[1];
6713 ted.mPoints[0] = new Point(x, y);
Huahui Wu88b869a2011-03-17 17:42:12 -07006714 ted.mPointsInView = new Point[1];
6715 int viewX = contentToViewX(x) - mScrollX;
6716 int viewY = contentToViewY(y) - mScrollY;
6717 ted.mPointsInView[0] = new Point(viewX, viewY);
Huahui Wu98933f32011-07-07 14:27:44 -07006718 ted.mAction = MotionEvent.ACTION_CANCEL;
Patrick Scottcfa734a2011-02-22 11:19:02 -05006719 ted.mNativeLayer = nativeScrollableLayer(
6720 x, y, ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08006721 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Grace Klobac2242f22010-03-05 14:00:26 -08006722 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
6723 mPreventDefault = PREVENT_DEFAULT_IGNORE;
Adam Powellbaa33802011-03-25 13:58:19 -07006724
6725 if (removeEvents) {
6726 // Mark this after sending the message above; we should
6727 // be willing to ignore the cancel event that we just sent.
6728 mTouchEventQueue.ignoreCurrentlyMissingEvents();
6729 }
Grace Klobac2242f22010-03-05 14:00:26 -08006730 }
6731 }
6732
Grace Kloba3a0def22010-01-23 21:11:54 -08006733 private void startTouch(float x, float y, long eventTime) {
6734 // Remember where the motion event started
John Reck75738722011-06-10 11:28:53 -07006735 mStartTouchX = mLastTouchX = Math.round(x);
6736 mStartTouchY = mLastTouchY = Math.round(y);
Grace Kloba3a0def22010-01-23 21:11:54 -08006737 mLastTouchTime = eventTime;
6738 mVelocityTracker = VelocityTracker.obtain();
6739 mSnapScrollMode = SNAP_NONE;
John Reck0966dd22011-09-18 11:03:00 -07006740 mPrivateHandler.sendEmptyMessageDelayed(UPDATE_SELECTION,
6741 ViewConfiguration.getTapTimeout());
Grace Kloba3a0def22010-01-23 21:11:54 -08006742 }
6743
Grace Klobac2242f22010-03-05 14:00:26 -08006744 private void startDrag() {
6745 WebViewCore.reducePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006746 // to get better performance, pause updating the picture
6747 WebViewCore.pauseUpdatePicture(mWebViewCore);
Chris Craik58d94af2011-08-18 11:42:13 -07006748 nativeSetIsScrolling(true);
6749
Grace Klobac2242f22010-03-05 14:00:26 -08006750 if (!mDragFromTextInput) {
6751 nativeHideCursor();
6752 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006753
6754 if (mHorizontalScrollBarMode != SCROLLBAR_ALWAYSOFF
6755 || mVerticalScrollBarMode != SCROLLBAR_ALWAYSOFF) {
6756 mZoomManager.invokeZoomPicker();
Grace Klobac2242f22010-03-05 14:00:26 -08006757 }
6758 }
6759
6760 private void doDrag(int deltaX, int deltaY) {
6761 if ((deltaX | deltaY) != 0) {
Patrick Scott62310912010-12-06 17:44:50 -05006762 int oldX = mScrollX;
6763 int oldY = mScrollY;
6764 int rangeX = computeMaxScrollX();
6765 int rangeY = computeMaxScrollY();
6766 int overscrollDistance = mOverscrollDistance;
Adam Powell637d3372010-08-25 14:37:03 -07006767
Patrick Scott62310912010-12-06 17:44:50 -05006768 // Check for the original scrolling layer in case we change
6769 // directions. mTouchMode might be TOUCH_DRAG_MODE if we have
6770 // reached the edge of a layer but mScrollingLayer will be non-zero
6771 // if we initiated the drag on a layer.
Michael Kolb5da91bd2011-11-29 15:29:03 -08006772 if (mCurrentScrollingLayerId != 0) {
Patrick Scott62310912010-12-06 17:44:50 -05006773 final int contentX = viewToContentDimension(deltaX);
6774 final int contentY = viewToContentDimension(deltaY);
6775
6776 // Check the scrolling bounds to see if we will actually do any
6777 // scrolling. The rectangle is in document coordinates.
6778 final int maxX = mScrollingLayerRect.right;
6779 final int maxY = mScrollingLayerRect.bottom;
6780 final int resultX = Math.max(0,
6781 Math.min(mScrollingLayerRect.left + contentX, maxX));
6782 final int resultY = Math.max(0,
6783 Math.min(mScrollingLayerRect.top + contentY, maxY));
6784
6785 if (resultX != mScrollingLayerRect.left ||
6786 resultY != mScrollingLayerRect.top) {
6787 // In case we switched to dragging the page.
6788 mTouchMode = TOUCH_DRAG_LAYER_MODE;
6789 deltaX = contentX;
6790 deltaY = contentY;
6791 oldX = mScrollingLayerRect.left;
6792 oldY = mScrollingLayerRect.top;
6793 rangeX = maxX;
6794 rangeY = maxY;
6795 } else {
6796 // Scroll the main page if we are not going to scroll the
6797 // layer. This does not reset mScrollingLayer in case the
6798 // user changes directions and the layer can scroll the
6799 // other way.
6800 mTouchMode = TOUCH_DRAG_MODE;
6801 }
6802 }
Adam Powell637d3372010-08-25 14:37:03 -07006803
6804 if (mOverScrollGlow != null) {
6805 mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
6806 }
6807
6808 overScrollBy(deltaX, deltaY, oldX, oldY,
6809 rangeX, rangeY,
6810 mOverscrollDistance, mOverscrollDistance, true);
6811 if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
6812 invalidate();
6813 }
Grace Klobac2242f22010-03-05 14:00:26 -08006814 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04006815 mZoomManager.keepZoomPickerVisible();
Grace Klobac2242f22010-03-05 14:00:26 -08006816 }
6817
6818 private void stopTouch() {
Chris Craike2f3aee2011-09-02 18:30:12 -07006819 if (mScroller.isFinished() && !mSelectingText
6820 && (mTouchMode == TOUCH_DRAG_MODE || mTouchMode == TOUCH_DRAG_LAYER_MODE)) {
6821 WebViewCore.resumePriority();
6822 WebViewCore.resumeUpdatePicture(mWebViewCore);
6823 nativeSetIsScrolling(false);
6824 }
6825
Grace Klobac2242f22010-03-05 14:00:26 -08006826 // we also use mVelocityTracker == null to tell us that we are
6827 // not "moving around", so we can take the slower/prettier
6828 // mode in the drawing code
6829 if (mVelocityTracker != null) {
6830 mVelocityTracker.recycle();
6831 mVelocityTracker = null;
6832 }
Adam Powell637d3372010-08-25 14:37:03 -07006833
6834 // Release any pulled glows
6835 if (mOverScrollGlow != null) {
6836 mOverScrollGlow.releaseAll();
6837 }
Grace Klobac2242f22010-03-05 14:00:26 -08006838 }
6839
Grace Kloba3a0def22010-01-23 21:11:54 -08006840 private void cancelTouch() {
Grace Kloba3a0def22010-01-23 21:11:54 -08006841 // we also use mVelocityTracker == null to tell us that we are
6842 // not "moving around", so we can take the slower/prettier
6843 // mode in the drawing code
6844 if (mVelocityTracker != null) {
6845 mVelocityTracker.recycle();
6846 mVelocityTracker = null;
6847 }
Adam Powell637d3372010-08-25 14:37:03 -07006848
Cary Clark0df02692010-11-24 11:01:37 -05006849 if ((mTouchMode == TOUCH_DRAG_MODE
6850 || mTouchMode == TOUCH_DRAG_LAYER_MODE) && !mSelectingText) {
Grace Klobaa7bc87c2010-01-29 14:56:25 -08006851 WebViewCore.resumePriority();
Grace Kloba524aab572010-04-07 11:12:52 -07006852 WebViewCore.resumeUpdatePicture(mWebViewCore);
Chris Craik58d94af2011-08-18 11:42:13 -07006853 nativeSetIsScrolling(false);
Grace Kloba3a0def22010-01-23 21:11:54 -08006854 }
6855 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
6856 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
6857 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
6858 mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
John Reck335f4542011-08-25 18:25:09 -07006859 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
6860 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07006861 }
Grace Kloba3a0def22010-01-23 21:11:54 -08006862 mHeldMotionless = MOTIONLESS_TRUE;
6863 mTouchMode = TOUCH_DONE_MODE;
6864 nativeHideCursor();
6865 }
6866
Jeff Brown33bbfd22011-02-24 20:55:35 -08006867 @Override
6868 public boolean onGenericMotionEvent(MotionEvent event) {
6869 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
6870 switch (event.getAction()) {
6871 case MotionEvent.ACTION_SCROLL: {
6872 final float vscroll;
6873 final float hscroll;
6874 if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
6875 vscroll = 0;
6876 hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
6877 } else {
6878 vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
6879 hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
6880 }
6881 if (hscroll != 0 || vscroll != 0) {
6882 final int vdelta = (int) (vscroll * getVerticalScrollFactor());
6883 final int hdelta = (int) (hscroll * getHorizontalScrollFactor());
Jeff Brown7f5b9962011-06-06 18:59:41 -07006884 if (pinScrollBy(hdelta, vdelta, false, 0)) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08006885 return true;
6886 }
6887 }
6888 }
6889 }
6890 }
6891 return super.onGenericMotionEvent(event);
6892 }
6893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006894 private long mTrackballFirstTime = 0;
6895 private long mTrackballLastTime = 0;
6896 private float mTrackballRemainsX = 0.0f;
6897 private float mTrackballRemainsY = 0.0f;
6898 private int mTrackballXMove = 0;
6899 private int mTrackballYMove = 0;
Cary Clark924af702010-06-04 16:37:43 -04006900 private boolean mSelectingText = false;
6901 private boolean mSelectionStarted = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006902 private boolean mExtendSelection = false;
Cary Clark924af702010-06-04 16:37:43 -04006903 private boolean mDrawSelectionPointer = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006904 private static final int TRACKBALL_KEY_TIMEOUT = 1000;
6905 private static final int TRACKBALL_TIMEOUT = 200;
6906 private static final int TRACKBALL_WAIT = 100;
6907 private static final int TRACKBALL_SCALE = 400;
6908 private static final int TRACKBALL_SCROLL_COUNT = 5;
6909 private static final int TRACKBALL_MOVE_COUNT = 10;
6910 private static final int TRACKBALL_MULTIPLIER = 3;
6911 private static final int SELECT_CURSOR_OFFSET = 16;
Cary Clark6f5dfc62010-11-11 13:09:20 -05006912 private static final int SELECT_SCROLL = 5;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006913 private int mSelectX = 0;
6914 private int mSelectY = 0;
Cary Clark5da9aeb2009-10-06 17:40:53 -04006915 private boolean mFocusSizeChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006916 private boolean mTrackballDown = false;
6917 private long mTrackballUpTime = 0;
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006918 private long mLastCursorTime = 0;
6919 private Rect mLastCursorBounds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006920
6921 // Set by default; BrowserActivity clears to interpret trackball data
Cary Clarkd6982c92009-05-29 11:02:22 -04006922 // directly for movement. Currently, the framework only passes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006923 // arrow key events, not trackball events, from one child to the next
6924 private boolean mMapTrackballToArrowKeys = true;
Cary Clarkd6982c92009-05-29 11:02:22 -04006925
John Reck83e59292011-06-04 00:46:45 -07006926 private DrawData mDelaySetPicture;
John Reck60c84d62011-06-08 18:00:02 -07006927 private DrawData mLoadedPicture;
John Reck83e59292011-06-04 00:46:45 -07006928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006929 public void setMapTrackballToArrowKeys(boolean setMap) {
Steve Block51b08912011-04-27 15:04:48 +01006930 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006931 mMapTrackballToArrowKeys = setMap;
6932 }
6933
6934 void resetTrackballTime() {
6935 mTrackballLastTime = 0;
6936 }
6937
6938 @Override
6939 public boolean onTrackballEvent(MotionEvent ev) {
6940 long time = ev.getEventTime();
6941 if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
6942 if (ev.getY() > 0) pageDown(true);
6943 if (ev.getY() < 0) pageUp(true);
6944 return true;
6945 }
6946 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Cary Clark924af702010-06-04 16:37:43 -04006947 if (mSelectingText) {
Cary Clarkbadd8392009-10-15 13:32:08 -04006948 return true; // discard press if copy in progress
6949 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006950 mTrackballDown = true;
Leon Scroggins3ccd3652009-06-26 17:22:50 -04006951 if (mNativeClass == 0) {
6952 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006953 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006954 if (time - mLastCursorTime <= TRACKBALL_TIMEOUT
6955 && !mLastCursorBounds.equals(nativeGetCursorRingBounds())) {
6956 nativeSelectBestAt(mLastCursorBounds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006957 }
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006958 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006959 Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
Cary Clarkd6982c92009-05-29 11:02:22 -04006960 + " time=" + time
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04006961 + " mLastCursorTime=" + mLastCursorTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006962 }
6963 if (isInTouchMode()) requestFocusFromTouch();
6964 return false; // let common code in onKeyDown at it
Cary Clarkd6982c92009-05-29 11:02:22 -04006965 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006966 if (ev.getAction() == MotionEvent.ACTION_UP) {
Leon Scrogginse3225672009-06-03 15:53:13 -04006967 // LONG_PRESS_CENTER is set in common onKeyDown
6968 mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006969 mTrackballDown = false;
6970 mTrackballUpTime = time;
Cary Clark924af702010-06-04 16:37:43 -04006971 if (mSelectingText) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006972 if (mExtendSelection) {
Cary Clark924af702010-06-04 16:37:43 -04006973 copySelection();
6974 selectionDone();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006975 } else {
6976 mExtendSelection = true;
Cary Clark924af702010-06-04 16:37:43 -04006977 nativeSetExtendSelection();
Cary Clark09e383c2009-10-26 16:43:58 -04006978 invalidate(); // draw the i-beam instead of the arrow
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006979 }
Cary Clarkbadd8392009-10-15 13:32:08 -04006980 return true; // discard press if copy in progress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006981 }
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006982 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006983 Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
Cary Clarkd6982c92009-05-29 11:02:22 -04006984 + " time=" + time
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006985 );
6986 }
6987 return false; // let common code in onKeyUp at it
6988 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07006989 if ((mMapTrackballToArrowKeys && (ev.getMetaState() & KeyEvent.META_SHIFT_ON) == 0) ||
Svetoslav Ganov12bed782011-01-03 14:14:50 -08006990 AccessibilityManager.getInstance(mContext).isEnabled()) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006991 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006992 return false;
6993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006994 if (mTrackballDown) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006995 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006996 return true; // discard move if trackball is down
6997 }
6998 if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04006999 if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007000 return true;
7001 }
7002 // TODO: alternatively we can do panning as touch does
7003 switchOutDrawHistory();
7004 if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007005 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04007006 Log.v(LOGTAG, "onTrackballEvent time="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007007 + time + " last=" + mTrackballLastTime);
7008 }
7009 mTrackballFirstTime = time;
7010 mTrackballXMove = mTrackballYMove = 0;
7011 }
7012 mTrackballLastTime = time;
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007013 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007014 Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time);
7015 }
7016 mTrackballRemainsX += ev.getX();
7017 mTrackballRemainsY += ev.getY();
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007018 doTrackball(time, ev.getMetaState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007019 return true;
7020 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007022 void moveSelection(float xRate, float yRate) {
7023 if (mNativeClass == 0)
7024 return;
7025 int width = getViewWidth();
7026 int height = getViewHeight();
Cary Clarkc05af372009-10-16 10:52:27 -04007027 mSelectX += xRate;
7028 mSelectY += yRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007029 int maxX = width + mScrollX;
7030 int maxY = height + mScrollY;
7031 mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
7032 , mSelectX));
7033 mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
7034 , mSelectY));
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007035 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04007036 Log.v(LOGTAG, "moveSelection"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007037 + " mSelectX=" + mSelectX
7038 + " mSelectY=" + mSelectY
7039 + " mScrollX=" + mScrollX
7040 + " mScrollY=" + mScrollY
7041 + " xRate=" + xRate
7042 + " yRate=" + yRate
7043 );
7044 }
Cary Clark924af702010-06-04 16:37:43 -04007045 nativeMoveSelection(viewToContentX(mSelectX), viewToContentY(mSelectY));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007046 int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
Cary Clarkd6982c92009-05-29 11:02:22 -04007047 : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007048 : 0;
7049 int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
Cary Clarkd6982c92009-05-29 11:02:22 -04007050 : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007051 : 0;
7052 pinScrollBy(scrollX, scrollY, true, 0);
7053 Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
7054 requestRectangleOnScreen(select);
7055 invalidate();
7056 }
7057
7058 private int scaleTrackballX(float xRate, int width) {
7059 int xMove = (int) (xRate / TRACKBALL_SCALE * width);
7060 int nextXMove = xMove;
7061 if (xMove > 0) {
7062 if (xMove > mTrackballXMove) {
7063 xMove -= mTrackballXMove;
7064 }
7065 } else if (xMove < mTrackballXMove) {
7066 xMove -= mTrackballXMove;
7067 }
7068 mTrackballXMove = nextXMove;
7069 return xMove;
7070 }
7071
7072 private int scaleTrackballY(float yRate, int height) {
7073 int yMove = (int) (yRate / TRACKBALL_SCALE * height);
7074 int nextYMove = yMove;
7075 if (yMove > 0) {
7076 if (yMove > mTrackballYMove) {
7077 yMove -= mTrackballYMove;
7078 }
7079 } else if (yMove < mTrackballYMove) {
7080 yMove -= mTrackballYMove;
7081 }
7082 mTrackballYMove = nextYMove;
7083 return yMove;
7084 }
7085
7086 private int keyCodeToSoundsEffect(int keyCode) {
7087 switch(keyCode) {
7088 case KeyEvent.KEYCODE_DPAD_UP:
7089 return SoundEffectConstants.NAVIGATION_UP;
7090 case KeyEvent.KEYCODE_DPAD_RIGHT:
7091 return SoundEffectConstants.NAVIGATION_RIGHT;
7092 case KeyEvent.KEYCODE_DPAD_DOWN:
7093 return SoundEffectConstants.NAVIGATION_DOWN;
7094 case KeyEvent.KEYCODE_DPAD_LEFT:
7095 return SoundEffectConstants.NAVIGATION_LEFT;
7096 }
7097 throw new IllegalArgumentException("keyCode must be one of " +
7098 "{KEYCODE_DPAD_UP, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_DOWN, " +
7099 "KEYCODE_DPAD_LEFT}.");
7100 }
7101
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007102 private void doTrackball(long time, int metaState) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007103 int elapsed = (int) (mTrackballLastTime - mTrackballFirstTime);
7104 if (elapsed == 0) {
7105 elapsed = TRACKBALL_TIMEOUT;
7106 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007107 float xRate = mTrackballRemainsX * 1000 / elapsed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007108 float yRate = mTrackballRemainsY * 1000 / elapsed;
Cary Clarkc05af372009-10-16 10:52:27 -04007109 int viewWidth = getViewWidth();
7110 int viewHeight = getViewHeight();
Cary Clark924af702010-06-04 16:37:43 -04007111 if (mSelectingText) {
7112 if (!mDrawSelectionPointer) {
7113 // The last selection was made by touch, disabling drawing the
7114 // selection pointer. Allow the trackball to adjust the
7115 // position of the touch control.
7116 mSelectX = contentToViewX(nativeSelectionX());
7117 mSelectY = contentToViewY(nativeSelectionY());
7118 mDrawSelectionPointer = mExtendSelection = true;
7119 nativeSetExtendSelection();
7120 }
Cary Clarkc05af372009-10-16 10:52:27 -04007121 moveSelection(scaleTrackballX(xRate, viewWidth),
7122 scaleTrackballY(yRate, viewHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007123 mTrackballRemainsX = mTrackballRemainsY = 0;
7124 return;
7125 }
7126 float ax = Math.abs(xRate);
7127 float ay = Math.abs(yRate);
7128 float maxA = Math.max(ax, ay);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007129 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007130 Log.v(LOGTAG, "doTrackball elapsed=" + elapsed
7131 + " xRate=" + xRate
7132 + " yRate=" + yRate
7133 + " mTrackballRemainsX=" + mTrackballRemainsX
7134 + " mTrackballRemainsY=" + mTrackballRemainsY);
7135 }
Cary Clarkc05af372009-10-16 10:52:27 -04007136 int width = mContentWidth - viewWidth;
7137 int height = mContentHeight - viewHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007138 if (width < 0) width = 0;
7139 if (height < 0) height = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007140 ax = Math.abs(mTrackballRemainsX * TRACKBALL_MULTIPLIER);
7141 ay = Math.abs(mTrackballRemainsY * TRACKBALL_MULTIPLIER);
7142 maxA = Math.max(ax, ay);
7143 int count = Math.max(0, (int) maxA);
7144 int oldScrollX = mScrollX;
7145 int oldScrollY = mScrollY;
7146 if (count > 0) {
Cary Clarkd6982c92009-05-29 11:02:22 -04007147 int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
7148 KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007149 mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
7150 KeyEvent.KEYCODE_DPAD_RIGHT;
7151 count = Math.min(count, TRACKBALL_MOVE_COUNT);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007152 if (DebugFlags.WEB_VIEW) {
Cary Clarkd6982c92009-05-29 11:02:22 -04007153 Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007154 + " count=" + count
7155 + " mTrackballRemainsX=" + mTrackballRemainsX
7156 + " mTrackballRemainsY=" + mTrackballRemainsY);
7157 }
Leon Scroggins9ab32b62010-05-03 14:19:50 +01007158 if (mNativeClass != 0 && nativePageShouldHandleShiftAndArrows()) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007159 for (int i = 0; i < count; i++) {
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007160 letPageHandleNavKey(selectKeyCode, time, true, metaState);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007161 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07007162 letPageHandleNavKey(selectKeyCode, time, false, metaState);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007163 } else if (navHandledKey(selectKeyCode, count, false, time)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007164 playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
7165 }
7166 mTrackballRemainsX = mTrackballRemainsY = 0;
7167 }
7168 if (count >= TRACKBALL_SCROLL_COUNT) {
7169 int xMove = scaleTrackballX(xRate, width);
7170 int yMove = scaleTrackballY(yRate, height);
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04007171 if (DebugFlags.WEB_VIEW) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007172 Log.v(LOGTAG, "doTrackball pinScrollBy"
7173 + " count=" + count
7174 + " xMove=" + xMove + " yMove=" + yMove
Cary Clarkd6982c92009-05-29 11:02:22 -04007175 + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
7176 + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007177 );
7178 }
7179 if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
7180 xMove = 0;
7181 }
7182 if (Math.abs(mScrollY - oldScrollY) > Math.abs(yMove)) {
7183 yMove = 0;
7184 }
7185 if (xMove != 0 || yMove != 0) {
7186 pinScrollBy(xMove, yMove, true, 0);
7187 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007189 }
7190
Adam Powell637d3372010-08-25 14:37:03 -07007191 /**
7192 * Compute the maximum horizontal scroll position. Used by {@link OverScrollGlow}.
7193 * @return Maximum horizontal scroll position within real content
7194 */
7195 int computeMaxScrollX() {
7196 return Math.max(computeRealHorizontalScrollRange() - getViewWidth(), 0);
Grace Klobad7625dd2010-03-04 11:46:12 -08007197 }
7198
Adam Powell637d3372010-08-25 14:37:03 -07007199 /**
7200 * Compute the maximum vertical scroll position. Used by {@link OverScrollGlow}.
7201 * @return Maximum vertical scroll position within real content
7202 */
7203 int computeMaxScrollY() {
7204 return Math.max(computeRealVerticalScrollRange() + getTitleHeight()
Mike Reede5e63f42010-03-19 14:38:23 -04007205 - getViewHeightWithTitle(), 0);
Mike Reede8853fc2009-09-04 14:01:48 -04007206 }
7207
Derek Sollenberger03e48912010-05-18 17:03:42 -04007208 boolean updateScrollCoordinates(int x, int y) {
7209 int oldX = mScrollX;
7210 int oldY = mScrollY;
7211 mScrollX = x;
7212 mScrollY = y;
7213 if (oldX != mScrollX || oldY != mScrollY) {
7214 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
7215 return true;
7216 } else {
7217 return false;
7218 }
7219 }
7220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007221 public void flingScroll(int vx, int vy) {
Steve Block51b08912011-04-27 15:04:48 +01007222 checkThread();
Grace Klobad7625dd2010-03-04 11:46:12 -08007223 mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
Adam Powell637d3372010-08-25 14:37:03 -07007224 computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007225 invalidate();
7226 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007228 private void doFling() {
7229 if (mVelocityTracker == null) {
7230 return;
7231 }
Grace Klobad7625dd2010-03-04 11:46:12 -08007232 int maxX = computeMaxScrollX();
Mike Reede8853fc2009-09-04 14:01:48 -04007233 int maxY = computeMaxScrollY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007234
Romain Guy4296fc42009-07-06 11:48:52 -07007235 mVelocityTracker.computeCurrentVelocity(1000, mMaximumFling);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007236 int vx = (int) mVelocityTracker.getXVelocity();
7237 int vy = (int) mVelocityTracker.getYVelocity();
7238
Patrick Scott62310912010-12-06 17:44:50 -05007239 int scrollX = mScrollX;
7240 int scrollY = mScrollY;
7241 int overscrollDistance = mOverscrollDistance;
7242 int overflingDistance = mOverflingDistance;
7243
7244 // Use the layer's scroll data if applicable.
7245 if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
7246 scrollX = mScrollingLayerRect.left;
7247 scrollY = mScrollingLayerRect.top;
7248 maxX = mScrollingLayerRect.right;
7249 maxY = mScrollingLayerRect.bottom;
7250 // No overscrolling for layers.
7251 overscrollDistance = overflingDistance = 0;
7252 }
7253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007254 if (mSnapScrollMode != SNAP_NONE) {
Cary Clarkac492e12009-10-14 14:53:37 -04007255 if ((mSnapScrollMode & SNAP_X) == SNAP_X) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007256 vy = 0;
7257 } else {
7258 vx = 0;
7259 }
7260 }
Cary Clarkaa7caa62009-09-08 14:15:07 -04007261 if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) {
Grace Klobaa7bc87c2010-01-29 14:56:25 -08007262 WebViewCore.resumePriority();
Cary Clark0df02692010-11-24 11:01:37 -05007263 if (!mSelectingText) {
7264 WebViewCore.resumeUpdatePicture(mWebViewCore);
7265 }
Patrick Scott62310912010-12-06 17:44:50 -05007266 if (mScroller.springBack(scrollX, scrollY, 0, maxX, 0, maxY)) {
Adam Powell637d3372010-08-25 14:37:03 -07007267 invalidate();
7268 }
Cary Clarkaa7caa62009-09-08 14:15:07 -04007269 return;
7270 }
Cary Clark278ce052009-08-31 16:08:42 -04007271 float currentVelocity = mScroller.getCurrVelocity();
Grace Kloba3c19d992010-05-17 19:19:06 -07007272 float velocity = (float) Math.hypot(vx, vy);
7273 if (mLastVelocity > 0 && currentVelocity > 0 && velocity
7274 > mLastVelocity * MINIMUM_VELOCITY_RATIO_FOR_ACCELERATION) {
Cary Clark278ce052009-08-31 16:08:42 -04007275 float deltaR = (float) (Math.abs(Math.atan2(mLastVelY, mLastVelX)
7276 - Math.atan2(vy, vx)));
7277 final float circle = (float) (Math.PI) * 2.0f;
7278 if (deltaR > circle * 0.9f || deltaR < circle * 0.1f) {
7279 vx += currentVelocity * mLastVelX / mLastVelocity;
7280 vy += currentVelocity * mLastVelY / mLastVelocity;
Grace Kloba3c19d992010-05-17 19:19:06 -07007281 velocity = (float) Math.hypot(vx, vy);
Cary Clark278ce052009-08-31 16:08:42 -04007282 if (DebugFlags.WEB_VIEW) {
7283 Log.v(LOGTAG, "doFling vx= " + vx + " vy=" + vy);
7284 }
7285 } else if (DebugFlags.WEB_VIEW) {
7286 Log.v(LOGTAG, "doFling missed " + deltaR / circle);
7287 }
7288 } else if (DebugFlags.WEB_VIEW) {
7289 Log.v(LOGTAG, "doFling start last=" + mLastVelocity
Cary Clarkaa7caa62009-09-08 14:15:07 -04007290 + " current=" + currentVelocity
7291 + " vx=" + vx + " vy=" + vy
7292 + " maxX=" + maxX + " maxY=" + maxY
Patrick Scott62310912010-12-06 17:44:50 -05007293 + " scrollX=" + scrollX + " scrollY=" + scrollY
Michael Kolb5da91bd2011-11-29 15:29:03 -08007294 + " layer=" + mCurrentScrollingLayerId);
Cary Clark278ce052009-08-31 16:08:42 -04007295 }
Adam Powell637d3372010-08-25 14:37:03 -07007296
7297 // Allow sloppy flings without overscrolling at the edges.
Patrick Scott62310912010-12-06 17:44:50 -05007298 if ((scrollX == 0 || scrollX == maxX) && Math.abs(vx) < Math.abs(vy)) {
Adam Powell637d3372010-08-25 14:37:03 -07007299 vx = 0;
7300 }
Patrick Scott62310912010-12-06 17:44:50 -05007301 if ((scrollY == 0 || scrollY == maxY) && Math.abs(vy) < Math.abs(vx)) {
Adam Powell637d3372010-08-25 14:37:03 -07007302 vy = 0;
7303 }
7304
Patrick Scott62310912010-12-06 17:44:50 -05007305 if (overscrollDistance < overflingDistance) {
7306 if ((vx > 0 && scrollX == -overscrollDistance) ||
7307 (vx < 0 && scrollX == maxX + overscrollDistance)) {
Adam Powell637d3372010-08-25 14:37:03 -07007308 vx = 0;
7309 }
Patrick Scott62310912010-12-06 17:44:50 -05007310 if ((vy > 0 && scrollY == -overscrollDistance) ||
7311 (vy < 0 && scrollY == maxY + overscrollDistance)) {
Adam Powell637d3372010-08-25 14:37:03 -07007312 vy = 0;
7313 }
7314 }
7315
Cary Clark278ce052009-08-31 16:08:42 -04007316 mLastVelX = vx;
7317 mLastVelY = vy;
Grace Kloba3c19d992010-05-17 19:19:06 -07007318 mLastVelocity = velocity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007319
Adam Powell637d3372010-08-25 14:37:03 -07007320 // no horizontal overscroll if the content just fits
Patrick Scott62310912010-12-06 17:44:50 -05007321 mScroller.fling(scrollX, scrollY, -vx, -vy, 0, maxX, 0, maxY,
7322 maxX == 0 ? 0 : overflingDistance, overflingDistance);
Adam Powell637d3372010-08-25 14:37:03 -07007323 // Duration is calculated based on velocity. With range boundaries and overscroll
7324 // we may not know how long the final animation will take. (Hence the deprecation
7325 // warning on the call below.) It's not a big deal for scroll bars but if webcore
7326 // resumes during this effect we will take a performance hit. See computeScroll;
7327 // we resume webcore there when the animation is finished.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007328 final int time = mScroller.getDuration();
Patrick Scott5b87e292010-12-13 09:20:32 -05007329
7330 // Suppress scrollbars for layer scrolling.
7331 if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
7332 awakenScrollBars(time);
7333 }
7334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007335 invalidate();
7336 }
7337
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007338 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007339 * Returns a view containing zoom controls i.e. +/- buttons. The caller is
7340 * in charge of installing this view to the view hierarchy. This view will
7341 * become visible when the user starts scrolling via touch and fade away if
7342 * the user does not interact with it.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007343 * <p/>
The Android Open Source Project10592532009-03-18 17:39:46 -07007344 * API version 3 introduces a built-in zoom mechanism that is shown
7345 * automatically by the MapView. This is the preferred approach for
7346 * showing the zoom UI.
7347 *
7348 * @deprecated The built-in zoom mechanism is preferred, see
7349 * {@link WebSettings#setBuiltInZoomControls(boolean)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007350 */
The Android Open Source Project10592532009-03-18 17:39:46 -07007351 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007352 public View getZoomControls() {
Steve Block51b08912011-04-27 15:04:48 +01007353 checkThread();
The Android Open Source Project10592532009-03-18 17:39:46 -07007354 if (!getSettings().supportZoom()) {
7355 Log.w(LOGTAG, "This WebView doesn't support zoom.");
7356 return null;
7357 }
Derek Sollenberger90b6e482010-05-10 12:38:54 -04007358 return mZoomManager.getExternalZoomPicker();
The Android Open Source Project10592532009-03-18 17:39:46 -07007359 }
7360
Derek Sollenberger90b6e482010-05-10 12:38:54 -04007361 void dismissZoomControl() {
7362 mZoomManager.dismissZoomPicker();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007363 }
7364
Derek Sollenberger03e48912010-05-18 17:03:42 -04007365 float getDefaultZoomScale() {
Derek Sollenberger341e22f2010-06-02 12:34:34 -04007366 return mZoomManager.getDefaultScale();
Derek Sollenberger03e48912010-05-18 17:03:42 -04007367 }
7368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007369 /**
Mangesh Ghiwarefaab93d2011-09-21 13:58:47 -07007370 * Return the overview scale of the WebView
7371 * @return The overview scale.
7372 */
7373 float getZoomOverviewScale() {
7374 return mZoomManager.getZoomOverviewScale();
7375 }
7376
7377 /**
Grace Kloba6164ef12010-06-01 15:59:13 -07007378 * @return TRUE if the WebView can be zoomed in.
7379 */
7380 public boolean canZoomIn() {
Steve Block51b08912011-04-27 15:04:48 +01007381 checkThread();
Grace Kloba6164ef12010-06-01 15:59:13 -07007382 return mZoomManager.canZoomIn();
7383 }
7384
7385 /**
7386 * @return TRUE if the WebView can be zoomed out.
7387 */
7388 public boolean canZoomOut() {
Steve Block51b08912011-04-27 15:04:48 +01007389 checkThread();
Grace Kloba6164ef12010-06-01 15:59:13 -07007390 return mZoomManager.canZoomOut();
7391 }
7392
7393 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007394 * Perform zoom in in the webview
7395 * @return TRUE if zoom in succeeds. FALSE if no zoom changes.
7396 */
7397 public boolean zoomIn() {
Steve Block51b08912011-04-27 15:04:48 +01007398 checkThread();
Derek Sollenberger03e48912010-05-18 17:03:42 -04007399 return mZoomManager.zoomIn();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007400 }
7401
7402 /**
7403 * Perform zoom out in the webview
7404 * @return TRUE if zoom out succeeds. FALSE if no zoom changes.
7405 */
7406 public boolean zoomOut() {
Steve Block51b08912011-04-27 15:04:48 +01007407 checkThread();
Derek Sollenberger03e48912010-05-18 17:03:42 -04007408 return mZoomManager.zoomOut();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007409 }
7410
John Reck0966dd22011-09-18 11:03:00 -07007411 /**
7412 * This selects the best clickable target at mLastTouchX and mLastTouchY
7413 * and calls showCursorTimed on the native side
7414 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007415 private void updateSelection() {
7416 if (mNativeClass == 0) {
7417 return;
7418 }
John Reck0966dd22011-09-18 11:03:00 -07007419 mPrivateHandler.removeMessages(UPDATE_SELECTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007420 // mLastTouchX and mLastTouchY are the point in the current viewport
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007421 int contentX = viewToContentX(mLastTouchX + mScrollX);
7422 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clarke9290822011-02-22 13:20:56 -05007423 int slop = viewToContentDimension(mNavSlop);
7424 Rect rect = new Rect(contentX - slop, contentY - slop,
7425 contentX + slop, contentY + slop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007426 nativeSelectBestAt(rect);
Cary Clarkb8491342010-11-29 16:23:19 -05007427 mInitialHitTestResult = hitTestResult(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007428 }
7429
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007430 /**
Leon Scrogginsd5188652011-01-19 17:01:55 -05007431 * Scroll the focused text field to match the WebTextView
Cary Clarkeaa18de2009-09-28 12:50:42 -04007432 * @param xPercent New x position of the WebTextView from 0 to 1.
Leon Scroggins72543e12009-07-23 15:29:45 -04007433 */
Leon Scrogginsd5188652011-01-19 17:01:55 -05007434 /*package*/ void scrollFocusedTextInputX(float xPercent) {
Leon Scroggins72543e12009-07-23 15:29:45 -04007435 if (!inEditingMode() || mWebViewCore == null) {
7436 return;
7437 }
Leon Scrogginsd5188652011-01-19 17:01:55 -05007438 mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0,
Cary Clarkeaa18de2009-09-28 12:50:42 -04007439 new Float(xPercent));
Leon Scroggins72543e12009-07-23 15:29:45 -04007440 }
7441
7442 /**
Leon Scrogginsd5188652011-01-19 17:01:55 -05007443 * Scroll the focused textarea vertically to match the WebTextView
7444 * @param y New y position of the WebTextView in view coordinates
7445 */
7446 /* package */ void scrollFocusedTextInputY(int y) {
Leon Scroggins22e883d2011-01-31 10:54:19 -05007447 if (!inEditingMode() || mWebViewCore == null) {
Leon Scrogginsd5188652011-01-19 17:01:55 -05007448 return;
7449 }
Leon Scroggins22e883d2011-01-31 10:54:19 -05007450 mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0, viewToContentDimension(y));
Leon Scrogginsd5188652011-01-19 17:01:55 -05007451 }
7452
7453 /**
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007454 * Set our starting point and time for a drag from the WebTextView.
7455 */
7456 /*package*/ void initiateTextFieldDrag(float x, float y, long eventTime) {
7457 if (!inEditingMode()) {
7458 return;
7459 }
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007460 mLastTouchX = Math.round(x + mWebTextView.getLeft() - mScrollX);
7461 mLastTouchY = Math.round(y + mWebTextView.getTop() - mScrollY);
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007462 mLastTouchTime = eventTime;
7463 if (!mScroller.isFinished()) {
Cary Clark278ce052009-08-31 16:08:42 -04007464 abortAnimation();
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007465 }
7466 mSnapScrollMode = SNAP_NONE;
7467 mVelocityTracker = VelocityTracker.obtain();
7468 mTouchMode = TOUCH_DRAG_START_MODE;
7469 }
7470
7471 /**
7472 * Given a motion event from the WebTextView, set its location to our
7473 * coordinates, and handle the event.
7474 */
7475 /*package*/ boolean textFieldDrag(MotionEvent event) {
7476 if (!inEditingMode()) {
7477 return false;
7478 }
Leon Scroggins72543e12009-07-23 15:29:45 -04007479 mDragFromTextInput = true;
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007480 event.offsetLocation((float) (mWebTextView.getLeft() - mScrollX),
7481 (float) (mWebTextView.getTop() - mScrollY));
Leon Scroggins72543e12009-07-23 15:29:45 -04007482 boolean result = onTouchEvent(event);
7483 mDragFromTextInput = false;
7484 return result;
Leon Scroggins0f5ad842009-07-17 15:08:34 -04007485 }
7486
Leon Scroggins6679f2f2009-08-12 18:48:10 -04007487 /**
Leon Scrogginsf90b1262009-11-24 14:49:21 -05007488 * Due a touch up from a WebTextView. This will be handled by webkit to
Leon Scroggins6679f2f2009-08-12 18:48:10 -04007489 * change the selection.
7490 * @param event MotionEvent in the WebTextView's coordinates.
7491 */
7492 /*package*/ void touchUpOnTextField(MotionEvent event) {
7493 if (!inEditingMode()) {
7494 return;
7495 }
Leon Scroggins0236e672009-09-02 21:12:08 -04007496 int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
7497 int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
Cary Clarke9290822011-02-22 13:20:56 -05007498 int slop = viewToContentDimension(mNavSlop);
7499 nativeMotionUp(x, y, slop);
Leon Scroggins6679f2f2009-08-12 18:48:10 -04007500 }
7501
Leon Scroggins1d96ca02009-10-23 11:49:03 -04007502 /**
7503 * Called when pressing the center key or trackball on a textfield.
7504 */
7505 /*package*/ void centerKeyPressOnTextField() {
7506 mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
7507 nativeCursorNodePointer());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007508 }
7509
7510 private void doShortPress() {
7511 if (mNativeClass == 0) {
7512 return;
7513 }
Grace Klobac2242f22010-03-05 14:00:26 -08007514 if (mPreventDefault == PREVENT_DEFAULT_YES) {
7515 return;
7516 }
7517 mTouchMode = TOUCH_DONE_MODE;
John Reck0966dd22011-09-18 11:03:00 -07007518 updateSelection();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007519 switchOutDrawHistory();
7520 // mLastTouchX and mLastTouchY are the point in the current viewport
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08007521 int contentX = viewToContentX(mLastTouchX + mScrollX);
7522 int contentY = viewToContentY(mLastTouchY + mScrollY);
Cary Clarke9290822011-02-22 13:20:56 -05007523 int slop = viewToContentDimension(mNavSlop);
John Reck335f4542011-08-25 18:25:09 -07007524 if (USE_WEBKIT_RINGS && !mTouchHighlightRegion.isEmpty()) {
7525 // set mTouchHighlightRequested to 0 to cause an immediate
7526 // drawing of the touch rings
7527 mTouchHighlightRequested = 0;
7528 invalidate(mTouchHighlightRegion.getBounds());
7529 mPrivateHandler.postDelayed(new Runnable() {
7530 @Override
7531 public void run() {
7532 removeTouchHighlight();
7533 }
7534 }, ViewConfiguration.getPressedStateDuration());
7535 }
Grace Kloba178db412010-05-18 22:22:23 -07007536 if (getSettings().supportTouchOnly()) {
John Reck335f4542011-08-25 18:25:09 -07007537 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07007538 WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
7539 // use "0" as generation id to inform WebKit to use the same x/y as
7540 // it used when processing GET_TOUCH_HIGHLIGHT_RECTS
7541 touchUpData.mMoveGeneration = 0;
7542 mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
Cary Clarke9290822011-02-22 13:20:56 -05007543 } else if (nativePointInNavCache(contentX, contentY, slop)) {
Cary Clark1cb97ee2009-12-11 12:10:36 -05007544 WebViewCore.MotionUpData motionUpData = new WebViewCore
7545 .MotionUpData();
7546 motionUpData.mFrame = nativeCacheHitFramePointer();
7547 motionUpData.mNode = nativeCacheHitNodePointer();
7548 motionUpData.mBounds = nativeCacheHitNodeBounds();
7549 motionUpData.mX = contentX;
7550 motionUpData.mY = contentY;
7551 mWebViewCore.sendMessageAtFrontOfQueue(EventHub.VALID_NODE_BOUNDS,
7552 motionUpData);
7553 } else {
Cary Clarkbad0c542010-01-11 14:58:21 -05007554 doMotionUp(contentX, contentY);
Cary Clark1cb97ee2009-12-11 12:10:36 -05007555 }
7556 }
7557
Cary Clarkbad0c542010-01-11 14:58:21 -05007558 private void doMotionUp(int contentX, int contentY) {
Cary Clarke9290822011-02-22 13:20:56 -05007559 int slop = viewToContentDimension(mNavSlop);
7560 if (nativeMotionUp(contentX, contentY, slop) && mLogEvent) {
Dan Egnor18e93962010-02-10 19:27:58 -08007561 EventLog.writeEvent(EventLogTags.BROWSER_SNAP_CENTER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007562 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007563 if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007564 playSoundEffect(SoundEffectConstants.CLICK);
7565 }
7566 }
7567
Derek Sollenberger281432c2011-08-22 14:05:49 -04007568 void sendPluginDrawMsg() {
7569 mWebViewCore.sendMessage(EventHub.PLUGIN_SURFACE_READY);
7570 }
7571
Cary Clarkb2601352011-01-11 11:32:01 -05007572 /**
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007573 * Returns plugin bounds if x/y in content coordinates corresponds to a
7574 * plugin. Otherwise a NULL rectangle is returned.
Cary Clarkb2601352011-01-11 11:32:01 -05007575 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007576 Rect getPluginBounds(int x, int y) {
Cary Clarke9290822011-02-22 13:20:56 -05007577 int slop = viewToContentDimension(mNavSlop);
7578 if (nativePointInNavCache(x, y, slop) && nativeCacheHitIsPlugin()) {
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007579 return nativeCacheHitNodeBounds();
7580 } else {
7581 return null;
7582 }
Cary Clarkb2601352011-01-11 11:32:01 -05007583 }
7584
Grace Klobac6f95fe2010-03-10 13:25:34 -08007585 /*
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007586 * Return true if the rect (e.g. plugin) is fully visible and maximized
7587 * inside the WebView.
Grace Klobac6f95fe2010-03-10 13:25:34 -08007588 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007589 boolean isRectFitOnScreen(Rect rect) {
7590 final int rectWidth = rect.width();
7591 final int rectHeight = rect.height();
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04007592 final int viewWidth = getViewWidth();
7593 final int viewHeight = getViewHeightWithTitle();
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007594 float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight / rectHeight);
Derek Sollenberger369aca22010-06-09 14:11:59 -04007595 scale = mZoomManager.computeScaleWithLimits(scale);
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04007596 return !mZoomManager.willScaleTriggerZoom(scale)
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007597 && contentToViewX(rect.left) >= mScrollX
7598 && contentToViewX(rect.right) <= mScrollX + viewWidth
7599 && contentToViewY(rect.top) >= mScrollY
7600 && contentToViewY(rect.bottom) <= mScrollY + viewHeight;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007601 }
7602
7603 /*
Grace Klobae8300a12010-03-12 13:32:55 -08007604 * Maximize and center the rectangle, specified in the document coordinate
7605 * space, inside the WebView. If the zoom doesn't need to be changed, do an
7606 * animated scroll to center it. If the zoom needs to be changed, find the
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007607 * zoom center and do a smooth zoom transition. The rect is in document
7608 * coordinates
Grace Klobac6f95fe2010-03-10 13:25:34 -08007609 */
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007610 void centerFitRect(Rect rect) {
7611 final int rectWidth = rect.width();
7612 final int rectHeight = rect.height();
7613 final int viewWidth = getViewWidth();
7614 final int viewHeight = getViewHeightWithTitle();
7615 float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight
7616 / rectHeight);
Derek Sollenberger369aca22010-06-09 14:11:59 -04007617 scale = mZoomManager.computeScaleWithLimits(scale);
Derek Sollenberger03e48912010-05-18 17:03:42 -04007618 if (!mZoomManager.willScaleTriggerZoom(scale)) {
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007619 pinScrollTo(contentToViewX(rect.left + rectWidth / 2) - viewWidth / 2,
7620 contentToViewY(rect.top + rectHeight / 2) - viewHeight / 2,
Grace Klobac6f95fe2010-03-10 13:25:34 -08007621 true, 0);
7622 } else {
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04007623 float actualScale = mZoomManager.getScale();
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007624 float oldScreenX = rect.left * actualScale - mScrollX;
7625 float rectViewX = rect.left * scale;
7626 float rectViewWidth = rectWidth * scale;
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007627 float newMaxWidth = mContentWidth * scale;
7628 float newScreenX = (viewWidth - rectViewWidth) / 2;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007629 // pin the newX to the WebView
Grace Klobae8300a12010-03-12 13:32:55 -08007630 if (newScreenX > rectViewX) {
7631 newScreenX = rectViewX;
7632 } else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) {
7633 newScreenX = viewWidth - (newMaxWidth - rectViewX);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007634 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007635 float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale)
7636 / (scale - actualScale);
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007637 float oldScreenY = rect.top * actualScale + getTitleHeight()
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007638 - mScrollY;
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05007639 float rectViewY = rect.top * scale + getTitleHeight();
7640 float rectViewHeight = rectHeight * scale;
Grace Kloba1e65d9e2010-03-12 19:19:48 -08007641 float newMaxHeight = mContentHeight * scale + getTitleHeight();
7642 float newScreenY = (viewHeight - rectViewHeight) / 2;
Grace Klobac6f95fe2010-03-10 13:25:34 -08007643 // pin the newY to the WebView
Grace Klobae8300a12010-03-12 13:32:55 -08007644 if (newScreenY > rectViewY) {
7645 newScreenY = rectViewY;
7646 } else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) {
7647 newScreenY = viewHeight - (newMaxHeight - rectViewY);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007648 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007649 float zoomCenterY = (oldScreenY * scale - newScreenY * actualScale)
7650 / (scale - actualScale);
7651 mZoomManager.setZoomCenter(zoomCenterX, zoomCenterY);
Derek Sollenberger87b17be52010-06-01 11:49:31 -04007652 mZoomManager.startZoomAnimation(scale, false);
Grace Klobac6f95fe2010-03-10 13:25:34 -08007653 }
7654 }
7655
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007656 // Called by JNI to handle a touch on a node representing an email address,
7657 // address, or phone number
7658 private void overrideLoading(String url) {
7659 mCallbackProxy.uiOverrideUrlLoading(url);
7660 }
7661
7662 @Override
7663 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
Leon Scroggins III26723fc2010-04-19 13:21:42 -04007664 // FIXME: If a subwindow is showing find, and the user touches the
7665 // background window, it can steal focus.
7666 if (mFindIsUp) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007667 boolean result = false;
7668 if (inEditingMode()) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04007669 result = mWebTextView.requestFocus(direction,
7670 previouslyFocusedRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007671 } else {
7672 result = super.requestFocus(direction, previouslyFocusedRect);
Leon Scroggins572ba782011-01-28 11:25:53 -05007673 if (mWebViewCore.getSettings().getNeedInitialFocus() && !isInTouchMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007674 // For cases such as GMail, where we gain focus from a direction,
7675 // we want to move to the first available link.
7676 // FIXME: If there are no visible links, we may not want to
7677 int fakeKeyDirection = 0;
7678 switch(direction) {
7679 case View.FOCUS_UP:
7680 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_UP;
7681 break;
7682 case View.FOCUS_DOWN:
7683 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_DOWN;
7684 break;
7685 case View.FOCUS_LEFT:
7686 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_LEFT;
7687 break;
7688 case View.FOCUS_RIGHT:
7689 fakeKeyDirection = KeyEvent.KEYCODE_DPAD_RIGHT;
7690 break;
7691 default:
7692 return result;
7693 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007694 if (mNativeClass != 0 && !nativeHasCursorNode()) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05007695 navHandledKey(fakeKeyDirection, 1, true, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007696 }
7697 }
7698 }
7699 return result;
7700 }
7701
7702 @Override
7703 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
7704 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
7705
7706 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
7707 int heightSize = MeasureSpec.getSize(heightMeasureSpec);
7708 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
7709 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
7710
7711 int measuredHeight = heightSize;
7712 int measuredWidth = widthSize;
7713
7714 // Grab the content size from WebViewCore.
Grace Klobae621d6f2009-09-11 13:20:39 -07007715 int contentHeight = contentToViewDimension(mContentHeight);
7716 int contentWidth = contentToViewDimension(mContentWidth);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717
7718// Log.d(LOGTAG, "------- measure " + heightMode);
7719
7720 if (heightMode != MeasureSpec.EXACTLY) {
7721 mHeightCanMeasure = true;
7722 measuredHeight = contentHeight;
7723 if (heightMode == MeasureSpec.AT_MOST) {
7724 // If we are larger than the AT_MOST height, then our height can
7725 // no longer be measured and we should scroll internally.
7726 if (measuredHeight > heightSize) {
7727 measuredHeight = heightSize;
7728 mHeightCanMeasure = false;
Dianne Hackborn189ee182010-12-02 21:48:53 -08007729 measuredHeight |= MEASURED_STATE_TOO_SMALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007730 }
7731 }
7732 } else {
7733 mHeightCanMeasure = false;
7734 }
7735 if (mNativeClass != 0) {
7736 nativeSetHeightCanMeasure(mHeightCanMeasure);
7737 }
7738 // For the width, always use the given size unless unspecified.
7739 if (widthMode == MeasureSpec.UNSPECIFIED) {
7740 mWidthCanMeasure = true;
7741 measuredWidth = contentWidth;
7742 } else {
Dianne Hackborn189ee182010-12-02 21:48:53 -08007743 if (measuredWidth < contentWidth) {
7744 measuredWidth |= MEASURED_STATE_TOO_SMALL;
7745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007746 mWidthCanMeasure = false;
7747 }
7748
7749 synchronized (this) {
7750 setMeasuredDimension(measuredWidth, measuredHeight);
7751 }
7752 }
7753
7754 @Override
7755 public boolean requestChildRectangleOnScreen(View child,
7756 Rect rect,
7757 boolean immediate) {
Cary Clarkdc09b5a2010-12-07 08:48:10 -05007758 if (mNativeClass == 0) {
7759 return false;
7760 }
Derek Sollenberger03e48912010-05-18 17:03:42 -04007761 // don't scroll while in zoom animation. When it is done, we will adjust
7762 // the necessary components (e.g., WebTextView if it is in editing mode)
Derek Sollenberger293c3602010-06-04 10:44:48 -04007763 if (mZoomManager.isFixedLengthAnimationInProgress()) {
Derek Sollenberger03e48912010-05-18 17:03:42 -04007764 return false;
7765 }
7766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007767 rect.offset(child.getLeft() - child.getScrollX(),
7768 child.getTop() - child.getScrollY());
7769
Cary Clark31b83672010-03-09 09:20:34 -05007770 Rect content = new Rect(viewToContentX(mScrollX),
7771 viewToContentY(mScrollY),
7772 viewToContentX(mScrollX + getWidth()
7773 - getVerticalScrollbarWidth()),
7774 viewToContentY(mScrollY + getViewHeightWithTitle()));
7775 content = nativeSubtractLayers(content);
7776 int screenTop = contentToViewY(content.top);
7777 int screenBottom = contentToViewY(content.bottom);
7778 int height = screenBottom - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007779 int scrollYDelta = 0;
7780
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007781 if (rect.bottom > screenBottom) {
7782 int oneThirdOfScreenHeight = height / 3;
7783 if (rect.height() > 2 * oneThirdOfScreenHeight) {
7784 // If the rectangle is too tall to fit in the bottom two thirds
7785 // of the screen, place it at the top.
7786 scrollYDelta = rect.top - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007787 } else {
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007788 // If the rectangle will still fit on screen, we want its
7789 // top to be in the top third of the screen.
7790 scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007791 }
7792 } else if (rect.top < screenTop) {
Leon Scrogginsbed911a2009-03-31 14:29:35 -07007793 scrollYDelta = rect.top - screenTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007794 }
7795
Cary Clark31b83672010-03-09 09:20:34 -05007796 int screenLeft = contentToViewX(content.left);
7797 int screenRight = contentToViewX(content.right);
7798 int width = screenRight - screenLeft;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007799 int scrollXDelta = 0;
7800
7801 if (rect.right > screenRight && rect.left > screenLeft) {
7802 if (rect.width() > width) {
7803 scrollXDelta += (rect.left - screenLeft);
7804 } else {
7805 scrollXDelta += (rect.right - screenRight);
7806 }
7807 } else if (rect.left < screenLeft) {
7808 scrollXDelta -= (screenLeft - rect.left);
7809 }
7810
7811 if ((scrollYDelta | scrollXDelta) != 0) {
7812 return pinScrollBy(scrollXDelta, scrollYDelta, !immediate, 0);
7813 }
7814
7815 return false;
7816 }
Cary Clarkd6982c92009-05-29 11:02:22 -04007817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007818 /* package */ void replaceTextfieldText(int oldStart, int oldEnd,
7819 String replace, int newStart, int newEnd) {
Cary Clarkded054c2009-06-15 10:26:08 -04007820 WebViewCore.ReplaceTextData arg = new WebViewCore.ReplaceTextData();
7821 arg.mReplace = replace;
7822 arg.mNewStart = newStart;
7823 arg.mNewEnd = newEnd;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07007824 mTextGeneration++;
Leon Scroggins43488fc2009-07-06 14:32:49 -04007825 arg.mTextGeneration = mTextGeneration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007826 mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
7827 }
7828
7829 /* package */ void passToJavaScript(String currentText, KeyEvent event) {
George Mount1fa26cb2011-10-03 10:56:28 -07007830 // check if mWebViewCore has been destroyed
7831 if (mWebViewCore == null) {
7832 return;
7833 }
Cary Clarkded054c2009-06-15 10:26:08 -04007834 WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
7835 arg.mEvent = event;
7836 arg.mCurrentText = currentText;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007837 // Increase our text generation number, and pass it to webcore thread
7838 mTextGeneration++;
7839 mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
7840 // WebKit's document state is not saved until about to leave the page.
Cary Clarkd6982c92009-05-29 11:02:22 -04007841 // To make sure the host application, like Browser, has the up to date
7842 // document state when it goes to background, we force to save the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007843 // document state.
7844 mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
7845 mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
Cary Clarkd6982c92009-05-29 11:02:22 -04007846 cursorData(), 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007847 }
7848
Dounia Berrada940a1982011-04-27 13:53:13 -07007849 /**
7850 * @hide
7851 */
7852 public synchronized WebViewCore getWebViewCore() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007853 return mWebViewCore;
7854 }
7855
Adam Powell4fb35d42011-03-03 17:54:55 -08007856 /**
7857 * Used only by TouchEventQueue to store pending touch events.
7858 */
7859 private static class QueuedTouch {
7860 long mSequence;
7861 MotionEvent mEvent; // Optional
7862 TouchEventData mTed; // Optional
7863
7864 QueuedTouch mNext;
7865
7866 public QueuedTouch set(TouchEventData ted) {
7867 mSequence = ted.mSequence;
7868 mTed = ted;
7869 mEvent = null;
7870 mNext = null;
7871 return this;
7872 }
7873
7874 public QueuedTouch set(MotionEvent ev, long sequence) {
7875 mEvent = MotionEvent.obtain(ev);
7876 mSequence = sequence;
7877 mTed = null;
7878 mNext = null;
7879 return this;
7880 }
7881
7882 public QueuedTouch add(QueuedTouch other) {
7883 if (other.mSequence < mSequence) {
7884 other.mNext = this;
7885 return other;
7886 }
7887
7888 QueuedTouch insertAt = this;
7889 while (insertAt.mNext != null && insertAt.mNext.mSequence < other.mSequence) {
7890 insertAt = insertAt.mNext;
7891 }
7892 other.mNext = insertAt.mNext;
7893 insertAt.mNext = other;
7894 return this;
7895 }
7896 }
7897
7898 /**
7899 * WebView handles touch events asynchronously since some events must be passed to WebKit
7900 * for potentially slower processing. TouchEventQueue serializes touch events regardless
7901 * of which path they take to ensure that no events are ever processed out of order
7902 * by WebView.
7903 */
7904 private class TouchEventQueue {
7905 private long mNextTouchSequence = Long.MIN_VALUE + 1;
7906 private long mLastHandledTouchSequence = Long.MIN_VALUE;
Adam Powelld0197f32011-03-17 00:09:03 -07007907 private long mIgnoreUntilSequence = Long.MIN_VALUE + 1;
Adam Powell3c534772011-04-04 14:27:12 -07007908
7909 // Events waiting to be processed.
Adam Powell4fb35d42011-03-03 17:54:55 -08007910 private QueuedTouch mTouchEventQueue;
Adam Powell3c534772011-04-04 14:27:12 -07007911
7912 // Known events that are waiting on a response before being enqueued.
7913 private QueuedTouch mPreQueue;
7914
7915 // Pool of QueuedTouch objects saved for later use.
Adam Powell4fb35d42011-03-03 17:54:55 -08007916 private QueuedTouch mQueuedTouchRecycleBin;
7917 private int mQueuedTouchRecycleCount;
Adam Powell3c534772011-04-04 14:27:12 -07007918
Adam Powelld0197f32011-03-17 00:09:03 -07007919 private long mLastEventTime = Long.MAX_VALUE;
Adam Powell4fb35d42011-03-03 17:54:55 -08007920 private static final int MAX_RECYCLED_QUEUED_TOUCH = 15;
7921
Adam Powell80615b02011-03-10 15:53:24 -08007922 // milliseconds until we abandon hope of getting all of a previous gesture
Adam Powelld0197f32011-03-17 00:09:03 -07007923 private static final int QUEUED_GESTURE_TIMEOUT = 1000;
Adam Powell80615b02011-03-10 15:53:24 -08007924
Adam Powell4fb35d42011-03-03 17:54:55 -08007925 private QueuedTouch obtainQueuedTouch() {
7926 if (mQueuedTouchRecycleBin != null) {
7927 QueuedTouch result = mQueuedTouchRecycleBin;
7928 mQueuedTouchRecycleBin = result.mNext;
7929 mQueuedTouchRecycleCount--;
7930 return result;
7931 }
7932 return new QueuedTouch();
7933 }
7934
Adam Powell80615b02011-03-10 15:53:24 -08007935 /**
7936 * Allow events with any currently missing sequence numbers to be skipped in processing.
7937 */
7938 public void ignoreCurrentlyMissingEvents() {
7939 mIgnoreUntilSequence = mNextTouchSequence;
Adam Powell3c534772011-04-04 14:27:12 -07007940
7941 // Run any events we have available and complete, pre-queued or otherwise.
7942 runQueuedAndPreQueuedEvents();
7943 }
7944
7945 private void runQueuedAndPreQueuedEvents() {
7946 QueuedTouch qd = mPreQueue;
7947 boolean fromPreQueue = true;
7948 while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
7949 handleQueuedTouch(qd);
7950 QueuedTouch recycleMe = qd;
7951 if (fromPreQueue) {
7952 mPreQueue = qd.mNext;
7953 } else {
7954 mTouchEventQueue = qd.mNext;
7955 }
7956 recycleQueuedTouch(recycleMe);
7957 mLastHandledTouchSequence++;
7958
7959 long nextPre = mPreQueue != null ? mPreQueue.mSequence : Long.MAX_VALUE;
7960 long nextQueued = mTouchEventQueue != null ?
7961 mTouchEventQueue.mSequence : Long.MAX_VALUE;
7962 fromPreQueue = nextPre < nextQueued;
7963 qd = fromPreQueue ? mPreQueue : mTouchEventQueue;
7964 }
7965 }
7966
7967 /**
7968 * Add a TouchEventData to the pre-queue.
7969 *
7970 * An event in the pre-queue is an event that we know about that
7971 * has been sent to webkit, but that we haven't received back and
7972 * enqueued into the normal touch queue yet. If webkit ever times
7973 * out and we need to ignore currently missing events, we'll run
7974 * events from the pre-queue to patch the holes.
7975 *
7976 * @param ted TouchEventData to pre-queue
7977 */
7978 public void preQueueTouchEventData(TouchEventData ted) {
7979 QueuedTouch newTouch = obtainQueuedTouch().set(ted);
7980 if (mPreQueue == null) {
7981 mPreQueue = newTouch;
7982 } else {
7983 QueuedTouch insertionPoint = mPreQueue;
7984 while (insertionPoint.mNext != null &&
7985 insertionPoint.mNext.mSequence < newTouch.mSequence) {
7986 insertionPoint = insertionPoint.mNext;
7987 }
7988 newTouch.mNext = insertionPoint.mNext;
7989 insertionPoint.mNext = newTouch;
7990 }
Adam Powell80615b02011-03-10 15:53:24 -08007991 }
7992
Adam Powell4fb35d42011-03-03 17:54:55 -08007993 private void recycleQueuedTouch(QueuedTouch qd) {
7994 if (mQueuedTouchRecycleCount < MAX_RECYCLED_QUEUED_TOUCH) {
7995 qd.mNext = mQueuedTouchRecycleBin;
7996 mQueuedTouchRecycleBin = qd;
7997 mQueuedTouchRecycleCount++;
7998 }
7999 }
8000
8001 /**
8002 * Reset the touch event queue. This will dump any pending events
8003 * and reset the sequence numbering.
8004 */
8005 public void reset() {
8006 mNextTouchSequence = Long.MIN_VALUE + 1;
8007 mLastHandledTouchSequence = Long.MIN_VALUE;
Adam Powelld0197f32011-03-17 00:09:03 -07008008 mIgnoreUntilSequence = Long.MIN_VALUE + 1;
Adam Powell4fb35d42011-03-03 17:54:55 -08008009 while (mTouchEventQueue != null) {
8010 QueuedTouch recycleMe = mTouchEventQueue;
8011 mTouchEventQueue = mTouchEventQueue.mNext;
8012 recycleQueuedTouch(recycleMe);
8013 }
Adam Powell3c534772011-04-04 14:27:12 -07008014 while (mPreQueue != null) {
8015 QueuedTouch recycleMe = mPreQueue;
8016 mPreQueue = mPreQueue.mNext;
8017 recycleQueuedTouch(recycleMe);
8018 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008019 }
8020
8021 /**
8022 * Return the next valid sequence number for tagging incoming touch events.
8023 * @return The next touch event sequence number
8024 */
8025 public long nextTouchSequence() {
8026 return mNextTouchSequence++;
8027 }
8028
8029 /**
8030 * Enqueue a touch event in the form of TouchEventData.
8031 * The sequence number will be read from the mSequence field of the argument.
8032 *
8033 * If the touch event's sequence number is the next in line to be processed, it will
8034 * be handled before this method returns. Any subsequent events that have already
8035 * been queued will also be processed in their proper order.
8036 *
8037 * @param ted Touch data to be processed in order.
Adam Powellbaa33802011-03-25 13:58:19 -07008038 * @return true if the event was processed before returning, false if it was just enqueued.
Adam Powell4fb35d42011-03-03 17:54:55 -08008039 */
Adam Powellbaa33802011-03-25 13:58:19 -07008040 public boolean enqueueTouchEvent(TouchEventData ted) {
Adam Powell3c534772011-04-04 14:27:12 -07008041 // Remove from the pre-queue if present
8042 QueuedTouch preQueue = mPreQueue;
8043 if (preQueue != null) {
8044 // On exiting this block, preQueue is set to the pre-queued QueuedTouch object
8045 // if it was present in the pre-queue, and removed from the pre-queue itself.
8046 if (preQueue.mSequence == ted.mSequence) {
8047 mPreQueue = preQueue.mNext;
8048 } else {
8049 QueuedTouch prev = preQueue;
8050 preQueue = null;
8051 while (prev.mNext != null) {
8052 if (prev.mNext.mSequence == ted.mSequence) {
8053 preQueue = prev.mNext;
8054 prev.mNext = preQueue.mNext;
8055 break;
8056 } else {
8057 prev = prev.mNext;
8058 }
8059 }
8060 }
8061 }
8062
Adam Powell80615b02011-03-10 15:53:24 -08008063 if (ted.mSequence < mLastHandledTouchSequence) {
8064 // Stale event and we already moved on; drop it. (Should not be common.)
8065 Log.w(LOGTAG, "Stale touch event " + MotionEvent.actionToString(ted.mAction) +
8066 " received from webcore; ignoring");
Adam Powellbaa33802011-03-25 13:58:19 -07008067 return false;
Adam Powell80615b02011-03-10 15:53:24 -08008068 }
8069
Adam Powelld0197f32011-03-17 00:09:03 -07008070 if (dropStaleGestures(ted.mMotionEvent, ted.mSequence)) {
Adam Powellbaa33802011-03-25 13:58:19 -07008071 return false;
Adam Powelld0197f32011-03-17 00:09:03 -07008072 }
Adam Powell80615b02011-03-10 15:53:24 -08008073
Adam Powell3c534772011-04-04 14:27:12 -07008074 // dropStaleGestures above might have fast-forwarded us to
8075 // an event we have already.
8076 runNextQueuedEvents();
8077
Adam Powell4fb35d42011-03-03 17:54:55 -08008078 if (mLastHandledTouchSequence + 1 == ted.mSequence) {
Adam Powell3c534772011-04-04 14:27:12 -07008079 if (preQueue != null) {
8080 recycleQueuedTouch(preQueue);
8081 preQueue = null;
8082 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008083 handleQueuedTouchEventData(ted);
8084
8085 mLastHandledTouchSequence++;
8086
8087 // Do we have any more? Run them if so.
Adam Powell3c534772011-04-04 14:27:12 -07008088 runNextQueuedEvents();
Adam Powell4fb35d42011-03-03 17:54:55 -08008089 } else {
Adam Powell3c534772011-04-04 14:27:12 -07008090 // Reuse the pre-queued object if we had it.
8091 QueuedTouch qd = preQueue != null ? preQueue : obtainQueuedTouch().set(ted);
Adam Powell4fb35d42011-03-03 17:54:55 -08008092 mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
8093 }
Adam Powellbaa33802011-03-25 13:58:19 -07008094 return true;
Adam Powell4fb35d42011-03-03 17:54:55 -08008095 }
8096
8097 /**
8098 * Enqueue a touch event in the form of a MotionEvent from the framework.
8099 *
8100 * If the touch event's sequence number is the next in line to be processed, it will
8101 * be handled before this method returns. Any subsequent events that have already
8102 * been queued will also be processed in their proper order.
8103 *
8104 * @param ev MotionEvent to be processed in order
8105 */
8106 public void enqueueTouchEvent(MotionEvent ev) {
8107 final long sequence = nextTouchSequence();
Adam Powell80615b02011-03-10 15:53:24 -08008108
Adam Powelld0197f32011-03-17 00:09:03 -07008109 if (dropStaleGestures(ev, sequence)) {
8110 return;
8111 }
Adam Powell80615b02011-03-10 15:53:24 -08008112
Adam Powell3c534772011-04-04 14:27:12 -07008113 // dropStaleGestures above might have fast-forwarded us to
8114 // an event we have already.
8115 runNextQueuedEvents();
8116
Adam Powell4fb35d42011-03-03 17:54:55 -08008117 if (mLastHandledTouchSequence + 1 == sequence) {
8118 handleQueuedMotionEvent(ev);
8119
8120 mLastHandledTouchSequence++;
8121
8122 // Do we have any more? Run them if so.
Adam Powell3c534772011-04-04 14:27:12 -07008123 runNextQueuedEvents();
Adam Powell4fb35d42011-03-03 17:54:55 -08008124 } else {
8125 QueuedTouch qd = obtainQueuedTouch().set(ev, sequence);
8126 mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
8127 }
8128 }
8129
Adam Powell3c534772011-04-04 14:27:12 -07008130 private void runNextQueuedEvents() {
8131 QueuedTouch qd = mTouchEventQueue;
8132 while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
8133 handleQueuedTouch(qd);
8134 QueuedTouch recycleMe = qd;
8135 qd = qd.mNext;
8136 recycleQueuedTouch(recycleMe);
8137 mLastHandledTouchSequence++;
8138 }
8139 mTouchEventQueue = qd;
8140 }
8141
Adam Powelld0197f32011-03-17 00:09:03 -07008142 private boolean dropStaleGestures(MotionEvent ev, long sequence) {
8143 if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && !mConfirmMove) {
8144 // This is to make sure that we don't attempt to process a tap
8145 // or long press when webkit takes too long to get back to us.
8146 // The movement will be properly confirmed when we process the
8147 // enqueued event later.
8148 final int dx = Math.round(ev.getX()) - mLastTouchX;
8149 final int dy = Math.round(ev.getY()) - mLastTouchY;
8150 if (dx * dx + dy * dy > mTouchSlopSquare) {
8151 mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
8152 mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
8153 }
8154 }
Adam Powell8f626a12011-03-10 19:27:15 -08008155
Adam Powelld0197f32011-03-17 00:09:03 -07008156 if (mTouchEventQueue == null) {
8157 return sequence <= mLastHandledTouchSequence;
8158 }
Adam Powell8f626a12011-03-10 19:27:15 -08008159
Adam Powelld0197f32011-03-17 00:09:03 -07008160 // If we have a new down event and it's been a while since the last event
Adam Powell3c534772011-04-04 14:27:12 -07008161 // we saw, catch up as best we can and keep going.
Adam Powelld0197f32011-03-17 00:09:03 -07008162 if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) {
Adam Powell80615b02011-03-10 15:53:24 -08008163 long eventTime = ev.getEventTime();
Adam Powelld0197f32011-03-17 00:09:03 -07008164 long lastHandledEventTime = mLastEventTime;
8165 if (eventTime > lastHandledEventTime + QUEUED_GESTURE_TIMEOUT) {
Adam Powell80615b02011-03-10 15:53:24 -08008166 Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " +
Adam Powell3c534772011-04-04 14:27:12 -07008167 "Catching up.");
8168 runQueuedAndPreQueuedEvents();
8169
8170 // Drop leftovers that we truly don't have.
Adam Powell80615b02011-03-10 15:53:24 -08008171 QueuedTouch qd = mTouchEventQueue;
8172 while (qd != null && qd.mSequence < sequence) {
8173 QueuedTouch recycleMe = qd;
8174 qd = qd.mNext;
8175 recycleQueuedTouch(recycleMe);
8176 }
8177 mTouchEventQueue = qd;
8178 mLastHandledTouchSequence = sequence - 1;
8179 }
8180 }
8181
Adam Powelld0197f32011-03-17 00:09:03 -07008182 if (mIgnoreUntilSequence - 1 > mLastHandledTouchSequence) {
Adam Powell80615b02011-03-10 15:53:24 -08008183 QueuedTouch qd = mTouchEventQueue;
Adam Powelld0197f32011-03-17 00:09:03 -07008184 while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
Adam Powell80615b02011-03-10 15:53:24 -08008185 QueuedTouch recycleMe = qd;
8186 qd = qd.mNext;
8187 recycleQueuedTouch(recycleMe);
8188 }
8189 mTouchEventQueue = qd;
Adam Powelld0197f32011-03-17 00:09:03 -07008190 mLastHandledTouchSequence = mIgnoreUntilSequence - 1;
Adam Powell80615b02011-03-10 15:53:24 -08008191 }
Adam Powelld0197f32011-03-17 00:09:03 -07008192
Adam Powell3c534772011-04-04 14:27:12 -07008193 if (mPreQueue != null) {
8194 // Drop stale prequeued events
8195 QueuedTouch qd = mPreQueue;
8196 while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
8197 QueuedTouch recycleMe = qd;
8198 qd = qd.mNext;
8199 recycleQueuedTouch(recycleMe);
8200 }
8201 mPreQueue = qd;
8202 }
8203
Adam Powelld0197f32011-03-17 00:09:03 -07008204 return sequence <= mLastHandledTouchSequence;
Adam Powell80615b02011-03-10 15:53:24 -08008205 }
8206
Adam Powell4fb35d42011-03-03 17:54:55 -08008207 private void handleQueuedTouch(QueuedTouch qt) {
8208 if (qt.mTed != null) {
8209 handleQueuedTouchEventData(qt.mTed);
8210 } else {
8211 handleQueuedMotionEvent(qt.mEvent);
8212 qt.mEvent.recycle();
8213 }
8214 }
8215
8216 private void handleQueuedMotionEvent(MotionEvent ev) {
Adam Powelld0197f32011-03-17 00:09:03 -07008217 mLastEventTime = ev.getEventTime();
Adam Powell4fb35d42011-03-03 17:54:55 -08008218 int action = ev.getActionMasked();
8219 if (ev.getPointerCount() > 1) { // Multi-touch
Adam Powell4fb35d42011-03-03 17:54:55 -08008220 handleMultiTouchInWebView(ev);
8221 } else {
8222 final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
Adam Powell8f626a12011-03-10 19:27:15 -08008223 if (detector != null && mPreventDefault != PREVENT_DEFAULT_YES) {
Adam Powell4fb35d42011-03-03 17:54:55 -08008224 // ScaleGestureDetector needs a consistent event stream to operate properly.
8225 // It won't take any action with fewer than two pointers, but it needs to
8226 // update internal bookkeeping state.
8227 detector.onTouchEvent(ev);
8228 }
8229
8230 handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY()));
8231 }
8232 }
8233
8234 private void handleQueuedTouchEventData(TouchEventData ted) {
Adam Powelld0197f32011-03-17 00:09:03 -07008235 if (ted.mMotionEvent != null) {
8236 mLastEventTime = ted.mMotionEvent.getEventTime();
8237 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008238 if (!ted.mReprocess) {
8239 if (ted.mAction == MotionEvent.ACTION_DOWN
8240 && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {
8241 // if prevent default is called from WebCore, UI
8242 // will not handle the rest of the touch events any
8243 // more.
8244 mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
8245 : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN;
8246 } else if (ted.mAction == MotionEvent.ACTION_MOVE
8247 && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
8248 // the return for the first ACTION_MOVE will decide
8249 // whether UI will handle touch or not. Currently no
8250 // support for alternating prevent default
8251 mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
8252 : PREVENT_DEFAULT_NO;
8253 }
8254 if (mPreventDefault == PREVENT_DEFAULT_YES) {
8255 mTouchHighlightRegion.setEmpty();
8256 }
8257 } else {
8258 if (ted.mPoints.length > 1) { // multi-touch
Adam Powell8f626a12011-03-10 19:27:15 -08008259 if (!ted.mNativeResult && mPreventDefault != PREVENT_DEFAULT_YES) {
Adam Powell4fb35d42011-03-03 17:54:55 -08008260 mPreventDefault = PREVENT_DEFAULT_NO;
8261 handleMultiTouchInWebView(ted.mMotionEvent);
8262 } else {
8263 mPreventDefault = PREVENT_DEFAULT_YES;
8264 }
8265 return;
8266 }
8267
8268 // prevent default is not called in WebCore, so the
8269 // message needs to be reprocessed in UI
8270 if (!ted.mNativeResult) {
8271 // Following is for single touch.
8272 switch (ted.mAction) {
8273 case MotionEvent.ACTION_DOWN:
Huahui Wu88b869a2011-03-17 17:42:12 -07008274 mLastDeferTouchX = ted.mPointsInView[0].x;
8275 mLastDeferTouchY = ted.mPointsInView[0].y;
Adam Powell4fb35d42011-03-03 17:54:55 -08008276 mDeferTouchMode = TOUCH_INIT_MODE;
8277 break;
8278 case MotionEvent.ACTION_MOVE: {
8279 // no snapping in defer process
Huahui Wu88b869a2011-03-17 17:42:12 -07008280 int x = ted.mPointsInView[0].x;
8281 int y = ted.mPointsInView[0].y;
8282
Adam Powell4fb35d42011-03-03 17:54:55 -08008283 if (mDeferTouchMode != TOUCH_DRAG_MODE) {
8284 mDeferTouchMode = TOUCH_DRAG_MODE;
8285 mLastDeferTouchX = x;
8286 mLastDeferTouchY = y;
8287 startScrollingLayer(x, y);
8288 startDrag();
8289 }
8290 int deltaX = pinLocX((int) (mScrollX
8291 + mLastDeferTouchX - x))
8292 - mScrollX;
8293 int deltaY = pinLocY((int) (mScrollY
8294 + mLastDeferTouchY - y))
8295 - mScrollY;
8296 doDrag(deltaX, deltaY);
8297 if (deltaX != 0) mLastDeferTouchX = x;
8298 if (deltaY != 0) mLastDeferTouchY = y;
8299 break;
8300 }
8301 case MotionEvent.ACTION_UP:
8302 case MotionEvent.ACTION_CANCEL:
8303 if (mDeferTouchMode == TOUCH_DRAG_MODE) {
8304 // no fling in defer process
8305 mScroller.springBack(mScrollX, mScrollY, 0,
8306 computeMaxScrollX(), 0,
8307 computeMaxScrollY());
8308 invalidate();
8309 WebViewCore.resumePriority();
8310 WebViewCore.resumeUpdatePicture(mWebViewCore);
8311 }
8312 mDeferTouchMode = TOUCH_DONE_MODE;
8313 break;
8314 case WebViewCore.ACTION_DOUBLETAP:
8315 // doDoubleTap() needs mLastTouchX/Y as anchor
Huahui Wu88b869a2011-03-17 17:42:12 -07008316 mLastDeferTouchX = ted.mPointsInView[0].x;
8317 mLastDeferTouchY = ted.mPointsInView[0].y;
Adam Powell4fb35d42011-03-03 17:54:55 -08008318 mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
8319 mDeferTouchMode = TOUCH_DONE_MODE;
8320 break;
8321 case WebViewCore.ACTION_LONGPRESS:
8322 HitTestResult hitTest = getHitTestResult();
8323 if (hitTest != null && hitTest.mType
8324 != HitTestResult.UNKNOWN_TYPE) {
8325 performLongClick();
8326 }
8327 mDeferTouchMode = TOUCH_DONE_MODE;
8328 break;
8329 }
8330 }
8331 }
8332 }
8333 }
8334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008335 //-------------------------------------------------------------------------
8336 // Methods can be called from a separate thread, like WebViewCore
8337 // If it needs to call the View system, it has to send message.
8338 //-------------------------------------------------------------------------
8339
8340 /**
8341 * General handler to receive message coming from webkit thread
8342 */
8343 class PrivateHandler extends Handler {
8344 @Override
8345 public void handleMessage(Message msg) {
Cary Clark3e88ddc2009-10-08 14:59:46 -04008346 // exclude INVAL_RECT_MSG_ID since it is frequently output
8347 if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) {
Grace Klobac2242f22010-03-05 14:00:26 -08008348 if (msg.what >= FIRST_PRIVATE_MSG_ID
8349 && msg.what <= LAST_PRIVATE_MSG_ID) {
8350 Log.v(LOGTAG, HandlerPrivateDebugString[msg.what
8351 - FIRST_PRIVATE_MSG_ID]);
8352 } else if (msg.what >= FIRST_PACKAGE_MSG_ID
8353 && msg.what <= LAST_PACKAGE_MSG_ID) {
8354 Log.v(LOGTAG, HandlerPackageDebugString[msg.what
8355 - FIRST_PACKAGE_MSG_ID]);
8356 } else {
8357 Log.v(LOGTAG, Integer.toString(msg.what));
8358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008359 }
Grace Kloba207308a2009-09-27 11:44:14 -07008360 if (mWebViewCore == null) {
8361 // after WebView's destroy() is called, skip handling messages.
8362 return;
8363 }
John Reck83e59292011-06-04 00:46:45 -07008364 if (mBlockWebkitViewMessages
8365 && msg.what != WEBCORE_INITIALIZED_MSG_ID) {
John Reck95b7d6f2011-06-03 15:23:43 -07008366 // Blocking messages from webkit
8367 return;
8368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008369 switch (msg.what) {
8370 case REMEMBER_PASSWORD: {
8371 mDatabase.setUsernamePassword(
8372 msg.getData().getString("host"),
8373 msg.getData().getString("username"),
8374 msg.getData().getString("password"));
8375 ((Message) msg.obj).sendToTarget();
8376 break;
8377 }
8378 case NEVER_REMEMBER_PASSWORD: {
8379 mDatabase.setUsernamePassword(
8380 msg.getData().getString("host"), null, null);
8381 ((Message) msg.obj).sendToTarget();
8382 break;
8383 }
Grace Klobac2242f22010-03-05 14:00:26 -08008384 case PREVENT_DEFAULT_TIMEOUT: {
8385 // if timeout happens, cancel it so that it won't block UI
8386 // to continue handling touch events
8387 if ((msg.arg1 == MotionEvent.ACTION_DOWN
8388 && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES)
8389 || (msg.arg1 == MotionEvent.ACTION_MOVE
8390 && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN)) {
8391 cancelWebCoreTouchEvent(
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08008392 viewToContentX(mLastTouchX + mScrollX),
8393 viewToContentY(mLastTouchY + mScrollY),
Grace Klobac2242f22010-03-05 14:00:26 -08008394 true);
Grace Klobaf58af622009-09-24 17:41:23 -07008395 }
Grace Klobac2242f22010-03-05 14:00:26 -08008396 break;
8397 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05008398 case SCROLL_SELECT_TEXT: {
8399 if (mAutoScrollX == 0 && mAutoScrollY == 0) {
8400 mSentAutoScrollMessage = false;
8401 break;
8402 }
Michael Kolb5da91bd2011-11-29 15:29:03 -08008403 if (mCurrentScrollingLayerId == 0) {
Cary Clarkb9aaa772011-01-07 16:14:54 -05008404 pinScrollBy(mAutoScrollX, mAutoScrollY, true, 0);
8405 } else {
John Reck83b9e1d2011-11-02 10:18:12 -07008406 scrollLayerTo(mScrollingLayerRect.left + mAutoScrollX,
8407 mScrollingLayerRect.top + mAutoScrollY);
Cary Clarkb9aaa772011-01-07 16:14:54 -05008408 }
Cary Clark6f5dfc62010-11-11 13:09:20 -05008409 sendEmptyMessageDelayed(
8410 SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
8411 break;
8412 }
John Reck0966dd22011-09-18 11:03:00 -07008413 case UPDATE_SELECTION: {
8414 if (mTouchMode == TOUCH_INIT_MODE
8415 || mTouchMode == TOUCH_SHORTPRESS_MODE
8416 || mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
8417 updateSelection();
8418 }
8419 break;
8420 }
Grace Klobac2242f22010-03-05 14:00:26 -08008421 case SWITCH_TO_SHORTPRESS: {
Cary Clarkb8491342010-11-29 16:23:19 -05008422 mInitialHitTestResult = null; // set by updateSelection()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008423 if (mTouchMode == TOUCH_INIT_MODE) {
Grace Kloba178db412010-05-18 22:22:23 -07008424 if (!getSettings().supportTouchOnly()
8425 && mPreventDefault != PREVENT_DEFAULT_YES) {
Grace Klobac2242f22010-03-05 14:00:26 -08008426 mTouchMode = TOUCH_SHORTPRESS_START_MODE;
8427 updateSelection();
8428 } else {
8429 // set to TOUCH_SHORTPRESS_MODE so that it won't
8430 // trigger double tap any more
8431 mTouchMode = TOUCH_SHORTPRESS_MODE;
8432 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07008433 } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
8434 mTouchMode = TOUCH_DONE_MODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008435 }
8436 break;
8437 }
8438 case SWITCH_TO_LONGPRESS: {
John Reck335f4542011-08-25 18:25:09 -07008439 if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
8440 removeTouchHighlight();
Grace Kloba178db412010-05-18 22:22:23 -07008441 }
Grace Klobac2242f22010-03-05 14:00:26 -08008442 if (inFullScreenMode() || mDeferTouchProcess) {
8443 TouchEventData ted = new TouchEventData();
Grace Kloba5f68d6f2009-12-08 18:42:54 -08008444 ted.mAction = WebViewCore.ACTION_LONGPRESS;
Huahui Wue838a422011-01-13 16:03:43 -08008445 ted.mIds = new int[1];
8446 ted.mIds[0] = 0;
Huahui Wu41865f42010-09-02 13:41:41 -07008447 ted.mPoints = new Point[1];
Shimeng (Simon) Wang1e07da32011-01-19 12:02:13 -08008448 ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX),
8449 viewToContentY(mLastTouchY + mScrollY));
Huahui Wu88b869a2011-03-17 17:42:12 -07008450 ted.mPointsInView = new Point[1];
8451 ted.mPointsInView[0] = new Point(mLastTouchX, mLastTouchY);
Grace Klobac2242f22010-03-05 14:00:26 -08008452 // metaState for long press is tricky. Should it be the
8453 // state when the press started or when the press was
8454 // released? Or some intermediary key state? For
8455 // simplicity for now, we don't set it.
Ben Murdoch8a032a32010-02-02 18:20:11 +00008456 ted.mMetaState = 0;
Grace Klobac2242f22010-03-05 14:00:26 -08008457 ted.mReprocess = mDeferTouchProcess;
Patrick Scottcfa734a2011-02-22 11:19:02 -05008458 ted.mNativeLayer = nativeScrollableLayer(
8459 ted.mPoints[0].x, ted.mPoints[0].y,
8460 ted.mNativeLayerRect, null);
Adam Powellae9d2642011-03-08 16:00:30 -08008461 ted.mSequence = mTouchEventQueue.nextTouchSequence();
Adam Powell3c534772011-04-04 14:27:12 -07008462 mTouchEventQueue.preQueueTouchEventData(ted);
Grace Kloba5f68d6f2009-12-08 18:42:54 -08008463 mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
Grace Klobac2242f22010-03-05 14:00:26 -08008464 } else if (mPreventDefault != PREVENT_DEFAULT_YES) {
Grace Kloba6c451b72009-06-25 12:25:30 -07008465 mTouchMode = TOUCH_DONE_MODE;
Grace Klobac2242f22010-03-05 14:00:26 -08008466 performLongClick();
Grace Kloba6c451b72009-06-25 12:25:30 -07008467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008468 break;
8469 }
Grace Kloba8b97e4b2009-07-28 13:11:38 -07008470 case RELEASE_SINGLE_TAP: {
Grace Klobac2242f22010-03-05 14:00:26 -08008471 doShortPress();
Grace Kloba8b97e4b2009-07-28 13:11:38 -07008472 break;
8473 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05008474 case SCROLL_TO_MSG_ID: {
8475 // arg1 = animate, arg2 = onlyIfImeIsShowing
8476 // obj = Point(x, y)
8477 if (msg.arg2 == 1) {
Leon Scrogginsfe77eb62011-02-01 11:05:22 -05008478 // This scroll is intended to bring the textfield into
8479 // view, but is only necessary if the IME is showing
8480 InputMethodManager imm = InputMethodManager.peekInstance();
8481 if (imm == null || !imm.isAcceptingText()
8482 || (!imm.isActive(WebView.this) && (!inEditingMode()
8483 || !imm.isActive(mWebTextView)))) {
8484 break;
8485 }
8486 }
Patrick Scottfa8be1c2011-02-02 14:09:34 -05008487 final Point p = (Point) msg.obj;
8488 if (msg.arg1 == 1) {
8489 spawnContentScrollTo(p.x, p.y);
8490 } else {
8491 setContentScrollTo(p.x, p.y);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008492 }
8493 break;
Patrick Scottfa8be1c2011-02-02 14:09:34 -05008494 }
Grace Kloba769ed212010-01-27 10:52:47 -08008495 case UPDATE_ZOOM_RANGE: {
Derek Sollenbergerb983c892010-06-28 08:38:28 -04008496 WebViewCore.ViewState viewState = (WebViewCore.ViewState) msg.obj;
Grace Kloba188bf8d2010-04-07 11:30:19 -07008497 // mScrollX contains the new minPrefWidth
Derek Sollenbergerb983c892010-06-28 08:38:28 -04008498 mZoomManager.updateZoomRange(viewState, getViewWidth(), viewState.mScrollX);
Grace Kloba769ed212010-01-27 10:52:47 -08008499 break;
8500 }
Mangesh Ghiware31f263d2011-11-21 16:54:20 -08008501 case UPDATE_ZOOM_DENSITY: {
8502 final float density = (Float) msg.obj;
8503 mZoomManager.updateDefaultZoomDensity(density);
8504 break;
8505 }
Grace Kloba8abd50b2010-07-08 15:02:14 -07008506 case REPLACE_BASE_CONTENT: {
8507 nativeReplaceBaseContent(msg.arg1);
8508 break;
8509 }
Grace Klobae397a882009-08-06 12:04:14 -07008510 case NEW_PICTURE_MSG_ID: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 // called for new content
Derek Sollenberger341e22f2010-06-02 12:34:34 -04008512 final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
John Reck60c84d62011-06-08 18:00:02 -07008513 setNewPicture(draw, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008514 break;
Grace Klobae397a882009-08-06 12:04:14 -07008515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008516 case WEBCORE_INITIALIZED_MSG_ID:
8517 // nativeCreate sets mNativeClass to a non-zero value
Leon Scrogginscdaff15bd2011-03-04 12:30:03 -05008518 String drawableDir = BrowserFrame.getRawResFilename(
8519 BrowserFrame.DRAWABLEDIR, mContext);
John Reck0507ac42011-11-21 13:30:32 -08008520 WindowManager windowManager =
8521 (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
8522 Display display = windowManager.getDefaultDisplay();
8523 nativeCreate(msg.arg1, drawableDir,
8524 ActivityManager.isHighEndGfx(display));
John Reck83e59292011-06-04 00:46:45 -07008525 if (mDelaySetPicture != null) {
John Reck60c84d62011-06-08 18:00:02 -07008526 setNewPicture(mDelaySetPicture, true);
John Reck83e59292011-06-04 00:46:45 -07008527 mDelaySetPicture = null;
8528 }
John Reck5f1c5492011-11-09 16:23:07 -08008529 if (mIsPaused) {
8530 nativeSetPauseDrawing(mNativeClass, true);
8531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008532 break;
8533 case UPDATE_TEXTFIELD_TEXT_MSG_ID:
8534 // Make sure that the textfield is currently focused
Cary Clarkd6982c92009-05-29 11:02:22 -04008535 // and representing the same node as the pointer.
8536 if (inEditingMode() &&
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008537 mWebTextView.isSameTextField(msg.arg1)) {
Chris Craike3e7a882011-07-25 14:35:22 -07008538 if (msg.arg2 == mTextGeneration) {
Leon Scrogginsef7af282010-11-11 14:20:06 -05008539 String text = (String) msg.obj;
8540 if (null == text) {
8541 text = "";
8542 }
8543 mWebTextView.setTextAndKeepSelection(text);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008544 }
8545 }
8546 break;
Leon Scrogginsb4157792010-03-18 12:42:33 -04008547 case REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID:
8548 displaySoftKeyboard(true);
Leon Scroggins III901a7c22010-04-20 15:14:02 -04008549 // fall through to UPDATE_TEXT_SELECTION_MSG_ID
Leon Scroggins6679f2f2009-08-12 18:48:10 -04008550 case UPDATE_TEXT_SELECTION_MSG_ID:
Leon Scrogginsb4157792010-03-18 12:42:33 -04008551 updateTextSelectionFromMessage(msg.arg1, msg.arg2,
8552 (WebViewCore.TextSelectionData) msg.obj);
Leon Scroggins6679f2f2009-08-12 18:48:10 -04008553 break;
Leon Scrogginsf2e17a82010-09-24 15:58:50 -04008554 case FORM_DID_BLUR:
8555 if (inEditingMode()
8556 && mWebTextView.isSameTextField(msg.arg1)) {
8557 hideSoftKeyboard();
8558 }
8559 break;
Leon Scroggins3a503392010-01-06 17:04:38 -05008560 case RETURN_LABEL:
8561 if (inEditingMode()
8562 && mWebTextView.isSameTextField(msg.arg1)) {
8563 mWebTextView.setHint((String) msg.obj);
8564 InputMethodManager imm
8565 = InputMethodManager.peekInstance();
8566 // The hint is propagated to the IME in
8567 // onCreateInputConnection. If the IME is already
8568 // active, restart it so that its hint text is updated.
8569 if (imm != null && imm.isActive(mWebTextView)) {
8570 imm.restartInput(mWebTextView);
8571 }
8572 }
8573 break;
Leon Scroggins9ab32b62010-05-03 14:19:50 +01008574 case UNHANDLED_NAV_KEY:
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05008575 navHandledKey(msg.arg1, 1, false, 0);
Cary Clark215b72c2009-06-26 14:38:43 -04008576 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008577 case UPDATE_TEXT_ENTRY_MSG_ID:
Cary Clarkd6982c92009-05-29 11:02:22 -04008578 // this is sent after finishing resize in WebViewCore. Make
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008579 // sure the text edit box is still on the screen.
Cary Clarkd6982c92009-05-29 11:02:22 -04008580 if (inEditingMode() && nativeCursorIsTextInput()) {
John Reckc0e9fb92011-10-21 12:39:43 -07008581 updateWebTextViewPosition();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008583 break;
Cary Clark243ea062009-06-25 10:49:32 -04008584 case CLEAR_TEXT_ENTRY:
Leon Scroggins2aed7762010-08-13 17:11:42 -04008585 clearTextEntry();
Cary Clark243ea062009-06-25 10:49:32 -04008586 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008587 case INVAL_RECT_MSG_ID: {
8588 Rect r = (Rect)msg.obj;
8589 if (r == null) {
8590 invalidate();
8591 } else {
8592 // we need to scale r from content into view coords,
8593 // which viewInvalidate() does for us
8594 viewInvalidate(r.left, r.top, r.right, r.bottom);
8595 }
8596 break;
8597 }
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008598 case REQUEST_FORM_DATA:
Cary Clarkded054c2009-06-15 10:26:08 -04008599 AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj;
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008600 if (mWebTextView.isSameTextField(msg.arg1)) {
Leon Scrogginsd3465f62009-06-02 10:57:54 -04008601 mWebTextView.setAdapterCustom(adapter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008602 }
8603 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008604
Leon Scrogginse3225672009-06-03 15:53:13 -04008605 case LONG_PRESS_CENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008606 // as this is shared by keydown and trackballdown, reset all
8607 // the states
Leon Scrogginse3225672009-06-03 15:53:13 -04008608 mGotCenterDown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008609 mTrackballDown = false;
Grace Kloba98e6fcf2010-01-27 15:20:30 -08008610 performLongClick();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008611 break;
8612
8613 case WEBCORE_NEED_TOUCH_EVENTS:
8614 mForwardTouchEvents = (msg.arg1 != 0);
8615 break;
8616
8617 case PREVENT_TOUCH_ID:
Grace Klobac2242f22010-03-05 14:00:26 -08008618 if (inFullScreenMode()) {
8619 break;
8620 }
Adam Powell4fb35d42011-03-03 17:54:55 -08008621 TouchEventData ted = (TouchEventData) msg.obj;
Adam Powellae9d2642011-03-08 16:00:30 -08008622
Adam Powellbaa33802011-03-25 13:58:19 -07008623 if (mTouchEventQueue.enqueueTouchEvent(ted)) {
8624 // WebCore is responding to us; remove pending timeout.
8625 // It will be re-posted when needed.
8626 removeMessages(PREVENT_DEFAULT_TIMEOUT);
8627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008628 break;
8629
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04008630 case REQUEST_KEYBOARD:
8631 if (msg.arg1 == 0) {
8632 hideSoftKeyboard();
8633 } else {
Leon Scrogginsb4157792010-03-18 12:42:33 -04008634 displaySoftKeyboard(false);
Derek Sollenberger4c41e8d2009-06-29 13:49:27 -04008635 }
8636 break;
8637
Leon Scroggins5de63892009-10-29 09:48:43 -04008638 case FIND_AGAIN:
8639 // Ignore if find has been dismissed.
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04008640 if (mFindIsUp && mFindCallback != null) {
8641 mFindCallback.findAll();
Leon Scroggins5de63892009-10-29 09:48:43 -04008642 }
8643 break;
8644
Cary Clark25415e22009-10-12 13:41:28 -04008645 case DRAG_HELD_MOTIONLESS:
8646 mHeldMotionless = MOTIONLESS_TRUE;
8647 invalidate();
8648 // fall through to keep scrollbars awake
8649
8650 case AWAKEN_SCROLL_BARS:
8651 if (mTouchMode == TOUCH_DRAG_MODE
8652 && mHeldMotionless == MOTIONLESS_TRUE) {
8653 awakenScrollBars(ViewConfiguration
8654 .getScrollDefaultDelay(), false);
8655 mPrivateHandler.sendMessageDelayed(mPrivateHandler
8656 .obtainMessage(AWAKEN_SCROLL_BARS),
8657 ViewConfiguration.getScrollDefaultDelay());
8658 }
8659 break;
Cary Clark1cb97ee2009-12-11 12:10:36 -05008660
8661 case DO_MOTION_UP:
Cary Clarkbad0c542010-01-11 14:58:21 -05008662 doMotionUp(msg.arg1, msg.arg2);
Cary Clark1cb97ee2009-12-11 12:10:36 -05008663 break;
8664
Derek Sollenbergerf3196cd2011-01-27 17:33:14 -05008665 case SCREEN_ON:
8666 setKeepScreenOn(msg.arg1 == 1);
8667 break;
8668
Nicolas Roard0e778a12011-03-11 14:29:05 -08008669 case ENTER_FULLSCREEN_VIDEO:
8670 int layerId = msg.arg1;
Teng-Hui Zhu10ab6542011-03-16 16:42:32 -07008671
8672 String url = (String) msg.obj;
8673 if (mHTML5VideoViewProxy != null) {
8674 mHTML5VideoViewProxy.enterFullScreenVideo(layerId, url);
8675 }
Nicolas Roard0e778a12011-03-11 14:29:05 -08008676 break;
8677
Grace Kloba3a0def22010-01-23 21:11:54 -08008678 case SHOW_FULLSCREEN: {
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008679 View view = (View) msg.obj;
Derek Sollenberger7ab3d672011-06-01 14:45:05 -04008680 int orientation = msg.arg1;
8681 int npp = msg.arg2;
Grace Kloba11438c32009-12-16 11:39:12 -08008682
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008683 if (inFullScreenMode()) {
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008684 Log.w(LOGTAG, "Should not have another full screen.");
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008685 dismissFullScreenMode();
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008686 }
Derek Sollenberger7ab3d672011-06-01 14:45:05 -04008687 mFullScreenHolder = new PluginFullScreenHolder(WebView.this, orientation, npp);
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008688 mFullScreenHolder.setContentView(view);
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008689 mFullScreenHolder.show();
George Mount5d3f6e62011-12-05 15:19:00 -08008690 invalidate();
Derek Sollenbergerc28ff442010-03-09 17:38:49 -05008691
8692 break;
8693 }
Grace Kloba11438c32009-12-16 11:39:12 -08008694 case HIDE_FULLSCREEN:
Derek Sollenbergerfa89c502010-10-01 11:19:36 -04008695 dismissFullScreenMode();
Grace Kloba11438c32009-12-16 11:39:12 -08008696 break;
8697
Leon Scrogginse26efa32009-12-15 16:38:45 -05008698 case DOM_FOCUS_CHANGED:
8699 if (inEditingMode()) {
8700 nativeClearCursor();
8701 rebuildWebTextView();
8702 }
8703 break;
8704
Grace Kloba3a0def22010-01-23 21:11:54 -08008705 case SHOW_RECT_MSG_ID: {
8706 WebViewCore.ShowRectData data = (WebViewCore.ShowRectData) msg.obj;
8707 int x = mScrollX;
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008708 int left = contentToViewX(data.mLeft);
Grace Kloba3a0def22010-01-23 21:11:54 -08008709 int width = contentToViewDimension(data.mWidth);
8710 int maxWidth = contentToViewDimension(data.mContentWidth);
8711 int viewWidth = getViewWidth();
8712 if (width < viewWidth) {
8713 // center align
8714 x += left + width / 2 - mScrollX - viewWidth / 2;
8715 } else {
8716 x += (int) (left + data.mXPercentInDoc * width
8717 - mScrollX - data.mXPercentInView * viewWidth);
8718 }
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008719 if (DebugFlags.WEB_VIEW) {
8720 Log.v(LOGTAG, "showRectMsg=(left=" + left + ",width=" +
8721 width + ",maxWidth=" + maxWidth +
8722 ",viewWidth=" + viewWidth + ",x="
8723 + x + ",xPercentInDoc=" + data.mXPercentInDoc +
8724 ",xPercentInView=" + data.mXPercentInView+ ")");
8725 }
Grace Kloba3a0def22010-01-23 21:11:54 -08008726 // use the passing content width to cap x as the current
8727 // mContentWidth may not be updated yet
8728 x = Math.max(0,
8729 (Math.min(maxWidth, x + viewWidth)) - viewWidth);
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008730 int top = contentToViewY(data.mTop);
Grace Kloba3a0def22010-01-23 21:11:54 -08008731 int height = contentToViewDimension(data.mHeight);
8732 int maxHeight = contentToViewDimension(data.mContentHeight);
8733 int viewHeight = getViewHeight();
Shimeng (Simon) Wang8a7ac8d2010-01-28 15:05:51 -08008734 int y = (int) (top + data.mYPercentInDoc * height -
8735 data.mYPercentInView * viewHeight);
8736 if (DebugFlags.WEB_VIEW) {
8737 Log.v(LOGTAG, "showRectMsg=(top=" + top + ",height=" +
8738 height + ",maxHeight=" + maxHeight +
8739 ",viewHeight=" + viewHeight + ",y="
8740 + y + ",yPercentInDoc=" + data.mYPercentInDoc +
8741 ",yPercentInView=" + data.mYPercentInView+ ")");
Grace Kloba3a0def22010-01-23 21:11:54 -08008742 }
8743 // use the passing content height to cap y as the current
8744 // mContentHeight may not be updated yet
8745 y = Math.max(0,
8746 (Math.min(maxHeight, y + viewHeight) - viewHeight));
Shimeng (Simon) Wangb7f17d42010-02-08 15:17:21 -08008747 // We need to take into account the visible title height
8748 // when scrolling since y is an absolute view position.
Steve Block92c99162011-05-23 17:36:01 +01008749 y = Math.max(0, y - getVisibleTitleHeightImpl());
Grace Kloba3a0def22010-01-23 21:11:54 -08008750 scrollTo(x, y);
8751 }
8752 break;
8753
Grace Klobae8300a12010-03-12 13:32:55 -08008754 case CENTER_FIT_RECT:
Derek Sollenbergerdd1173b2011-01-18 11:11:28 -05008755 centerFitRect((Rect)msg.obj);
Grace Klobae8300a12010-03-12 13:32:55 -08008756 break;
8757
Grace Kloba50004bc2010-04-13 22:58:51 -07008758 case SET_SCROLLBAR_MODES:
8759 mHorizontalScrollBarMode = msg.arg1;
8760 mVerticalScrollBarMode = msg.arg2;
8761 break;
8762
Svetoslav Ganovda355512010-05-12 22:04:44 -07008763 case SELECTION_STRING_CHANGED:
8764 if (mAccessibilityInjector != null) {
8765 String selectionString = (String) msg.obj;
8766 mAccessibilityInjector.onSelectionStringChange(selectionString);
8767 }
8768 break;
8769
Grace Kloba178db412010-05-18 22:22:23 -07008770 case SET_TOUCH_HIGHLIGHT_RECTS:
John Reck335f4542011-08-25 18:25:09 -07008771 @SuppressWarnings("unchecked")
8772 ArrayList<Rect> rects = (ArrayList<Rect>) msg.obj;
8773 setTouchHighlightRects(rects);
Grace Kloba178db412010-05-18 22:22:23 -07008774 break;
8775
Elliott Slaughterb48fdbe2010-06-30 11:39:52 -07008776 case SAVE_WEBARCHIVE_FINISHED:
8777 SaveWebArchiveMessage saveMessage = (SaveWebArchiveMessage)msg.obj;
8778 if (saveMessage.mCallback != null) {
8779 saveMessage.mCallback.onReceiveValue(saveMessage.mResultFile);
8780 }
8781 break;
8782
Ben Murdoch62275a42010-09-07 11:27:28 +01008783 case SET_AUTOFILLABLE:
Ben Murdochdb8d19c2010-10-29 11:44:17 +01008784 mAutoFillData = (WebViewCore.AutoFillData) msg.obj;
Ben Murdoch62275a42010-09-07 11:27:28 +01008785 if (mWebTextView != null) {
Ben Murdochdb8d19c2010-10-29 11:44:17 +01008786 mWebTextView.setAutoFillable(mAutoFillData.getQueryId());
Ben Murdoch62275a42010-09-07 11:27:28 +01008787 rebuildWebTextView();
8788 }
8789 break;
8790
Ben Murdoch961d55f2010-12-02 13:58:24 +00008791 case AUTOFILL_COMPLETE:
8792 if (mWebTextView != null) {
8793 // Clear the WebTextView adapter when AutoFill finishes
8794 // so that the drop down gets cleared.
8795 mWebTextView.setAdapterCustom(null);
8796 }
8797 break;
8798
Svetoslav Ganov9504f572011-01-14 11:38:17 -08008799 case SELECT_AT:
8800 nativeSelectAt(msg.arg1, msg.arg2);
8801 break;
8802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008803 default:
8804 super.handleMessage(msg);
8805 break;
8806 }
8807 }
8808 }
8809
John Reck335f4542011-08-25 18:25:09 -07008810 private void setTouchHighlightRects(ArrayList<Rect> rects) {
8811 invalidate(mTouchHighlightRegion.getBounds());
8812 mTouchHighlightRegion.setEmpty();
8813 if (rects != null) {
8814 for (Rect rect : rects) {
8815 Rect viewRect = contentToViewRect(rect);
8816 // some sites, like stories in nytimes.com, set
8817 // mouse event handler in the top div. It is not
8818 // user friendly to highlight the div if it covers
8819 // more than half of the screen.
8820 if (viewRect.width() < getWidth() >> 1
8821 || viewRect.height() < getHeight() >> 1) {
8822 mTouchHighlightRegion.union(viewRect);
8823 } else {
8824 Log.w(LOGTAG, "Skip the huge selection rect:"
8825 + viewRect);
8826 }
8827 }
8828 invalidate(mTouchHighlightRegion.getBounds());
8829 }
8830 }
8831
Chris Craik555c55e2011-07-28 15:39:43 -07008832 /** @hide Called by JNI when pages are swapped (only occurs with hardware
8833 * acceleration) */
Chris Craikd0051c02011-11-29 10:26:10 -08008834 protected void pageSwapCallback(boolean notifyAnimationStarted) {
Chris Craik5cf78f72011-07-28 11:34:31 -07008835 if (inEditingMode()) {
8836 didUpdateWebTextViewDimensions(ANYWHERE);
8837 }
Chris Craikd0051c02011-11-29 10:26:10 -08008838 if (notifyAnimationStarted) {
8839 mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
8840 }
Chris Craik5cf78f72011-07-28 11:34:31 -07008841 }
8842
John Reck60c84d62011-06-08 18:00:02 -07008843 void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) {
John Reck83e59292011-06-04 00:46:45 -07008844 if (mNativeClass == 0) {
8845 if (mDelaySetPicture != null) {
John Reck60c84d62011-06-08 18:00:02 -07008846 throw new IllegalStateException("Tried to setNewPicture with"
8847 + " a delay picture already set! (memory leak)");
John Reck83e59292011-06-04 00:46:45 -07008848 }
8849 // Not initialized yet, delay set
8850 mDelaySetPicture = draw;
8851 return;
8852 }
John Reck816c0de2011-06-02 16:04:53 -07008853 WebViewCore.ViewState viewState = draw.mViewState;
8854 boolean isPictureAfterFirstLayout = viewState != null;
Chris Craik5cf78f72011-07-28 11:34:31 -07008855
John Reck60c84d62011-06-08 18:00:02 -07008856 if (updateBaseLayer) {
Chris Craik555c55e2011-07-28 15:39:43 -07008857 // Request a callback on pageSwap (to reposition the webtextview)
8858 boolean registerPageSwapCallback =
8859 !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
8860
John Reck60c84d62011-06-08 18:00:02 -07008861 setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
8862 getSettings().getShowVisualIndicator(),
Chris Craik5cf78f72011-07-28 11:34:31 -07008863 isPictureAfterFirstLayout, registerPageSwapCallback);
John Reck60c84d62011-06-08 18:00:02 -07008864 }
John Reck816c0de2011-06-02 16:04:53 -07008865 final Point viewSize = draw.mViewSize;
John Reck816c0de2011-06-02 16:04:53 -07008866 // We update the layout (i.e. request a layout from the
8867 // view system) if the last view size that we sent to
8868 // WebCore matches the view size of the picture we just
8869 // received in the fixed dimension.
8870 final boolean updateLayout = viewSize.x == mLastWidthSent
8871 && viewSize.y == mLastHeightSent;
8872 // Don't send scroll event for picture coming from webkit,
8873 // since the new picture may cause a scroll event to override
8874 // the saved history scroll position.
8875 mSendScrollEvent = false;
8876 recordNewContentSize(draw.mContentSize.x,
8877 draw.mContentSize.y, updateLayout);
George Mounte263bc12011-10-31 13:49:03 -07008878 if (isPictureAfterFirstLayout) {
8879 // Reset the last sent data here since dealing with new page.
8880 mLastWidthSent = 0;
8881 mZoomManager.onFirstLayout(draw);
8882 int scrollX = viewState.mShouldStartScrolledRight
8883 ? getContentWidth() : viewState.mScrollX;
8884 int scrollY = viewState.mScrollY;
8885 setContentScrollTo(scrollX, scrollY);
8886 if (!mDrawHistory) {
8887 // As we are on a new page, remove the WebTextView. This
8888 // is necessary for page loads driven by webkit, and in
8889 // particular when the user was on a password field, so
8890 // the WebTextView was visible.
8891 clearTextEntry();
8892 }
8893 }
John Reck816c0de2011-06-02 16:04:53 -07008894 mSendScrollEvent = true;
George Mounte263bc12011-10-31 13:49:03 -07008895
John Reck816c0de2011-06-02 16:04:53 -07008896 if (DebugFlags.WEB_VIEW) {
8897 Rect b = draw.mInvalRegion.getBounds();
8898 Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
8899 b.left+","+b.top+","+b.right+","+b.bottom+"}");
8900 }
8901 invalidateContentRect(draw.mInvalRegion.getBounds());
8902
8903 if (mPictureListener != null) {
8904 mPictureListener.onNewPicture(WebView.this, capturePicture());
8905 }
8906
8907 // update the zoom information based on the new picture
8908 mZoomManager.onNewPicture(draw);
8909
8910 if (draw.mFocusSizeChanged && inEditingMode()) {
8911 mFocusSizeChanged = true;
8912 }
8913 if (isPictureAfterFirstLayout) {
8914 mViewManager.postReadyToDrawAll();
8915 }
8916 }
8917
Leon Scrogginsb4157792010-03-18 12:42:33 -04008918 /**
8919 * Used when receiving messages for REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID
8920 * and UPDATE_TEXT_SELECTION_MSG_ID. Update the selection of WebTextView.
8921 */
8922 private void updateTextSelectionFromMessage(int nodePointer,
8923 int textGeneration, WebViewCore.TextSelectionData data) {
8924 if (inEditingMode()
8925 && mWebTextView.isSameTextField(nodePointer)
8926 && textGeneration == mTextGeneration) {
8927 mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd);
8928 }
8929 }
8930
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 // Class used to use a dropdown for a <select> element
8932 private class InvokeListBox implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008933 // Whether the listbox allows multiple selection.
8934 private boolean mMultiple;
8935 // Passed in to a list with multiple selection to tell
8936 // which items are selected.
8937 private int[] mSelectedArray;
Cary Clarkd6982c92009-05-29 11:02:22 -04008938 // Passed in to a list with single selection to tell
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008939 // where the initial selection is.
8940 private int mSelection;
8941
8942 private Container[] mContainers;
8943
8944 // Need these to provide stable ids to my ArrayAdapter,
8945 // which normally does not have stable ids. (Bug 1250098)
8946 private class Container extends Object {
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008947 /**
8948 * Possible values for mEnabled. Keep in sync with OptionStatus in
8949 * WebViewCore.cpp
8950 */
8951 final static int OPTGROUP = -1;
8952 final static int OPTION_DISABLED = 0;
8953 final static int OPTION_ENABLED = 1;
8954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008955 String mString;
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008956 int mEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008957 int mId;
8958
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08008959 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008960 public String toString() {
8961 return mString;
8962 }
8963 }
8964
8965 /**
Cary Clarkd6982c92009-05-29 11:02:22 -04008966 * Subclass ArrayAdapter so we can disable OptionGroupLabels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008967 * and allow filtering.
8968 */
8969 private class MyArrayListAdapter extends ArrayAdapter<Container> {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05008970 public MyArrayListAdapter() {
8971 super(mContext,
8972 mMultiple ? com.android.internal.R.layout.select_dialog_multichoice :
8973 com.android.internal.R.layout.webview_select_singlechoice,
8974 mContainers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008975 }
8976
8977 @Override
Leon Scrogginsa8da1732009-10-19 19:04:30 -04008978 public View getView(int position, View convertView,
8979 ViewGroup parent) {
8980 // Always pass in null so that we will get a new CheckedTextView
8981 // Otherwise, an item which was previously used as an <optgroup>
8982 // element (i.e. has no check), could get used as an <option>
8983 // element, which needs a checkbox/radio, but it would not have
8984 // one.
8985 convertView = super.getView(position, null, parent);
8986 Container c = item(position);
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -04008987 if (c != null && Container.OPTION_ENABLED != c.mEnabled) {
8988 // ListView does not draw dividers between disabled and
8989 // enabled elements. Use a LinearLayout to provide dividers
8990 LinearLayout layout = new LinearLayout(mContext);
8991 layout.setOrientation(LinearLayout.VERTICAL);
8992 if (position > 0) {
8993 View dividerTop = new View(mContext);
8994 dividerTop.setBackgroundResource(
8995 android.R.drawable.divider_horizontal_bright);
8996 layout.addView(dividerTop);
8997 }
8998
8999 if (Container.OPTGROUP == c.mEnabled) {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05009000 // Currently select_dialog_multichoice uses CheckedTextViews.
9001 // If that changes, the class cast will no longer be valid.
9002 if (mMultiple) {
9003 Assert.assertTrue(convertView instanceof CheckedTextView);
9004 ((CheckedTextView) convertView).setCheckMarkDrawable(null);
9005 }
Leon Scrogginsf1e1fb32009-10-21 13:39:33 -04009006 } else {
9007 // c.mEnabled == Container.OPTION_DISABLED
9008 // Draw the disabled element in a disabled state.
9009 convertView.setEnabled(false);
9010 }
9011
9012 layout.addView(convertView);
9013 if (position < getCount() - 1) {
9014 View dividerBottom = new View(mContext);
9015 dividerBottom.setBackgroundResource(
9016 android.R.drawable.divider_horizontal_bright);
9017 layout.addView(dividerBottom);
9018 }
9019 return layout;
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009020 }
9021 return convertView;
9022 }
9023
9024 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009025 public boolean hasStableIds() {
Leon Scroggins3667ce42009-05-13 15:58:03 -04009026 // AdapterView's onChanged method uses this to determine whether
9027 // to restore the old state. Return false so that the old (out
9028 // of date) state does not replace the new, valid state.
9029 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009030 }
9031
9032 private Container item(int position) {
9033 if (position < 0 || position >= getCount()) {
9034 return null;
9035 }
9036 return (Container) getItem(position);
9037 }
9038
9039 @Override
9040 public long getItemId(int position) {
9041 Container item = item(position);
9042 if (item == null) {
9043 return -1;
9044 }
9045 return item.mId;
9046 }
9047
9048 @Override
9049 public boolean areAllItemsEnabled() {
9050 return false;
9051 }
9052
9053 @Override
9054 public boolean isEnabled(int position) {
9055 Container item = item(position);
9056 if (item == null) {
9057 return false;
9058 }
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009059 return Container.OPTION_ENABLED == item.mEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009060 }
9061 }
9062
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009063 private InvokeListBox(String[] array, int[] enabled, int[] selected) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009064 mMultiple = true;
9065 mSelectedArray = selected;
9066
9067 int length = array.length;
9068 mContainers = new Container[length];
9069 for (int i = 0; i < length; i++) {
9070 mContainers[i] = new Container();
9071 mContainers[i].mString = array[i];
9072 mContainers[i].mEnabled = enabled[i];
9073 mContainers[i].mId = i;
9074 }
9075 }
9076
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009077 private InvokeListBox(String[] array, int[] enabled, int selection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009078 mSelection = selection;
9079 mMultiple = false;
9080
9081 int length = array.length;
9082 mContainers = new Container[length];
9083 for (int i = 0; i < length; i++) {
9084 mContainers[i] = new Container();
9085 mContainers[i].mString = array[i];
9086 mContainers[i].mEnabled = enabled[i];
9087 mContainers[i].mId = i;
9088 }
9089 }
9090
Leon Scroggins3667ce42009-05-13 15:58:03 -04009091 /*
9092 * Whenever the data set changes due to filtering, this class ensures
9093 * that the checked item remains checked.
9094 */
9095 private class SingleDataSetObserver extends DataSetObserver {
9096 private long mCheckedId;
9097 private ListView mListView;
9098 private Adapter mAdapter;
9099
9100 /*
9101 * Create a new observer.
9102 * @param id The ID of the item to keep checked.
9103 * @param l ListView for getting and clearing the checked states
9104 * @param a Adapter for getting the IDs
9105 */
9106 public SingleDataSetObserver(long id, ListView l, Adapter a) {
9107 mCheckedId = id;
9108 mListView = l;
9109 mAdapter = a;
9110 }
9111
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05009112 @Override
Leon Scroggins3667ce42009-05-13 15:58:03 -04009113 public void onChanged() {
9114 // The filter may have changed which item is checked. Find the
9115 // item that the ListView thinks is checked.
9116 int position = mListView.getCheckedItemPosition();
9117 long id = mAdapter.getItemId(position);
9118 if (mCheckedId != id) {
9119 // Clear the ListView's idea of the checked item, since
9120 // it is incorrect
9121 mListView.clearChoices();
9122 // Search for mCheckedId. If it is in the filtered list,
9123 // mark it as checked
9124 int count = mAdapter.getCount();
9125 for (int i = 0; i < count; i++) {
9126 if (mAdapter.getItemId(i) == mCheckedId) {
9127 mListView.setItemChecked(i, true);
9128 break;
9129 }
9130 }
9131 }
9132 }
Leon Scroggins3667ce42009-05-13 15:58:03 -04009133 }
9134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009135 public void run() {
9136 final ListView listView = (ListView) LayoutInflater.from(mContext)
9137 .inflate(com.android.internal.R.layout.select_dialog, null);
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05009138 final MyArrayListAdapter adapter = new MyArrayListAdapter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009139 AlertDialog.Builder b = new AlertDialog.Builder(mContext)
9140 .setView(listView).setCancelable(true)
9141 .setInverseBackgroundForced(true);
Cary Clarkd6982c92009-05-29 11:02:22 -04009142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009143 if (mMultiple) {
9144 b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
9145 public void onClick(DialogInterface dialog, int which) {
9146 mWebViewCore.sendMessage(
Cary Clarkd6982c92009-05-29 11:02:22 -04009147 EventHub.LISTBOX_CHOICES,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009148 adapter.getCount(), 0,
9149 listView.getCheckedItemPositions());
9150 }});
Leon Scroggins238ddbb2009-04-02 10:47:53 -07009151 b.setNegativeButton(android.R.string.cancel,
9152 new DialogInterface.OnClickListener() {
9153 public void onClick(DialogInterface dialog, int which) {
9154 mWebViewCore.sendMessage(
9155 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
9156 }});
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009157 }
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009158 mListBoxDialog = b.create();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009159 listView.setAdapter(adapter);
9160 listView.setFocusableInTouchMode(true);
9161 // There is a bug (1250103) where the checks in a ListView with
9162 // multiple items selected are associated with the positions, not
Cary Clarkd6982c92009-05-29 11:02:22 -04009163 // the ids, so the items do not properly retain their checks when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009164 // filtered. Do not allow filtering on multiple lists until
9165 // that bug is fixed.
Cary Clarkd6982c92009-05-29 11:02:22 -04009166
Leon Scroggins3667ce42009-05-13 15:58:03 -04009167 listView.setTextFilterEnabled(!mMultiple);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009168 if (mMultiple) {
9169 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
9170 int length = mSelectedArray.length;
9171 for (int i = 0; i < length; i++) {
9172 listView.setItemChecked(mSelectedArray[i], true);
9173 }
9174 } else {
9175 listView.setOnItemClickListener(new OnItemClickListener() {
Leon Scrogginsd529bfd2011-02-15 11:10:38 -05009176 public void onItemClick(AdapterView<?> parent, View v,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009177 int position, long id) {
Leon Scroggins244d2d42010-12-06 16:29:38 -05009178 // Rather than sending the message right away, send it
9179 // after the page regains focus.
9180 mListBoxMessage = Message.obtain(null,
9181 EventHub.SINGLE_LISTBOX_CHOICE, (int) id, 0);
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009182 mListBoxDialog.dismiss();
9183 mListBoxDialog = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009184 }
9185 });
9186 if (mSelection != -1) {
9187 listView.setSelection(mSelection);
9188 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
9189 listView.setItemChecked(mSelection, true);
Leon Scroggins3667ce42009-05-13 15:58:03 -04009190 DataSetObserver observer = new SingleDataSetObserver(
9191 adapter.getItemId(mSelection), listView, adapter);
9192 adapter.registerDataSetObserver(observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009193 }
9194 }
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009195 mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009196 public void onCancel(DialogInterface dialog) {
9197 mWebViewCore.sendMessage(
9198 EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009199 mListBoxDialog = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009200 }
9201 });
Mattias Falk0ae2ec82010-09-16 16:24:46 +02009202 mListBoxDialog.show();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009203 }
9204 }
9205
Leon Scroggins244d2d42010-12-06 16:29:38 -05009206 private Message mListBoxMessage;
9207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009208 /*
9209 * Request a dropdown menu for a listbox with multiple selection.
9210 *
9211 * @param array Labels for the listbox.
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009212 * @param enabledArray State for each element in the list. See static
9213 * integers in Container class.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009214 * @param selectedArray Which positions are initally selected.
9215 */
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009216 void requestListBox(String[] array, int[] enabledArray, int[]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009217 selectedArray) {
9218 mPrivateHandler.post(
9219 new InvokeListBox(array, enabledArray, selectedArray));
9220 }
9221
9222 /*
9223 * Request a dropdown menu for a listbox with single selection or a single
9224 * <select> element.
9225 *
9226 * @param array Labels for the listbox.
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009227 * @param enabledArray State for each element in the list. See static
9228 * integers in Container class.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009229 * @param selection Which position is initally selected.
9230 */
Leon Scrogginsa8da1732009-10-19 19:04:30 -04009231 void requestListBox(String[] array, int[] enabledArray, int selection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009232 mPrivateHandler.post(
9233 new InvokeListBox(array, enabledArray, selection));
9234 }
9235
9236 // called by JNI
Leon Scroggins47fabbf2009-12-08 16:57:26 -05009237 private void sendMoveFocus(int frame, int node) {
9238 mWebViewCore.sendMessage(EventHub.SET_MOVE_FOCUS,
9239 new WebViewCore.CursorData(frame, node, 0, 0));
9240 }
9241
9242 // called by JNI
Cary Clarkd6982c92009-05-29 11:02:22 -04009243 private void sendMoveMouse(int frame, int node, int x, int y) {
9244 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
9245 new WebViewCore.CursorData(frame, node, x, y));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009246 }
9247
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009248 /*
9249 * Send a mouse move event to the webcore thread.
9250 *
Leon Scrogginsb6112132011-02-24 12:35:50 -05009251 * @param removeFocus Pass true to remove the WebTextView, if present.
9252 * @param stopPaintingCaret Stop drawing the blinking caret if true.
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009253 * called by JNI
9254 */
Leon Scrogginsb6112132011-02-24 12:35:50 -05009255 @SuppressWarnings("unused")
9256 private void sendMoveMouseIfLatest(boolean removeFocus, boolean stopPaintingCaret) {
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009257 if (removeFocus) {
Leon Scroggins2aed7762010-08-13 17:11:42 -04009258 clearTextEntry();
Cary Clark19436562009-06-04 16:25:07 -04009259 }
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009260 mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST,
Leon Scrogginsb6112132011-02-24 12:35:50 -05009261 stopPaintingCaret ? 1 : 0, 0,
Leon Scroggins0658e8f2009-06-26 14:09:09 -04009262 cursorData());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009263 }
9264
Leon Scrogginsd5188652011-01-19 17:01:55 -05009265 /**
9266 * Called by JNI to send a message to the webcore thread that the user
9267 * touched the webpage.
9268 * @param touchGeneration Generation number of the touch, to ignore touches
9269 * after a new one has been generated.
9270 * @param frame Pointer to the frame holding the node that was touched.
9271 * @param node Pointer to the node touched.
9272 * @param x x-position of the touch.
9273 * @param y y-position of the touch.
Leon Scrogginsd5188652011-01-19 17:01:55 -05009274 */
Cary Clarkd6982c92009-05-29 11:02:22 -04009275 private void sendMotionUp(int touchGeneration,
Leon Scroggins22e883d2011-01-31 10:54:19 -05009276 int frame, int node, int x, int y) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009277 WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
9278 touchUpData.mMoveGeneration = touchGeneration;
Cary Clarkd6982c92009-05-29 11:02:22 -04009279 touchUpData.mFrame = frame;
9280 touchUpData.mNode = node;
9281 touchUpData.mX = x;
9282 touchUpData.mY = y;
Patrick Scottcfa734a2011-02-22 11:19:02 -05009283 touchUpData.mNativeLayer = nativeScrollableLayer(
9284 x, y, touchUpData.mNativeLayerRect, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009285 mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
9286 }
9287
9288
9289 private int getScaledMaxXScroll() {
9290 int width;
9291 if (mHeightCanMeasure == false) {
9292 width = getViewWidth() / 4;
9293 } else {
9294 Rect visRect = new Rect();
9295 calcOurVisibleRect(visRect);
9296 width = visRect.width() / 2;
9297 }
9298 // FIXME the divisor should be retrieved from somewhere
Leon Scroggins0236e672009-09-02 21:12:08 -04009299 return viewToContentX(width);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009300 }
9301
9302 private int getScaledMaxYScroll() {
9303 int height;
9304 if (mHeightCanMeasure == false) {
9305 height = getViewHeight() / 4;
9306 } else {
9307 Rect visRect = new Rect();
9308 calcOurVisibleRect(visRect);
9309 height = visRect.height() / 2;
9310 }
9311 // FIXME the divisor should be retrieved from somewhere
9312 // the closest thing today is hard-coded into ScrollView.java
9313 // (from ScrollView.java, line 363) int maxJump = height/2;
Derek Sollenbergerbffa8512010-06-10 14:24:03 -04009314 return Math.round(height * mZoomManager.getInvScale());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009315 }
9316
9317 /**
9318 * Called by JNI to invalidate view
9319 */
9320 private void viewInvalidate() {
9321 invalidate();
9322 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009323
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009324 /**
Leon Scroggins9ab32b62010-05-03 14:19:50 +01009325 * Pass the key directly to the page. This assumes that
9326 * nativePageShouldHandleShiftAndArrows() returned true.
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009327 */
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07009328 private void letPageHandleNavKey(int keyCode, long time, boolean down, int metaState) {
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009329 int keyEventAction;
9330 int eventHubAction;
9331 if (down) {
9332 keyEventAction = KeyEvent.ACTION_DOWN;
9333 eventHubAction = EventHub.KEY_DOWN;
9334 playSoundEffect(keyCodeToSoundsEffect(keyCode));
9335 } else {
9336 keyEventAction = KeyEvent.ACTION_UP;
9337 eventHubAction = EventHub.KEY_UP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009338 }
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07009339
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009340 KeyEvent event = new KeyEvent(time, time, keyEventAction, keyCode,
Svetoslav Ganov9b756ac2010-11-05 15:42:22 -07009341 1, (metaState & KeyEvent.META_SHIFT_ON)
9342 | (metaState & KeyEvent.META_ALT_ON)
9343 | (metaState & KeyEvent.META_SYM_ON)
Jeff Brown6b53e8d2010-11-10 16:03:06 -08009344 , KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0);
Leon Scrogginsb127c8f2010-03-05 15:42:17 -05009345 mWebViewCore.sendMessage(eventHubAction, event);
9346 }
9347
9348 // return true if the key was handled
9349 private boolean navHandledKey(int keyCode, int count, boolean noScroll,
9350 long time) {
9351 if (mNativeClass == 0) {
9352 return false;
Cary Clark215b72c2009-06-26 14:38:43 -04009353 }
Cary Clark32820242010-12-03 10:27:20 -05009354 mInitialHitTestResult = null;
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009355 mLastCursorTime = time;
9356 mLastCursorBounds = nativeGetCursorRingBounds();
9357 boolean keyHandled
9358 = nativeMoveCursor(keyCode, count, noScroll) == false;
Derek Sollenberger2e5c1502009-06-03 10:44:42 -04009359 if (DebugFlags.WEB_VIEW) {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009360 Log.v(LOGTAG, "navHandledKey mLastCursorBounds=" + mLastCursorBounds
9361 + " mLastCursorTime=" + mLastCursorTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009362 + " handled=" + keyHandled);
9363 }
Leon Scrogginscef1c592011-01-26 11:13:24 -05009364 if (keyHandled == false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009365 return keyHandled;
9366 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009367 Rect contentCursorRingBounds = nativeGetCursorRingBounds();
9368 if (contentCursorRingBounds.isEmpty()) return keyHandled;
Mike Reede9e86b82009-09-15 11:26:53 -04009369 Rect viewCursorRingBounds = contentToViewRect(contentCursorRingBounds);
Cary Clarka3ee56f2011-01-10 11:20:56 -05009370 // set last touch so that context menu related functions will work
9371 mLastTouchX = (viewCursorRingBounds.left + viewCursorRingBounds.right) / 2;
9372 mLastTouchY = (viewCursorRingBounds.top + viewCursorRingBounds.bottom) / 2;
Leon Scrogginscef1c592011-01-26 11:13:24 -05009373 if (mHeightCanMeasure == false) {
9374 return keyHandled;
9375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009376 Rect visRect = new Rect();
9377 calcOurVisibleRect(visRect);
9378 Rect outset = new Rect(visRect);
9379 int maxXScroll = visRect.width() / 2;
9380 int maxYScroll = visRect.height() / 2;
9381 outset.inset(-maxXScroll, -maxYScroll);
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009382 if (Rect.intersects(outset, viewCursorRingBounds) == false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009383 return keyHandled;
9384 }
9385 // FIXME: Necessary because ScrollView/ListView do not scroll left/right
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009386 int maxH = Math.min(viewCursorRingBounds.right - visRect.right,
9387 maxXScroll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009388 if (maxH > 0) {
9389 pinScrollBy(maxH, 0, true, 0);
9390 } else {
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009391 maxH = Math.max(viewCursorRingBounds.left - visRect.left,
9392 -maxXScroll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009393 if (maxH < 0) {
9394 pinScrollBy(maxH, 0, true, 0);
9395 }
9396 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009397 if (mLastCursorBounds.isEmpty()) return keyHandled;
9398 if (mLastCursorBounds.equals(contentCursorRingBounds)) {
9399 return keyHandled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009400 }
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009401 if (DebugFlags.WEB_VIEW) {
9402 Log.v(LOGTAG, "navHandledKey contentCursorRingBounds="
9403 + contentCursorRingBounds);
9404 }
9405 requestRectangleOnScreen(viewCursorRingBounds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009406 return keyHandled;
9407 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009409 /**
Svetoslav Ganov12bed782011-01-03 14:14:50 -08009410 * @return Whether accessibility script has been injected.
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07009411 */
Svetoslav Ganov12bed782011-01-03 14:14:50 -08009412 private boolean accessibilityScriptInjected() {
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07009413 // TODO: Maybe the injected script should announce its presence in
9414 // the page meta-tag so the nativePageShouldHandleShiftAndArrows
9415 // will check that as one of the conditions it looks for
Svetoslav Ganov12bed782011-01-03 14:14:50 -08009416 return mAccessibilityScriptInjected;
Svetoslav Ganov585f13f8d2010-08-10 07:59:15 -07009417 }
9418
9419 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009420 * Set the background color. It's white by default. Pass
9421 * zero to make the view transparent.
9422 * @param color the ARGB color described by Color.java
9423 */
Gilles Debunne0e7d652d2011-02-22 15:26:14 -08009424 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009425 public void setBackgroundColor(int color) {
9426 mBackgroundColor = color;
9427 mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color);
9428 }
9429
Kristian Monsenfc771652011-05-10 16:44:05 +01009430 /**
9431 * @deprecated This method is now obsolete.
9432 */
9433 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009434 public void debugDump() {
Steve Block51b08912011-04-27 15:04:48 +01009435 checkThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009436 nativeDebugDump();
9437 mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
9438 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009440 /**
Mike Reedefe2c722009-10-14 09:42:02 -04009441 * Draw the HTML page into the specified canvas. This call ignores any
9442 * view-specific zoom, scroll offset, or other changes. It does not draw
9443 * any view-specific chrome, such as progress or URL bars.
9444 *
9445 * @hide only needs to be accessible to Browser and testing
9446 */
9447 public void drawPage(Canvas canvas) {
George Mount82ed95f2011-11-15 11:27:47 -08009448 calcOurContentVisibleRectF(mVisibleContentRect);
9449 nativeDraw(canvas, mVisibleContentRect, 0, 0, false);
Mike Reedefe2c722009-10-14 09:42:02 -04009450 }
9451
9452 /**
Teng-Hui Zhu661e8b12011-03-02 15:09:34 -08009453 * Enable the communication b/t the webView and VideoViewProxy
9454 *
9455 * @hide only used by the Browser
9456 */
9457 public void setHTML5VideoViewProxy(HTML5VideoViewProxy proxy) {
9458 mHTML5VideoViewProxy = proxy;
9459 }
9460
9461 /**
Ben Murdochecbc65c2010-01-13 10:54:56 +00009462 * Set the time to wait between passing touches to WebCore. See also the
9463 * TOUCH_SENT_INTERVAL member for further discussion.
9464 *
9465 * @hide This is only used by the DRT test application.
9466 */
9467 public void setTouchInterval(int interval) {
9468 mCurrentTouchInterval = interval;
9469 }
9470
9471 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009472 * Update our cache with updatedText.
9473 * @param updatedText The new text to put in our cache.
John Reck4bfd6f02011-06-09 16:59:40 -07009474 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009475 */
John Reck4bfd6f02011-06-09 16:59:40 -07009476 protected void updateCachedTextfield(String updatedText) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009477 // Also place our generation number so that when we look at the cache
9478 // we recognize that it is up to date.
9479 nativeUpdateCachedTextfield(updatedText, mTextGeneration);
9480 }
Cary Clarkd6982c92009-05-29 11:02:22 -04009481
Ben Murdoch62275a42010-09-07 11:27:28 +01009482 /*package*/ void autoFillForm(int autoFillQueryId) {
9483 mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM, autoFillQueryId, /* unused */0);
9484 }
9485
Ben Murdoch1708ad52010-11-11 15:56:16 +00009486 /* package */ ViewManager getViewManager() {
9487 return mViewManager;
9488 }
9489
Steve Block51b08912011-04-27 15:04:48 +01009490 private static void checkThread() {
Steve Block08d584c2011-05-17 19:05:03 +01009491 if (Looper.myLooper() != Looper.getMainLooper()) {
Steve Block7a01d942011-09-26 12:30:31 +01009492 Throwable throwable = new Throwable(
9493 "Warning: A WebView method was called on thread '" +
Steve Block08d584c2011-05-17 19:05:03 +01009494 Thread.currentThread().getName() + "'. " +
9495 "All WebView methods must be called on the UI thread. " +
9496 "Future versions of WebView may not support use on other threads.");
Steve Block7a01d942011-09-26 12:30:31 +01009497 Log.w(LOGTAG, Log.getStackTraceString(throwable));
9498 StrictMode.onWebViewMethodCalledOnWrongThread(throwable);
Steve Block51b08912011-04-27 15:04:48 +01009499 }
9500 }
9501
Chris Craik555c55e2011-07-28 15:39:43 -07009502 /** @hide send content invalidate */
9503 protected void contentInvalidateAll() {
John Reckc87b7702011-08-29 11:45:30 -07009504 if (mWebViewCore != null && !mBlockWebkitViewMessages) {
9505 mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL);
9506 }
Chris Craik555c55e2011-07-28 15:39:43 -07009507 }
9508
9509 /** @hide call pageSwapCallback upon next page swap */
9510 protected void registerPageSwapCallback() {
Chris Craik09a71e02011-12-12 18:03:29 -08009511 nativeRegisterPageSwapCallback(mNativeClass);
9512 }
9513
9514 /** @hide discard all textures from tiles */
9515 protected void discardAllTextures() {
9516 nativeDiscardAllTextures();
Chris Craik555c55e2011-07-28 15:39:43 -07009517 }
9518
Chris Craik445ab742011-07-13 13:19:37 -07009519 /**
9520 * Begin collecting per-tile profiling data
9521 *
9522 * @hide only used by profiling tests
9523 */
9524 public void tileProfilingStart() {
9525 nativeTileProfilingStart();
9526 }
9527 /**
9528 * Return per-tile profiling data
9529 *
9530 * @hide only used by profiling tests
9531 */
9532 public float tileProfilingStop() {
9533 return nativeTileProfilingStop();
9534 }
9535
9536 /** @hide only used by profiling tests */
9537 public void tileProfilingClear() {
9538 nativeTileProfilingClear();
9539 }
9540 /** @hide only used by profiling tests */
9541 public int tileProfilingNumFrames() {
9542 return nativeTileProfilingNumFrames();
9543 }
9544 /** @hide only used by profiling tests */
9545 public int tileProfilingNumTilesInFrame(int frame) {
9546 return nativeTileProfilingNumTilesInFrame(frame);
9547 }
9548 /** @hide only used by profiling tests */
Chris Craik21555ab2011-07-21 11:52:19 -07009549 public int tileProfilingGetInt(int frame, int tile, String key) {
9550 return nativeTileProfilingGetInt(frame, tile, key);
Chris Craik445ab742011-07-13 13:19:37 -07009551 }
9552 /** @hide only used by profiling tests */
Chris Craik21555ab2011-07-21 11:52:19 -07009553 public float tileProfilingGetFloat(int frame, int tile, String key) {
9554 return nativeTileProfilingGetFloat(frame, tile, key);
Chris Craik445ab742011-07-13 13:19:37 -07009555 }
9556
Cary Clark1cb97ee2009-12-11 12:10:36 -05009557 private native int nativeCacheHitFramePointer();
Cary Clarkb2601352011-01-11 11:32:01 -05009558 private native boolean nativeCacheHitIsPlugin();
Cary Clark1cb97ee2009-12-11 12:10:36 -05009559 private native Rect nativeCacheHitNodeBounds();
9560 private native int nativeCacheHitNodePointer();
Leon Scroggins4890feb2009-07-02 10:37:10 -04009561 /* package */ native void nativeClearCursor();
John Reck0507ac42011-11-21 13:30:32 -08009562 private native void nativeCreate(int ptr, String drawableDir, boolean isHighEndGfx);
Cary Clarkd6982c92009-05-29 11:02:22 -04009563 private native int nativeCursorFramePointer();
9564 private native Rect nativeCursorNodeBounds();
Cary Clarkaffa5d22010-01-07 12:18:23 -05009565 private native int nativeCursorNodePointer();
Cary Clarkd6982c92009-05-29 11:02:22 -04009566 private native boolean nativeCursorIntersects(Rect visibleRect);
9567 private native boolean nativeCursorIsAnchor();
9568 private native boolean nativeCursorIsTextInput();
Cary Clarked56eda2009-06-18 09:48:47 -04009569 private native Point nativeCursorPosition();
Cary Clarkd6982c92009-05-29 11:02:22 -04009570 private native String nativeCursorText();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009571 /**
9572 * Returns true if the native cursor node says it wants to handle key events
9573 * (ala plugins). This can only be called if mNativeClass is non-zero!
9574 */
Cary Clark2f1d60c2009-06-03 08:05:53 -04009575 private native boolean nativeCursorWantsKeyEvents();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009576 private native void nativeDebugDump();
9577 private native void nativeDestroy();
Grace Kloba8abd50b2010-07-08 15:02:14 -07009578
9579 /**
9580 * Draw the picture set with a background color and extra. If
9581 * "splitIfNeeded" is true and the return value is not 0, the return value
9582 * MUST be passed to WebViewCore with SPLIT_PICTURE_SET message so that the
9583 * native allocation can be freed.
9584 */
George Mount82ed95f2011-11-15 11:27:47 -08009585 private native int nativeDraw(Canvas canvas, RectF visibleRect,
9586 int color, int extra, boolean splitIfNeeded);
Cary Clarkd6982c92009-05-29 11:02:22 -04009587 private native void nativeDumpDisplayTree(String urlOrNull);
John Reckb61bfed2011-10-13 19:07:50 -07009588 private native boolean nativeEvaluateLayersAnimations(int nativeInstance);
9589 private native int nativeGetDrawGLFunction(int nativeInstance, Rect rect,
George Mount82ed95f2011-11-15 11:27:47 -08009590 Rect viewRect, RectF visibleRect, float scale, int extras);
9591 private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect,
9592 RectF visibleRect);
Cary Clark924af702010-06-04 16:37:43 -04009593 private native void nativeExtendSelection(int x, int y);
Leon Scroggins4f4a5672010-10-19 13:58:11 -04009594 private native int nativeFindAll(String findLower, String findUpper,
9595 boolean sameAsLastSearch);
Cary Clarkd6982c92009-05-29 11:02:22 -04009596 private native void nativeFindNext(boolean forward);
Leon Scroggins3a503392010-01-06 17:04:38 -05009597 /* package */ native int nativeFocusCandidateFramePointer();
Leon Scrogginsf9b1a092010-03-31 15:32:36 -04009598 /* package */ native boolean nativeFocusCandidateHasNextTextfield();
Leon Scroggins69ec5c22010-04-22 16:27:21 -04009599 /* package */ native boolean nativeFocusCandidateIsPassword();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009600 private native boolean nativeFocusCandidateIsRtlText();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009601 private native boolean nativeFocusCandidateIsTextInput();
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05009602 /* package */ native int nativeFocusCandidateMaxLength();
Leon Scrogginsae0238c2011-01-05 15:12:55 -05009603 /* package */ native boolean nativeFocusCandidateIsAutoComplete();
Michael Kolb64b4f162011-10-11 14:16:50 -07009604 /* package */ native boolean nativeFocusCandidateIsSpellcheck();
Leon Scroggins0ca70882009-06-26 17:45:29 -04009605 /* package */ native String nativeFocusCandidateName();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009606 private native Rect nativeFocusCandidateNodeBounds();
Leon Scrogginsdfc07272010-10-12 13:40:23 -04009607 /**
9608 * @return A Rect with left, top, right, bottom set to the corresponding
9609 * padding values in the focus candidate, if it is a textfield/textarea with
9610 * a style. Otherwise return null. This is not actually a rectangle; Rect
9611 * is being used to pass four integers.
9612 */
9613 private native Rect nativeFocusCandidatePaddingRect();
Leon Scroggins69ec5c22010-04-22 16:27:21 -04009614 /* package */ native int nativeFocusCandidatePointer();
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009615 private native String nativeFocusCandidateText();
Leon Scroggins56a102c2010-11-12 14:40:07 -05009616 /* package */ native float nativeFocusCandidateTextSize();
Leon Scroggins1ca56262010-11-18 14:03:03 -05009617 /* package */ native int nativeFocusCandidateLineHeight();
Leon Scrogginsaa7b9d72009-12-07 13:38:07 -05009618 /**
9619 * Returns an integer corresponding to WebView.cpp::type.
9620 * See WebTextView.setType()
9621 */
9622 private native int nativeFocusCandidateType();
Michael Kolb5da91bd2011-11-29 15:29:03 -08009623 private native int nativeFocusCandidateLayerId();
Derek Sollenberger718d69f2009-10-19 15:56:43 -04009624 private native boolean nativeFocusIsPlugin();
Cary Clarke84a0db2010-03-17 15:58:20 -04009625 private native Rect nativeFocusNodeBounds();
Leon Scroggins4890feb2009-07-02 10:37:10 -04009626 /* package */ native int nativeFocusNodePointer();
Cary Clarkd6982c92009-05-29 11:02:22 -04009627 private native Rect nativeGetCursorRingBounds();
Cary Clark57d2c3a2009-12-23 13:57:15 -05009628 private native String nativeGetSelection();
Cary Clarkd6982c92009-05-29 11:02:22 -04009629 private native boolean nativeHasCursorNode();
9630 private native boolean nativeHasFocusNode();
Cary Clarke872f3a2009-06-11 09:51:11 -04009631 private native void nativeHideCursor();
Cary Clark924af702010-06-04 16:37:43 -04009632 private native boolean nativeHitSelection(int x, int y);
Cary Clarkd6982c92009-05-29 11:02:22 -04009633 private native String nativeImageURI(int x, int y);
Cary Clark6f5dfc62010-11-11 13:09:20 -05009634 private native Rect nativeLayerBounds(int layer);
Leon Scroggins1be40982010-03-01 11:20:31 -05009635 /* package */ native boolean nativeMoveCursorToNextTextInput();
Cary Clarkd6982c92009-05-29 11:02:22 -04009636 // return true if the page has been scrolled
9637 private native boolean nativeMotionUp(int x, int y, int slop);
9638 // returns false if it handled the key
Leon Scroggins1c7f8c52009-06-05 13:49:26 -04009639 private native boolean nativeMoveCursor(int keyCode, int count,
Cary Clarkd6982c92009-05-29 11:02:22 -04009640 boolean noScroll);
9641 private native int nativeMoveGeneration();
Cary Clark924af702010-06-04 16:37:43 -04009642 private native void nativeMoveSelection(int x, int y);
Leon Scroggins9ab32b62010-05-03 14:19:50 +01009643 /**
9644 * @return true if the page should get the shift and arrow keys, rather
9645 * than select text/navigation.
9646 *
9647 * If the focus is a plugin, or if the focus and cursor match and are
9648 * a contentEditable element, then the page should handle these keys.
9649 */
9650 private native boolean nativePageShouldHandleShiftAndArrows();
Cary Clark1cb97ee2009-12-11 12:10:36 -05009651 private native boolean nativePointInNavCache(int x, int y, int slop);
Cary Clarkd6982c92009-05-29 11:02:22 -04009652 // Like many other of our native methods, you must make sure that
9653 // mNativeClass is not null before calling this method.
Cary Clark924af702010-06-04 16:37:43 -04009654 private native void nativeResetSelection();
Cary Clark2cdee232010-12-29 14:59:24 -05009655 private native Point nativeSelectableText();
Cary Clark924af702010-06-04 16:37:43 -04009656 private native void nativeSelectAll();
Cary Clarkd6982c92009-05-29 11:02:22 -04009657 private native void nativeSelectBestAt(Rect rect);
Svetoslav Ganov9504f572011-01-14 11:38:17 -08009658 private native void nativeSelectAt(int x, int y);
Cary Clark924af702010-06-04 16:37:43 -04009659 private native int nativeSelectionX();
9660 private native int nativeSelectionY();
Leon Scroggins6a367f52010-05-06 17:37:40 -04009661 private native int nativeFindIndex();
Cary Clark924af702010-06-04 16:37:43 -04009662 private native void nativeSetExtendSelection();
Cary Clarkde023c12010-03-03 10:05:16 -05009663 private native void nativeSetFindIsEmpty();
9664 private native void nativeSetFindIsUp(boolean isUp);
Cary Clarkd6982c92009-05-29 11:02:22 -04009665 private native void nativeSetHeightCanMeasure(boolean measure);
Chris Craik09a71e02011-12-12 18:03:29 -08009666 private native void nativeSetBaseLayer(int nativeInstance,
9667 int layer, Region invalRegion,
Chris Craik5cf78f72011-07-28 11:34:31 -07009668 boolean showVisualIndicator, boolean isPictureAfterFirstLayout,
9669 boolean registerPageSwapCallback);
John Reck816c0de2011-06-02 16:04:53 -07009670 private native int nativeGetBaseLayer();
Cary Clarke60cb7f2010-08-25 14:56:00 -04009671 private native void nativeShowCursorTimed();
Grace Kloba8abd50b2010-07-08 15:02:14 -07009672 private native void nativeReplaceBaseContent(int content);
9673 private native void nativeCopyBaseContentToPicture(Picture pict);
9674 private native boolean nativeHasContent();
John Reckb61bfed2011-10-13 19:07:50 -07009675 private native void nativeSetSelectionPointer(int nativeInstance,
9676 boolean set, float scale, int x, int y);
Cary Clark924af702010-06-04 16:37:43 -04009677 private native boolean nativeStartSelection(int x, int y);
Cary Clarkd9fd8572011-02-03 05:25:05 -05009678 private native void nativeStopGL();
Cary Clark31b83672010-03-09 09:20:34 -05009679 private native Rect nativeSubtractLayers(Rect content);
Cary Clarkd6982c92009-05-29 11:02:22 -04009680 private native int nativeTextGeneration();
Chris Craik09a71e02011-12-12 18:03:29 -08009681 private native void nativeRegisterPageSwapCallback(int nativeInstance);
9682 private native void nativeDiscardAllTextures();
Chris Craik445ab742011-07-13 13:19:37 -07009683 private native void nativeTileProfilingStart();
9684 private native float nativeTileProfilingStop();
9685 private native void nativeTileProfilingClear();
9686 private native int nativeTileProfilingNumFrames();
9687 private native int nativeTileProfilingNumTilesInFrame(int frame);
Chris Craik21555ab2011-07-21 11:52:19 -07009688 private native int nativeTileProfilingGetInt(int frame, int tile, String key);
9689 private native float nativeTileProfilingGetFloat(int frame, int tile, String key);
Cary Clarkd6982c92009-05-29 11:02:22 -04009690 // Never call this version except by updateCachedTextfield(String) -
9691 // we always want to pass in our generation number.
9692 private native void nativeUpdateCachedTextfield(String updatedText,
9693 int generation);
Cary Clark924af702010-06-04 16:37:43 -04009694 private native boolean nativeWordSelection(int x, int y);
Grace Kloba8b97e4b2009-07-28 13:11:38 -07009695 // return NO_LEFTEDGE means failure.
Derek Sollenberger15c5ddb2010-06-10 12:31:29 -04009696 static final int NO_LEFTEDGE = -1;
9697 native int nativeGetBlockLeftEdge(int x, int y, float scale);
Patrick Scotta3ebcc92010-07-16 11:52:22 -04009698
Derek Sollenberger1d335f32011-07-08 11:28:23 -04009699 private native void nativeUseHardwareAccelSkia(boolean enabled);
Ben Murdochfa148f62011-02-01 20:51:27 +00009700
Patrick Scotta3ebcc92010-07-16 11:52:22 -04009701 // Returns a pointer to the scrollable LayerAndroid at the given point.
Cary Clarkb9aaa772011-01-07 16:14:54 -05009702 private native int nativeScrollableLayer(int x, int y, Rect scrollRect,
9703 Rect scrollBounds);
Leon Scrogginsd5188652011-01-19 17:01:55 -05009704 /**
9705 * Scroll the specified layer.
9706 * @param layer Id of the layer to scroll, as determined by nativeScrollableLayer.
9707 * @param newX Destination x position to which to scroll.
9708 * @param newY Destination y position to which to scroll.
9709 * @return True if the layer is successfully scrolled.
9710 */
9711 private native boolean nativeScrollLayer(int layer, int newX, int newY);
Chris Craik58d94af2011-08-18 11:42:13 -07009712 private native void nativeSetIsScrolling(boolean isScrolling);
John Reck9b90d552011-06-14 15:19:17 -07009713 private native int nativeGetBackgroundColor();
Nicolas Roard872cf222011-08-18 11:53:04 -07009714 native boolean nativeSetProperty(String key, String value);
John Reck637758942011-07-15 11:14:43 -07009715 native String nativeGetProperty(String key);
John Reckeffabe82011-10-27 09:09:36 -07009716 private native void nativeGetTextSelectionRegion(int instance, Region region);
9717 private native void nativeGetSelectionHandles(int instance, int[] handles);
John Reckfaa42db2011-09-07 11:33:34 -07009718 /**
9719 * See {@link ComponentCallbacks2} for the trim levels and descriptions
9720 */
9721 private static native void nativeOnTrimMemory(int level);
John Reck5f1c5492011-11-09 16:23:07 -08009722 private static native void nativeSetPauseDrawing(int instance, boolean pause);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009723}