LayoutTestsExecutor.java revision 2c38de8436fefb5c2834d843ab3520474bc3a35a
1/* 2 * Copyright (C) 2010 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 com.android.dumprendertree2; 18 19import android.app.Activity; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.ServiceConnection; 24import android.net.Uri; 25import android.os.Bundle; 26import android.os.Environment; 27import android.os.Handler; 28import android.os.IBinder; 29import android.os.Message; 30import android.os.Messenger; 31import android.os.PowerManager; 32import android.os.Process; 33import android.os.RemoteException; 34import android.os.PowerManager.WakeLock; 35import android.util.Log; 36import android.view.Window; 37import android.webkit.ConsoleMessage; 38import android.webkit.HttpAuthHandler; 39import android.webkit.JsPromptResult; 40import android.webkit.JsResult; 41import android.webkit.WebChromeClient; 42import android.webkit.WebSettings; 43import android.webkit.WebView; 44import android.webkit.WebViewClient; 45import android.webkit.GeolocationPermissions; 46import android.webkit.WebStorage.QuotaUpdater; 47 48import java.io.File; 49import java.lang.Thread.UncaughtExceptionHandler; 50import java.net.MalformedURLException; 51import java.net.URL; 52import java.util.HashMap; 53import java.util.Iterator; 54import java.util.List; 55import java.util.Map; 56 57/** 58 * This activity executes the test. It contains WebView and logic of LayoutTestController 59 * functions. It runs in a separate process and sends the results of running the test 60 * to ManagerService. The reason why is to handle crashing (test that crashes brings down 61 * whole process with it). 62 */ 63public class LayoutTestsExecutor extends Activity { 64 65 private enum CurrentState { 66 IDLE, 67 RENDERING_PAGE, 68 WAITING_FOR_ASYNCHRONOUS_TEST, 69 OBTAINING_RESULT; 70 71 public boolean isRunningState() { 72 return this == CurrentState.RENDERING_PAGE || 73 this == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST; 74 } 75 } 76 77 private static final String LOG_TAG = "LayoutTestExecutor"; 78 79 public static final String EXTRA_TESTS_LIST = "TestsList"; 80 public static final String EXTRA_TEST_INDEX = "TestIndex"; 81 82 private static final int MSG_ACTUAL_RESULT_OBTAINED = 0; 83 private static final int MSG_TEST_TIMED_OUT = 1; 84 85 private static final int DEFAULT_TIME_OUT_MS = 15 * 1000; 86 87 /** A list of tests that remain to run since last crash */ 88 private List<String> mTestsList; 89 90 /** 91 * This is a number of currently running test. It is 0-based and doesn't reset after 92 * the crash. Initial index is passed to LayoutTestsExecuter in the intent that starts 93 * it. 94 */ 95 private int mCurrentTestIndex; 96 97 /** The total number of tests to run, doesn't reset after crash */ 98 private int mTotalTestCount; 99 100 private WebView mCurrentWebView; 101 private String mCurrentTestRelativePath; 102 private String mCurrentTestUri; 103 private CurrentState mCurrentState = CurrentState.IDLE; 104 105 private boolean mCurrentTestTimedOut; 106 private AbstractResult mCurrentResult; 107 private AdditionalTextOutput mCurrentAdditionalTextOutput; 108 109 private LayoutTestController mLayoutTestController = new LayoutTestController(this); 110 private boolean mCanOpenWindows; 111 private boolean mDumpDatabaseCallbacks; 112 private boolean mIsGeolocationPermissionSet; 113 private boolean mGeolocationPermission; 114 private Map<GeolocationPermissions.Callback, String> mPendingGeolocationPermissionCallbacks; 115 116 private EventSender mEventSender = new EventSender(); 117 118 private WakeLock mScreenDimLock; 119 120 /** COMMUNICATION WITH ManagerService */ 121 122 private Messenger mManagerServiceMessenger; 123 124 private ServiceConnection mServiceConnection = new ServiceConnection() { 125 126 @Override 127 public void onServiceConnected(ComponentName name, IBinder service) { 128 mManagerServiceMessenger = new Messenger(service); 129 startTests(); 130 } 131 132 @Override 133 public void onServiceDisconnected(ComponentName name) { 134 /** TODO */ 135 } 136 }; 137 138 private final Handler mResultHandler = new Handler() { 139 @Override 140 public void handleMessage(Message msg) { 141 switch (msg.what) { 142 case MSG_ACTUAL_RESULT_OBTAINED: 143 onActualResultsObtained(); 144 break; 145 146 case MSG_TEST_TIMED_OUT: 147 onTestTimedOut(); 148 break; 149 150 default: 151 break; 152 } 153 } 154 }; 155 156 /** WEBVIEW CONFIGURATION */ 157 158 private WebViewClient mWebViewClient = new WebViewClient() { 159 @Override 160 public void onPageFinished(WebView view, String url) { 161 /** Some tests fire up many page loads, we don't want to detect them */ 162 if (!url.equals(mCurrentTestUri)) { 163 return; 164 } 165 166 if (mCurrentState == CurrentState.RENDERING_PAGE) { 167 onTestFinished(); 168 } 169 } 170 171 @Override 172 public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, 173 String host, String realm) { 174 if (handler.useHttpAuthUsernamePassword() && view != null) { 175 String[] credentials = view.getHttpAuthUsernamePassword(host, realm); 176 if (credentials != null && credentials.length == 2) { 177 handler.proceed(credentials[0], credentials[1]); 178 return; 179 } 180 } 181 handler.cancel(); 182 } 183 }; 184 185 private WebChromeClient mWebChromeClient = new WebChromeClient() { 186 @Override 187 public void onExceededDatabaseQuota(String url, String databaseIdentifier, 188 long currentQuota, long estimatedSize, long totalUsedQuota, 189 QuotaUpdater quotaUpdater) { 190 /** TODO: This should be recorded as part of the text result */ 191 /** TODO: The quota should also probably be reset somehow for every test? */ 192 if (mDumpDatabaseCallbacks) { 193 getCurrentAdditionalTextOutput().appendExceededDbQuotaMessage(url, 194 databaseIdentifier); 195 } 196 quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024); 197 } 198 199 @Override 200 public boolean onJsAlert(WebView view, String url, String message, JsResult result) { 201 getCurrentAdditionalTextOutput().appendJsAlert(message); 202 result.confirm(); 203 return true; 204 } 205 206 @Override 207 public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { 208 getCurrentAdditionalTextOutput().appendJsConfirm(message); 209 result.confirm(); 210 return true; 211 } 212 213 @Override 214 public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, 215 JsPromptResult result) { 216 getCurrentAdditionalTextOutput().appendJsPrompt(message, defaultValue); 217 result.confirm(); 218 return true; 219 } 220 221 @Override 222 public boolean onConsoleMessage(ConsoleMessage consoleMessage) { 223 getCurrentAdditionalTextOutput().appendConsoleMessage(consoleMessage); 224 return true; 225 } 226 227 @Override 228 public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, 229 Message resultMsg) { 230 WebView.WebViewTransport transport = (WebView.WebViewTransport)resultMsg.obj; 231 /** By default windows cannot be opened, so just send null back. */ 232 WebView newWindowWebView = null; 233 234 if (mCanOpenWindows) { 235 /** 236 * We never display the new window, just create the view and allow it's content to 237 * execute and be recorded by the executor. 238 */ 239 newWindowWebView = new WebView(LayoutTestsExecutor.this); 240 setupWebView(newWindowWebView); 241 } 242 243 transport.setWebView(newWindowWebView); 244 resultMsg.sendToTarget(); 245 return true; 246 } 247 248 @Override 249 public void onGeolocationPermissionsShowPrompt(String origin, 250 GeolocationPermissions.Callback callback) { 251 if (mIsGeolocationPermissionSet) { 252 callback.invoke(origin, mGeolocationPermission, false); 253 return; 254 } 255 if (mPendingGeolocationPermissionCallbacks == null) { 256 mPendingGeolocationPermissionCallbacks = 257 new HashMap<GeolocationPermissions.Callback, String>(); 258 } 259 mPendingGeolocationPermissionCallbacks.put(callback, origin); 260 } 261 }; 262 263 /** IMPLEMENTATION */ 264 265 @Override 266 protected void onCreate(Bundle savedInstanceState) { 267 super.onCreate(savedInstanceState); 268 269 /** 270 * It detects the crash by catching all the uncaught exceptions. However, we 271 * still have to kill the process, because after catching the exception the 272 * activity remains in a strange state, where intents don't revive it. 273 * However, we send the message to the service to speed up the rebooting 274 * (we don't have to wait for time-out to kick in). 275 */ 276 Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { 277 @Override 278 public void uncaughtException(Thread thread, Throwable e) { 279 Log.w(LOG_TAG, 280 "onTestCrashed(): " + mCurrentTestRelativePath + " thread=" + thread, e); 281 282 try { 283 Message serviceMsg = 284 Message.obtain(null, ManagerService.MSG_CURRENT_TEST_CRASHED); 285 286 mManagerServiceMessenger.send(serviceMsg); 287 } catch (RemoteException e2) { 288 Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e2); 289 } 290 291 Process.killProcess(Process.myPid()); 292 } 293 }); 294 295 requestWindowFeature(Window.FEATURE_PROGRESS); 296 297 Intent intent = getIntent(); 298 mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST); 299 mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1); 300 mTotalTestCount = mCurrentTestIndex + mTestsList.size(); 301 302 PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); 303 mScreenDimLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK 304 | PowerManager.ON_AFTER_RELEASE, "WakeLock in LayoutTester"); 305 mScreenDimLock.acquire(); 306 307 bindService(new Intent(this, ManagerService.class), mServiceConnection, 308 Context.BIND_AUTO_CREATE); 309 } 310 311 private void reset() { 312 WebView previousWebView = mCurrentWebView; 313 314 resetLayoutTestController(); 315 316 mCurrentTestTimedOut = false; 317 mCurrentResult = null; 318 mCurrentAdditionalTextOutput = null; 319 320 mCurrentWebView = new WebView(this); 321 setupWebView(mCurrentWebView); 322 323 mEventSender.reset(mCurrentWebView); 324 325 setContentView(mCurrentWebView); 326 if (previousWebView != null) { 327 Log.d(LOG_TAG + "::reset", "previousWebView != null"); 328 previousWebView.destroy(); 329 } 330 } 331 332 private void setupWebView(WebView webView) { 333 webView.setWebViewClient(mWebViewClient); 334 webView.setWebChromeClient(mWebChromeClient); 335 webView.addJavascriptInterface(mLayoutTestController, "layoutTestController"); 336 webView.addJavascriptInterface(mEventSender, "eventSender"); 337 338 /** 339 * Setting a touch interval of -1 effectively disables the optimisation in WebView 340 * that stops repeated touch events flooding WebCore. The Event Sender only sends a 341 * single event rather than a stream of events (like what would generally happen in 342 * a real use of touch events in a WebView) and so if the WebView drops the event, 343 * the test will fail as the test expects one callback for every touch it synthesizes. 344 */ 345 webView.setTouchInterval(-1); 346 347 webView.clearCache(true); 348 349 WebSettings webViewSettings = webView.getSettings(); 350 webViewSettings.setAppCacheEnabled(true); 351 webViewSettings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); 352 webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE); 353 webViewSettings.setJavaScriptEnabled(true); 354 webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true); 355 webViewSettings.setSupportMultipleWindows(true); 356 webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); 357 webViewSettings.setDatabaseEnabled(true); 358 webViewSettings.setDatabasePath(getDir("databases", 0).getAbsolutePath()); 359 webViewSettings.setDomStorageEnabled(true); 360 webViewSettings.setWorkersEnabled(false); 361 webViewSettings.setXSSAuditorEnabled(false); 362 363 // This is asynchronous, but it gets processed by WebCore before it starts loading pages. 364 mCurrentWebView.useMockDeviceOrientation(); 365 } 366 367 private void startTests() { 368 try { 369 Message serviceMsg = 370 Message.obtain(null, ManagerService.MSG_FIRST_TEST); 371 372 Bundle bundle = new Bundle(); 373 if (!mTestsList.isEmpty()) { 374 bundle.putString("firstTest", mTestsList.get(0)); 375 bundle.putInt("index", mCurrentTestIndex); 376 } 377 378 serviceMsg.setData(bundle); 379 mManagerServiceMessenger.send(serviceMsg); 380 } catch (RemoteException e) { 381 Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e); 382 } 383 384 runNextTest(); 385 } 386 387 private void runNextTest() { 388 assert mCurrentState == CurrentState.IDLE : "mCurrentState = " + mCurrentState.name(); 389 390 if (mTestsList.isEmpty()) { 391 onAllTestsFinished(); 392 return; 393 } 394 395 mCurrentTestRelativePath = mTestsList.remove(0); 396 397 Log.i(LOG_TAG, "runNextTest(): Start: " + mCurrentTestRelativePath + 398 " (" + mCurrentTestIndex + ")"); 399 400 mCurrentTestUri = FileFilter.getUrl(mCurrentTestRelativePath).toString(); 401 402 reset(); 403 404 /** Start time-out countdown and the test */ 405 mCurrentState = CurrentState.RENDERING_PAGE; 406 mResultHandler.sendEmptyMessageDelayed(MSG_TEST_TIMED_OUT, DEFAULT_TIME_OUT_MS); 407 mCurrentWebView.loadUrl(mCurrentTestUri); 408 } 409 410 private void onTestTimedOut() { 411 assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name(); 412 413 Log.w(LOG_TAG, "onTestTimedOut(): " + mCurrentTestRelativePath); 414 mCurrentTestTimedOut = true; 415 416 /** 417 * While it is theoretically possible that the test times out because 418 * of webview becoming unresponsive, it is very unlikely. Therefore it's 419 * assumed that obtaining results (that calls various webview methods) 420 * will not itself hang. 421 */ 422 obtainActualResultsFromWebView(); 423 } 424 425 private void onTestFinished() { 426 assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name(); 427 428 Log.i(LOG_TAG, "onTestFinished(): " + mCurrentTestRelativePath); 429 obtainActualResultsFromWebView(); 430 } 431 432 private void obtainActualResultsFromWebView() { 433 /** 434 * If the result has not been set by the time the test finishes we create 435 * a default type of result. 436 */ 437 if (mCurrentResult == null) { 438 /** TODO: Default type should be RenderTreeResult. We don't support it now. */ 439 mCurrentResult = new TextResult(mCurrentTestRelativePath); 440 } 441 442 mCurrentState = CurrentState.OBTAINING_RESULT; 443 444 mCurrentResult.obtainActualResults(mCurrentWebView, 445 mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED)); 446 } 447 448 private void onActualResultsObtained() { 449 assert mCurrentState == CurrentState.OBTAINING_RESULT 450 : "mCurrentState = " + mCurrentState.name(); 451 452 Log.i(LOG_TAG, "onActualResultsObtained(): " + mCurrentTestRelativePath); 453 mCurrentState = CurrentState.IDLE; 454 455 mResultHandler.removeMessages(MSG_TEST_TIMED_OUT); 456 reportResultToService(); 457 mCurrentTestIndex++; 458 updateProgressBar(); 459 runNextTest(); 460 } 461 462 private void reportResultToService() { 463 if (mCurrentAdditionalTextOutput != null) { 464 mCurrentResult.setAdditionalTextOutputString(mCurrentAdditionalTextOutput.toString()); 465 } 466 467 try { 468 Message serviceMsg = 469 Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS); 470 471 Bundle bundle = mCurrentResult.getBundle(); 472 bundle.putInt("testIndex", mCurrentTestIndex); 473 if (mCurrentTestTimedOut) { 474 bundle.putString("resultCode", AbstractResult.ResultCode.FAIL_TIMED_OUT.name()); 475 } 476 if (!mTestsList.isEmpty()) { 477 bundle.putString("nextTest", mTestsList.get(0)); 478 } 479 480 serviceMsg.setData(bundle); 481 mManagerServiceMessenger.send(serviceMsg); 482 } catch (RemoteException e) { 483 Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e); 484 } 485 } 486 487 private void updateProgressBar() { 488 getWindow().setFeatureInt(Window.FEATURE_PROGRESS, 489 mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount); 490 setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " + 491 "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")"); 492 } 493 494 private void onAllTestsFinished() { 495 mScreenDimLock.release(); 496 497 try { 498 Message serviceMsg = 499 Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED); 500 mManagerServiceMessenger.send(serviceMsg); 501 } catch (RemoteException e) { 502 Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e); 503 } 504 505 unbindService(mServiceConnection); 506 } 507 508 private AdditionalTextOutput getCurrentAdditionalTextOutput() { 509 if (mCurrentAdditionalTextOutput == null) { 510 mCurrentAdditionalTextOutput = new AdditionalTextOutput(); 511 } 512 return mCurrentAdditionalTextOutput; 513 } 514 515 /** LAYOUT TEST CONTROLLER */ 516 517 private static final int MSG_WAIT_UNTIL_DONE = 0; 518 private static final int MSG_NOTIFY_DONE = 1; 519 private static final int MSG_DUMP_AS_TEXT = 2; 520 private static final int MSG_DUMP_CHILD_FRAMES_AS_TEXT = 3; 521 private static final int MSG_SET_CAN_OPEN_WINDOWS = 4; 522 private static final int MSG_DUMP_DATABASE_CALLBACKS = 5; 523 private static final int MSG_SET_GEOLOCATION_PERMISSION = 6; 524 private static final int MSG_OVERRIDE_PREFERENCE = 7; 525 private static final int MSG_SET_XSS_AUDITOR_ENABLED = 8; 526 527 /** String constants for use with layoutTestController.overridePreference() */ 528 private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED = 529 "WebKitOfflineWebApplicationCacheEnabled"; 530 531 Handler mLayoutTestControllerHandler = new Handler() { 532 @Override 533 public void handleMessage(Message msg) { 534 assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name(); 535 536 switch (msg.what) { 537 case MSG_DUMP_AS_TEXT: 538 if (mCurrentResult == null) { 539 mCurrentResult = new TextResult(mCurrentTestRelativePath); 540 } 541 assert mCurrentResult instanceof TextResult 542 : "mCurrentResult instanceof" + mCurrentResult.getClass().getName(); 543 break; 544 545 case MSG_DUMP_CHILD_FRAMES_AS_TEXT: 546 /** If dumpAsText was not called we assume that the result should be text */ 547 if (mCurrentResult == null) { 548 mCurrentResult = new TextResult(mCurrentTestRelativePath); 549 } 550 551 assert mCurrentResult instanceof TextResult 552 : "mCurrentResult instanceof" + mCurrentResult.getClass().getName(); 553 554 ((TextResult)mCurrentResult).setDumpChildFramesAsText(true); 555 break; 556 557 case MSG_DUMP_DATABASE_CALLBACKS: 558 mDumpDatabaseCallbacks = true; 559 break; 560 561 case MSG_NOTIFY_DONE: 562 if (mCurrentState == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST) { 563 onTestFinished(); 564 } 565 break; 566 567 case MSG_OVERRIDE_PREFERENCE: 568 /** 569 * TODO: We should look up the correct WebView for the frame which 570 * called the layoutTestController method. Currently, we just use the 571 * WebView for the main frame. EventSender suffers from the same 572 * problem. 573 */ 574 if (msg.getData().getString("key").equals( 575 WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) { 576 mCurrentWebView.getSettings().setAppCacheEnabled(msg.getData().getBoolean( 577 "value")); 578 } else { 579 Log.w(LOG_TAG, "MSG_OVERRIDE_PREFERENCE: unsupported preference!"); 580 } 581 break; 582 583 case MSG_SET_CAN_OPEN_WINDOWS: 584 mCanOpenWindows = true; 585 break; 586 587 case MSG_SET_GEOLOCATION_PERMISSION: 588 mIsGeolocationPermissionSet = true; 589 mGeolocationPermission = msg.arg1 == 1; 590 591 if (mPendingGeolocationPermissionCallbacks != null) { 592 Iterator<GeolocationPermissions.Callback> iter = 593 mPendingGeolocationPermissionCallbacks.keySet().iterator(); 594 while (iter.hasNext()) { 595 GeolocationPermissions.Callback callback = iter.next(); 596 String origin = mPendingGeolocationPermissionCallbacks.get(callback); 597 callback.invoke(origin, mGeolocationPermission, false); 598 } 599 mPendingGeolocationPermissionCallbacks = null; 600 } 601 break; 602 603 case MSG_SET_XSS_AUDITOR_ENABLED: 604 mCurrentWebView.getSettings().setXSSAuditorEnabled(msg.arg1 == 1); 605 break; 606 607 case MSG_WAIT_UNTIL_DONE: 608 mCurrentState = CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST; 609 break; 610 611 default: 612 assert false : "msg.what=" + msg.what; 613 break; 614 } 615 } 616 }; 617 618 private void resetLayoutTestController() { 619 mCanOpenWindows = false; 620 mDumpDatabaseCallbacks = false; 621 mIsGeolocationPermissionSet = false; 622 mPendingGeolocationPermissionCallbacks = null; 623 } 624 625 public void dumpAsText(boolean enablePixelTest) { 626 Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpAsText(" + enablePixelTest + ") called"); 627 /** TODO: Implement */ 628 if (enablePixelTest) { 629 Log.w(LOG_TAG, "enablePixelTest not implemented, switching to false"); 630 } 631 mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_AS_TEXT); 632 } 633 634 public void dumpChildFramesAsText() { 635 Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpChildFramesAsText() called"); 636 mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_CHILD_FRAMES_AS_TEXT); 637 } 638 639 public void dumpDatabaseCallbacks() { 640 Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpDatabaseCallbacks() called"); 641 mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_DATABASE_CALLBACKS); 642 } 643 644 public void notifyDone() { 645 Log.i(LOG_TAG, mCurrentTestRelativePath + ": notifyDone() called"); 646 mLayoutTestControllerHandler.sendEmptyMessage(MSG_NOTIFY_DONE); 647 } 648 649 public void overridePreference(String key, boolean value) { 650 Log.i(LOG_TAG, mCurrentTestRelativePath + ": overridePreference(" + key + ", " + value + 651 ") called"); 652 Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_OVERRIDE_PREFERENCE); 653 msg.getData().putString("key", key); 654 msg.getData().putBoolean("value", value); 655 msg.sendToTarget(); 656 } 657 658 public void setCanOpenWindows() { 659 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setCanOpenWindows() called"); 660 mLayoutTestControllerHandler.sendEmptyMessage(MSG_SET_CAN_OPEN_WINDOWS); 661 } 662 663 public void setGeolocationPermission(boolean allow) { 664 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setGeolocationPermission(" + allow + 665 ") called"); 666 Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_GEOLOCATION_PERMISSION); 667 msg.arg1 = allow ? 1 : 0; 668 msg.sendToTarget(); 669 } 670 671 public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha, 672 boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) { 673 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setMockDeviceOrientation(" + canProvideAlpha + 674 ", " + alpha + ", " + canProvideBeta + ", " + beta + ", " + canProvideGamma + 675 ", " + gamma + ")"); 676 mCurrentWebView.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, 677 canProvideGamma, gamma); 678 } 679 680 public void setXSSAuditorEnabled(boolean flag) { 681 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setXSSAuditorEnabled(" + flag + ") called"); 682 Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_XSS_AUDITOR_ENABLED); 683 msg.arg1 = flag ? 1 : 0; 684 msg.sendToTarget(); 685 } 686 687 public void waitUntilDone() { 688 Log.i(LOG_TAG, mCurrentTestRelativePath + ": waitUntilDone() called"); 689 mLayoutTestControllerHandler.sendEmptyMessage(MSG_WAIT_UNTIL_DONE); 690 } 691} 692