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