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