WebViewCore.java revision 76064644a73b09ef29c3cd361e450eff88850443
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 try { 60 System.loadLibrary("webcore"); 61 } catch (UnsatisfiedLinkError e) { 62 Log.e(LOGTAG, "Unable to load webcore library"); 63 } 64 } 65 66 /* 67 * WebViewCore always executes in the same thread as the native webkit. 68 */ 69 70 // The WebView that corresponds to this WebViewCore. 71 private WebView mWebView; 72 // Proxy for handling callbacks from native code 73 private final CallbackProxy mCallbackProxy; 74 // Settings object for maintaining all settings 75 private final WebSettings mSettings; 76 // Context for initializing the BrowserFrame with the proper assets. 77 private final Context mContext; 78 // The pointer to a native view object. 79 private int mNativeClass; 80 // The BrowserFrame is an interface to the native Frame component. 81 private BrowserFrame mBrowserFrame; 82 // Custom JS interfaces to add during the initialization. 83 private Map<String, Object> mJavascriptInterfaces; 84 /* 85 * range is from 200 to 10,000. 0 is a special value means device-width. -1 86 * means undefined. 87 */ 88 private int mViewportWidth = -1; 89 90 /* 91 * range is from 200 to 10,000. 0 is a special value means device-height. -1 92 * means undefined. 93 */ 94 private int mViewportHeight = -1; 95 96 /* 97 * scale in percent, range is from 1 to 1000. 0 means undefined. 98 */ 99 private int mViewportInitialScale = 0; 100 101 /* 102 * scale in percent, range is from 1 to 1000. 0 means undefined. 103 */ 104 private int mViewportMinimumScale = 0; 105 106 /* 107 * scale in percent, range is from 1 to 1000. 0 means undefined. 108 */ 109 private int mViewportMaximumScale = 0; 110 111 private boolean mViewportUserScalable = true; 112 113 /* 114 * range is from 70 to 400. 115 * 0 is a special value means device-dpi. The default scale factor will be 116 * always 100. 117 * -1 means undefined. The default scale factor will be 118 * WebView.DEFAULT_SCALE_PERCENT. 119 */ 120 private int mViewportDensityDpi = -1; 121 122 private float mRestoredScale = 0; 123 private float mRestoredTextWrapScale = 0; 124 private int mRestoredX = 0; 125 private int mRestoredY = 0; 126 127 private DeviceMotionAndOrientationManager mDeviceMotionAndOrientationManager = 128 new DeviceMotionAndOrientationManager(this); 129 private DeviceMotionService mDeviceMotionService; 130 private DeviceOrientationService mDeviceOrientationService; 131 132 private int mLowMemoryUsageThresholdMb; 133 private int mHighMemoryUsageThresholdMb; 134 private int mHighUsageDeltaMb; 135 136 // The thread name used to identify the WebCore thread and for use in 137 // debugging other classes that require operation within the WebCore thread. 138 /* package */ static final String THREAD_NAME = "WebViewCoreThread"; 139 140 public WebViewCore(Context context, WebView w, CallbackProxy proxy, 141 Map<String, Object> javascriptInterfaces) { 142 // No need to assign this in the WebCore thread. 143 mCallbackProxy = proxy; 144 mWebView = w; 145 mJavascriptInterfaces = javascriptInterfaces; 146 // This context object is used to initialize the WebViewCore during 147 // subwindow creation. 148 mContext = context; 149 150 // We need to wait for the initial thread creation before sending 151 // a message to the WebCore thread. 152 // XXX: This is the only time the UI thread will wait for the WebCore 153 // thread! 154 synchronized (WebViewCore.class) { 155 if (sWebCoreHandler == null) { 156 // Create a global thread and start it. 157 Thread t = new Thread(new WebCoreThread()); 158 t.setName(THREAD_NAME); 159 t.start(); 160 try { 161 WebViewCore.class.wait(); 162 } catch (InterruptedException e) { 163 Log.e(LOGTAG, "Caught exception while waiting for thread " + 164 "creation."); 165 Log.e(LOGTAG, Log.getStackTraceString(e)); 166 } 167 } 168 } 169 // Create an EventHub to handle messages before and after the thread is 170 // ready. 171 mEventHub = new EventHub(); 172 // Create a WebSettings object for maintaining all settings 173 mSettings = new WebSettings(mContext, mWebView); 174 // The WebIconDatabase needs to be initialized within the UI thread so 175 // just request the instance here. 176 WebIconDatabase.getInstance(); 177 // Create the WebStorage singleton and the UI handler 178 WebStorage.getInstance().createUIHandler(); 179 // Create the UI handler for GeolocationPermissions 180 GeolocationPermissions.getInstance().createUIHandler(); 181 182 // Get the memory class of the current device. V8 will use these values 183 // to GC more effectively. 184 ActivityManager manager = (ActivityManager) mContext.getSystemService( 185 Context.ACTIVITY_SERVICE); 186 ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); 187 manager.getMemoryInfo(memInfo); 188 189 // Allow us to use up to our memory class value before V8's GC kicks in. 190 // These values have been determined by experimentation. 191 mLowMemoryUsageThresholdMb = manager.getLargeMemoryClass(); 192 mHighMemoryUsageThresholdMb = (int) (mLowMemoryUsageThresholdMb * 1.5); 193 // Avoid constant V8 GC when memory usage equals to working set estimate. 194 mHighUsageDeltaMb = mLowMemoryUsageThresholdMb / 32; 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 // EventHub for processing messages 641 private final EventHub mEventHub; 642 // WebCore thread handler 643 private static Handler sWebCoreHandler; 644 // Class for providing Handler creation inside the WebCore thread. 645 private static class WebCoreThread implements Runnable { 646 // Message id for initializing a new WebViewCore. 647 private static final int INITIALIZE = 0; 648 private static final int REDUCE_PRIORITY = 1; 649 private static final int RESUME_PRIORITY = 2; 650 651 public void run() { 652 Looper.prepare(); 653 Assert.assertNull(sWebCoreHandler); 654 synchronized (WebViewCore.class) { 655 sWebCoreHandler = new Handler() { 656 @Override 657 public void handleMessage(Message msg) { 658 switch (msg.what) { 659 case INITIALIZE: 660 WebViewCore core = (WebViewCore) msg.obj; 661 core.initialize(); 662 break; 663 664 case REDUCE_PRIORITY: 665 // 3 is an adjustable number. 666 Process.setThreadPriority( 667 Process.THREAD_PRIORITY_DEFAULT + 3 * 668 Process.THREAD_PRIORITY_LESS_FAVORABLE); 669 break; 670 671 case RESUME_PRIORITY: 672 Process.setThreadPriority( 673 Process.THREAD_PRIORITY_DEFAULT); 674 break; 675 676 case EventHub.ADD_PACKAGE_NAME: 677 if (BrowserFrame.sJavaBridge == null) { 678 throw new IllegalStateException( 679 "No WebView has been created in this process!"); 680 } 681 BrowserFrame.sJavaBridge.addPackageName((String) msg.obj); 682 break; 683 684 case EventHub.REMOVE_PACKAGE_NAME: 685 if (BrowserFrame.sJavaBridge == null) { 686 throw new IllegalStateException( 687 "No WebView has been created in this process!"); 688 } 689 BrowserFrame.sJavaBridge.removePackageName((String) msg.obj); 690 break; 691 692 case EventHub.PROXY_CHANGED: 693 if (BrowserFrame.sJavaBridge == null) { 694 throw new IllegalStateException( 695 "No WebView has been created in this process!"); 696 } 697 BrowserFrame.sJavaBridge.updateProxy((String) msg.obj); 698 break; 699 } 700 } 701 }; 702 WebViewCore.class.notify(); 703 } 704 Looper.loop(); 705 } 706 } 707 708 static class BaseUrlData { 709 String mBaseUrl; 710 String mData; 711 String mMimeType; 712 String mEncoding; 713 String mHistoryUrl; 714 } 715 716 static class CursorData { 717 CursorData() {} 718 CursorData(int frame, int node, int x, int y) { 719 mFrame = frame; 720 mNode = node; 721 mX = x; 722 mY = y; 723 } 724 int mMoveGeneration; 725 int mFrame; 726 int mNode; 727 int mX; 728 int mY; 729 } 730 731 static class JSInterfaceData { 732 Object mObject; 733 String mInterfaceName; 734 } 735 736 static class JSKeyData { 737 String mCurrentText; 738 KeyEvent mEvent; 739 } 740 741 static class MotionUpData { 742 int mFrame; 743 int mNode; 744 Rect mBounds; 745 int mX; 746 int mY; 747 } 748 749 static class GetUrlData { 750 String mUrl; 751 Map<String, String> mExtraHeaders; 752 } 753 754 static class PostUrlData { 755 String mUrl; 756 byte[] mPostData; 757 } 758 759 static class ReplaceTextData { 760 String mReplace; 761 int mNewStart; 762 int mNewEnd; 763 int mTextGeneration; 764 } 765 766 static class TextSelectionData { 767 public TextSelectionData(int start, int end) { 768 mStart = start; 769 mEnd = end; 770 } 771 int mStart; 772 int mEnd; 773 } 774 775 static class TouchUpData { 776 int mMoveGeneration; 777 int mFrame; 778 int mNode; 779 int mX; 780 int mY; 781 int mNativeLayer; 782 Rect mNativeLayerRect = new Rect(); 783 } 784 785 static class TouchHighlightData { 786 int mX; 787 int mY; 788 int mSlop; 789 } 790 791 static class AutoFillData { 792 public AutoFillData() { 793 mQueryId = WebTextView.FORM_NOT_AUTOFILLABLE; 794 mPreview = ""; 795 } 796 797 public AutoFillData(int queryId, String preview) { 798 mQueryId = queryId; 799 mPreview = preview; 800 } 801 802 public int getQueryId() { 803 return mQueryId; 804 } 805 806 public String getPreviewString() { 807 return mPreview; 808 } 809 810 private int mQueryId; 811 private String mPreview; 812 } 813 814 // mAction of TouchEventData can be MotionEvent.getAction() which uses the 815 // last two bytes or one of the following values 816 static final int ACTION_LONGPRESS = 0x100; 817 static final int ACTION_DOUBLETAP = 0x200; 818 819 static class TouchEventData { 820 int mAction; 821 int[] mIds; // Ids of the touch points 822 Point[] mPoints; 823 int mMetaState; 824 boolean mReprocess; 825 MotionEvent mMotionEvent; 826 int mNativeLayer; 827 Rect mNativeLayerRect = new Rect(); 828 } 829 830 static class GeolocationPermissionsData { 831 String mOrigin; 832 boolean mAllow; 833 boolean mRemember; 834 } 835 836 static final String[] HandlerDebugString = { 837 "REVEAL_SELECTION", // 96 838 "REQUEST_LABEL", // 97 839 "UPDATE_FRAME_CACHE_IF_LOADING", // = 98 840 "SCROLL_TEXT_INPUT", // = 99 841 "LOAD_URL", // = 100; 842 "STOP_LOADING", // = 101; 843 "RELOAD", // = 102; 844 "KEY_DOWN", // = 103; 845 "KEY_UP", // = 104; 846 "VIEW_SIZE_CHANGED", // = 105; 847 "GO_BACK_FORWARD", // = 106; 848 "SET_SCROLL_OFFSET", // = 107; 849 "RESTORE_STATE", // = 108; 850 "PAUSE_TIMERS", // = 109; 851 "RESUME_TIMERS", // = 110; 852 "CLEAR_CACHE", // = 111; 853 "CLEAR_HISTORY", // = 112; 854 "SET_SELECTION", // = 113; 855 "REPLACE_TEXT", // = 114; 856 "PASS_TO_JS", // = 115; 857 "SET_GLOBAL_BOUNDS", // = 116; 858 "UPDATE_CACHE_AND_TEXT_ENTRY", // = 117; 859 "CLICK", // = 118; 860 "SET_NETWORK_STATE", // = 119; 861 "DOC_HAS_IMAGES", // = 120; 862 "FAKE_CLICK", // = 121; 863 "DELETE_SELECTION", // = 122; 864 "LISTBOX_CHOICES", // = 123; 865 "SINGLE_LISTBOX_CHOICE", // = 124; 866 "MESSAGE_RELAY", // = 125; 867 "SET_BACKGROUND_COLOR", // = 126; 868 "SET_MOVE_FOCUS", // = 127 869 "SAVE_DOCUMENT_STATE", // = 128; 870 "129", // = 129; 871 "WEBKIT_DRAW", // = 130; 872 "131", // = 131; 873 "POST_URL", // = 132; 874 "SPLIT_PICTURE_SET", // = 133; 875 "CLEAR_CONTENT", // = 134; 876 "SET_MOVE_MOUSE", // = 135; 877 "SET_MOVE_MOUSE_IF_LATEST", // = 136; 878 "REQUEST_CURSOR_HREF", // = 137; 879 "ADD_JS_INTERFACE", // = 138; 880 "LOAD_DATA", // = 139; 881 "TOUCH_UP", // = 140; 882 "TOUCH_EVENT", // = 141; 883 "SET_ACTIVE", // = 142; 884 "ON_PAUSE", // = 143 885 "ON_RESUME", // = 144 886 "FREE_MEMORY", // = 145 887 "VALID_NODE_BOUNDS", // = 146 888 "SAVE_WEBARCHIVE", // = 147 889 "WEBKIT_DRAW_LAYERS", // = 148; 890 "REMOVE_JS_INTERFACE", // = 149; 891 }; 892 893 class EventHub { 894 // Message Ids 895 static final int REVEAL_SELECTION = 96; 896 static final int REQUEST_LABEL = 97; 897 static final int UPDATE_FRAME_CACHE_IF_LOADING = 98; 898 static final int SCROLL_TEXT_INPUT = 99; 899 static final int LOAD_URL = 100; 900 static final int STOP_LOADING = 101; 901 static final int RELOAD = 102; 902 static final int KEY_DOWN = 103; 903 static final int KEY_UP = 104; 904 static final int VIEW_SIZE_CHANGED = 105; 905 static final int GO_BACK_FORWARD = 106; 906 static final int SET_SCROLL_OFFSET = 107; 907 static final int RESTORE_STATE = 108; 908 static final int PAUSE_TIMERS = 109; 909 static final int RESUME_TIMERS = 110; 910 static final int CLEAR_CACHE = 111; 911 static final int CLEAR_HISTORY = 112; 912 static final int SET_SELECTION = 113; 913 static final int REPLACE_TEXT = 114; 914 static final int PASS_TO_JS = 115; 915 static final int SET_GLOBAL_BOUNDS = 116; 916 static final int UPDATE_CACHE_AND_TEXT_ENTRY = 117; 917 static final int CLICK = 118; 918 static final int SET_NETWORK_STATE = 119; 919 static final int DOC_HAS_IMAGES = 120; 920 static final int FAKE_CLICK = 121; 921 static final int DELETE_SELECTION = 122; 922 static final int LISTBOX_CHOICES = 123; 923 static final int SINGLE_LISTBOX_CHOICE = 124; 924 static final int MESSAGE_RELAY = 125; 925 static final int SET_BACKGROUND_COLOR = 126; 926 static final int SET_MOVE_FOCUS = 127; 927 static final int SAVE_DOCUMENT_STATE = 128; 928 929 static final int WEBKIT_DRAW = 130; 930 static final int POST_URL = 132; 931 static final int SPLIT_PICTURE_SET = 133; 932 static final int CLEAR_CONTENT = 134; 933 934 // UI nav messages 935 static final int SET_MOVE_MOUSE = 135; 936 static final int SET_MOVE_MOUSE_IF_LATEST = 136; 937 static final int REQUEST_CURSOR_HREF = 137; 938 static final int ADD_JS_INTERFACE = 138; 939 static final int LOAD_DATA = 139; 940 941 // motion 942 static final int TOUCH_UP = 140; 943 // message used to pass UI touch events to WebCore 944 static final int TOUCH_EVENT = 141; 945 946 // Used to tell the focus controller not to draw the blinking cursor, 947 // based on whether the WebView has focus and whether the WebView's 948 // cursor matches the webpage's focus. 949 static final int SET_ACTIVE = 142; 950 951 // lifecycle activities for just this DOM (unlike pauseTimers, which 952 // is global) 953 static final int ON_PAUSE = 143; 954 static final int ON_RESUME = 144; 955 static final int FREE_MEMORY = 145; 956 static final int VALID_NODE_BOUNDS = 146; 957 958 // Load and save web archives 959 static final int SAVE_WEBARCHIVE = 147; 960 961 // Update layers 962 static final int WEBKIT_DRAW_LAYERS = 148; 963 964 static final int REMOVE_JS_INTERFACE = 149; 965 966 // Network-based messaging 967 static final int CLEAR_SSL_PREF_TABLE = 150; 968 969 // Test harness messages 970 static final int REQUEST_EXT_REPRESENTATION = 160; 971 static final int REQUEST_DOC_AS_TEXT = 161; 972 973 // debugging 974 static final int DUMP_DOMTREE = 170; 975 static final int DUMP_RENDERTREE = 171; 976 static final int DUMP_NAVTREE = 172; 977 static final int DUMP_V8COUNTERS = 173; 978 979 static final int SET_JS_FLAGS = 174; 980 // Geolocation 981 static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180; 982 983 static final int POPULATE_VISITED_LINKS = 181; 984 985 static final int HIDE_FULLSCREEN = 182; 986 987 static final int SET_NETWORK_TYPE = 183; 988 989 // navigator.isApplicationInstalled() 990 static final int ADD_PACKAGE_NAMES = 184; 991 static final int ADD_PACKAGE_NAME = 185; 992 static final int REMOVE_PACKAGE_NAME = 186; 993 994 static final int GET_TOUCH_HIGHLIGHT_RECTS = 187; 995 static final int REMOVE_TOUCH_HIGHLIGHT_RECTS = 188; 996 997 // accessibility support 998 static final int MODIFY_SELECTION = 190; 999 1000 static final int USE_MOCK_DEVICE_ORIENTATION = 191; 1001 1002 static final int AUTOFILL_FORM = 192; 1003 1004 static final int PROXY_CHANGED = 193; 1005 1006 // private message ids 1007 private static final int DESTROY = 200; 1008 1009 // Private handler for WebCore messages. 1010 private Handler mHandler; 1011 // Message queue for containing messages before the WebCore thread is 1012 // ready. 1013 private ArrayList<Message> mMessages = new ArrayList<Message>(); 1014 // Flag for blocking messages. This is used during DESTROY to avoid 1015 // posting more messages to the EventHub or to WebView's event handler. 1016 private boolean mBlockMessages; 1017 1018 private int mTid; 1019 private int mSavedPriority; 1020 1021 /** 1022 * Prevent other classes from creating an EventHub. 1023 */ 1024 private EventHub() {} 1025 1026 private static final int FIRST_PACKAGE_MSG_ID = REVEAL_SELECTION; 1027 private static final int LAST_PACKAGE_MSG_ID = VALID_NODE_BOUNDS; 1028 1029 /** 1030 * Transfer all messages to the newly created webcore thread handler. 1031 */ 1032 private void transferMessages() { 1033 mTid = Process.myTid(); 1034 mSavedPriority = Process.getThreadPriority(mTid); 1035 1036 mHandler = new Handler() { 1037 @Override 1038 public void handleMessage(Message msg) { 1039 if (DebugFlags.WEB_VIEW_CORE) { 1040 Log.v(LOGTAG, (msg.what < FIRST_PACKAGE_MSG_ID 1041 || msg.what > LAST_PACKAGE_MSG_ID 1042 ? Integer.toString(msg.what) 1043 : HandlerDebugString[msg.what 1044 - FIRST_PACKAGE_MSG_ID]) 1045 + " arg1=" + msg.arg1 + " arg2=" + msg.arg2 1046 + " obj=" + msg.obj); 1047 } 1048 switch (msg.what) { 1049 case WEBKIT_DRAW: 1050 webkitDraw(); 1051 break; 1052 1053 case WEBKIT_DRAW_LAYERS: 1054 webkitDrawLayers(); 1055 break; 1056 1057 case DESTROY: 1058 // Time to take down the world. Cancel all pending 1059 // loads and destroy the native view and frame. 1060 synchronized (WebViewCore.this) { 1061 mBrowserFrame.destroy(); 1062 mBrowserFrame = null; 1063 mSettings.onDestroyed(); 1064 mNativeClass = 0; 1065 mWebView = null; 1066 } 1067 break; 1068 1069 case REVEAL_SELECTION: 1070 nativeRevealSelection(); 1071 break; 1072 1073 case REQUEST_LABEL: 1074 if (mWebView != null) { 1075 int nodePointer = msg.arg2; 1076 String label = nativeRequestLabel(msg.arg1, 1077 nodePointer); 1078 if (label != null && label.length() > 0) { 1079 Message.obtain(mWebView.mPrivateHandler, 1080 WebView.RETURN_LABEL, nodePointer, 1081 0, label).sendToTarget(); 1082 } 1083 } 1084 break; 1085 1086 case UPDATE_FRAME_CACHE_IF_LOADING: 1087 nativeUpdateFrameCacheIfLoading(); 1088 break; 1089 1090 case SCROLL_TEXT_INPUT: 1091 float xPercent; 1092 if (msg.obj == null) { 1093 xPercent = 0f; 1094 } else { 1095 xPercent = ((Float) msg.obj).floatValue(); 1096 } 1097 nativeScrollFocusedTextInput(xPercent, msg.arg2); 1098 break; 1099 1100 case LOAD_URL: { 1101 CookieManager.getInstance().waitForCookieOperationsToComplete(); 1102 GetUrlData param = (GetUrlData) msg.obj; 1103 loadUrl(param.mUrl, param.mExtraHeaders); 1104 break; 1105 } 1106 1107 case POST_URL: { 1108 CookieManager.getInstance().waitForCookieOperationsToComplete(); 1109 PostUrlData param = (PostUrlData) msg.obj; 1110 mBrowserFrame.postUrl(param.mUrl, param.mPostData); 1111 break; 1112 } 1113 case LOAD_DATA: 1114 CookieManager.getInstance().waitForCookieOperationsToComplete(); 1115 BaseUrlData loadParams = (BaseUrlData) msg.obj; 1116 String baseUrl = loadParams.mBaseUrl; 1117 if (baseUrl != null) { 1118 int i = baseUrl.indexOf(':'); 1119 if (i > 0) { 1120 /* 1121 * In 1.0, {@link 1122 * WebView#loadDataWithBaseURL} can access 1123 * local asset files as long as the data is 1124 * valid. In the new WebKit, the restriction 1125 * is tightened. To be compatible with 1.0, 1126 * we automatically add the scheme of the 1127 * baseUrl for local access as long as it is 1128 * not http(s)/ftp(s)/about/javascript 1129 */ 1130 String scheme = baseUrl.substring(0, i); 1131 if (!scheme.startsWith("http") && 1132 !scheme.startsWith("ftp") && 1133 !scheme.startsWith("about") && 1134 !scheme.startsWith("javascript")) { 1135 nativeRegisterURLSchemeAsLocal(scheme); 1136 } 1137 } 1138 } 1139 mBrowserFrame.loadData(baseUrl, 1140 loadParams.mData, 1141 loadParams.mMimeType, 1142 loadParams.mEncoding, 1143 loadParams.mHistoryUrl); 1144 break; 1145 1146 case STOP_LOADING: 1147 // If the WebCore has committed the load, but not 1148 // finished the first layout yet, we need to set 1149 // first layout done to trigger the interpreted side sync 1150 // up with native side 1151 if (mBrowserFrame.committed() 1152 && !mBrowserFrame.firstLayoutDone()) { 1153 mBrowserFrame.didFirstLayout(); 1154 } 1155 // Do this after syncing up the layout state. 1156 stopLoading(); 1157 break; 1158 1159 case RELOAD: 1160 mBrowserFrame.reload(false); 1161 break; 1162 1163 case KEY_DOWN: 1164 key((KeyEvent) msg.obj, true); 1165 break; 1166 1167 case KEY_UP: 1168 key((KeyEvent) msg.obj, false); 1169 break; 1170 1171 case FAKE_CLICK: 1172 nativeClick(msg.arg1, msg.arg2, true); 1173 break; 1174 1175 case CLICK: 1176 nativeClick(msg.arg1, msg.arg2, false); 1177 break; 1178 1179 case VIEW_SIZE_CHANGED: { 1180 viewSizeChanged((WebView.ViewSizeData) msg.obj); 1181 break; 1182 } 1183 case SET_SCROLL_OFFSET: 1184 // note: these are in document coordinates 1185 // (inv-zoom) 1186 Point pt = (Point) msg.obj; 1187 nativeSetScrollOffset(msg.arg1, msg.arg2 == 1, 1188 pt.x, pt.y); 1189 break; 1190 1191 case SET_GLOBAL_BOUNDS: 1192 Rect r = (Rect) msg.obj; 1193 nativeSetGlobalBounds(r.left, r.top, r.width(), 1194 r.height()); 1195 break; 1196 1197 case GO_BACK_FORWARD: 1198 // If it is a standard load and the load is not 1199 // committed yet, we interpret BACK as RELOAD 1200 if (!mBrowserFrame.committed() && msg.arg1 == -1 && 1201 (mBrowserFrame.loadType() == 1202 BrowserFrame.FRAME_LOADTYPE_STANDARD)) { 1203 mBrowserFrame.reload(true); 1204 } else { 1205 mBrowserFrame.goBackOrForward(msg.arg1); 1206 } 1207 break; 1208 1209 case RESTORE_STATE: 1210 stopLoading(); 1211 restoreState(msg.arg1); 1212 break; 1213 1214 case PAUSE_TIMERS: 1215 mSavedPriority = Process.getThreadPriority(mTid); 1216 Process.setThreadPriority(mTid, 1217 Process.THREAD_PRIORITY_BACKGROUND); 1218 pauseTimers(); 1219 if (!JniUtil.useChromiumHttpStack()) { 1220 WebViewWorker.getHandler().sendEmptyMessage( 1221 WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION); 1222 } 1223 break; 1224 1225 case RESUME_TIMERS: 1226 Process.setThreadPriority(mTid, mSavedPriority); 1227 resumeTimers(); 1228 if (!JniUtil.useChromiumHttpStack()) { 1229 WebViewWorker.getHandler().sendEmptyMessage( 1230 WebViewWorker.MSG_RESUME_CACHE_TRANSACTION); 1231 } 1232 break; 1233 1234 case ON_PAUSE: 1235 nativePause(); 1236 break; 1237 1238 case ON_RESUME: 1239 nativeResume(); 1240 break; 1241 1242 case FREE_MEMORY: 1243 clearCache(false); 1244 nativeFreeMemory(); 1245 break; 1246 1247 case SET_NETWORK_STATE: 1248 if (BrowserFrame.sJavaBridge == null) { 1249 throw new IllegalStateException("No WebView " + 1250 "has been created in this process!"); 1251 } 1252 BrowserFrame.sJavaBridge 1253 .setNetworkOnLine(msg.arg1 == 1); 1254 break; 1255 1256 case SET_NETWORK_TYPE: 1257 if (BrowserFrame.sJavaBridge == null) { 1258 throw new IllegalStateException("No WebView " + 1259 "has been created in this process!"); 1260 } 1261 Map<String, String> map = (Map<String, String>) msg.obj; 1262 BrowserFrame.sJavaBridge 1263 .setNetworkType(map.get("type"), map.get("subtype")); 1264 break; 1265 1266 case CLEAR_CACHE: 1267 clearCache(msg.arg1 == 1); 1268 break; 1269 1270 case CLEAR_HISTORY: 1271 mCallbackProxy.getBackForwardList(). 1272 close(mBrowserFrame.mNativeFrame); 1273 break; 1274 1275 case REPLACE_TEXT: 1276 ReplaceTextData rep = (ReplaceTextData) msg.obj; 1277 nativeReplaceTextfieldText(msg.arg1, msg.arg2, 1278 rep.mReplace, rep.mNewStart, rep.mNewEnd, 1279 rep.mTextGeneration); 1280 break; 1281 1282 case PASS_TO_JS: { 1283 JSKeyData jsData = (JSKeyData) msg.obj; 1284 KeyEvent evt = jsData.mEvent; 1285 int keyCode = evt.getKeyCode(); 1286 int keyValue = evt.getUnicodeChar(); 1287 int generation = msg.arg1; 1288 passToJs(generation, 1289 jsData.mCurrentText, 1290 keyCode, 1291 keyValue, 1292 evt.isDown(), 1293 evt.isShiftPressed(), evt.isAltPressed(), 1294 evt.isSymPressed()); 1295 break; 1296 } 1297 1298 case SAVE_DOCUMENT_STATE: { 1299 CursorData cDat = (CursorData) msg.obj; 1300 nativeSaveDocumentState(cDat.mFrame); 1301 break; 1302 } 1303 1304 case CLEAR_SSL_PREF_TABLE: 1305 Network.getInstance(mContext) 1306 .clearUserSslPrefTable(); 1307 break; 1308 1309 case TOUCH_UP: 1310 TouchUpData touchUpData = (TouchUpData) msg.obj; 1311 if (touchUpData.mNativeLayer != 0) { 1312 nativeScrollLayer(touchUpData.mNativeLayer, 1313 touchUpData.mNativeLayerRect); 1314 } 1315 nativeTouchUp(touchUpData.mMoveGeneration, 1316 touchUpData.mFrame, touchUpData.mNode, 1317 touchUpData.mX, touchUpData.mY); 1318 break; 1319 1320 case TOUCH_EVENT: { 1321 TouchEventData ted = (TouchEventData) msg.obj; 1322 final int count = ted.mPoints.length; 1323 int[] xArray = new int[count]; 1324 int[] yArray = new int[count]; 1325 for (int c = 0; c < count; c++) { 1326 xArray[c] = ted.mPoints[c].x; 1327 yArray[c] = ted.mPoints[c].y; 1328 } 1329 if (ted.mNativeLayer != 0) { 1330 nativeScrollLayer(ted.mNativeLayer, 1331 ted.mNativeLayerRect); 1332 } 1333 Message.obtain( 1334 mWebView.mPrivateHandler, 1335 WebView.PREVENT_TOUCH_ID, 1336 ted.mAction, 1337 nativeHandleTouchEvent(ted.mAction, ted.mIds, 1338 xArray, yArray, count, ted.mMetaState) ? 1 : 0, 1339 ted.mReprocess ? ted : null).sendToTarget(); 1340 break; 1341 } 1342 1343 case SET_ACTIVE: 1344 nativeSetFocusControllerActive(msg.arg1 == 1); 1345 break; 1346 1347 case ADD_JS_INTERFACE: 1348 JSInterfaceData jsData = (JSInterfaceData) msg.obj; 1349 mBrowserFrame.addJavascriptInterface(jsData.mObject, 1350 jsData.mInterfaceName); 1351 break; 1352 1353 case REMOVE_JS_INTERFACE: 1354 jsData = (JSInterfaceData) msg.obj; 1355 mBrowserFrame.removeJavascriptInterface( 1356 jsData.mInterfaceName); 1357 break; 1358 1359 case REQUEST_EXT_REPRESENTATION: 1360 mBrowserFrame.externalRepresentation( 1361 (Message) msg.obj); 1362 break; 1363 1364 case REQUEST_DOC_AS_TEXT: 1365 mBrowserFrame.documentAsText((Message) msg.obj); 1366 break; 1367 1368 case SET_MOVE_FOCUS: 1369 CursorData focusData = (CursorData) msg.obj; 1370 nativeMoveFocus(focusData.mFrame, focusData.mNode); 1371 break; 1372 1373 case SET_MOVE_MOUSE: 1374 CursorData cursorData = (CursorData) msg.obj; 1375 nativeMoveMouse(cursorData.mFrame, 1376 cursorData.mX, cursorData.mY); 1377 break; 1378 1379 case SET_MOVE_MOUSE_IF_LATEST: 1380 CursorData cData = (CursorData) msg.obj; 1381 nativeMoveMouseIfLatest(cData.mMoveGeneration, 1382 cData.mFrame, 1383 cData.mX, cData.mY); 1384 break; 1385 1386 case REQUEST_CURSOR_HREF: { 1387 Message hrefMsg = (Message) msg.obj; 1388 hrefMsg.getData().putString("url", 1389 nativeRetrieveHref(msg.arg1, msg.arg2)); 1390 hrefMsg.getData().putString("title", 1391 nativeRetrieveAnchorText(msg.arg1, msg.arg2)); 1392 hrefMsg.getData().putString("src", 1393 nativeRetrieveImageSource(msg.arg1, msg.arg2)); 1394 hrefMsg.sendToTarget(); 1395 break; 1396 } 1397 1398 case UPDATE_CACHE_AND_TEXT_ENTRY: 1399 nativeUpdateFrameCache(); 1400 // FIXME: this should provide a minimal rectangle 1401 if (mWebView != null) { 1402 mWebView.postInvalidate(); 1403 } 1404 sendUpdateTextEntry(); 1405 break; 1406 1407 case DOC_HAS_IMAGES: 1408 Message imageResult = (Message) msg.obj; 1409 imageResult.arg1 = 1410 mBrowserFrame.documentHasImages() ? 1 : 0; 1411 imageResult.sendToTarget(); 1412 break; 1413 1414 case DELETE_SELECTION: 1415 TextSelectionData deleteSelectionData 1416 = (TextSelectionData) msg.obj; 1417 nativeDeleteSelection(deleteSelectionData.mStart, 1418 deleteSelectionData.mEnd, msg.arg1); 1419 break; 1420 1421 case SET_SELECTION: 1422 nativeSetSelection(msg.arg1, msg.arg2); 1423 break; 1424 1425 case MODIFY_SELECTION: 1426 String modifiedSelectionString = nativeModifySelection(msg.arg1, 1427 msg.arg2); 1428 mWebView.mPrivateHandler.obtainMessage(WebView.SELECTION_STRING_CHANGED, 1429 modifiedSelectionString).sendToTarget(); 1430 break; 1431 1432 case LISTBOX_CHOICES: 1433 SparseBooleanArray choices = (SparseBooleanArray) 1434 msg.obj; 1435 int choicesSize = msg.arg1; 1436 boolean[] choicesArray = new boolean[choicesSize]; 1437 for (int c = 0; c < choicesSize; c++) { 1438 choicesArray[c] = choices.get(c); 1439 } 1440 nativeSendListBoxChoices(choicesArray, 1441 choicesSize); 1442 break; 1443 1444 case SINGLE_LISTBOX_CHOICE: 1445 nativeSendListBoxChoice(msg.arg1); 1446 break; 1447 1448 case SET_BACKGROUND_COLOR: 1449 nativeSetBackgroundColor(msg.arg1); 1450 break; 1451 1452 case DUMP_DOMTREE: 1453 nativeDumpDomTree(msg.arg1 == 1); 1454 break; 1455 1456 case DUMP_RENDERTREE: 1457 nativeDumpRenderTree(msg.arg1 == 1); 1458 break; 1459 1460 case DUMP_NAVTREE: 1461 nativeDumpNavTree(); 1462 break; 1463 1464 case DUMP_V8COUNTERS: 1465 nativeDumpV8Counters(); 1466 break; 1467 1468 case SET_JS_FLAGS: 1469 nativeSetJsFlags((String)msg.obj); 1470 break; 1471 1472 case SAVE_WEBARCHIVE: 1473 WebView.SaveWebArchiveMessage saveMessage = 1474 (WebView.SaveWebArchiveMessage)msg.obj; 1475 saveMessage.mResultFile = 1476 saveWebArchive(saveMessage.mBasename, saveMessage.mAutoname); 1477 mWebView.mPrivateHandler.obtainMessage( 1478 WebView.SAVE_WEBARCHIVE_FINISHED, saveMessage).sendToTarget(); 1479 break; 1480 1481 case GEOLOCATION_PERMISSIONS_PROVIDE: 1482 GeolocationPermissionsData data = 1483 (GeolocationPermissionsData) msg.obj; 1484 nativeGeolocationPermissionsProvide(data.mOrigin, 1485 data.mAllow, data.mRemember); 1486 break; 1487 1488 case SPLIT_PICTURE_SET: 1489 nativeSplitContent(msg.arg1); 1490 mWebView.mPrivateHandler.obtainMessage( 1491 WebView.REPLACE_BASE_CONTENT, msg.arg1, 0); 1492 mSplitPictureIsScheduled = false; 1493 break; 1494 1495 case CLEAR_CONTENT: 1496 // Clear the view so that onDraw() will draw nothing 1497 // but white background 1498 // (See public method WebView.clearView) 1499 nativeClearContent(); 1500 break; 1501 1502 case MESSAGE_RELAY: 1503 ((Message) msg.obj).sendToTarget(); 1504 break; 1505 1506 case POPULATE_VISITED_LINKS: 1507 nativeProvideVisitedHistory((String[])msg.obj); 1508 break; 1509 1510 case VALID_NODE_BOUNDS: { 1511 MotionUpData motionUpData = (MotionUpData) msg.obj; 1512 if (!nativeValidNodeAndBounds( 1513 motionUpData.mFrame, motionUpData.mNode, 1514 motionUpData.mBounds)) { 1515 nativeUpdateFrameCache(); 1516 } 1517 Message message = mWebView.mPrivateHandler 1518 .obtainMessage(WebView.DO_MOTION_UP, 1519 motionUpData.mX, motionUpData.mY); 1520 mWebView.mPrivateHandler.sendMessageAtFrontOfQueue( 1521 message); 1522 break; 1523 } 1524 1525 case HIDE_FULLSCREEN: 1526 nativeFullScreenPluginHidden(msg.arg1); 1527 break; 1528 1529 case ADD_PACKAGE_NAMES: 1530 if (BrowserFrame.sJavaBridge == null) { 1531 throw new IllegalStateException("No WebView " + 1532 "has been created in this process!"); 1533 } 1534 BrowserFrame.sJavaBridge.addPackageNames( 1535 (Set<String>) msg.obj); 1536 break; 1537 1538 case GET_TOUCH_HIGHLIGHT_RECTS: 1539 TouchHighlightData d = (TouchHighlightData) msg.obj; 1540 ArrayList<Rect> rects = nativeGetTouchHighlightRects 1541 (d.mX, d.mY, d.mSlop); 1542 mWebView.mPrivateHandler.obtainMessage( 1543 WebView.SET_TOUCH_HIGHLIGHT_RECTS, rects) 1544 .sendToTarget(); 1545 break; 1546 1547 case REMOVE_TOUCH_HIGHLIGHT_RECTS: 1548 mWebView.mPrivateHandler.obtainMessage( 1549 WebView.SET_TOUCH_HIGHLIGHT_RECTS, null) 1550 .sendToTarget(); 1551 break; 1552 1553 case USE_MOCK_DEVICE_ORIENTATION: 1554 useMockDeviceOrientation(); 1555 break; 1556 1557 case AUTOFILL_FORM: 1558 nativeAutoFillForm(msg.arg1); 1559 mWebView.mPrivateHandler.obtainMessage(WebView.AUTOFILL_COMPLETE, null) 1560 .sendToTarget(); 1561 break; 1562 } 1563 } 1564 }; 1565 // Take all queued messages and resend them to the new handler. 1566 synchronized (this) { 1567 int size = mMessages.size(); 1568 for (int i = 0; i < size; i++) { 1569 mHandler.sendMessage(mMessages.get(i)); 1570 } 1571 mMessages = null; 1572 } 1573 } 1574 1575 /** 1576 * Send a message internally to the queue or to the handler 1577 */ 1578 private synchronized void sendMessage(Message msg) { 1579 if (mBlockMessages) { 1580 return; 1581 } 1582 if (mMessages != null) { 1583 mMessages.add(msg); 1584 } else { 1585 mHandler.sendMessage(msg); 1586 } 1587 } 1588 1589 private synchronized void removeMessages(int what) { 1590 if (mBlockMessages) { 1591 return; 1592 } 1593 if (what == EventHub.WEBKIT_DRAW) { 1594 mDrawIsScheduled = false; 1595 } 1596 if (mMessages != null) { 1597 Log.w(LOGTAG, "Not supported in this case."); 1598 } else { 1599 mHandler.removeMessages(what); 1600 } 1601 } 1602 1603 private synchronized boolean hasMessages(int what) { 1604 if (mBlockMessages) { 1605 return false; 1606 } 1607 if (mMessages != null) { 1608 Log.w(LOGTAG, "hasMessages() is not supported in this case."); 1609 return false; 1610 } else { 1611 return mHandler.hasMessages(what); 1612 } 1613 } 1614 1615 private synchronized void sendMessageDelayed(Message msg, long delay) { 1616 if (mBlockMessages) { 1617 return; 1618 } 1619 mHandler.sendMessageDelayed(msg, delay); 1620 } 1621 1622 /** 1623 * Send a message internally to the front of the queue. 1624 */ 1625 private synchronized void sendMessageAtFrontOfQueue(Message msg) { 1626 if (mBlockMessages) { 1627 return; 1628 } 1629 if (mMessages != null) { 1630 mMessages.add(0, msg); 1631 } else { 1632 mHandler.sendMessageAtFrontOfQueue(msg); 1633 } 1634 } 1635 1636 /** 1637 * Remove all the messages. 1638 */ 1639 private synchronized void removeMessages() { 1640 // reset mDrawIsScheduled flag as WEBKIT_DRAW may be removed 1641 mDrawIsScheduled = false; 1642 mSplitPictureIsScheduled = false; 1643 if (mMessages != null) { 1644 mMessages.clear(); 1645 } else { 1646 mHandler.removeCallbacksAndMessages(null); 1647 } 1648 } 1649 1650 /** 1651 * Block sending messages to the EventHub. 1652 */ 1653 private synchronized void blockMessages() { 1654 mBlockMessages = true; 1655 } 1656 } 1657 1658 //------------------------------------------------------------------------- 1659 // Methods called by host activity (in the same thread) 1660 //------------------------------------------------------------------------- 1661 1662 void stopLoading() { 1663 if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "CORE stopLoading"); 1664 if (mBrowserFrame != null) { 1665 mBrowserFrame.stopLoading(); 1666 } 1667 } 1668 1669 //------------------------------------------------------------------------- 1670 // Methods called by WebView 1671 // If it refers to local variable, it needs synchronized(). 1672 // If it needs WebCore, it has to send message. 1673 //------------------------------------------------------------------------- 1674 1675 void sendMessage(Message msg) { 1676 mEventHub.sendMessage(msg); 1677 } 1678 1679 void sendMessage(int what) { 1680 mEventHub.sendMessage(Message.obtain(null, what)); 1681 } 1682 1683 void sendMessage(int what, Object obj) { 1684 mEventHub.sendMessage(Message.obtain(null, what, obj)); 1685 } 1686 1687 void sendMessage(int what, int arg1) { 1688 // just ignore the second argument (make it 0) 1689 mEventHub.sendMessage(Message.obtain(null, what, arg1, 0)); 1690 } 1691 1692 void sendMessage(int what, int arg1, int arg2) { 1693 mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2)); 1694 } 1695 1696 void sendMessage(int what, int arg1, Object obj) { 1697 // just ignore the second argument (make it 0) 1698 mEventHub.sendMessage(Message.obtain(null, what, arg1, 0, obj)); 1699 } 1700 1701 void sendMessage(int what, int arg1, int arg2, Object obj) { 1702 mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2, obj)); 1703 } 1704 1705 void sendMessageAtFrontOfQueue(int what, Object obj) { 1706 mEventHub.sendMessageAtFrontOfQueue(Message.obtain( 1707 null, what, obj)); 1708 } 1709 1710 void sendMessageDelayed(int what, Object obj, long delay) { 1711 mEventHub.sendMessageDelayed(Message.obtain(null, what, obj), delay); 1712 } 1713 1714 void removeMessages(int what) { 1715 mEventHub.removeMessages(what); 1716 } 1717 1718 void removeMessages() { 1719 mEventHub.removeMessages(); 1720 } 1721 1722 /** 1723 * Removes pending messages and trigger a DESTROY message to send to 1724 * WebCore. 1725 * Called from UI thread. 1726 */ 1727 void destroy() { 1728 // We don't want anyone to post a message between removing pending 1729 // messages and sending the destroy message. 1730 synchronized (mEventHub) { 1731 // RESUME_TIMERS and PAUSE_TIMERS are per process base. They need to 1732 // be preserved even the WebView is destroyed. 1733 // Note: we should not have more than one RESUME_TIMERS/PAUSE_TIMERS 1734 boolean hasResume = mEventHub.hasMessages(EventHub.RESUME_TIMERS); 1735 boolean hasPause = mEventHub.hasMessages(EventHub.PAUSE_TIMERS); 1736 mEventHub.removeMessages(); 1737 mEventHub.sendMessageAtFrontOfQueue( 1738 Message.obtain(null, EventHub.DESTROY)); 1739 if (hasPause) { 1740 mEventHub.sendMessageAtFrontOfQueue( 1741 Message.obtain(null, EventHub.PAUSE_TIMERS)); 1742 } 1743 if (hasResume) { 1744 mEventHub.sendMessageAtFrontOfQueue( 1745 Message.obtain(null, EventHub.RESUME_TIMERS)); 1746 } 1747 mEventHub.blockMessages(); 1748 } 1749 } 1750 1751 //------------------------------------------------------------------------- 1752 // WebViewCore private methods 1753 //------------------------------------------------------------------------- 1754 1755 private void clearCache(boolean includeDiskFiles) { 1756 mBrowserFrame.clearCache(); 1757 if (includeDiskFiles) { 1758 CacheManager.removeAllCacheFiles(); 1759 } 1760 } 1761 1762 private void loadUrl(String url, Map<String, String> extraHeaders) { 1763 if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, " CORE loadUrl " + url); 1764 mBrowserFrame.loadUrl(url, extraHeaders); 1765 } 1766 1767 private String saveWebArchive(String filename, boolean autoname) { 1768 if (DebugFlags.WEB_VIEW_CORE) { 1769 Log.v(LOGTAG, " CORE saveWebArchive " + filename + " " + autoname); 1770 } 1771 return mBrowserFrame.saveWebArchive(filename, autoname); 1772 } 1773 1774 private void key(KeyEvent evt, boolean isDown) { 1775 if (DebugFlags.WEB_VIEW_CORE) { 1776 Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", " 1777 + evt); 1778 } 1779 int keyCode = evt.getKeyCode(); 1780 int unicodeChar = evt.getUnicodeChar(); 1781 1782 if (keyCode == KeyEvent.KEYCODE_UNKNOWN && evt.getCharacters() != null 1783 && evt.getCharacters().length() > 0) { 1784 // we should only receive individual complex characters 1785 unicodeChar = evt.getCharacters().codePointAt(0); 1786 } 1787 1788 if (!nativeKey(keyCode, unicodeChar, evt.getRepeatCount(), evt.isShiftPressed(), 1789 evt.isAltPressed(), evt.isSymPressed(), 1790 isDown) && keyCode != KeyEvent.KEYCODE_ENTER) { 1791 if (keyCode >= KeyEvent.KEYCODE_DPAD_UP 1792 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) { 1793 if (DebugFlags.WEB_VIEW_CORE) { 1794 Log.v(LOGTAG, "key: arrow unused by page: " + keyCode); 1795 } 1796 if (mWebView != null && evt.isDown()) { 1797 Message.obtain(mWebView.mPrivateHandler, 1798 WebView.UNHANDLED_NAV_KEY, keyCode, 1799 0).sendToTarget(); 1800 } 1801 return; 1802 } 1803 // bubble up the event handling 1804 // but do not bubble up the ENTER key, which would open the search 1805 // bar without any text. 1806 mCallbackProxy.onUnhandledKeyEvent(evt); 1807 } 1808 } 1809 1810 // These values are used to avoid requesting a layout based on old values 1811 private int mCurrentViewWidth = 0; 1812 private int mCurrentViewHeight = 0; 1813 private float mCurrentViewScale = 1.0f; 1814 1815 // notify webkit that our virtual view size changed size (after inv-zoom) 1816 private void viewSizeChanged(WebView.ViewSizeData data) { 1817 int w = data.mWidth; 1818 int h = data.mHeight; 1819 int textwrapWidth = data.mTextWrapWidth; 1820 float scale = data.mScale; 1821 if (DebugFlags.WEB_VIEW_CORE) { 1822 Log.v(LOGTAG, "viewSizeChanged w=" + w + "; h=" + h 1823 + "; textwrapWidth=" + textwrapWidth + "; scale=" + scale); 1824 } 1825 if (w == 0) { 1826 Log.w(LOGTAG, "skip viewSizeChanged as w is 0"); 1827 return; 1828 } 1829 int width = calculateWindowWidth(w, textwrapWidth); 1830 int height = h; 1831 if (width != w) { 1832 float heightWidthRatio = data.mHeightWidthRatio; 1833 float ratio = (heightWidthRatio > 0) ? heightWidthRatio : (float) h / w; 1834 height = Math.round(ratio * width); 1835 } 1836 nativeSetSize(width, height, textwrapWidth, scale, w, 1837 data.mActualViewHeight > 0 ? data.mActualViewHeight : h, 1838 data.mAnchorX, data.mAnchorY, data.mIgnoreHeight); 1839 // Remember the current width and height 1840 boolean needInvalidate = (mCurrentViewWidth == 0); 1841 mCurrentViewWidth = w; 1842 mCurrentViewHeight = h; 1843 mCurrentViewScale = scale; 1844 if (needInvalidate) { 1845 // ensure {@link #webkitDraw} is called as we were blocking in 1846 // {@link #contentDraw} when mCurrentViewWidth is 0 1847 if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "viewSizeChanged"); 1848 contentDraw(); 1849 } 1850 mEventHub.sendMessage(Message.obtain(null, 1851 EventHub.UPDATE_CACHE_AND_TEXT_ENTRY)); 1852 } 1853 1854 // Calculate width to be used in webkit window. 1855 private int calculateWindowWidth(int viewWidth, int textwrapWidth) { 1856 int width = viewWidth; 1857 if (mSettings.getUseWideViewPort()) { 1858 if (mViewportWidth == -1) { 1859 if (mSettings.getLayoutAlgorithm() == 1860 WebSettings.LayoutAlgorithm.NORMAL || mSettings.getUseFixedViewport()) { 1861 width = WebView.DEFAULT_VIEWPORT_WIDTH; 1862 } else { 1863 /* 1864 * if a page's minimum preferred width is wider than the 1865 * given "w", use it instead to get better layout result. If 1866 * we start a page with MAX_ZOOM_WIDTH, "w" will be always 1867 * wider. If we start a page with screen width, due to the 1868 * delay between {@link #didFirstLayout} and 1869 * {@link #viewSizeChanged}, 1870 * {@link #nativeGetContentMinPrefWidth} will return a more 1871 * accurate value than initial 0 to result a better layout. 1872 * In the worse case, the native width will be adjusted when 1873 * next zoom or screen orientation change happens. 1874 */ 1875 width = Math.min(WebView.sMaxViewportWidth, Math.max(viewWidth, 1876 Math.max(WebView.DEFAULT_VIEWPORT_WIDTH, 1877 nativeGetContentMinPrefWidth()))); 1878 } 1879 } else if (mViewportWidth > 0) { 1880 if (mSettings.getUseFixedViewport()) { 1881 // Use website specified or desired fixed viewport width. 1882 width = mViewportWidth; 1883 } else { 1884 width = Math.max(viewWidth, mViewportWidth); 1885 } 1886 } else if (mSettings.getUseFixedViewport()) { 1887 width = mWebView.getViewWidth(); 1888 } else { 1889 width = textwrapWidth; 1890 } 1891 } 1892 return width; 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 } 2014 } 2015 2016 static void reducePriority() { 2017 // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages 2018 sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY); 2019 sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY); 2020 sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler 2021 .obtainMessage(WebCoreThread.REDUCE_PRIORITY)); 2022 } 2023 2024 static void resumePriority() { 2025 // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages 2026 sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY); 2027 sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY); 2028 sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler 2029 .obtainMessage(WebCoreThread.RESUME_PRIORITY)); 2030 } 2031 2032 static void sendStaticMessage(int messageType, Object argument) { 2033 if (sWebCoreHandler == null) 2034 return; 2035 2036 sWebCoreHandler.sendMessage(sWebCoreHandler.obtainMessage(messageType, argument)); 2037 } 2038 2039 static void pauseUpdatePicture(WebViewCore core) { 2040 // Note: there is one possible failure mode. If pauseUpdatePicture() is 2041 // called from UI thread while WEBKIT_DRAW is just pulled out of the 2042 // queue in WebCore thread to be executed. Then update won't be blocked. 2043 if (core != null) { 2044 if (!core.getSettings().enableSmoothTransition()) return; 2045 2046 synchronized (core) { 2047 core.mDrawIsPaused = true; 2048 if (core.mDrawIsScheduled) { 2049 core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW); 2050 } 2051 } 2052 } 2053 2054 } 2055 2056 static void resumeUpdatePicture(WebViewCore core) { 2057 if (core != null) { 2058 // if mDrawIsPaused is true, ignore the setting, continue to resume 2059 if (!core.mDrawIsPaused 2060 && !core.getSettings().enableSmoothTransition()) return; 2061 2062 synchronized (core) { 2063 core.mDrawIsPaused = false; 2064 // always redraw on resume to reenable gif animations 2065 core.mDrawIsScheduled = false; 2066 core.nativeContentInvalidateAll(); 2067 core.contentDraw(); 2068 } 2069 } 2070 } 2071 2072 ////////////////////////////////////////////////////////////////////////// 2073 2074 private void restoreState(int index) { 2075 WebBackForwardList list = mCallbackProxy.getBackForwardList(); 2076 int size = list.getSize(); 2077 for (int i = 0; i < size; i++) { 2078 list.getItemAtIndex(i).inflate(mBrowserFrame.mNativeFrame); 2079 } 2080 mBrowserFrame.mLoadInitFromJava = true; 2081 list.restoreIndex(mBrowserFrame.mNativeFrame, index); 2082 mBrowserFrame.mLoadInitFromJava = false; 2083 } 2084 2085 //------------------------------------------------------------------------- 2086 // Implement abstract methods in WebViewCore, native WebKit callback part 2087 //------------------------------------------------------------------------- 2088 2089 // called from JNI or WebView thread 2090 /* package */ void contentDraw() { 2091 // don't update the Picture until we have an initial width and finish 2092 // the first layout 2093 if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) { 2094 return; 2095 } 2096 // only fire an event if this is our first request 2097 synchronized (this) { 2098 if (mDrawIsScheduled) return; 2099 mDrawIsScheduled = true; 2100 if (mDrawIsPaused) return; 2101 mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW)); 2102 } 2103 } 2104 2105 // called from JNI 2106 void layersDraw() { 2107 synchronized (this) { 2108 if (mDrawLayersIsScheduled) return; 2109 mDrawLayersIsScheduled = true; 2110 mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW_LAYERS)); 2111 } 2112 } 2113 2114 // called by JNI 2115 private void contentScrollTo(int x, int y, boolean animate, 2116 boolean onlyIfImeIsShowing) { 2117 if (!mBrowserFrame.firstLayoutDone()) { 2118 /* 2119 * WebKit restore state will be called before didFirstLayout(), 2120 * remember the position as it has to be applied after restoring 2121 * zoom factor which is controlled by screenWidth. 2122 */ 2123 mRestoredX = x; 2124 mRestoredY = y; 2125 return; 2126 } 2127 if (mWebView != null) { 2128 Message msg = Message.obtain(mWebView.mPrivateHandler, 2129 WebView.SCROLL_TO_MSG_ID, animate ? 1 : 0, 2130 onlyIfImeIsShowing ? 1 : 0, new Point(x, y)); 2131 if (mDrawIsScheduled) { 2132 mEventHub.sendMessage(Message.obtain(null, 2133 EventHub.MESSAGE_RELAY, msg)); 2134 } else { 2135 msg.sendToTarget(); 2136 } 2137 } 2138 } 2139 2140 // called by JNI 2141 private void sendNotifyProgressFinished() { 2142 sendUpdateTextEntry(); 2143 if (!JniUtil.useChromiumHttpStack()) { 2144 // as CacheManager can behave based on database transaction, we need to 2145 // call tick() to trigger endTransaction 2146 WebViewWorker.getHandler().removeMessages( 2147 WebViewWorker.MSG_CACHE_TRANSACTION_TICKER); 2148 WebViewWorker.getHandler().sendEmptyMessage( 2149 WebViewWorker.MSG_CACHE_TRANSACTION_TICKER); 2150 } 2151 contentDraw(); 2152 } 2153 2154 /* Called by JNI. The coordinates are in doc coordinates, so they need to 2155 be scaled before they can be used by the view system, which happens 2156 in WebView since it (and its thread) know the current scale factor. 2157 */ 2158 private void sendViewInvalidate(int left, int top, int right, int bottom) { 2159 if (mWebView != null) { 2160 Message.obtain(mWebView.mPrivateHandler, 2161 WebView.INVAL_RECT_MSG_ID, 2162 new Rect(left, top, right, bottom)).sendToTarget(); 2163 } 2164 } 2165 2166 private static boolean mRepaintScheduled = false; 2167 2168 /* 2169 * Called by the WebView thread 2170 */ 2171 /* package */ void signalRepaintDone() { 2172 mRepaintScheduled = false; 2173 } 2174 2175 /* package */ WebView getWebView() { 2176 return mWebView; 2177 } 2178 2179 private native void setViewportSettingsFromNative(); 2180 2181 // called by JNI 2182 private void didFirstLayout(boolean standardLoad) { 2183 if (DebugFlags.WEB_VIEW_CORE) { 2184 Log.v(LOGTAG, "didFirstLayout standardLoad =" + standardLoad); 2185 } 2186 2187 mBrowserFrame.didFirstLayout(); 2188 2189 if (mWebView == null) return; 2190 2191 boolean updateViewState = standardLoad || mRestoredScale > 0; 2192 setupViewport(updateViewState); 2193 // if updateRestoreState is true, ViewManager.postReadyToDrawAll() will 2194 // be called after the WebView updates its state. If updateRestoreState 2195 // is false, start to draw now as it is ready. 2196 if (!updateViewState) { 2197 mWebView.mViewManager.postReadyToDrawAll(); 2198 } 2199 2200 // remove the touch highlight when moving to a new page 2201 if (getSettings().supportTouchOnly()) { 2202 mEventHub.sendMessage(Message.obtain(null, 2203 EventHub.REMOVE_TOUCH_HIGHLIGHT_RECTS)); 2204 } 2205 2206 // reset the scroll position, the restored offset and scales 2207 mRestoredX = mRestoredY = 0; 2208 mRestoredScale = mRestoredTextWrapScale = 0; 2209 } 2210 2211 // called by JNI 2212 private void updateViewport() { 2213 // if updateViewport is called before first layout, wait until first 2214 // layout to update the viewport. In the rare case, this is called after 2215 // first layout, force an update as we have just parsed the viewport 2216 // meta tag. 2217 if (mBrowserFrame.firstLayoutDone()) { 2218 setupViewport(true); 2219 } 2220 } 2221 2222 private void setupViewport(boolean updateViewState) { 2223 // set the viewport settings from WebKit 2224 setViewportSettingsFromNative(); 2225 2226 // adjust the default scale to match the densityDpi 2227 float adjust = 1.0f; 2228 if (mViewportDensityDpi == -1) { 2229 // convert default zoom scale to a integer (percentage) to avoid any 2230 // issues with floating point comparisons 2231 if (mWebView != null && (int)(mWebView.getDefaultZoomScale() * 100) != 100) { 2232 adjust = mWebView.getDefaultZoomScale(); 2233 } 2234 } else if (mViewportDensityDpi > 0) { 2235 adjust = (float) mContext.getResources().getDisplayMetrics().densityDpi 2236 / mViewportDensityDpi; 2237 } 2238 int defaultScale = (int) (adjust * 100); 2239 2240 if (mViewportInitialScale > 0) { 2241 mViewportInitialScale *= adjust; 2242 } 2243 if (mViewportMinimumScale > 0) { 2244 mViewportMinimumScale *= adjust; 2245 } 2246 if (mViewportMaximumScale > 0) { 2247 mViewportMaximumScale *= adjust; 2248 } 2249 2250 // infer the values if they are not defined. 2251 if (mViewportWidth == 0) { 2252 if (mViewportInitialScale == 0) { 2253 mViewportInitialScale = defaultScale; 2254 } 2255 } 2256 if (mViewportUserScalable == false) { 2257 mViewportInitialScale = defaultScale; 2258 mViewportMinimumScale = defaultScale; 2259 mViewportMaximumScale = defaultScale; 2260 } 2261 if (mViewportMinimumScale > mViewportInitialScale 2262 && mViewportInitialScale != 0) { 2263 mViewportMinimumScale = mViewportInitialScale; 2264 } 2265 if (mViewportMaximumScale > 0 2266 && mViewportMaximumScale < mViewportInitialScale) { 2267 mViewportMaximumScale = mViewportInitialScale; 2268 } 2269 if (mViewportWidth < 0 && mViewportInitialScale == defaultScale) { 2270 mViewportWidth = 0; 2271 } 2272 2273 // if mViewportWidth is 0, it means device-width, always update. 2274 if (mViewportWidth != 0 && !updateViewState) { 2275 ViewState viewState = new ViewState(); 2276 viewState.mMinScale = mViewportMinimumScale / 100.0f; 2277 viewState.mMaxScale = mViewportMaximumScale / 100.0f; 2278 viewState.mDefaultScale = adjust; 2279 // as mViewportWidth is not 0, it is not mobile site. 2280 viewState.mMobileSite = false; 2281 // for non-mobile site, we don't need minPrefWidth, set it as 0 2282 viewState.mScrollX = 0; 2283 Message.obtain(mWebView.mPrivateHandler, 2284 WebView.UPDATE_ZOOM_RANGE, viewState).sendToTarget(); 2285 return; 2286 } 2287 2288 // now notify webview 2289 // webViewWidth refers to the width in the view system 2290 int webViewWidth; 2291 // viewportWidth refers to the width in the document system 2292 int viewportWidth = mCurrentViewWidth; 2293 if (viewportWidth == 0) { 2294 // this may happen when WebView just starts. This is not perfect as 2295 // we call WebView method from WebCore thread. But not perfect 2296 // reference is better than no reference. 2297 webViewWidth = mWebView.getViewWidth(); 2298 viewportWidth = (int) (webViewWidth / adjust); 2299 if (viewportWidth == 0) { 2300 Log.w(LOGTAG, "Can't get the viewWidth after the first layout"); 2301 } 2302 } else { 2303 webViewWidth = Math.round(viewportWidth * mCurrentViewScale); 2304 } 2305 mInitialViewState = new ViewState(); 2306 mInitialViewState.mMinScale = mViewportMinimumScale / 100.0f; 2307 mInitialViewState.mMaxScale = mViewportMaximumScale / 100.0f; 2308 mInitialViewState.mDefaultScale = adjust; 2309 mInitialViewState.mScrollX = mRestoredX; 2310 mInitialViewState.mScrollY = mRestoredY; 2311 mInitialViewState.mMobileSite = (0 == mViewportWidth); 2312 if (mRestoredScale > 0) { 2313 mInitialViewState.mIsRestored = true; 2314 mInitialViewState.mViewScale = mRestoredScale; 2315 if (mRestoredTextWrapScale > 0) { 2316 mInitialViewState.mTextWrapScale = mRestoredTextWrapScale; 2317 } else { 2318 mInitialViewState.mTextWrapScale = mInitialViewState.mViewScale; 2319 } 2320 } else { 2321 if (mViewportInitialScale > 0) { 2322 mInitialViewState.mViewScale = mInitialViewState.mTextWrapScale = 2323 mViewportInitialScale / 100.0f; 2324 } else if (mViewportWidth > 0 && mViewportWidth < webViewWidth && 2325 !mWebView.getSettings().getUseFixedViewport()) { 2326 mInitialViewState.mViewScale = mInitialViewState.mTextWrapScale = 2327 (float) webViewWidth / mViewportWidth; 2328 } else { 2329 mInitialViewState.mTextWrapScale = adjust; 2330 // 0 will trigger WebView to turn on zoom overview mode 2331 mInitialViewState.mViewScale = 0; 2332 } 2333 } 2334 2335 if (mWebView.mHeightCanMeasure) { 2336 // Trick to ensure that the Picture has the exact height for the 2337 // content by forcing to layout with 0 height after the page is 2338 // ready, which is indicated by didFirstLayout. This is essential to 2339 // get rid of the white space in the GMail which uses WebView for 2340 // message view. 2341 mWebView.mLastHeightSent = 0; 2342 // Send a negative scale to indicate that WebCore should reuse 2343 // the current scale 2344 WebView.ViewSizeData data = new WebView.ViewSizeData(); 2345 data.mWidth = mWebView.mLastWidthSent; 2346 data.mHeight = 0; 2347 // if mHeightCanMeasure is true, getUseWideViewPort() can't be 2348 // true. It is safe to use mWidth for mTextWrapWidth. 2349 data.mTextWrapWidth = data.mWidth; 2350 data.mScale = -1.0f; 2351 data.mIgnoreHeight = false; 2352 data.mAnchorX = data.mAnchorY = 0; 2353 // send VIEW_SIZE_CHANGED to the front of the queue so that we can 2354 // avoid pushing the wrong picture to the WebView side. If there is 2355 // a VIEW_SIZE_CHANGED in the queue, probably from WebView side, 2356 // ignore it as we have a new size. If we leave VIEW_SIZE_CHANGED 2357 // in the queue, as mLastHeightSent has been updated here, we may 2358 // miss the requestLayout in WebView side after the new picture. 2359 mEventHub.removeMessages(EventHub.VIEW_SIZE_CHANGED); 2360 mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null, 2361 EventHub.VIEW_SIZE_CHANGED, data)); 2362 } else if (mSettings.getUseWideViewPort()) { 2363 if (viewportWidth == 0) { 2364 // Trick to ensure VIEW_SIZE_CHANGED will be sent from WebView 2365 // to WebViewCore 2366 mWebView.mLastWidthSent = 0; 2367 } else { 2368 WebView.ViewSizeData data = new WebView.ViewSizeData(); 2369 // mViewScale as 0 means it is in zoom overview mode. So we don't 2370 // know the exact scale. If mRestoredScale is non-zero, use it; 2371 // otherwise just use mTextWrapScale as the initial scale. 2372 float tentativeScale = mInitialViewState.mViewScale; 2373 if (tentativeScale == 0) { 2374 // The following tries to figure out more correct view scale 2375 // and text wrap scale to be sent to webkit, by using some 2376 // knowledge from web settings and zoom manager. 2377 2378 // Calculated window width will be used to guess the scale 2379 // in zoom overview mode. 2380 tentativeScale = mInitialViewState.mTextWrapScale; 2381 int tentativeViewWidth = Math.round(webViewWidth / tentativeScale); 2382 int windowWidth = calculateWindowWidth(tentativeViewWidth, 2383 tentativeViewWidth); 2384 // In viewport setup time, since no content width is known, we assume 2385 // the windowWidth will be the content width, to get a more likely 2386 // zoom overview scale. 2387 data.mScale = (float) webViewWidth / windowWidth; 2388 if (!mSettings.getLoadWithOverviewMode()) { 2389 // If user choose non-overview mode. 2390 data.mScale = Math.max(data.mScale, tentativeScale); 2391 } 2392 if (mSettings.isNarrowColumnLayout() && 2393 mSettings.getUseFixedViewport()) { 2394 // In case of automatic text reflow in fixed view port mode. 2395 mInitialViewState.mTextWrapScale = 2396 ZoomManager.computeReadingLevelScale(data.mScale); 2397 } 2398 } else { 2399 // Scale is given such as when page is restored, use it. 2400 data.mScale = tentativeScale; 2401 } 2402 if (DebugFlags.WEB_VIEW_CORE) { 2403 Log.v(LOGTAG, "setupViewport" 2404 + " mRestoredScale=" + mRestoredScale 2405 + " mViewScale=" + mInitialViewState.mViewScale 2406 + " mTextWrapScale=" + mInitialViewState.mTextWrapScale 2407 + " data.mScale= " + data.mScale 2408 ); 2409 } 2410 data.mWidth = Math.round(webViewWidth / data.mScale); 2411 // We may get a call here when mCurrentViewHeight == 0 if webcore completes the 2412 // first layout before we sync our webview dimensions to it. In that case, we 2413 // request the real height of the webview. This is not a perfect solution as we 2414 // are calling a WebView method from the WebCore thread. But this is preferable 2415 // to syncing an incorrect height. 2416 data.mHeight = mCurrentViewHeight == 0 ? 2417 Math.round(mWebView.getViewHeight() / data.mScale) 2418 : Math.round((float) mCurrentViewHeight * data.mWidth / viewportWidth); 2419 data.mTextWrapWidth = Math.round(webViewWidth 2420 / mInitialViewState.mTextWrapScale); 2421 data.mIgnoreHeight = false; 2422 data.mAnchorX = data.mAnchorY = 0; 2423 // send VIEW_SIZE_CHANGED to the front of the queue so that we 2424 // can avoid pushing the wrong picture to the WebView side. 2425 mEventHub.removeMessages(EventHub.VIEW_SIZE_CHANGED); 2426 // Let webkit know the scale and inner width/height immediately 2427 // in viewport setup time to avoid wrong information. 2428 viewSizeChanged(data); 2429 } 2430 } 2431 } 2432 2433 // called by JNI 2434 private void restoreScale(float scale, float textWrapScale) { 2435 if (mBrowserFrame.firstLayoutDone() == false) { 2436 mRestoredScale = scale; 2437 if (mSettings.getUseWideViewPort()) { 2438 mRestoredTextWrapScale = textWrapScale; 2439 } 2440 } 2441 } 2442 2443 // called by JNI 2444 private void needTouchEvents(boolean need) { 2445 if (mWebView != null) { 2446 Message.obtain(mWebView.mPrivateHandler, 2447 WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0) 2448 .sendToTarget(); 2449 } 2450 } 2451 2452 // called by JNI 2453 private void updateTextfield(int ptr, boolean changeToPassword, 2454 String text, int textGeneration) { 2455 if (mWebView != null) { 2456 Message msg = Message.obtain(mWebView.mPrivateHandler, 2457 WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr, 2458 textGeneration, text); 2459 msg.getData().putBoolean("password", changeToPassword); 2460 msg.sendToTarget(); 2461 } 2462 } 2463 2464 // called by JNI 2465 private void updateTextSelection(int pointer, int start, int end, 2466 int textGeneration) { 2467 if (mWebView != null) { 2468 Message.obtain(mWebView.mPrivateHandler, 2469 WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration, 2470 new TextSelectionData(start, end)).sendToTarget(); 2471 } 2472 } 2473 2474 // called by JNI 2475 private void clearTextEntry() { 2476 if (mWebView == null) return; 2477 Message.obtain(mWebView.mPrivateHandler, 2478 WebView.CLEAR_TEXT_ENTRY).sendToTarget(); 2479 } 2480 2481 // called by JNI 2482 private void sendFindAgain() { 2483 if (mWebView == null) return; 2484 Message.obtain(mWebView.mPrivateHandler, 2485 WebView.FIND_AGAIN).sendToTarget(); 2486 } 2487 2488 private native void nativeUpdateFrameCacheIfLoading(); 2489 private native void nativeRevealSelection(); 2490 private native String nativeRequestLabel(int framePtr, int nodePtr); 2491 /** 2492 * Scroll the focused textfield to (xPercent, y) in document space 2493 */ 2494 private native void nativeScrollFocusedTextInput(float xPercent, int y); 2495 2496 // these must be in document space (i.e. not scaled/zoomed). 2497 private native void nativeSetScrollOffset(int gen, boolean sendScrollEvent, int dx, int dy); 2498 2499 private native void nativeSetGlobalBounds(int x, int y, int w, int h); 2500 2501 // called by JNI 2502 private void requestListBox(String[] array, int[] enabledArray, 2503 int[] selectedArray) { 2504 if (mWebView != null) { 2505 mWebView.requestListBox(array, enabledArray, selectedArray); 2506 } 2507 } 2508 2509 // called by JNI 2510 private void requestListBox(String[] array, int[] enabledArray, 2511 int selection) { 2512 if (mWebView != null) { 2513 mWebView.requestListBox(array, enabledArray, selection); 2514 } 2515 2516 } 2517 2518 // called by JNI 2519 private void requestKeyboardWithSelection(int pointer, int selStart, 2520 int selEnd, int textGeneration) { 2521 if (mWebView != null) { 2522 Message.obtain(mWebView.mPrivateHandler, 2523 WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer, 2524 textGeneration, new TextSelectionData(selStart, selEnd)) 2525 .sendToTarget(); 2526 } 2527 } 2528 2529 // called by JNI 2530 private void requestKeyboard(boolean showKeyboard) { 2531 if (mWebView != null) { 2532 Message.obtain(mWebView.mPrivateHandler, 2533 WebView.REQUEST_KEYBOARD, showKeyboard ? 1 : 0, 0) 2534 .sendToTarget(); 2535 } 2536 } 2537 2538 private void setWebTextViewAutoFillable(int queryId, String preview) { 2539 if (mWebView != null) { 2540 Message.obtain(mWebView.mPrivateHandler, WebView.SET_AUTOFILLABLE, 2541 new AutoFillData(queryId, preview)) 2542 .sendToTarget(); 2543 } 2544 } 2545 2546 // called by JNI 2547 private Context getContext() { 2548 return mContext; 2549 } 2550 2551 // called by JNI 2552 private void keepScreenOn(boolean screenOn) { 2553 if (mWebView != null) { 2554 Message message = mWebView.mPrivateHandler.obtainMessage(WebView.SCREEN_ON); 2555 message.arg1 = screenOn ? 1 : 0; 2556 message.sendToTarget(); 2557 } 2558 } 2559 2560 // called by JNI 2561 private Class<?> getPluginClass(String libName, String clsName) { 2562 2563 if (mWebView == null) { 2564 return null; 2565 } 2566 2567 PluginManager pluginManager = PluginManager.getInstance(null); 2568 2569 String pkgName = pluginManager.getPluginsAPKName(libName); 2570 if (pkgName == null) { 2571 Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK"); 2572 return null; 2573 } 2574 2575 try { 2576 return pluginManager.getPluginClass(pkgName, clsName); 2577 } catch (NameNotFoundException e) { 2578 Log.e(LOGTAG, "Unable to find plugin classloader for the apk (" + pkgName + ")"); 2579 } catch (ClassNotFoundException e) { 2580 Log.e(LOGTAG, "Unable to find plugin class (" + clsName + 2581 ") in the apk (" + pkgName + ")"); 2582 } 2583 2584 return null; 2585 } 2586 2587 // called by JNI. PluginWidget function to launch a full-screen view using a 2588 // View object provided by the plugin class. 2589 private void showFullScreenPlugin(ViewManager.ChildView childView, int npp) { 2590 if (mWebView == null) { 2591 return; 2592 } 2593 2594 Message message = mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN); 2595 message.obj = childView.mView; 2596 message.arg1 = npp; 2597 message.sendToTarget(); 2598 } 2599 2600 // called by JNI 2601 private void hideFullScreenPlugin() { 2602 if (mWebView == null) { 2603 return; 2604 } 2605 mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN) 2606 .sendToTarget(); 2607 } 2608 2609 private ViewManager.ChildView createSurface(View pluginView) { 2610 if (mWebView == null) { 2611 return null; 2612 } 2613 2614 if (pluginView == null) { 2615 Log.e(LOGTAG, "Attempted to add an empty plugin view to the view hierarchy"); 2616 return null; 2617 } 2618 2619 // ensures the view system knows the view can redraw itself 2620 pluginView.setWillNotDraw(false); 2621 2622 if(pluginView instanceof SurfaceView) 2623 ((SurfaceView)pluginView).setZOrderOnTop(true); 2624 2625 ViewManager.ChildView view = mWebView.mViewManager.createView(); 2626 view.mView = pluginView; 2627 return view; 2628 } 2629 2630 // called by JNI. PluginWidget functions for creating an embedded View for 2631 // the surface drawing model. 2632 private ViewManager.ChildView addSurface(View pluginView, int x, int y, 2633 int width, int height) { 2634 ViewManager.ChildView view = createSurface(pluginView); 2635 view.attachView(x, y, width, height); 2636 return view; 2637 } 2638 2639 private void updateSurface(ViewManager.ChildView childView, int x, int y, 2640 int width, int height) { 2641 childView.attachView(x, y, width, height); 2642 } 2643 2644 private void destroySurface(ViewManager.ChildView childView) { 2645 childView.removeView(); 2646 } 2647 2648 // called by JNI 2649 static class ShowRectData { 2650 int mLeft; 2651 int mTop; 2652 int mWidth; 2653 int mHeight; 2654 int mContentWidth; 2655 int mContentHeight; 2656 float mXPercentInDoc; 2657 float mXPercentInView; 2658 float mYPercentInDoc; 2659 float mYPercentInView; 2660 } 2661 2662 private void showRect(int left, int top, int width, int height, 2663 int contentWidth, int contentHeight, float xPercentInDoc, 2664 float xPercentInView, float yPercentInDoc, float yPercentInView) { 2665 if (mWebView != null) { 2666 ShowRectData data = new ShowRectData(); 2667 data.mLeft = left; 2668 data.mTop = top; 2669 data.mWidth = width; 2670 data.mHeight = height; 2671 data.mContentWidth = contentWidth; 2672 data.mContentHeight = contentHeight; 2673 data.mXPercentInDoc = xPercentInDoc; 2674 data.mXPercentInView = xPercentInView; 2675 data.mYPercentInDoc = yPercentInDoc; 2676 data.mYPercentInView = yPercentInView; 2677 Message.obtain(mWebView.mPrivateHandler, WebView.SHOW_RECT_MSG_ID, 2678 data).sendToTarget(); 2679 } 2680 } 2681 2682 // called by JNI 2683 private void centerFitRect(int x, int y, int width, int height) { 2684 if (mWebView == null) { 2685 return; 2686 } 2687 mWebView.mPrivateHandler.obtainMessage(WebView.CENTER_FIT_RECT, 2688 new Rect(x, y, x + width, y + height)).sendToTarget(); 2689 } 2690 2691 // called by JNI 2692 private void setScrollbarModes(int hMode, int vMode) { 2693 if (mWebView == null) { 2694 return; 2695 } 2696 mWebView.mPrivateHandler.obtainMessage(WebView.SET_SCROLLBAR_MODES, 2697 hMode, vMode).sendToTarget(); 2698 } 2699 2700 // called by JNI 2701 @SuppressWarnings("unused") 2702 private void selectAt(int x, int y) { 2703 if (mWebView != null) { 2704 mWebView.mPrivateHandler.obtainMessage(WebView.SELECT_AT, x, y).sendToTarget(); 2705 } 2706 } 2707 2708 private void useMockDeviceOrientation() { 2709 mDeviceMotionAndOrientationManager.useMock(); 2710 } 2711 2712 public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha, 2713 boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) { 2714 mDeviceMotionAndOrientationManager.setMockOrientation(canProvideAlpha, alpha, 2715 canProvideBeta, beta, canProvideGamma, gamma); 2716 } 2717 2718 protected DeviceMotionService getDeviceMotionService() { 2719 if (mDeviceMotionService == null) { 2720 mDeviceMotionService = 2721 new DeviceMotionService(mDeviceMotionAndOrientationManager, mContext); 2722 } 2723 return mDeviceMotionService; 2724 } 2725 2726 protected DeviceOrientationService getDeviceOrientationService() { 2727 if (mDeviceOrientationService == null) { 2728 mDeviceOrientationService = 2729 new DeviceOrientationService(mDeviceMotionAndOrientationManager, mContext); 2730 } 2731 return mDeviceOrientationService; 2732 } 2733 2734 private native void nativePause(); 2735 private native void nativeResume(); 2736 private native void nativeFreeMemory(); 2737 private native void nativeFullScreenPluginHidden(int npp); 2738 private native boolean nativeValidNodeAndBounds(int frame, int node, 2739 Rect bounds); 2740 2741 private native ArrayList<Rect> nativeGetTouchHighlightRects(int x, int y, 2742 int slop); 2743 2744 private native void nativeAutoFillForm(int queryId); 2745 private native void nativeScrollLayer(int layer, Rect rect); 2746} 2747