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