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