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