WebViewCore.java revision 689a342b0f8badbc87e67938f7a2fd3798e6f8eb
1/*
2 * Copyright (C) 2007 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
19import android.app.ActivityManager;
20import android.content.Context;
21import android.content.pm.PackageManager.NameNotFoundException;
22import android.database.Cursor;
23import android.graphics.Point;
24import android.graphics.Rect;
25import android.graphics.Region;
26import android.media.MediaFile;
27import android.net.Uri;
28import android.os.Handler;
29import android.os.Looper;
30import android.os.Message;
31import android.os.Process;
32import android.provider.MediaStore;
33import android.util.Log;
34import android.util.SparseBooleanArray;
35import android.view.KeyEvent;
36import android.view.SurfaceView;
37import android.view.View;
38import android.webkit.DeviceMotionService;
39import android.webkit.DeviceMotionAndOrientationManager;
40import android.webkit.DeviceOrientationService;
41
42import java.util.ArrayList;
43import java.util.Collection;
44import java.util.Map;
45import java.util.Set;
46
47import junit.framework.Assert;
48
49final class WebViewCore {
50
51    private static final String LOGTAG = "webcore";
52
53    static {
54        // Load libwebcore during static initialization. This happens in the
55        // zygote process so it will be shared read-only across all app
56        // processes.
57        System.loadLibrary("webcore");
58    }
59
60    /*
61     * WebViewCore always executes in the same thread as the native webkit.
62     */
63
64    // The WebView that corresponds to this WebViewCore.
65    private WebView mWebView;
66    // Proxy for handling callbacks from native code
67    private final CallbackProxy mCallbackProxy;
68    // Settings object for maintaining all settings
69    private final WebSettings mSettings;
70    // Context for initializing the BrowserFrame with the proper assets.
71    private final Context mContext;
72    // The pointer to a native view object.
73    private int mNativeClass;
74    // The BrowserFrame is an interface to the native Frame component.
75    private BrowserFrame mBrowserFrame;
76    // Custom JS interfaces to add during the initialization.
77    private Map<String, Object> mJavascriptInterfaces;
78    /*
79     * range is from 200 to 10,000. 0 is a special value means device-width. -1
80     * means undefined.
81     */
82    private int mViewportWidth = -1;
83
84    /*
85     * range is from 200 to 10,000. 0 is a special value means device-height. -1
86     * means undefined.
87     */
88    private int mViewportHeight = -1;
89
90    /*
91     * scale in percent, range is from 1 to 1000. 0 means undefined.
92     */
93    private int mViewportInitialScale = 0;
94
95    /*
96     * scale in percent, range is from 1 to 1000. 0 means undefined.
97     */
98    private int mViewportMinimumScale = 0;
99
100    /*
101     * scale in percent, range is from 1 to 1000. 0 means undefined.
102     */
103    private int mViewportMaximumScale = 0;
104
105    private boolean mViewportUserScalable = true;
106
107    /*
108     * range is from 70 to 400.
109     * 0 is a special value means device-dpi. The default scale factor will be
110     * always 100.
111     * -1 means undefined. The default scale factor will be
112     * WebView.DEFAULT_SCALE_PERCENT.
113     */
114    private int mViewportDensityDpi = -1;
115
116    private int mRestoredScale = 0;
117    private int mRestoredTextWrapScale = 0;
118    private int mRestoredX = 0;
119    private int mRestoredY = 0;
120
121    private int mWebkitScrollX = 0;
122    private int mWebkitScrollY = 0;
123
124    private DeviceMotionAndOrientationManager mDeviceMotionAndOrientationManager =
125            new DeviceMotionAndOrientationManager(this);
126    private DeviceMotionService mDeviceMotionService;
127    private DeviceOrientationService mDeviceOrientationService;
128
129    private int mLowMemoryUsageThresholdMb;
130    private int mHighMemoryUsageThresholdMb;
131
132    // The thread name used to identify the WebCore thread and for use in
133    // debugging other classes that require operation within the WebCore thread.
134    /* package */ static final String THREAD_NAME = "WebViewCoreThread";
135
136    public WebViewCore(Context context, WebView w, CallbackProxy proxy,
137            Map<String, Object> javascriptInterfaces) {
138        // No need to assign this in the WebCore thread.
139        mCallbackProxy = proxy;
140        mWebView = w;
141        mJavascriptInterfaces = javascriptInterfaces;
142        // This context object is used to initialize the WebViewCore during
143        // subwindow creation.
144        mContext = context;
145
146        // We need to wait for the initial thread creation before sending
147        // a message to the WebCore thread.
148        // XXX: This is the only time the UI thread will wait for the WebCore
149        // thread!
150        synchronized (WebViewCore.class) {
151            if (sWebCoreHandler == null) {
152                // Create a global thread and start it.
153                Thread t = new Thread(new WebCoreThread());
154                t.setName(THREAD_NAME);
155                t.start();
156                try {
157                    WebViewCore.class.wait();
158                } catch (InterruptedException e) {
159                    Log.e(LOGTAG, "Caught exception while waiting for thread " +
160                           "creation.");
161                    Log.e(LOGTAG, Log.getStackTraceString(e));
162                }
163            }
164        }
165        // Create an EventHub to handle messages before and after the thread is
166        // ready.
167        mEventHub = new EventHub();
168        // Create a WebSettings object for maintaining all settings
169        mSettings = new WebSettings(mContext, mWebView);
170        // The WebIconDatabase needs to be initialized within the UI thread so
171        // just request the instance here.
172        WebIconDatabase.getInstance();
173        // Create the WebStorage singleton and the UI handler
174        WebStorage.getInstance().createUIHandler();
175        // Create the UI handler for GeolocationPermissions
176        GeolocationPermissions.getInstance().createUIHandler();
177
178        // Get the memory class of the current device. V8 will use these values
179        // to GC more effectively.
180        ActivityManager manager = (ActivityManager) mContext.getSystemService(
181                Context.ACTIVITY_SERVICE);
182        ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
183        manager.getMemoryInfo(memInfo);
184
185        // Allow us to use up to our memory class value before V8's GC kicks in.
186        // These values have been determined by experimentation.
187        mLowMemoryUsageThresholdMb = manager.getMemoryClass();
188        // If things get crazy, allow V8 to use up to 3 times our memory class, or a third of the
189        // device's total available memory, whichever is smaller. At that point V8 will start
190        // attempting more aggressive garbage collection.
191        mHighMemoryUsageThresholdMb = Math.min(mLowMemoryUsageThresholdMb * 3,
192                (int) (memInfo.availMem / 3) >> 20);
193
194        // Send a message to initialize the WebViewCore.
195        Message init = sWebCoreHandler.obtainMessage(
196                WebCoreThread.INITIALIZE, this);
197        sWebCoreHandler.sendMessage(init);
198    }
199
200    /* Initialize private data within the WebCore thread.
201     */
202    private void initialize() {
203        /* Initialize our private BrowserFrame class to handle all
204         * frame-related functions. We need to create a new view which
205         * in turn creates a C level FrameView and attaches it to the frame.
206         */
207        mBrowserFrame = new BrowserFrame(mContext, this, mCallbackProxy,
208                mSettings, mJavascriptInterfaces);
209        mJavascriptInterfaces = null;
210        // Sync the native settings and also create the WebCore thread handler.
211        mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
212        // Create the handler and transfer messages for the IconDatabase
213        WebIconDatabase.getInstance().createHandler();
214        // Create the handler for WebStorage
215        WebStorage.getInstance().createHandler();
216        // Create the handler for GeolocationPermissions.
217        GeolocationPermissions.getInstance().createHandler();
218        // The transferMessages call will transfer all pending messages to the
219        // WebCore thread handler.
220        mEventHub.transferMessages();
221
222        // Send a message back to WebView to tell it that we have set up the
223        // WebCore thread.
224        if (mWebView != null) {
225            Message.obtain(mWebView.mPrivateHandler,
226                    WebView.WEBCORE_INITIALIZED_MSG_ID,
227                    mNativeClass, 0).sendToTarget();
228        }
229
230    }
231
232    /* Handle the initialization of WebViewCore during subwindow creation. This
233     * method is called from the WebCore thread but it is called before the
234     * INITIALIZE message can be handled.
235     */
236    /* package */ void initializeSubwindow() {
237        // Go ahead and initialize the core components.
238        initialize();
239        // Remove the INITIALIZE method so we don't try to initialize twice.
240        sWebCoreHandler.removeMessages(WebCoreThread.INITIALIZE, this);
241    }
242
243    /* Get the BrowserFrame component. This is used for subwindow creation and
244     * is called only from BrowserFrame in the WebCore thread. */
245    /* package */ BrowserFrame getBrowserFrame() {
246        return mBrowserFrame;
247    }
248
249    //-------------------------------------------------------------------------
250    // Common methods
251    //-------------------------------------------------------------------------
252
253    /**
254     * Causes all timers to pause. This applies to all WebViews in the current
255     * app process.
256     */
257    public static void pauseTimers() {
258        if (BrowserFrame.sJavaBridge == null) {
259            throw new IllegalStateException(
260                    "No WebView has been created in this process!");
261        }
262        BrowserFrame.sJavaBridge.pause();
263    }
264
265    /**
266     * Resume all timers. This applies to all WebViews in the current process.
267     */
268    public static void resumeTimers() {
269        if (BrowserFrame.sJavaBridge == null) {
270            throw new IllegalStateException(
271                    "No WebView has been created in this process!");
272        }
273        BrowserFrame.sJavaBridge.resume();
274    }
275
276    public WebSettings getSettings() {
277        return mSettings;
278    }
279
280    /*
281     * Given mimeType, check whether it's supported in Android media framework.
282     * mimeType could be such as "audio/ogg" and "video/mp4".
283     */
284    /* package */ static boolean isSupportedMediaMimeType(String mimeType) {
285        int fileType = MediaFile.getFileTypeForMimeType(mimeType);
286        return MediaFile.isAudioFileType(fileType)
287            || MediaFile.isVideoFileType(fileType)
288            || MediaFile.isPlayListFileType(fileType)
289            // The following is not in Media framework, but it's supported.
290            || (mimeType != null && mimeType.startsWith("video/m4v"));
291    }
292
293    /**
294     * Add an error message to the client's console.
295     * @param message The message to add
296     * @param lineNumber the line on which the error occurred
297     * @param sourceID the filename of the source that caused the error.
298     * @param msgLevel the log level of this message. This is a value casted to int
299     *     from WebCore::MessageLevel in WebCore/page/Console.h.
300     */
301    protected void addMessageToConsole(String message, int lineNumber, String sourceID,
302            int msgLevel) {
303        mCallbackProxy.addMessageToConsole(message, lineNumber, sourceID, msgLevel);
304    }
305
306    /**
307     * Invoke a javascript alert.
308     * @param message The message displayed in the alert.
309     */
310    protected void jsAlert(String url, String message) {
311        mCallbackProxy.onJsAlert(url, message);
312    }
313
314    /**
315     * Called by JNI.  Send a message to the UI thread to hide the soft keyboard
316     * if the node pointed to by nodePointer is still in focus.
317     * @param nodePointer The node which just blurred.
318     */
319    private void formDidBlur(int nodePointer) {
320        if (mWebView == null) return;
321        Message.obtain(mWebView.mPrivateHandler, WebView.FORM_DID_BLUR,
322                nodePointer, 0).sendToTarget();
323    }
324
325    /**
326     * Called by JNI.  Open a file chooser to upload a file.
327     * @param acceptType The value of the 'accept' attribute of the
328     *         input tag associated with this file picker.
329     * @return String version of the URI.
330     */
331    private String openFileChooser(String acceptType) {
332        Uri uri = mCallbackProxy.openFileChooser(acceptType);
333        if (uri != null) {
334            String filePath = "";
335            // Note - querying for MediaStore.Images.Media.DATA
336            // seems to work for all content URIs, not just images
337            Cursor cursor = mContext.getContentResolver().query(
338                    uri,
339                    new String[] { MediaStore.Images.Media.DATA },
340                    null, null, null);
341            if (cursor != null) {
342                try {
343                    if (cursor.moveToNext()) {
344                        filePath = cursor.getString(0);
345                    }
346                } finally {
347                    cursor.close();
348                }
349            } else {
350                filePath = uri.getLastPathSegment();
351            }
352            String uriString = uri.toString();
353            BrowserFrame.sJavaBridge.storeFilePathForContentUri(filePath, uriString);
354            return uriString;
355        }
356        return "";
357    }
358
359    /**
360     * Notify the browser that the origin has exceeded it's database quota.
361     * @param url The URL that caused the overflow.
362     * @param databaseIdentifier The identifier of the database.
363     * @param currentQuota The current quota for the origin.
364     * @param estimatedSize The estimated size of the database.
365     */
366    protected void exceededDatabaseQuota(String url,
367                                         String databaseIdentifier,
368                                         long currentQuota,
369                                         long estimatedSize) {
370        // Inform the callback proxy of the quota overflow. Send an object
371        // that encapsulates a call to the nativeSetDatabaseQuota method to
372        // awaken the sleeping webcore thread when a decision from the
373        // client to allow or deny quota is available.
374        mCallbackProxy.onExceededDatabaseQuota(url, databaseIdentifier,
375                currentQuota, estimatedSize, getUsedQuota(),
376                new WebStorage.QuotaUpdater() {
377                        public void updateQuota(long quota) {
378                            nativeSetNewStorageLimit(quota);
379                        }
380                });
381    }
382
383    /**
384     * Notify the browser that the appcache has exceeded its max size.
385     * @param spaceNeeded is the amount of disk space that would be needed
386     * in order for the last appcache operation to succeed.
387     */
388    protected void reachedMaxAppCacheSize(long spaceNeeded) {
389        mCallbackProxy.onReachedMaxAppCacheSize(spaceNeeded, getUsedQuota(),
390                new WebStorage.QuotaUpdater() {
391                    public void updateQuota(long quota) {
392                        nativeSetNewStorageLimit(quota);
393                    }
394                });
395    }
396
397    protected void populateVisitedLinks() {
398        ValueCallback callback = new ValueCallback<String[]>() {
399            public void onReceiveValue(String[] value) {
400                sendMessage(EventHub.POPULATE_VISITED_LINKS, (Object)value);
401            }
402        };
403        mCallbackProxy.getVisitedHistory(callback);
404    }
405
406    /**
407     * Shows a prompt to ask the user to set the Geolocation permission state
408     * for the given origin.
409     * @param origin The origin for which Geolocation permissions are
410     *     requested.
411     */
412    protected void geolocationPermissionsShowPrompt(String origin) {
413        mCallbackProxy.onGeolocationPermissionsShowPrompt(origin,
414                new GeolocationPermissions.Callback() {
415          public void invoke(String origin, boolean allow, boolean remember) {
416            GeolocationPermissionsData data = new GeolocationPermissionsData();
417            data.mOrigin = origin;
418            data.mAllow = allow;
419            data.mRemember = remember;
420            // Marshall to WebCore thread.
421            sendMessage(EventHub.GEOLOCATION_PERMISSIONS_PROVIDE, data);
422          }
423        });
424    }
425
426    /**
427     * Hides the Geolocation permissions prompt.
428     */
429    protected void geolocationPermissionsHidePrompt() {
430        mCallbackProxy.onGeolocationPermissionsHidePrompt();
431    }
432
433    /**
434     * Invoke a javascript confirm dialog.
435     * @param message The message displayed in the dialog.
436     * @return True if the user confirmed or false if the user cancelled.
437     */
438    protected boolean jsConfirm(String url, String message) {
439        return mCallbackProxy.onJsConfirm(url, message);
440    }
441
442    /**
443     * Invoke a javascript prompt dialog.
444     * @param message The message to be displayed in the dialog.
445     * @param defaultValue The default value in the prompt input.
446     * @return The input from the user or null to indicate the user cancelled
447     *         the dialog.
448     */
449    protected String jsPrompt(String url, String message, String defaultValue) {
450        return mCallbackProxy.onJsPrompt(url, message, defaultValue);
451    }
452
453    /**
454     * Invoke a javascript before unload dialog.
455     * @param url The url that is requesting the dialog.
456     * @param message The message displayed in the dialog.
457     * @return True if the user confirmed or false if the user cancelled. False
458     *         will cancel the navigation.
459     */
460    protected boolean jsUnload(String url, String message) {
461        return mCallbackProxy.onJsBeforeUnload(url, message);
462    }
463
464    /**
465     *
466     * Callback to notify that a JavaScript execution timeout has occured.
467     * @return True if the JavaScript execution should be interrupted. False
468     *         will continue the execution.
469     */
470    protected boolean jsInterrupt() {
471        return mCallbackProxy.onJsTimeout();
472    }
473
474    /**
475     * Notify the webview that this is an installable web app.
476     */
477    protected void setInstallableWebApp() {
478        mCallbackProxy.setInstallableWebApp();
479    }
480
481    //-------------------------------------------------------------------------
482    // JNI methods
483    //-------------------------------------------------------------------------
484
485    static native String nativeFindAddress(String addr, boolean caseInsensitive);
486
487    /**
488     * Empty the picture set.
489     */
490    private native void nativeClearContent();
491
492    private native void nativeContentInvalidateAll();
493
494    /**
495     * Redraw a portion of the picture set. The Point wh returns the
496     * width and height of the overall picture.
497     */
498    private native int nativeRecordContent(Region invalRegion, Point wh);
499
500    /**
501     * Update the layers' content
502     */
503    private native int nativeUpdateLayers(Region invalRegion);
504
505    private native boolean nativeFocusBoundsChanged();
506
507    /**
508     * Splits slow parts of the picture set. Called from the webkit thread after
509     * WebView.nativeDraw() returns content to be split.
510     */
511    private native void nativeSplitContent(int content);
512
513    private native boolean nativeKey(int keyCode, int unichar,
514            int repeatCount, boolean isShift, boolean isAlt, boolean isSym,
515            boolean isDown);
516
517    private native void nativeClick(int framePtr, int nodePtr);
518
519    private native void nativeSendListBoxChoices(boolean[] choices, int size);
520
521    private native void nativeSendListBoxChoice(int choice);
522
523    /*  Tell webkit what its width and height are, for the purposes
524        of layout/line-breaking. These coordinates are in document space,
525        which is the same as View coords unless we have zoomed the document
526        (see nativeSetZoom).
527        textWrapWidth is used by layout to wrap column around. If viewport uses
528        fixed size, textWrapWidth can be different from width with zooming.
529        should this be called nativeSetViewPortSize?
530    */
531    private native void nativeSetSize(int width, int height, int textWrapWidth,
532            float scale, int screenWidth, int screenHeight, int anchorX,
533            int anchorY, boolean ignoreHeight);
534
535    private native int nativeGetContentMinPrefWidth();
536
537    // Start: functions that deal with text editing
538    private native void nativeReplaceTextfieldText(
539            int oldStart, int oldEnd, String replace, int newStart, int newEnd,
540            int textGeneration);
541
542    private native void passToJs(int gen,
543            String currentText, int keyCode, int keyValue, boolean down,
544            boolean cap, boolean fn, boolean sym);
545
546    private native void nativeSetFocusControllerActive(boolean active);
547
548    private native void nativeSaveDocumentState(int frame);
549
550    private native void nativeMoveFocus(int framePtr, int nodePointer);
551    private native void nativeMoveMouse(int framePtr, int x, int y);
552
553    private native void nativeMoveMouseIfLatest(int moveGeneration,
554            int framePtr, int x, int y);
555
556    private native String nativeRetrieveHref(int x, int y);
557    private native String nativeRetrieveAnchorText(int x, int y);
558
559    private native void nativeTouchUp(int touchGeneration,
560            int framePtr, int nodePtr, int x, int y);
561
562    private native boolean nativeHandleTouchEvent(int action, int[] x, int[] y,
563            int count, int metaState);
564
565    private native void nativeUpdateFrameCache();
566
567    private native void nativeSetBackgroundColor(int color);
568
569    private native void nativeDumpDomTree(boolean useFile);
570
571    private native void nativeDumpRenderTree(boolean useFile);
572
573    private native void nativeDumpNavTree();
574
575    private native void nativeDumpV8Counters();
576
577    private native void nativeSetJsFlags(String flags);
578
579    /**
580     *  Delete text from start to end in the focused textfield. If there is no
581     *  focus, or if start == end, silently fail.  If start and end are out of
582     *  order, swap them.
583     *  @param  start   Beginning of selection to delete.
584     *  @param  end     End of selection to delete.
585     *  @param  textGeneration Text generation number when delete was pressed.
586     */
587    private native void nativeDeleteSelection(int start, int end,
588            int textGeneration);
589
590    /**
591     *  Set the selection to (start, end) in the focused textfield. If start and
592     *  end are out of order, swap them.
593     *  @param  start   Beginning of selection.
594     *  @param  end     End of selection.
595     */
596    private native void nativeSetSelection(int start, int end);
597
598    // Register a scheme to be treated as local scheme so that it can access
599    // local asset files for resources
600    private native void nativeRegisterURLSchemeAsLocal(String scheme);
601
602    /*
603     * Inform webcore that the user has decided whether to allow or deny new
604     * quota for the current origin or more space for the app cache, and that
605     * the main thread should wake up now.
606     * @param limit Is the new quota for an origin or new app cache max size.
607     */
608    private native void nativeSetNewStorageLimit(long limit);
609
610    /**
611     * Provide WebCore with a Geolocation permission state for the specified
612     * origin.
613     * @param origin The origin for which Geolocation permissions are provided.
614     * @param allow Whether Geolocation permissions are allowed.
615     * @param remember Whether this decision should be remembered beyond the
616     *     life of the current page.
617     */
618    private native void nativeGeolocationPermissionsProvide(String origin, boolean allow, boolean remember);
619
620    /**
621     * Provide WebCore with the previously visted links from the history database
622     */
623    private native void nativeProvideVisitedHistory(String[] history);
624
625    /**
626     * Modifies the current selection.
627     *
628     * @param direction The direction in which to alter the selection.
629     * @param granularity The granularity of the selection modification.
630     *
631     * @return The selection string.
632     */
633    private native String nativeModifySelection(int direction, int granularity);
634
635    // EventHub for processing messages
636    private final EventHub mEventHub;
637    // WebCore thread handler
638    private static Handler sWebCoreHandler;
639    // Class for providing Handler creation inside the WebCore thread.
640    private static class WebCoreThread implements Runnable {
641        // Message id for initializing a new WebViewCore.
642        private static final int INITIALIZE = 0;
643        private static final int REDUCE_PRIORITY = 1;
644        private static final int RESUME_PRIORITY = 2;
645
646        public void run() {
647            Looper.prepare();
648            Assert.assertNull(sWebCoreHandler);
649            synchronized (WebViewCore.class) {
650                sWebCoreHandler = new Handler() {
651                    @Override
652                    public void handleMessage(Message msg) {
653                        switch (msg.what) {
654                            case INITIALIZE:
655                                WebViewCore core = (WebViewCore) msg.obj;
656                                core.initialize();
657                                break;
658
659                            case REDUCE_PRIORITY:
660                                // 3 is an adjustable number.
661                                Process.setThreadPriority(
662                                        Process.THREAD_PRIORITY_DEFAULT + 3 *
663                                        Process.THREAD_PRIORITY_LESS_FAVORABLE);
664                                break;
665
666                            case RESUME_PRIORITY:
667                                Process.setThreadPriority(
668                                        Process.THREAD_PRIORITY_DEFAULT);
669                                break;
670                        }
671                    }
672                };
673                WebViewCore.class.notify();
674            }
675            Looper.loop();
676        }
677    }
678
679    static class BaseUrlData {
680        String mBaseUrl;
681        String mData;
682        String mMimeType;
683        String mEncoding;
684        String mHistoryUrl;
685    }
686
687    static class CursorData {
688        CursorData() {}
689        CursorData(int frame, int node, int x, int y) {
690            mFrame = frame;
691            mNode = node;
692            mX = x;
693            mY = y;
694        }
695        int mMoveGeneration;
696        int mFrame;
697        int mNode;
698        int mX;
699        int mY;
700    }
701
702    static class JSInterfaceData {
703        Object mObject;
704        String mInterfaceName;
705    }
706
707    static class JSKeyData {
708        String mCurrentText;
709        KeyEvent mEvent;
710    }
711
712    static class MotionUpData {
713        int mFrame;
714        int mNode;
715        Rect mBounds;
716        int mX;
717        int mY;
718    }
719
720    static class GetUrlData {
721        String mUrl;
722        Map<String, String> mExtraHeaders;
723    }
724
725    static class PostUrlData {
726        String mUrl;
727        byte[] mPostData;
728    }
729
730    static class ReplaceTextData {
731        String mReplace;
732        int mNewStart;
733        int mNewEnd;
734        int mTextGeneration;
735    }
736
737    static class TextSelectionData {
738        public TextSelectionData(int start, int end) {
739            mStart = start;
740            mEnd = end;
741        }
742        int mStart;
743        int mEnd;
744    }
745
746    static class TouchUpData {
747        int mMoveGeneration;
748        int mFrame;
749        int mNode;
750        int mX;
751        int mY;
752    }
753
754    static class TouchHighlightData {
755        int mX;
756        int mY;
757        int mSlop;
758    }
759
760    static class AutoFillData {
761        public AutoFillData() {
762            mQueryId = WebTextView.FORM_NOT_AUTOFILLABLE;
763            mPreview = "";
764        }
765
766        public AutoFillData(int queryId, String preview) {
767            mQueryId = queryId;
768            mPreview = preview;
769        }
770
771        public int getQueryId() {
772            return mQueryId;
773        }
774
775        public String getPreviewString() {
776            return mPreview;
777        }
778
779        private int mQueryId;
780        private String mPreview;
781    }
782
783    // mAction of TouchEventData can be MotionEvent.getAction() which uses the
784    // last two bytes or one of the following values
785    static final int ACTION_LONGPRESS = 0x100;
786    static final int ACTION_DOUBLETAP = 0x200;
787
788    static class TouchEventData {
789        int mAction;
790        Point[] mPoints;
791        int mMetaState;
792        boolean mReprocess;
793    }
794
795    static class GeolocationPermissionsData {
796        String mOrigin;
797        boolean mAllow;
798        boolean mRemember;
799    }
800
801        static final String[] HandlerDebugString = {
802            "REVEAL_SELECTION", // 96
803            "REQUEST_LABEL", // 97
804            "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
805            "SCROLL_TEXT_INPUT", // = 99
806            "LOAD_URL", // = 100;
807            "STOP_LOADING", // = 101;
808            "RELOAD", // = 102;
809            "KEY_DOWN", // = 103;
810            "KEY_UP", // = 104;
811            "VIEW_SIZE_CHANGED", // = 105;
812            "GO_BACK_FORWARD", // = 106;
813            "SET_SCROLL_OFFSET", // = 107;
814            "RESTORE_STATE", // = 108;
815            "PAUSE_TIMERS", // = 109;
816            "RESUME_TIMERS", // = 110;
817            "CLEAR_CACHE", // = 111;
818            "CLEAR_HISTORY", // = 112;
819            "SET_SELECTION", // = 113;
820            "REPLACE_TEXT", // = 114;
821            "PASS_TO_JS", // = 115;
822            "SET_GLOBAL_BOUNDS", // = 116;
823            "UPDATE_CACHE_AND_TEXT_ENTRY", // = 117;
824            "CLICK", // = 118;
825            "SET_NETWORK_STATE", // = 119;
826            "DOC_HAS_IMAGES", // = 120;
827            "121", // = 121;
828            "DELETE_SELECTION", // = 122;
829            "LISTBOX_CHOICES", // = 123;
830            "SINGLE_LISTBOX_CHOICE", // = 124;
831            "MESSAGE_RELAY", // = 125;
832            "SET_BACKGROUND_COLOR", // = 126;
833            "SET_MOVE_FOCUS", // = 127
834            "SAVE_DOCUMENT_STATE", // = 128;
835            "129", // = 129;
836            "WEBKIT_DRAW", // = 130;
837            "SYNC_SCROLL", // = 131;
838            "POST_URL", // = 132;
839            "SPLIT_PICTURE_SET", // = 133;
840            "CLEAR_CONTENT", // = 134;
841            "SET_MOVE_MOUSE", // = 135;
842            "SET_MOVE_MOUSE_IF_LATEST", // = 136;
843            "REQUEST_CURSOR_HREF", // = 137;
844            "ADD_JS_INTERFACE", // = 138;
845            "LOAD_DATA", // = 139;
846            "TOUCH_UP", // = 140;
847            "TOUCH_EVENT", // = 141;
848            "SET_ACTIVE", // = 142;
849            "ON_PAUSE",     // = 143
850            "ON_RESUME",    // = 144
851            "FREE_MEMORY",  // = 145
852            "VALID_NODE_BOUNDS", // = 146
853            "SAVE_WEBARCHIVE", // = 147
854            "WEBKIT_DRAW_LAYERS", // = 148;
855            "REMOVE_JS_INTERFACE", // = 149;
856        };
857
858    class EventHub {
859        // Message Ids
860        static final int REVEAL_SELECTION = 96;
861        static final int REQUEST_LABEL = 97;
862        static final int UPDATE_FRAME_CACHE_IF_LOADING = 98;
863        static final int SCROLL_TEXT_INPUT = 99;
864        static final int LOAD_URL = 100;
865        static final int STOP_LOADING = 101;
866        static final int RELOAD = 102;
867        static final int KEY_DOWN = 103;
868        static final int KEY_UP = 104;
869        static final int VIEW_SIZE_CHANGED = 105;
870        static final int GO_BACK_FORWARD = 106;
871        static final int SET_SCROLL_OFFSET = 107;
872        static final int RESTORE_STATE = 108;
873        static final int PAUSE_TIMERS = 109;
874        static final int RESUME_TIMERS = 110;
875        static final int CLEAR_CACHE = 111;
876        static final int CLEAR_HISTORY = 112;
877        static final int SET_SELECTION = 113;
878        static final int REPLACE_TEXT = 114;
879        static final int PASS_TO_JS = 115;
880        static final int SET_GLOBAL_BOUNDS = 116;
881        static final int UPDATE_CACHE_AND_TEXT_ENTRY = 117;
882        static final int CLICK = 118;
883        static final int SET_NETWORK_STATE = 119;
884        static final int DOC_HAS_IMAGES = 120;
885        static final int DELETE_SELECTION = 122;
886        static final int LISTBOX_CHOICES = 123;
887        static final int SINGLE_LISTBOX_CHOICE = 124;
888        static final int MESSAGE_RELAY = 125;
889        static final int SET_BACKGROUND_COLOR = 126;
890        static final int SET_MOVE_FOCUS = 127;
891        static final int SAVE_DOCUMENT_STATE = 128;
892
893        static final int WEBKIT_DRAW = 130;
894        static final int SYNC_SCROLL = 131;
895        static final int POST_URL = 132;
896        static final int SPLIT_PICTURE_SET = 133;
897        static final int CLEAR_CONTENT = 134;
898
899        // UI nav messages
900        static final int SET_MOVE_MOUSE = 135;
901        static final int SET_MOVE_MOUSE_IF_LATEST = 136;
902        static final int REQUEST_CURSOR_HREF = 137;
903        static final int ADD_JS_INTERFACE = 138;
904        static final int LOAD_DATA = 139;
905
906        // motion
907        static final int TOUCH_UP = 140;
908        // message used to pass UI touch events to WebCore
909        static final int TOUCH_EVENT = 141;
910
911        // Used to tell the focus controller not to draw the blinking cursor,
912        // based on whether the WebView has focus and whether the WebView's
913        // cursor matches the webpage's focus.
914        static final int SET_ACTIVE = 142;
915
916        // lifecycle activities for just this DOM (unlike pauseTimers, which
917        // is global)
918        static final int ON_PAUSE = 143;
919        static final int ON_RESUME = 144;
920        static final int FREE_MEMORY = 145;
921        static final int VALID_NODE_BOUNDS = 146;
922
923        // Load and save web archives
924        static final int SAVE_WEBARCHIVE = 147;
925
926        // Update layers
927        static final int WEBKIT_DRAW_LAYERS = 148;
928
929        static final int REMOVE_JS_INTERFACE = 149;
930
931        // Network-based messaging
932        static final int CLEAR_SSL_PREF_TABLE = 150;
933
934        // Test harness messages
935        static final int REQUEST_EXT_REPRESENTATION = 160;
936        static final int REQUEST_DOC_AS_TEXT = 161;
937
938        // debugging
939        static final int DUMP_DOMTREE = 170;
940        static final int DUMP_RENDERTREE = 171;
941        static final int DUMP_NAVTREE = 172;
942        static final int DUMP_V8COUNTERS = 173;
943
944        static final int SET_JS_FLAGS = 174;
945        // Geolocation
946        static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180;
947
948        static final int POPULATE_VISITED_LINKS = 181;
949
950        static final int HIDE_FULLSCREEN = 182;
951
952        static final int SET_NETWORK_TYPE = 183;
953
954        // navigator.isApplicationInstalled()
955        static final int ADD_PACKAGE_NAMES = 184;
956        static final int ADD_PACKAGE_NAME = 185;
957        static final int REMOVE_PACKAGE_NAME = 186;
958
959        static final int GET_TOUCH_HIGHLIGHT_RECTS = 187;
960        static final int REMOVE_TOUCH_HIGHLIGHT_RECTS = 188;
961
962        // accessibility support
963        static final int MODIFY_SELECTION = 190;
964
965        static final int USE_MOCK_DEVICE_ORIENTATION = 191;
966
967        static final int AUTOFILL_FORM = 192;
968
969        // private message ids
970        private static final int DESTROY =     200;
971
972        // Private handler for WebCore messages.
973        private Handler mHandler;
974        // Message queue for containing messages before the WebCore thread is
975        // ready.
976        private ArrayList<Message> mMessages = new ArrayList<Message>();
977        // Flag for blocking messages. This is used during DESTROY to avoid
978        // posting more messages to the EventHub or to WebView's event handler.
979        private boolean mBlockMessages;
980
981        private int mTid;
982        private int mSavedPriority;
983
984        /**
985         * Prevent other classes from creating an EventHub.
986         */
987        private EventHub() {}
988
989        private static final int FIRST_PACKAGE_MSG_ID = REVEAL_SELECTION;
990        private static final int LAST_PACKAGE_MSG_ID = VALID_NODE_BOUNDS;
991
992        /**
993         * Transfer all messages to the newly created webcore thread handler.
994         */
995        private void transferMessages() {
996            mTid = Process.myTid();
997            mSavedPriority = Process.getThreadPriority(mTid);
998
999            mHandler = new Handler() {
1000                @Override
1001                public void handleMessage(Message msg) {
1002                    if (DebugFlags.WEB_VIEW_CORE) {
1003                        Log.v(LOGTAG, (msg.what < FIRST_PACKAGE_MSG_ID
1004                                || msg.what > LAST_PACKAGE_MSG_ID
1005                                ? Integer.toString(msg.what)
1006                                : HandlerDebugString[msg.what
1007                                        - FIRST_PACKAGE_MSG_ID])
1008                                + " arg1=" + msg.arg1 + " arg2=" + msg.arg2
1009                                + " obj=" + msg.obj);
1010                    }
1011                    switch (msg.what) {
1012                        case WEBKIT_DRAW:
1013                            webkitDraw();
1014                            break;
1015
1016                        case WEBKIT_DRAW_LAYERS:
1017                            webkitDrawLayers();
1018                            break;
1019
1020                        case DESTROY:
1021                            // Time to take down the world. Cancel all pending
1022                            // loads and destroy the native view and frame.
1023                            synchronized (WebViewCore.this) {
1024                                mBrowserFrame.destroy();
1025                                mBrowserFrame = null;
1026                                mSettings.onDestroyed();
1027                                mNativeClass = 0;
1028                                mWebView = null;
1029                            }
1030                            break;
1031
1032                        case REVEAL_SELECTION:
1033                            nativeRevealSelection();
1034                            break;
1035
1036                        case REQUEST_LABEL:
1037                            if (mWebView != null) {
1038                                int nodePointer = msg.arg2;
1039                                String label = nativeRequestLabel(msg.arg1,
1040                                        nodePointer);
1041                                if (label != null && label.length() > 0) {
1042                                    Message.obtain(mWebView.mPrivateHandler,
1043                                            WebView.RETURN_LABEL, nodePointer,
1044                                            0, label).sendToTarget();
1045                                }
1046                            }
1047                            break;
1048
1049                        case UPDATE_FRAME_CACHE_IF_LOADING:
1050                            nativeUpdateFrameCacheIfLoading();
1051                            break;
1052
1053                        case SCROLL_TEXT_INPUT:
1054                            nativeScrollFocusedTextInput(
1055                                    ((Float) msg.obj).floatValue(), msg.arg1);
1056                            break;
1057
1058                        case LOAD_URL: {
1059                            GetUrlData param = (GetUrlData) msg.obj;
1060                            loadUrl(param.mUrl, param.mExtraHeaders);
1061                            break;
1062                        }
1063
1064                        case POST_URL: {
1065                            PostUrlData param = (PostUrlData) msg.obj;
1066                            mBrowserFrame.postUrl(param.mUrl, param.mPostData);
1067                            break;
1068                        }
1069                        case LOAD_DATA:
1070                            BaseUrlData loadParams = (BaseUrlData) msg.obj;
1071                            String baseUrl = loadParams.mBaseUrl;
1072                            if (baseUrl != null) {
1073                                int i = baseUrl.indexOf(':');
1074                                if (i > 0) {
1075                                    /*
1076                                     * In 1.0, {@link
1077                                     * WebView#loadDataWithBaseURL} can access
1078                                     * local asset files as long as the data is
1079                                     * valid. In the new WebKit, the restriction
1080                                     * is tightened. To be compatible with 1.0,
1081                                     * we automatically add the scheme of the
1082                                     * baseUrl for local access as long as it is
1083                                     * not http(s)/ftp(s)/about/javascript
1084                                     */
1085                                    String scheme = baseUrl.substring(0, i);
1086                                    if (!scheme.startsWith("http") &&
1087                                            !scheme.startsWith("ftp") &&
1088                                            !scheme.startsWith("about") &&
1089                                            !scheme.startsWith("javascript")) {
1090                                        nativeRegisterURLSchemeAsLocal(scheme);
1091                                    }
1092                                }
1093                            }
1094                            mBrowserFrame.loadData(baseUrl,
1095                                    loadParams.mData,
1096                                    loadParams.mMimeType,
1097                                    loadParams.mEncoding,
1098                                    loadParams.mHistoryUrl);
1099                            break;
1100
1101                        case STOP_LOADING:
1102                            // If the WebCore has committed the load, but not
1103                            // finished the first layout yet, we need to set
1104                            // first layout done to trigger the interpreted side sync
1105                            // up with native side
1106                            if (mBrowserFrame.committed()
1107                                    && !mBrowserFrame.firstLayoutDone()) {
1108                                mBrowserFrame.didFirstLayout();
1109                            }
1110                            // Do this after syncing up the layout state.
1111                            stopLoading();
1112                            break;
1113
1114                        case RELOAD:
1115                            mBrowserFrame.reload(false);
1116                            break;
1117
1118                        case KEY_DOWN:
1119                            key((KeyEvent) msg.obj, true);
1120                            break;
1121
1122                        case KEY_UP:
1123                            key((KeyEvent) msg.obj, false);
1124                            break;
1125
1126                        case CLICK:
1127                            nativeClick(msg.arg1, msg.arg2);
1128                            break;
1129
1130                        case VIEW_SIZE_CHANGED: {
1131                            WebView.ViewSizeData data =
1132                                    (WebView.ViewSizeData) msg.obj;
1133                            viewSizeChanged(data.mWidth, data.mHeight,
1134                                    data.mTextWrapWidth, data.mScale,
1135                                    data.mAnchorX, data.mAnchorY,
1136                                    data.mIgnoreHeight);
1137                            break;
1138                        }
1139                        case SET_SCROLL_OFFSET:
1140                            // note: these are in document coordinates
1141                            // (inv-zoom)
1142                            Point pt = (Point) msg.obj;
1143                            nativeSetScrollOffset(msg.arg1, msg.arg2, pt.x, pt.y);
1144                            break;
1145
1146                        case SET_GLOBAL_BOUNDS:
1147                            Rect r = (Rect) msg.obj;
1148                            nativeSetGlobalBounds(r.left, r.top, r.width(),
1149                                r.height());
1150                            break;
1151
1152                        case GO_BACK_FORWARD:
1153                            // If it is a standard load and the load is not
1154                            // committed yet, we interpret BACK as RELOAD
1155                            if (!mBrowserFrame.committed() && msg.arg1 == -1 &&
1156                                    (mBrowserFrame.loadType() ==
1157                                    BrowserFrame.FRAME_LOADTYPE_STANDARD)) {
1158                                mBrowserFrame.reload(true);
1159                            } else {
1160                                mBrowserFrame.goBackOrForward(msg.arg1);
1161                            }
1162                            break;
1163
1164                        case RESTORE_STATE:
1165                            stopLoading();
1166                            restoreState(msg.arg1);
1167                            break;
1168
1169                        case PAUSE_TIMERS:
1170                            mSavedPriority = Process.getThreadPriority(mTid);
1171                            Process.setThreadPriority(mTid,
1172                                    Process.THREAD_PRIORITY_BACKGROUND);
1173                            pauseTimers();
1174                            WebViewWorker.getHandler().sendEmptyMessage(
1175                                    WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION);
1176                            break;
1177
1178                        case RESUME_TIMERS:
1179                            Process.setThreadPriority(mTid, mSavedPriority);
1180                            resumeTimers();
1181                            WebViewWorker.getHandler().sendEmptyMessage(
1182                                    WebViewWorker.MSG_RESUME_CACHE_TRANSACTION);
1183                            break;
1184
1185                        case ON_PAUSE:
1186                            nativePause();
1187                            break;
1188
1189                        case ON_RESUME:
1190                            nativeResume();
1191                            break;
1192
1193                        case FREE_MEMORY:
1194                            clearCache(false);
1195                            nativeFreeMemory();
1196                            break;
1197
1198                        case SET_NETWORK_STATE:
1199                            if (BrowserFrame.sJavaBridge == null) {
1200                                throw new IllegalStateException("No WebView " +
1201                                        "has been created in this process!");
1202                            }
1203                            BrowserFrame.sJavaBridge
1204                                    .setNetworkOnLine(msg.arg1 == 1);
1205                            break;
1206
1207                        case SET_NETWORK_TYPE:
1208                            if (BrowserFrame.sJavaBridge == null) {
1209                                throw new IllegalStateException("No WebView " +
1210                                        "has been created in this process!");
1211                            }
1212                            Map<String, String> map = (Map<String, String>) msg.obj;
1213                            BrowserFrame.sJavaBridge
1214                                    .setNetworkType(map.get("type"), map.get("subtype"));
1215                            break;
1216
1217                        case CLEAR_CACHE:
1218                            clearCache(msg.arg1 == 1);
1219                            break;
1220
1221                        case CLEAR_HISTORY:
1222                            mCallbackProxy.getBackForwardList().
1223                                    close(mBrowserFrame.mNativeFrame);
1224                            break;
1225
1226                        case REPLACE_TEXT:
1227                            ReplaceTextData rep = (ReplaceTextData) msg.obj;
1228                            nativeReplaceTextfieldText(msg.arg1, msg.arg2,
1229                                    rep.mReplace, rep.mNewStart, rep.mNewEnd,
1230                                    rep.mTextGeneration);
1231                            break;
1232
1233                        case PASS_TO_JS: {
1234                            JSKeyData jsData = (JSKeyData) msg.obj;
1235                            KeyEvent evt = jsData.mEvent;
1236                            int keyCode = evt.getKeyCode();
1237                            int keyValue = evt.getUnicodeChar();
1238                            int generation = msg.arg1;
1239                            passToJs(generation,
1240                                    jsData.mCurrentText,
1241                                    keyCode,
1242                                    keyValue,
1243                                    evt.isDown(),
1244                                    evt.isShiftPressed(), evt.isAltPressed(),
1245                                    evt.isSymPressed());
1246                            break;
1247                        }
1248
1249                        case SAVE_DOCUMENT_STATE: {
1250                            CursorData cDat = (CursorData) msg.obj;
1251                            nativeSaveDocumentState(cDat.mFrame);
1252                            break;
1253                        }
1254
1255                        case CLEAR_SSL_PREF_TABLE:
1256                            Network.getInstance(mContext)
1257                                    .clearUserSslPrefTable();
1258                            break;
1259
1260                        case TOUCH_UP:
1261                            TouchUpData touchUpData = (TouchUpData) msg.obj;
1262                            nativeTouchUp(touchUpData.mMoveGeneration,
1263                                    touchUpData.mFrame, touchUpData.mNode,
1264                                    touchUpData.mX, touchUpData.mY);
1265                            break;
1266
1267                        case TOUCH_EVENT: {
1268                            TouchEventData ted = (TouchEventData) msg.obj;
1269                            final int count = ted.mPoints.length;
1270                            int[] xArray = new int[count];
1271                            int[] yArray = new int[count];
1272                            for (int c = 0; c < count; c++) {
1273                                xArray[c] = ted.mPoints[c].x;
1274                                yArray[c] = ted.mPoints[c].y;
1275                            }
1276                            Message.obtain(
1277                                    mWebView.mPrivateHandler,
1278                                    WebView.PREVENT_TOUCH_ID,
1279                                    ted.mAction,
1280                                    nativeHandleTouchEvent(ted.mAction, xArray,
1281                                            yArray, count, ted.mMetaState) ? 1 : 0,
1282                                    ted.mReprocess ? ted : null).sendToTarget();
1283                            break;
1284                        }
1285
1286                        case SET_ACTIVE:
1287                            nativeSetFocusControllerActive(msg.arg1 == 1);
1288                            break;
1289
1290                        case ADD_JS_INTERFACE:
1291                            JSInterfaceData jsData = (JSInterfaceData) msg.obj;
1292                            mBrowserFrame.addJavascriptInterface(jsData.mObject,
1293                                    jsData.mInterfaceName);
1294                            break;
1295
1296                        case REMOVE_JS_INTERFACE:
1297                            jsData = (JSInterfaceData) msg.obj;
1298                            mBrowserFrame.removeJavascriptInterface(
1299                                    jsData.mInterfaceName);
1300                            break;
1301
1302                        case REQUEST_EXT_REPRESENTATION:
1303                            mBrowserFrame.externalRepresentation(
1304                                    (Message) msg.obj);
1305                            break;
1306
1307                        case REQUEST_DOC_AS_TEXT:
1308                            mBrowserFrame.documentAsText((Message) msg.obj);
1309                            break;
1310
1311                        case SET_MOVE_FOCUS:
1312                            CursorData focusData = (CursorData) msg.obj;
1313                            nativeMoveFocus(focusData.mFrame, focusData.mNode);
1314                            break;
1315
1316                        case SET_MOVE_MOUSE:
1317                            CursorData cursorData = (CursorData) msg.obj;
1318                            nativeMoveMouse(cursorData.mFrame,
1319                                     cursorData.mX, cursorData.mY);
1320                            break;
1321
1322                        case SET_MOVE_MOUSE_IF_LATEST:
1323                            CursorData cData = (CursorData) msg.obj;
1324                            nativeMoveMouseIfLatest(cData.mMoveGeneration,
1325                                    cData.mFrame,
1326                                    cData.mX, cData.mY);
1327                            break;
1328
1329                        case REQUEST_CURSOR_HREF: {
1330                            Message hrefMsg = (Message) msg.obj;
1331                            hrefMsg.getData().putString("url",
1332                                    nativeRetrieveHref(msg.arg1, msg.arg2));
1333                            hrefMsg.getData().putString("title",
1334                                    nativeRetrieveAnchorText(msg.arg1, msg.arg2));
1335                            hrefMsg.sendToTarget();
1336                            break;
1337                        }
1338
1339                        case UPDATE_CACHE_AND_TEXT_ENTRY:
1340                            nativeUpdateFrameCache();
1341                            // FIXME: this should provide a minimal rectangle
1342                            if (mWebView != null) {
1343                                mWebView.postInvalidate();
1344                            }
1345                            sendUpdateTextEntry();
1346                            break;
1347
1348                        case DOC_HAS_IMAGES:
1349                            Message imageResult = (Message) msg.obj;
1350                            imageResult.arg1 =
1351                                    mBrowserFrame.documentHasImages() ? 1 : 0;
1352                            imageResult.sendToTarget();
1353                            break;
1354
1355                        case DELETE_SELECTION:
1356                            TextSelectionData deleteSelectionData
1357                                    = (TextSelectionData) msg.obj;
1358                            nativeDeleteSelection(deleteSelectionData.mStart,
1359                                    deleteSelectionData.mEnd, msg.arg1);
1360                            break;
1361
1362                        case SET_SELECTION:
1363                            nativeSetSelection(msg.arg1, msg.arg2);
1364                            break;
1365
1366                        case MODIFY_SELECTION:
1367                            String selectionString = nativeModifySelection(msg.arg1, msg.arg2);
1368                            mWebView.mPrivateHandler.obtainMessage(WebView.SELECTION_STRING_CHANGED,
1369                                    selectionString).sendToTarget();
1370                            break;
1371
1372                        case LISTBOX_CHOICES:
1373                            SparseBooleanArray choices = (SparseBooleanArray)
1374                                    msg.obj;
1375                            int choicesSize = msg.arg1;
1376                            boolean[] choicesArray = new boolean[choicesSize];
1377                            for (int c = 0; c < choicesSize; c++) {
1378                                choicesArray[c] = choices.get(c);
1379                            }
1380                            nativeSendListBoxChoices(choicesArray,
1381                                    choicesSize);
1382                            break;
1383
1384                        case SINGLE_LISTBOX_CHOICE:
1385                            nativeSendListBoxChoice(msg.arg1);
1386                            break;
1387
1388                        case SET_BACKGROUND_COLOR:
1389                            nativeSetBackgroundColor(msg.arg1);
1390                            break;
1391
1392                        case DUMP_DOMTREE:
1393                            nativeDumpDomTree(msg.arg1 == 1);
1394                            break;
1395
1396                        case DUMP_RENDERTREE:
1397                            nativeDumpRenderTree(msg.arg1 == 1);
1398                            break;
1399
1400                        case DUMP_NAVTREE:
1401                            nativeDumpNavTree();
1402                            break;
1403
1404                        case DUMP_V8COUNTERS:
1405                            nativeDumpV8Counters();
1406                            break;
1407
1408                        case SET_JS_FLAGS:
1409                            nativeSetJsFlags((String)msg.obj);
1410                            break;
1411
1412                        case SAVE_WEBARCHIVE:
1413                            WebView.SaveWebArchiveMessage saveMessage =
1414                                (WebView.SaveWebArchiveMessage)msg.obj;
1415                            saveMessage.mResultFile =
1416                                saveWebArchive(saveMessage.mBasename, saveMessage.mAutoname);
1417                            mWebView.mPrivateHandler.obtainMessage(
1418                                WebView.SAVE_WEBARCHIVE_FINISHED, saveMessage).sendToTarget();
1419                            break;
1420
1421                        case GEOLOCATION_PERMISSIONS_PROVIDE:
1422                            GeolocationPermissionsData data =
1423                                    (GeolocationPermissionsData) msg.obj;
1424                            nativeGeolocationPermissionsProvide(data.mOrigin,
1425                                    data.mAllow, data.mRemember);
1426                            break;
1427
1428                        case SYNC_SCROLL:
1429                            mWebkitScrollX = msg.arg1;
1430                            mWebkitScrollY = msg.arg2;
1431                            break;
1432
1433                        case SPLIT_PICTURE_SET:
1434                            nativeSplitContent(msg.arg1);
1435                            mWebView.mPrivateHandler.obtainMessage(
1436                                    WebView.REPLACE_BASE_CONTENT, msg.arg1, 0);
1437                            mSplitPictureIsScheduled = false;
1438                            break;
1439
1440                        case CLEAR_CONTENT:
1441                            // Clear the view so that onDraw() will draw nothing
1442                            // but white background
1443                            // (See public method WebView.clearView)
1444                            nativeClearContent();
1445                            break;
1446
1447                        case MESSAGE_RELAY:
1448                            if (msg.obj instanceof Message) {
1449                                ((Message) msg.obj).sendToTarget();
1450                            }
1451                            break;
1452
1453                        case POPULATE_VISITED_LINKS:
1454                            nativeProvideVisitedHistory((String[])msg.obj);
1455                            break;
1456
1457                        case VALID_NODE_BOUNDS: {
1458                            MotionUpData motionUpData = (MotionUpData) msg.obj;
1459                            if (!nativeValidNodeAndBounds(
1460                                    motionUpData.mFrame, motionUpData.mNode,
1461                                    motionUpData.mBounds)) {
1462                                nativeUpdateFrameCache();
1463                            }
1464                            Message message = mWebView.mPrivateHandler
1465                                    .obtainMessage(WebView.DO_MOTION_UP,
1466                                    motionUpData.mX, motionUpData.mY);
1467                            mWebView.mPrivateHandler.sendMessageAtFrontOfQueue(
1468                                    message);
1469                            break;
1470                        }
1471
1472                        case HIDE_FULLSCREEN:
1473                            nativeFullScreenPluginHidden(msg.arg1);
1474                            break;
1475
1476                        case ADD_PACKAGE_NAMES:
1477                            if (BrowserFrame.sJavaBridge == null) {
1478                                throw new IllegalStateException("No WebView " +
1479                                        "has been created in this process!");
1480                            }
1481                            BrowserFrame.sJavaBridge.addPackageNames(
1482                                    (Set<String>) msg.obj);
1483                            break;
1484
1485                        case ADD_PACKAGE_NAME:
1486                            if (BrowserFrame.sJavaBridge == null) {
1487                                throw new IllegalStateException("No WebView " +
1488                                        "has been created in this process!");
1489                            }
1490                            BrowserFrame.sJavaBridge.addPackageName(
1491                                    (String) msg.obj);
1492                            break;
1493
1494                        case REMOVE_PACKAGE_NAME:
1495                            if (BrowserFrame.sJavaBridge == null) {
1496                                throw new IllegalStateException("No WebView " +
1497                                        "has been created in this process!");
1498                            }
1499                            BrowserFrame.sJavaBridge.removePackageName(
1500                                    (String) msg.obj);
1501                            break;
1502
1503                        case GET_TOUCH_HIGHLIGHT_RECTS:
1504                            TouchHighlightData d = (TouchHighlightData) msg.obj;
1505                            ArrayList<Rect> rects = nativeGetTouchHighlightRects
1506                                    (d.mX, d.mY, d.mSlop);
1507                            mWebView.mPrivateHandler.obtainMessage(
1508                                    WebView.SET_TOUCH_HIGHLIGHT_RECTS, rects)
1509                                    .sendToTarget();
1510                            break;
1511
1512                        case REMOVE_TOUCH_HIGHLIGHT_RECTS:
1513                            mWebView.mPrivateHandler.obtainMessage(
1514                                    WebView.SET_TOUCH_HIGHLIGHT_RECTS, null)
1515                                    .sendToTarget();
1516                            break;
1517
1518                        case USE_MOCK_DEVICE_ORIENTATION:
1519                            useMockDeviceOrientation();
1520                            break;
1521
1522                        case AUTOFILL_FORM:
1523                            nativeAutoFillForm(msg.arg1);
1524                            mWebView.mPrivateHandler.obtainMessage(WebView.AUTOFILL_COMPLETE, null)
1525                                    .sendToTarget();
1526                            break;
1527                    }
1528                }
1529            };
1530            // Take all queued messages and resend them to the new handler.
1531            synchronized (this) {
1532                int size = mMessages.size();
1533                for (int i = 0; i < size; i++) {
1534                    mHandler.sendMessage(mMessages.get(i));
1535                }
1536                mMessages = null;
1537            }
1538        }
1539
1540        /**
1541         * Send a message internally to the queue or to the handler
1542         */
1543        private synchronized void sendMessage(Message msg) {
1544            if (mBlockMessages) {
1545                return;
1546            }
1547            if (mMessages != null) {
1548                mMessages.add(msg);
1549            } else {
1550                mHandler.sendMessage(msg);
1551            }
1552        }
1553
1554        private synchronized void removeMessages(int what) {
1555            if (mBlockMessages) {
1556                return;
1557            }
1558            if (what == EventHub.WEBKIT_DRAW) {
1559                mDrawIsScheduled = false;
1560            }
1561            if (mMessages != null) {
1562                Log.w(LOGTAG, "Not supported in this case.");
1563            } else {
1564                mHandler.removeMessages(what);
1565            }
1566        }
1567
1568        private synchronized boolean hasMessages(int what) {
1569            if (mBlockMessages) {
1570                return false;
1571            }
1572            if (mMessages != null) {
1573                Log.w(LOGTAG, "hasMessages() is not supported in this case.");
1574                return false;
1575            } else {
1576                return mHandler.hasMessages(what);
1577            }
1578        }
1579
1580        private synchronized void sendMessageDelayed(Message msg, long delay) {
1581            if (mBlockMessages) {
1582                return;
1583            }
1584            mHandler.sendMessageDelayed(msg, delay);
1585        }
1586
1587        /**
1588         * Send a message internally to the front of the queue.
1589         */
1590        private synchronized void sendMessageAtFrontOfQueue(Message msg) {
1591            if (mBlockMessages) {
1592                return;
1593            }
1594            if (mMessages != null) {
1595                mMessages.add(0, msg);
1596            } else {
1597                mHandler.sendMessageAtFrontOfQueue(msg);
1598            }
1599        }
1600
1601        /**
1602         * Remove all the messages.
1603         */
1604        private synchronized void removeMessages() {
1605            // reset mDrawIsScheduled flag as WEBKIT_DRAW may be removed
1606            mDrawIsScheduled = false;
1607            mSplitPictureIsScheduled = false;
1608            if (mMessages != null) {
1609                mMessages.clear();
1610            } else {
1611                mHandler.removeCallbacksAndMessages(null);
1612            }
1613        }
1614
1615        /**
1616         * Block sending messages to the EventHub.
1617         */
1618        private synchronized void blockMessages() {
1619            mBlockMessages = true;
1620        }
1621    }
1622
1623    //-------------------------------------------------------------------------
1624    // Methods called by host activity (in the same thread)
1625    //-------------------------------------------------------------------------
1626
1627    void stopLoading() {
1628        if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "CORE stopLoading");
1629        if (mBrowserFrame != null) {
1630            mBrowserFrame.stopLoading();
1631        }
1632    }
1633
1634    //-------------------------------------------------------------------------
1635    // Methods called by WebView
1636    // If it refers to local variable, it needs synchronized().
1637    // If it needs WebCore, it has to send message.
1638    //-------------------------------------------------------------------------
1639
1640    void sendMessage(Message msg) {
1641        mEventHub.sendMessage(msg);
1642    }
1643
1644    void sendMessage(int what) {
1645        mEventHub.sendMessage(Message.obtain(null, what));
1646    }
1647
1648    void sendMessage(int what, Object obj) {
1649        mEventHub.sendMessage(Message.obtain(null, what, obj));
1650    }
1651
1652    void sendMessage(int what, int arg1) {
1653        // just ignore the second argument (make it 0)
1654        mEventHub.sendMessage(Message.obtain(null, what, arg1, 0));
1655    }
1656
1657    void sendMessage(int what, int arg1, int arg2) {
1658        mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2));
1659    }
1660
1661    void sendMessage(int what, int arg1, Object obj) {
1662        // just ignore the second argument (make it 0)
1663        mEventHub.sendMessage(Message.obtain(null, what, arg1, 0, obj));
1664    }
1665
1666    void sendMessage(int what, int arg1, int arg2, Object obj) {
1667        mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2, obj));
1668    }
1669
1670    void sendMessageAtFrontOfQueue(int what, Object obj) {
1671        mEventHub.sendMessageAtFrontOfQueue(Message.obtain(
1672                null, what, obj));
1673    }
1674
1675    void sendMessageDelayed(int what, Object obj, long delay) {
1676        mEventHub.sendMessageDelayed(Message.obtain(null, what, obj), delay);
1677    }
1678
1679    void removeMessages(int what) {
1680        mEventHub.removeMessages(what);
1681    }
1682
1683    void removeMessages() {
1684        mEventHub.removeMessages();
1685    }
1686
1687    /**
1688     * Removes pending messages and trigger a DESTROY message to send to
1689     * WebCore.
1690     * Called from UI thread.
1691     */
1692    void destroy() {
1693        // We don't want anyone to post a message between removing pending
1694        // messages and sending the destroy message.
1695        synchronized (mEventHub) {
1696            // RESUME_TIMERS and PAUSE_TIMERS are per process base. They need to
1697            // be preserved even the WebView is destroyed.
1698            // Note: we should not have more than one RESUME_TIMERS/PAUSE_TIMERS
1699            boolean hasResume = mEventHub.hasMessages(EventHub.RESUME_TIMERS);
1700            boolean hasPause = mEventHub.hasMessages(EventHub.PAUSE_TIMERS);
1701            mEventHub.removeMessages();
1702            mEventHub.sendMessageAtFrontOfQueue(
1703                    Message.obtain(null, EventHub.DESTROY));
1704            if (hasPause) {
1705                mEventHub.sendMessageAtFrontOfQueue(
1706                        Message.obtain(null, EventHub.PAUSE_TIMERS));
1707            }
1708            if (hasResume) {
1709                mEventHub.sendMessageAtFrontOfQueue(
1710                        Message.obtain(null, EventHub.RESUME_TIMERS));
1711            }
1712            mEventHub.blockMessages();
1713        }
1714    }
1715
1716    //-------------------------------------------------------------------------
1717    // WebViewCore private methods
1718    //-------------------------------------------------------------------------
1719
1720    private void clearCache(boolean includeDiskFiles) {
1721        mBrowserFrame.clearCache();
1722        if (includeDiskFiles) {
1723            CacheManager.removeAllCacheFiles();
1724        }
1725    }
1726
1727    private void loadUrl(String url, Map<String, String> extraHeaders) {
1728        if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, " CORE loadUrl " + url);
1729        mBrowserFrame.loadUrl(url, extraHeaders);
1730    }
1731
1732    private String saveWebArchive(String filename, boolean autoname) {
1733        if (DebugFlags.WEB_VIEW_CORE) {
1734            Log.v(LOGTAG, " CORE saveWebArchive " + filename + " " + autoname);
1735        }
1736        return mBrowserFrame.saveWebArchive(filename, autoname);
1737    }
1738
1739    private void key(KeyEvent evt, boolean isDown) {
1740        if (DebugFlags.WEB_VIEW_CORE) {
1741            Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", "
1742                    + evt);
1743        }
1744        int keyCode = evt.getKeyCode();
1745        int unicodeChar = evt.getUnicodeChar();
1746
1747        if (keyCode == KeyEvent.KEYCODE_UNKNOWN && evt.getCharacters() != null
1748                && evt.getCharacters().length() > 0) {
1749            // we should only receive individual complex characters
1750            unicodeChar = evt.getCharacters().codePointAt(0);
1751        }
1752
1753        if (!nativeKey(keyCode, unicodeChar, evt.getRepeatCount(), evt.isShiftPressed(),
1754                evt.isAltPressed(), evt.isSymPressed(),
1755                isDown) && keyCode != KeyEvent.KEYCODE_ENTER) {
1756            if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
1757                    && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
1758                if (DebugFlags.WEB_VIEW_CORE) {
1759                    Log.v(LOGTAG, "key: arrow unused by page: " + keyCode);
1760                }
1761                if (mWebView != null && evt.isDown()) {
1762                    Message.obtain(mWebView.mPrivateHandler,
1763                            WebView.UNHANDLED_NAV_KEY, keyCode,
1764                            0).sendToTarget();
1765                }
1766                return;
1767            }
1768            // bubble up the event handling
1769            // but do not bubble up the ENTER key, which would open the search
1770            // bar without any text.
1771            mCallbackProxy.onUnhandledKeyEvent(evt);
1772        }
1773    }
1774
1775    // These values are used to avoid requesting a layout based on old values
1776    private int mCurrentViewWidth = 0;
1777    private int mCurrentViewHeight = 0;
1778    private float mCurrentViewScale = 1.0f;
1779
1780    // notify webkit that our virtual view size changed size (after inv-zoom)
1781    private void viewSizeChanged(int w, int h, int textwrapWidth, float scale,
1782            int anchorX, int anchorY, boolean ignoreHeight) {
1783        if (DebugFlags.WEB_VIEW_CORE) {
1784            Log.v(LOGTAG, "viewSizeChanged w=" + w + "; h=" + h
1785                    + "; textwrapWidth=" + textwrapWidth + "; scale=" + scale);
1786        }
1787        if (w == 0) {
1788            Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
1789            return;
1790        }
1791        int width = w;
1792        if (mSettings.getUseWideViewPort()) {
1793            if (mViewportWidth == -1) {
1794                if (mSettings.getLayoutAlgorithm() ==
1795                        WebSettings.LayoutAlgorithm.NORMAL || mSettings.getUseFixedViewport()) {
1796                    width = WebView.DEFAULT_VIEWPORT_WIDTH;
1797                } else {
1798                    /*
1799                     * if a page's minimum preferred width is wider than the
1800                     * given "w", use it instead to get better layout result. If
1801                     * we start a page with MAX_ZOOM_WIDTH, "w" will be always
1802                     * wider. If we start a page with screen width, due to the
1803                     * delay between {@link #didFirstLayout} and
1804                     * {@link #viewSizeChanged},
1805                     * {@link #nativeGetContentMinPrefWidth} will return a more
1806                     * accurate value than initial 0 to result a better layout.
1807                     * In the worse case, the native width will be adjusted when
1808                     * next zoom or screen orientation change happens.
1809                     */
1810                    width = Math.min(WebView.sMaxViewportWidth, Math.max(w,
1811                            Math.max(WebView.DEFAULT_VIEWPORT_WIDTH,
1812                                    nativeGetContentMinPrefWidth())));
1813                }
1814            } else if (mViewportWidth > 0) {
1815                if (mSettings.getUseFixedViewport()) {
1816                    // Use website specified or desired fixed viewport width.
1817                    width = mViewportWidth;
1818                } else {
1819                    width = Math.max(w, mViewportWidth);
1820                }
1821            } else if (mSettings.getUseFixedViewport()) {
1822                width = mWebView.getViewWidth();
1823            } else {
1824                width = textwrapWidth;
1825            }
1826        }
1827        nativeSetSize(width, width == w ? h : Math.round((float) width * h / w),
1828                textwrapWidth, scale, w, h, anchorX, anchorY, ignoreHeight);
1829        // Remember the current width and height
1830        boolean needInvalidate = (mCurrentViewWidth == 0);
1831        mCurrentViewWidth = w;
1832        mCurrentViewHeight = h;
1833        mCurrentViewScale = scale;
1834        if (needInvalidate) {
1835            // ensure {@link #webkitDraw} is called as we were blocking in
1836            // {@link #contentDraw} when mCurrentViewWidth is 0
1837            if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "viewSizeChanged");
1838            contentDraw();
1839        }
1840        mEventHub.sendMessage(Message.obtain(null,
1841                EventHub.UPDATE_CACHE_AND_TEXT_ENTRY));
1842    }
1843
1844    private void sendUpdateTextEntry() {
1845        if (mWebView != null) {
1846            Message.obtain(mWebView.mPrivateHandler,
1847                    WebView.UPDATE_TEXT_ENTRY_MSG_ID).sendToTarget();
1848        }
1849    }
1850
1851    // Utility method for exceededDatabaseQuota and reachedMaxAppCacheSize
1852    // callbacks. Computes the sum of database quota for all origins.
1853    private long getUsedQuota() {
1854        WebStorage webStorage = WebStorage.getInstance();
1855        Collection<WebStorage.Origin> origins = webStorage.getOriginsSync();
1856
1857        if (origins == null) {
1858            return 0;
1859        }
1860        long usedQuota = 0;
1861        for (WebStorage.Origin website : origins) {
1862            usedQuota += website.getQuota();
1863        }
1864        return usedQuota;
1865    }
1866
1867    // called from UI thread
1868    void splitContent(int content) {
1869        if (!mSplitPictureIsScheduled) {
1870            mSplitPictureIsScheduled = true;
1871            sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0);
1872        }
1873    }
1874
1875    // Used to avoid posting more than one draw message.
1876    private boolean mDrawIsScheduled;
1877    private boolean mDrawLayersIsScheduled;
1878
1879    // Used to avoid posting more than one split picture message.
1880    private boolean mSplitPictureIsScheduled;
1881
1882    // Used to suspend drawing.
1883    private boolean mDrawIsPaused;
1884
1885    // mInitialViewState is set by didFirstLayout() and then reset in the
1886    // next webkitDraw after passing the state to the UI thread.
1887    private ViewState mInitialViewState = null;
1888
1889    static class ViewState {
1890        float mMinScale;
1891        float mMaxScale;
1892        float mViewScale;
1893        float mTextWrapScale;
1894        float mDefaultScale;
1895        int mScrollX;
1896        int mScrollY;
1897        boolean mMobileSite;
1898        boolean mIsRestored;
1899    }
1900
1901    static class DrawData {
1902        DrawData() {
1903            mBaseLayer = 0;
1904            mInvalRegion = new Region();
1905            mContentSize = new Point();
1906        }
1907        int mBaseLayer;
1908        Region mInvalRegion;
1909        // view size that was used by webkit during the most recent layout
1910        Point mViewSize;
1911        Point mContentSize;
1912        int mMinPrefWidth;
1913        // only non-null if it is for the first picture set after the first layout
1914        ViewState mViewState;
1915        boolean mFocusSizeChanged;
1916    }
1917
1918    // Only update the layers' content, not the base surface
1919    // PictureSet.
1920    private void webkitDrawLayers() {
1921        mDrawLayersIsScheduled = false;
1922        if (mDrawIsScheduled) {
1923            removeMessages(EventHub.WEBKIT_DRAW);
1924            webkitDraw();
1925            return;
1926        }
1927        DrawData draw = new DrawData();
1928        draw.mBaseLayer = nativeUpdateLayers(draw.mInvalRegion);
1929        webkitDraw(draw);
1930    }
1931
1932    private void webkitDraw() {
1933        mDrawIsScheduled = false;
1934        DrawData draw = new DrawData();
1935        if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw start");
1936        draw.mBaseLayer = nativeRecordContent(draw.mInvalRegion, draw.mContentSize);
1937        if (draw.mBaseLayer == 0) {
1938            if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort");
1939            return;
1940        }
1941        webkitDraw(draw);
1942    }
1943
1944    private void webkitDraw(DrawData draw) {
1945        if (mWebView != null) {
1946            draw.mFocusSizeChanged = nativeFocusBoundsChanged();
1947            draw.mViewSize = new Point(mCurrentViewWidth, mCurrentViewHeight);
1948            if (mSettings.getUseWideViewPort()) {
1949                draw.mMinPrefWidth = Math.max(
1950                        mViewportWidth == -1 ? WebView.DEFAULT_VIEWPORT_WIDTH
1951                                : (mViewportWidth == 0 ? mCurrentViewWidth
1952                                        : mViewportWidth),
1953                        nativeGetContentMinPrefWidth());
1954            }
1955            if (mInitialViewState != null) {
1956                draw.mViewState = mInitialViewState;
1957                mInitialViewState = null;
1958            }
1959            if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
1960            Message.obtain(mWebView.mPrivateHandler,
1961                    WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
1962            if (mWebkitScrollX != 0 || mWebkitScrollY != 0) {
1963                // as we have the new picture, try to sync the scroll position
1964                Message.obtain(mWebView.mPrivateHandler,
1965                        WebView.SYNC_SCROLL_TO_MSG_ID, mWebkitScrollX,
1966                        mWebkitScrollY).sendToTarget();
1967                mWebkitScrollX = mWebkitScrollY = 0;
1968            }
1969        }
1970    }
1971
1972    static void reducePriority() {
1973        // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
1974        sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
1975        sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
1976        sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
1977                .obtainMessage(WebCoreThread.REDUCE_PRIORITY));
1978    }
1979
1980    static void resumePriority() {
1981        // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
1982        sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
1983        sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
1984        sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
1985                .obtainMessage(WebCoreThread.RESUME_PRIORITY));
1986    }
1987
1988    static void pauseUpdatePicture(WebViewCore core) {
1989        // Note: there is one possible failure mode. If pauseUpdatePicture() is
1990        // called from UI thread while WEBKIT_DRAW is just pulled out of the
1991        // queue in WebCore thread to be executed. Then update won't be blocked.
1992        if (core != null) {
1993            if (!core.getSettings().enableSmoothTransition()) return;
1994
1995            synchronized (core) {
1996                core.mDrawIsPaused = true;
1997                if (core.mDrawIsScheduled) {
1998                    core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
1999                }
2000            }
2001        }
2002
2003    }
2004
2005    static void resumeUpdatePicture(WebViewCore core) {
2006        if (core != null) {
2007            // if mDrawIsPaused is true, ignore the setting, continue to resume
2008            if (!core.mDrawIsPaused
2009                    && !core.getSettings().enableSmoothTransition()) return;
2010
2011            synchronized (core) {
2012                core.mDrawIsPaused = false;
2013                // always redraw on resume to reenable gif animations
2014                core.mDrawIsScheduled = false;
2015                core.nativeContentInvalidateAll();
2016                core.contentDraw();
2017            }
2018        }
2019    }
2020
2021    //////////////////////////////////////////////////////////////////////////
2022
2023    private void restoreState(int index) {
2024        WebBackForwardList list = mCallbackProxy.getBackForwardList();
2025        int size = list.getSize();
2026        for (int i = 0; i < size; i++) {
2027            list.getItemAtIndex(i).inflate(mBrowserFrame.mNativeFrame);
2028        }
2029        mBrowserFrame.mLoadInitFromJava = true;
2030        list.restoreIndex(mBrowserFrame.mNativeFrame, index);
2031        mBrowserFrame.mLoadInitFromJava = false;
2032    }
2033
2034    //-------------------------------------------------------------------------
2035    // Implement abstract methods in WebViewCore, native WebKit callback part
2036    //-------------------------------------------------------------------------
2037
2038    // called from JNI or WebView thread
2039    /* package */ void contentDraw() {
2040        // don't update the Picture until we have an initial width and finish
2041        // the first layout
2042        if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) {
2043            return;
2044        }
2045        // only fire an event if this is our first request
2046        synchronized (this) {
2047            if (mDrawIsScheduled) return;
2048            mDrawIsScheduled = true;
2049            if (mDrawIsPaused) return;
2050            mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
2051        }
2052    }
2053
2054    // called from JNI
2055    void layersDraw() {
2056        synchronized (this) {
2057            if (mDrawLayersIsScheduled) return;
2058            mDrawLayersIsScheduled = true;
2059            mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW_LAYERS));
2060        }
2061    }
2062
2063    // called by JNI
2064    private void contentScrollBy(int dx, int dy, boolean animate) {
2065        if (!mBrowserFrame.firstLayoutDone()) {
2066            // Will this happen? If yes, we need to do something here.
2067            return;
2068        }
2069        if (mWebView != null) {
2070            Message msg = Message.obtain(mWebView.mPrivateHandler,
2071                    WebView.SCROLL_BY_MSG_ID, dx, dy, Boolean.valueOf(animate));
2072            if (mDrawIsScheduled) {
2073                mEventHub.sendMessage(Message.obtain(null,
2074                        EventHub.MESSAGE_RELAY, msg));
2075            } else {
2076                msg.sendToTarget();
2077            }
2078        }
2079    }
2080
2081    // called by JNI
2082    private void contentScrollTo(int x, int y) {
2083        if (!mBrowserFrame.firstLayoutDone()) {
2084            /*
2085             * WebKit restore state will be called before didFirstLayout(),
2086             * remember the position as it has to be applied after restoring
2087             * zoom factor which is controlled by screenWidth.
2088             */
2089            mRestoredX = x;
2090            mRestoredY = y;
2091            return;
2092        }
2093        if (mWebView != null) {
2094            Message msg = Message.obtain(mWebView.mPrivateHandler,
2095                    WebView.SCROLL_TO_MSG_ID, x, y);
2096            if (mDrawIsScheduled) {
2097                mEventHub.sendMessage(Message.obtain(null,
2098                        EventHub.MESSAGE_RELAY, msg));
2099            } else {
2100                msg.sendToTarget();
2101            }
2102        }
2103    }
2104
2105    // called by JNI
2106    private void contentSpawnScrollTo(int x, int y) {
2107        if (!mBrowserFrame.firstLayoutDone()) {
2108            /*
2109             * WebKit restore state will be called before didFirstLayout(),
2110             * remember the position as it has to be applied after restoring
2111             * zoom factor which is controlled by screenWidth.
2112             */
2113            mRestoredX = x;
2114            mRestoredY = y;
2115            return;
2116        }
2117        if (mWebView != null) {
2118            Message msg = Message.obtain(mWebView.mPrivateHandler,
2119                    WebView.SPAWN_SCROLL_TO_MSG_ID, x, y);
2120            if (mDrawIsScheduled) {
2121                mEventHub.sendMessage(Message.obtain(null,
2122                        EventHub.MESSAGE_RELAY, msg));
2123            } else {
2124                msg.sendToTarget();
2125            }
2126        }
2127    }
2128
2129    // called by JNI
2130    private void sendNotifyProgressFinished() {
2131        sendUpdateTextEntry();
2132        // as CacheManager can behave based on database transaction, we need to
2133        // call tick() to trigger endTransaction
2134        WebViewWorker.getHandler().removeMessages(
2135                WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
2136        WebViewWorker.getHandler().sendEmptyMessage(
2137                WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
2138        contentDraw();
2139    }
2140
2141    /*  Called by JNI. The coordinates are in doc coordinates, so they need to
2142        be scaled before they can be used by the view system, which happens
2143        in WebView since it (and its thread) know the current scale factor.
2144     */
2145    private void sendViewInvalidate(int left, int top, int right, int bottom) {
2146        if (mWebView != null) {
2147            Message.obtain(mWebView.mPrivateHandler,
2148                           WebView.INVAL_RECT_MSG_ID,
2149                           new Rect(left, top, right, bottom)).sendToTarget();
2150        }
2151    }
2152
2153    private static boolean mRepaintScheduled = false;
2154
2155    /*
2156     * Called by the WebView thread
2157     */
2158    /* package */ void signalRepaintDone() {
2159        mRepaintScheduled = false;
2160    }
2161
2162    /* package */ WebView getWebView() {
2163        return mWebView;
2164    }
2165
2166    private native void setViewportSettingsFromNative();
2167
2168    // called by JNI
2169    private void didFirstLayout(boolean standardLoad) {
2170        if (DebugFlags.WEB_VIEW_CORE) {
2171            Log.v(LOGTAG, "didFirstLayout standardLoad =" + standardLoad);
2172        }
2173
2174        mBrowserFrame.didFirstLayout();
2175
2176        if (mWebView == null) return;
2177
2178        boolean updateViewState = standardLoad || mRestoredScale > 0;
2179        setupViewport(updateViewState);
2180        // if updateRestoreState is true, ViewManager.postReadyToDrawAll() will
2181        // be called after the WebView updates its state. If updateRestoreState
2182        // is false, start to draw now as it is ready.
2183        if (!updateViewState) {
2184            mWebView.mViewManager.postReadyToDrawAll();
2185        }
2186
2187        // remove the touch highlight when moving to a new page
2188        if (getSettings().supportTouchOnly()) {
2189            mEventHub.sendMessage(Message.obtain(null,
2190                    EventHub.REMOVE_TOUCH_HIGHLIGHT_RECTS));
2191        }
2192
2193        // reset the scroll position, the restored offset and scales
2194        mWebkitScrollX = mWebkitScrollY = mRestoredX = mRestoredY
2195                = mRestoredScale = mRestoredTextWrapScale = 0;
2196    }
2197
2198    // called by JNI
2199    private void updateViewport() {
2200        // if updateViewport is called before first layout, wait until first
2201        // layout to update the viewport. In the rare case, this is called after
2202        // first layout, force an update as we have just parsed the viewport
2203        // meta tag.
2204        if (mBrowserFrame.firstLayoutDone()) {
2205            setupViewport(true);
2206        }
2207    }
2208
2209    private void setupViewport(boolean updateViewState) {
2210        // set the viewport settings from WebKit
2211        setViewportSettingsFromNative();
2212
2213        // adjust the default scale to match the densityDpi
2214        float adjust = 1.0f;
2215        if (mViewportDensityDpi == -1) {
2216            // convert default zoom scale to a integer (percentage) to avoid any
2217            // issues with floating point comparisons
2218            if (mWebView != null && (int)(mWebView.getDefaultZoomScale() * 100) != 100) {
2219                adjust = mWebView.getDefaultZoomScale();
2220            }
2221        } else if (mViewportDensityDpi > 0) {
2222            adjust = (float) mContext.getResources().getDisplayMetrics().densityDpi
2223                    / mViewportDensityDpi;
2224        }
2225        int defaultScale = (int) (adjust * 100);
2226
2227        if (mViewportInitialScale > 0) {
2228            mViewportInitialScale *= adjust;
2229        }
2230        if (mViewportMinimumScale > 0) {
2231            mViewportMinimumScale *= adjust;
2232        }
2233        if (mViewportMaximumScale > 0) {
2234            mViewportMaximumScale *= adjust;
2235        }
2236
2237        // infer the values if they are not defined.
2238        if (mViewportWidth == 0) {
2239            if (mViewportInitialScale == 0) {
2240                mViewportInitialScale = defaultScale;
2241            }
2242        }
2243        if (mViewportUserScalable == false) {
2244            mViewportInitialScale = defaultScale;
2245            mViewportMinimumScale = defaultScale;
2246            mViewportMaximumScale = defaultScale;
2247        }
2248        if (mViewportMinimumScale > mViewportInitialScale
2249                && mViewportInitialScale != 0) {
2250            mViewportMinimumScale = mViewportInitialScale;
2251        }
2252        if (mViewportMaximumScale > 0
2253                && mViewportMaximumScale < mViewportInitialScale) {
2254            mViewportMaximumScale = mViewportInitialScale;
2255        }
2256        if (mViewportWidth < 0 && mViewportInitialScale == defaultScale) {
2257            mViewportWidth = 0;
2258        }
2259
2260        // if mViewportWidth is 0, it means device-width, always update.
2261        if (mViewportWidth != 0 && !updateViewState) {
2262            ViewState viewState = new ViewState();
2263            viewState.mMinScale = mViewportMinimumScale / 100.0f;
2264            viewState.mMaxScale = mViewportMaximumScale / 100.0f;
2265            viewState.mDefaultScale = adjust;
2266            // as mViewportWidth is not 0, it is not mobile site.
2267            viewState.mMobileSite = false;
2268            // for non-mobile site, we don't need minPrefWidth, set it as 0
2269            viewState.mScrollX = 0;
2270            Message.obtain(mWebView.mPrivateHandler,
2271                    WebView.UPDATE_ZOOM_RANGE, viewState).sendToTarget();
2272            return;
2273        }
2274
2275        // now notify webview
2276        // webViewWidth refers to the width in the view system
2277        int webViewWidth;
2278        // viewportWidth refers to the width in the document system
2279        int viewportWidth = mCurrentViewWidth;
2280        if (viewportWidth == 0) {
2281            // this may happen when WebView just starts. This is not perfect as
2282            // we call WebView method from WebCore thread. But not perfect
2283            // reference is better than no reference.
2284            webViewWidth = mWebView.getViewWidth();
2285            viewportWidth = (int) (webViewWidth / adjust);
2286            if (viewportWidth == 0) {
2287                Log.w(LOGTAG, "Can't get the viewWidth after the first layout");
2288            }
2289        } else {
2290            webViewWidth = Math.round(viewportWidth * mCurrentViewScale);
2291        }
2292        mInitialViewState = new ViewState();
2293        mInitialViewState.mMinScale = mViewportMinimumScale / 100.0f;
2294        mInitialViewState.mMaxScale = mViewportMaximumScale / 100.0f;
2295        mInitialViewState.mDefaultScale = adjust;
2296        mInitialViewState.mScrollX = mRestoredX;
2297        mInitialViewState.mScrollY = mRestoredY;
2298        mInitialViewState.mMobileSite = (0 == mViewportWidth);
2299        if (mRestoredScale > 0) {
2300            mInitialViewState.mIsRestored = true;
2301            mInitialViewState.mViewScale = mRestoredScale / 100.0f;
2302            if (mRestoredTextWrapScale > 0) {
2303                mInitialViewState.mTextWrapScale = mRestoredTextWrapScale / 100.0f;
2304            } else {
2305                mInitialViewState.mTextWrapScale = mInitialViewState.mViewScale;
2306            }
2307        } else {
2308            if (mViewportInitialScale > 0) {
2309                mInitialViewState.mViewScale = mInitialViewState.mTextWrapScale =
2310                        mViewportInitialScale / 100.0f;
2311            } else if (mViewportWidth > 0 && mViewportWidth < webViewWidth &&
2312                !mWebView.getSettings().getUseFixedViewport()) {
2313                mInitialViewState.mViewScale = mInitialViewState.mTextWrapScale =
2314                        (float) webViewWidth / mViewportWidth;
2315            } else {
2316                mInitialViewState.mTextWrapScale = adjust;
2317                // 0 will trigger WebView to turn on zoom overview mode
2318                mInitialViewState.mViewScale = 0;
2319            }
2320        }
2321
2322        if (mWebView.mHeightCanMeasure) {
2323            // Trick to ensure that the Picture has the exact height for the
2324            // content by forcing to layout with 0 height after the page is
2325            // ready, which is indicated by didFirstLayout. This is essential to
2326            // get rid of the white space in the GMail which uses WebView for
2327            // message view.
2328            mWebView.mLastHeightSent = 0;
2329            // Send a negative scale to indicate that WebCore should reuse
2330            // the current scale
2331            WebView.ViewSizeData data = new WebView.ViewSizeData();
2332            data.mWidth = mWebView.mLastWidthSent;
2333            data.mHeight = 0;
2334            // if mHeightCanMeasure is true, getUseWideViewPort() can't be
2335            // true. It is safe to use mWidth for mTextWrapWidth.
2336            data.mTextWrapWidth = data.mWidth;
2337            data.mScale = -1.0f;
2338            data.mIgnoreHeight = false;
2339            data.mAnchorX = data.mAnchorY = 0;
2340            // send VIEW_SIZE_CHANGED to the front of the queue so that we can
2341            // avoid pushing the wrong picture to the WebView side. If there is
2342            // a VIEW_SIZE_CHANGED in the queue, probably from WebView side,
2343            // ignore it as we have a new size. If we leave VIEW_SIZE_CHANGED
2344            // in the queue, as mLastHeightSent has been updated here, we may
2345            // miss the requestLayout in WebView side after the new picture.
2346            mEventHub.removeMessages(EventHub.VIEW_SIZE_CHANGED);
2347            mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
2348                    EventHub.VIEW_SIZE_CHANGED, data));
2349        } else if (mSettings.getUseWideViewPort()) {
2350            if (viewportWidth == 0) {
2351                // Trick to ensure VIEW_SIZE_CHANGED will be sent from WebView
2352                // to WebViewCore
2353                mWebView.mLastWidthSent = 0;
2354            } else {
2355                WebView.ViewSizeData data = new WebView.ViewSizeData();
2356                // mViewScale as 0 means it is in zoom overview mode. So we don't
2357                // know the exact scale. If mRestoredScale is non-zero, use it;
2358                // otherwise just use mTextWrapScale as the initial scale.
2359                data.mScale = mInitialViewState.mViewScale == 0
2360                        ? (mRestoredScale > 0 ? mRestoredScale / 100.0f
2361                                : mInitialViewState.mTextWrapScale)
2362                        : mInitialViewState.mViewScale;
2363                if (DebugFlags.WEB_VIEW_CORE) {
2364                    Log.v(LOGTAG, "setupViewport"
2365                             + " mRestoredScale=" + mRestoredScale
2366                             + " mViewScale=" + mInitialViewState.mViewScale
2367                             + " mTextWrapScale=" + mInitialViewState.mTextWrapScale
2368                             );
2369                }
2370                data.mWidth = Math.round(webViewWidth / data.mScale);
2371                // We may get a call here when mCurrentViewHeight == 0 if webcore completes the
2372                // first layout before we sync our webview dimensions to it. In that case, we
2373                // request the real height of the webview. This is not a perfect solution as we
2374                // are calling a WebView method from the WebCore thread. But this is preferable
2375                // to syncing an incorrect height.
2376                data.mHeight = mCurrentViewHeight == 0 ?
2377                        Math.round(mWebView.getViewHeight() / data.mScale)
2378                        : mCurrentViewHeight * data.mWidth / viewportWidth;
2379                data.mTextWrapWidth = Math.round(webViewWidth
2380                        / mInitialViewState.mTextWrapScale);
2381                data.mIgnoreHeight = false;
2382                data.mAnchorX = data.mAnchorY = 0;
2383                // send VIEW_SIZE_CHANGED to the front of the queue so that we
2384                // can avoid pushing the wrong picture to the WebView side.
2385                mEventHub.removeMessages(EventHub.VIEW_SIZE_CHANGED);
2386                mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
2387                        EventHub.VIEW_SIZE_CHANGED, data));
2388            }
2389        }
2390    }
2391
2392    // called by JNI
2393    private void restoreScale(int scale, int textWrapScale) {
2394        if (mBrowserFrame.firstLayoutDone() == false) {
2395            mRestoredScale = scale;
2396            if (mSettings.getUseWideViewPort()) {
2397                mRestoredTextWrapScale = textWrapScale;
2398            }
2399        }
2400    }
2401
2402    // called by JNI
2403    private void needTouchEvents(boolean need) {
2404        if (mWebView != null) {
2405            Message.obtain(mWebView.mPrivateHandler,
2406                    WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0)
2407                    .sendToTarget();
2408        }
2409    }
2410
2411    // called by JNI
2412    private void updateTextfield(int ptr, boolean changeToPassword,
2413            String text, int textGeneration) {
2414        if (mWebView != null) {
2415            Message msg = Message.obtain(mWebView.mPrivateHandler,
2416                    WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr,
2417                    textGeneration, text);
2418            msg.getData().putBoolean("password", changeToPassword);
2419            msg.sendToTarget();
2420        }
2421    }
2422
2423    // called by JNI
2424    private void updateTextSelection(int pointer, int start, int end,
2425            int textGeneration) {
2426        if (mWebView != null) {
2427            Message.obtain(mWebView.mPrivateHandler,
2428                WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
2429                new TextSelectionData(start, end)).sendToTarget();
2430        }
2431    }
2432
2433    // called by JNI
2434    private void clearTextEntry() {
2435        if (mWebView == null) return;
2436        Message.obtain(mWebView.mPrivateHandler,
2437                WebView.CLEAR_TEXT_ENTRY).sendToTarget();
2438    }
2439
2440    // called by JNI
2441    private void sendFindAgain() {
2442        if (mWebView == null) return;
2443        Message.obtain(mWebView.mPrivateHandler,
2444                WebView.FIND_AGAIN).sendToTarget();
2445    }
2446
2447    private native void nativeUpdateFrameCacheIfLoading();
2448    private native void nativeRevealSelection();
2449    private native String nativeRequestLabel(int framePtr, int nodePtr);
2450    /**
2451     * Scroll the focused textfield to (xPercent, y) in document space
2452     */
2453    private native void nativeScrollFocusedTextInput(float xPercent, int y);
2454
2455    // these must be in document space (i.e. not scaled/zoomed).
2456    private native void nativeSetScrollOffset(int gen, int userScrolled, int dx, int dy);
2457
2458    private native void nativeSetGlobalBounds(int x, int y, int w, int h);
2459
2460    // called by JNI
2461    private void requestListBox(String[] array, int[] enabledArray,
2462            int[] selectedArray) {
2463        if (mWebView != null) {
2464            mWebView.requestListBox(array, enabledArray, selectedArray);
2465        }
2466    }
2467
2468    // called by JNI
2469    private void requestListBox(String[] array, int[] enabledArray,
2470            int selection) {
2471        if (mWebView != null) {
2472            mWebView.requestListBox(array, enabledArray, selection);
2473        }
2474
2475    }
2476
2477    // called by JNI
2478    private void requestKeyboardWithSelection(int pointer, int selStart,
2479            int selEnd, int textGeneration) {
2480        if (mWebView != null) {
2481            Message.obtain(mWebView.mPrivateHandler,
2482                    WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer,
2483                    textGeneration, new TextSelectionData(selStart, selEnd))
2484                    .sendToTarget();
2485        }
2486    }
2487
2488    // called by JNI
2489    private void requestKeyboard(boolean showKeyboard) {
2490        if (mWebView != null) {
2491            Message.obtain(mWebView.mPrivateHandler,
2492                    WebView.REQUEST_KEYBOARD, showKeyboard ? 1 : 0, 0)
2493                    .sendToTarget();
2494        }
2495    }
2496
2497    private void setWebTextViewAutoFillable(int queryId, String preview) {
2498        if (mWebView != null) {
2499            Message.obtain(mWebView.mPrivateHandler, WebView.SET_AUTOFILLABLE,
2500                    new AutoFillData(queryId, preview))
2501                    .sendToTarget();
2502        }
2503    }
2504
2505    // called by JNI
2506    private Context getContext() {
2507        return mContext;
2508    }
2509
2510    // called by JNI
2511    private Class<?> getPluginClass(String libName, String clsName) {
2512
2513        if (mWebView == null) {
2514            return null;
2515        }
2516
2517        PluginManager pluginManager = PluginManager.getInstance(null);
2518
2519        String pkgName = pluginManager.getPluginsAPKName(libName);
2520        if (pkgName == null) {
2521            Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK");
2522            return null;
2523        }
2524
2525        try {
2526            return pluginManager.getPluginClass(pkgName, clsName);
2527        } catch (NameNotFoundException e) {
2528            Log.e(LOGTAG, "Unable to find plugin classloader for the apk (" + pkgName + ")");
2529        } catch (ClassNotFoundException e) {
2530            Log.e(LOGTAG, "Unable to find plugin class (" + clsName +
2531                    ") in the apk (" + pkgName + ")");
2532        }
2533
2534        return null;
2535    }
2536
2537    // called by JNI. PluginWidget function to launch a full-screen view using a
2538    // View object provided by the plugin class.
2539    private void showFullScreenPlugin(ViewManager.ChildView childView, int npp) {
2540        if (mWebView == null) {
2541            return;
2542        }
2543
2544        Message message = mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN);
2545        message.obj = childView.mView;
2546        message.arg1 = npp;
2547        message.sendToTarget();
2548    }
2549
2550    // called by JNI
2551    private void hideFullScreenPlugin() {
2552        if (mWebView == null) {
2553            return;
2554        }
2555        mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
2556                .sendToTarget();
2557    }
2558
2559    // called by JNI.  PluginWidget functions for creating an embedded View for
2560    // the surface drawing model.
2561    private ViewManager.ChildView addSurface(View pluginView, int x, int y,
2562                                             int width, int height) {
2563        if (mWebView == null) {
2564            return null;
2565        }
2566
2567        if (pluginView == null) {
2568            Log.e(LOGTAG, "Attempted to add an empty plugin view to the view hierarchy");
2569            return null;
2570        }
2571
2572        // ensures the view system knows the view can redraw itself
2573        pluginView.setWillNotDraw(false);
2574
2575        if(pluginView instanceof SurfaceView)
2576            ((SurfaceView)pluginView).setZOrderOnTop(true);
2577
2578        ViewManager.ChildView view = mWebView.mViewManager.createView();
2579        view.mView = pluginView;
2580        view.attachView(x, y, width, height);
2581        return view;
2582    }
2583
2584    private void updateSurface(ViewManager.ChildView childView, int x, int y,
2585            int width, int height) {
2586        childView.attachView(x, y, width, height);
2587    }
2588
2589    private void destroySurface(ViewManager.ChildView childView) {
2590        childView.removeView();
2591    }
2592
2593    // called by JNI
2594    static class ShowRectData {
2595        int mLeft;
2596        int mTop;
2597        int mWidth;
2598        int mHeight;
2599        int mContentWidth;
2600        int mContentHeight;
2601        float mXPercentInDoc;
2602        float mXPercentInView;
2603        float mYPercentInDoc;
2604        float mYPercentInView;
2605    }
2606
2607    private void showRect(int left, int top, int width, int height,
2608            int contentWidth, int contentHeight, float xPercentInDoc,
2609            float xPercentInView, float yPercentInDoc, float yPercentInView) {
2610        if (mWebView != null) {
2611            ShowRectData data = new ShowRectData();
2612            data.mLeft = left;
2613            data.mTop = top;
2614            data.mWidth = width;
2615            data.mHeight = height;
2616            data.mContentWidth = contentWidth;
2617            data.mContentHeight = contentHeight;
2618            data.mXPercentInDoc = xPercentInDoc;
2619            data.mXPercentInView = xPercentInView;
2620            data.mYPercentInDoc = yPercentInDoc;
2621            data.mYPercentInView = yPercentInView;
2622            Message.obtain(mWebView.mPrivateHandler, WebView.SHOW_RECT_MSG_ID,
2623                    data).sendToTarget();
2624        }
2625    }
2626
2627    // called by JNI
2628    private void centerFitRect(int x, int y, int width, int height) {
2629        if (mWebView == null) {
2630            return;
2631        }
2632        mWebView.mPrivateHandler.obtainMessage(WebView.CENTER_FIT_RECT,
2633                new Rect(x, y, x + width, y + height)).sendToTarget();
2634    }
2635
2636    // called by JNI
2637    private void setScrollbarModes(int hMode, int vMode) {
2638        if (mWebView == null) {
2639            return;
2640        }
2641        mWebView.mPrivateHandler.obtainMessage(WebView.SET_SCROLLBAR_MODES,
2642                hMode, vMode).sendToTarget();
2643    }
2644
2645    private void useMockDeviceOrientation() {
2646        mDeviceMotionAndOrientationManager.useMock();
2647    }
2648
2649    public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
2650            boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
2651        mDeviceMotionAndOrientationManager.setMockOrientation(canProvideAlpha, alpha,
2652                canProvideBeta, beta, canProvideGamma, gamma);
2653    }
2654
2655    protected DeviceMotionService getDeviceMotionService() {
2656        if (mDeviceMotionService == null) {
2657            mDeviceMotionService =
2658                    new DeviceMotionService(mDeviceMotionAndOrientationManager, mContext);
2659        }
2660        return mDeviceMotionService;
2661    }
2662
2663    protected DeviceOrientationService getDeviceOrientationService() {
2664        if (mDeviceOrientationService == null) {
2665            mDeviceOrientationService =
2666                    new DeviceOrientationService(mDeviceMotionAndOrientationManager, mContext);
2667        }
2668        return mDeviceOrientationService;
2669    }
2670
2671    private native void nativePause();
2672    private native void nativeResume();
2673    private native void nativeFreeMemory();
2674    private native void nativeFullScreenPluginHidden(int npp);
2675    private native boolean nativeValidNodeAndBounds(int frame, int node,
2676            Rect bounds);
2677
2678    private native ArrayList<Rect> nativeGetTouchHighlightRects(int x, int y,
2679            int slop);
2680
2681   private native void nativeAutoFillForm(int queryId);
2682}
2683