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