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