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