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