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