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