LayoutTestsExecutor.java revision f09aafa27503becdcbe2244356c2c7505dff8fe4
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 setupWebView(mCurrentWebView); 331 332 mEventSender.reset(mCurrentWebView); 333 334 setContentView(mCurrentWebView); 335 if (previousWebView != null) { 336 Log.d(LOG_TAG + "::reset", "previousWebView != null"); 337 previousWebView.destroy(); 338 } 339 } 340 341 private static class WebViewWithJavascriptInterfaces extends WebView { 342 public WebViewWithJavascriptInterfaces( 343 Context context, Map<String, Object> javascriptInterfaces) { 344 super(context, 345 null, // attribute set 346 0, // default style resource ID 347 javascriptInterfaces, 348 false); // is private browsing 349 } 350 } 351 private WebView createWebViewWithJavascriptInterfaces() { 352 Map<String, Object> javascriptInterfaces = new HashMap<String, Object>(); 353 javascriptInterfaces.put("layoutTestController", mLayoutTestController); 354 javascriptInterfaces.put("eventSender", mEventSender); 355 return new WebViewWithJavascriptInterfaces(this, javascriptInterfaces); 356 } 357 358 private void setupWebView(WebView webView) { 359 webView.setWebViewClient(mWebViewClient); 360 webView.setWebChromeClient(mWebChromeClient); 361 362 /** 363 * Setting a touch interval of -1 effectively disables the optimisation in WebView 364 * that stops repeated touch events flooding WebCore. The Event Sender only sends a 365 * single event rather than a stream of events (like what would generally happen in 366 * a real use of touch events in a WebView) and so if the WebView drops the event, 367 * the test will fail as the test expects one callback for every touch it synthesizes. 368 */ 369 webView.setTouchInterval(-1); 370 371 webView.clearCache(true); 372 373 WebSettings webViewSettings = webView.getSettings(); 374 webViewSettings.setAppCacheEnabled(true); 375 webViewSettings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); 376 webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE); 377 webViewSettings.setJavaScriptEnabled(true); 378 webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true); 379 webViewSettings.setSupportMultipleWindows(true); 380 webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); 381 webViewSettings.setDatabaseEnabled(true); 382 webViewSettings.setDatabasePath(getDir("databases", 0).getAbsolutePath()); 383 webViewSettings.setDomStorageEnabled(true); 384 webViewSettings.setWorkersEnabled(false); 385 webViewSettings.setXSSAuditorEnabled(false); 386 387 // This is asynchronous, but it gets processed by WebCore before it starts loading pages. 388 mCurrentWebView.useMockDeviceOrientation(); 389 } 390 391 private void startTests() { 392 try { 393 Message serviceMsg = 394 Message.obtain(null, ManagerService.MSG_FIRST_TEST); 395 396 Bundle bundle = new Bundle(); 397 if (!mTestsList.isEmpty()) { 398 bundle.putString("firstTest", mTestsList.get(0)); 399 bundle.putInt("index", mCurrentTestIndex); 400 } 401 402 serviceMsg.setData(bundle); 403 mManagerServiceMessenger.send(serviceMsg); 404 } catch (RemoteException e) { 405 Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e); 406 } 407 408 runNextTest(); 409 } 410 411 private void runNextTest() { 412 assert mCurrentState == CurrentState.IDLE : "mCurrentState = " + mCurrentState.name(); 413 414 if (mTestsList.isEmpty()) { 415 onAllTestsFinished(); 416 return; 417 } 418 419 mCurrentTestRelativePath = mTestsList.remove(0); 420 421 Log.i(LOG_TAG, "runNextTest(): Start: " + mCurrentTestRelativePath + 422 " (" + mCurrentTestIndex + ")"); 423 424 mCurrentTestUri = FileFilter.getUrl(mCurrentTestRelativePath).toString(); 425 426 reset(); 427 428 /** Start time-out countdown and the test */ 429 mCurrentState = CurrentState.RENDERING_PAGE; 430 mResultHandler.sendEmptyMessageDelayed(MSG_TEST_TIMED_OUT, DEFAULT_TIME_OUT_MS); 431 mCurrentWebView.loadUrl(mCurrentTestUri); 432 } 433 434 private void onTestTimedOut() { 435 assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name(); 436 437 Log.w(LOG_TAG, "onTestTimedOut(): " + mCurrentTestRelativePath); 438 mCurrentTestTimedOut = true; 439 440 /** 441 * While it is theoretically possible that the test times out because 442 * of webview becoming unresponsive, it is very unlikely. Therefore it's 443 * assumed that obtaining results (that calls various webview methods) 444 * will not itself hang. 445 */ 446 obtainActualResultsFromWebView(); 447 } 448 449 private void onTestFinished() { 450 assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name(); 451 452 Log.i(LOG_TAG, "onTestFinished(): " + mCurrentTestRelativePath); 453 mResultHandler.removeMessages(MSG_TEST_TIMED_OUT); 454 obtainActualResultsFromWebView(); 455 } 456 457 private void obtainActualResultsFromWebView() { 458 /** 459 * If the result has not been set by the time the test finishes we create 460 * a default type of result. 461 */ 462 if (mCurrentResult == null) { 463 /** TODO: Default type should be RenderTreeResult. We don't support it now. */ 464 mCurrentResult = new TextResult(mCurrentTestRelativePath); 465 } 466 467 mCurrentState = CurrentState.OBTAINING_RESULT; 468 469 if (mCurrentTestTimedOut) { 470 mCurrentResult.setDidTimeOut(); 471 } 472 mCurrentResult.obtainActualResults(mCurrentWebView, 473 mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED)); 474 } 475 476 private void onActualResultsObtained() { 477 assert mCurrentState == CurrentState.OBTAINING_RESULT 478 : "mCurrentState = " + mCurrentState.name(); 479 480 Log.i(LOG_TAG, "onActualResultsObtained(): " + mCurrentTestRelativePath); 481 mCurrentState = CurrentState.IDLE; 482 483 reportResultToService(); 484 mCurrentTestIndex++; 485 updateProgressBar(); 486 runNextTest(); 487 } 488 489 private void reportResultToService() { 490 if (mCurrentAdditionalTextOutput != null) { 491 mCurrentResult.setAdditionalTextOutputString(mCurrentAdditionalTextOutput.toString()); 492 } 493 494 try { 495 Message serviceMsg = 496 Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS); 497 498 Bundle bundle = mCurrentResult.getBundle(); 499 bundle.putInt("testIndex", mCurrentTestIndex); 500 if (!mTestsList.isEmpty()) { 501 bundle.putString("nextTest", mTestsList.get(0)); 502 } 503 504 serviceMsg.setData(bundle); 505 mManagerServiceMessenger.send(serviceMsg); 506 } catch (RemoteException e) { 507 Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e); 508 } 509 } 510 511 private void updateProgressBar() { 512 getWindow().setFeatureInt(Window.FEATURE_PROGRESS, 513 mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount); 514 setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " + 515 "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")"); 516 } 517 518 private void onAllTestsFinished() { 519 mScreenDimLock.release(); 520 521 try { 522 Message serviceMsg = 523 Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED); 524 mManagerServiceMessenger.send(serviceMsg); 525 } catch (RemoteException e) { 526 Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e); 527 } 528 529 unbindService(mServiceConnection); 530 } 531 532 private AdditionalTextOutput getCurrentAdditionalTextOutput() { 533 if (mCurrentAdditionalTextOutput == null) { 534 mCurrentAdditionalTextOutput = new AdditionalTextOutput(); 535 } 536 return mCurrentAdditionalTextOutput; 537 } 538 539 /** LAYOUT TEST CONTROLLER */ 540 541 private static final int MSG_WAIT_UNTIL_DONE = 0; 542 private static final int MSG_NOTIFY_DONE = 1; 543 private static final int MSG_DUMP_AS_TEXT = 2; 544 private static final int MSG_DUMP_CHILD_FRAMES_AS_TEXT = 3; 545 private static final int MSG_SET_CAN_OPEN_WINDOWS = 4; 546 private static final int MSG_DUMP_DATABASE_CALLBACKS = 5; 547 private static final int MSG_SET_GEOLOCATION_PERMISSION = 6; 548 private static final int MSG_OVERRIDE_PREFERENCE = 7; 549 private static final int MSG_SET_XSS_AUDITOR_ENABLED = 8; 550 551 /** String constants for use with layoutTestController.overridePreference() */ 552 private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED = 553 "WebKitOfflineWebApplicationCacheEnabled"; 554 555 Handler mLayoutTestControllerHandler = new Handler() { 556 @Override 557 public void handleMessage(Message msg) { 558 assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name(); 559 560 switch (msg.what) { 561 case MSG_DUMP_AS_TEXT: 562 if (mCurrentResult == null) { 563 mCurrentResult = new TextResult(mCurrentTestRelativePath); 564 } 565 assert mCurrentResult instanceof TextResult 566 : "mCurrentResult instanceof" + mCurrentResult.getClass().getName(); 567 break; 568 569 case MSG_DUMP_CHILD_FRAMES_AS_TEXT: 570 /** If dumpAsText was not called we assume that the result should be text */ 571 if (mCurrentResult == null) { 572 mCurrentResult = new TextResult(mCurrentTestRelativePath); 573 } 574 575 assert mCurrentResult instanceof TextResult 576 : "mCurrentResult instanceof" + mCurrentResult.getClass().getName(); 577 578 ((TextResult)mCurrentResult).setDumpChildFramesAsText(true); 579 break; 580 581 case MSG_DUMP_DATABASE_CALLBACKS: 582 mDumpDatabaseCallbacks = true; 583 break; 584 585 case MSG_NOTIFY_DONE: 586 if (mCurrentState == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST) { 587 onTestFinished(); 588 } 589 break; 590 591 case MSG_OVERRIDE_PREFERENCE: 592 /** 593 * TODO: We should look up the correct WebView for the frame which 594 * called the layoutTestController method. Currently, we just use the 595 * WebView for the main frame. EventSender suffers from the same 596 * problem. 597 */ 598 if (msg.getData().getString("key").equals( 599 WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) { 600 mCurrentWebView.getSettings().setAppCacheEnabled(msg.getData().getBoolean( 601 "value")); 602 } else { 603 Log.w(LOG_TAG, "MSG_OVERRIDE_PREFERENCE: unsupported preference!"); 604 } 605 break; 606 607 case MSG_SET_CAN_OPEN_WINDOWS: 608 mCanOpenWindows = true; 609 break; 610 611 case MSG_SET_GEOLOCATION_PERMISSION: 612 mIsGeolocationPermissionSet = true; 613 mGeolocationPermission = msg.arg1 == 1; 614 615 if (mPendingGeolocationPermissionCallbacks != null) { 616 Iterator<GeolocationPermissions.Callback> iter = 617 mPendingGeolocationPermissionCallbacks.keySet().iterator(); 618 while (iter.hasNext()) { 619 GeolocationPermissions.Callback callback = iter.next(); 620 String origin = mPendingGeolocationPermissionCallbacks.get(callback); 621 callback.invoke(origin, mGeolocationPermission, false); 622 } 623 mPendingGeolocationPermissionCallbacks = null; 624 } 625 break; 626 627 case MSG_SET_XSS_AUDITOR_ENABLED: 628 mCurrentWebView.getSettings().setXSSAuditorEnabled(msg.arg1 == 1); 629 break; 630 631 case MSG_WAIT_UNTIL_DONE: 632 mCurrentState = CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST; 633 break; 634 635 default: 636 assert false : "msg.what=" + msg.what; 637 break; 638 } 639 } 640 }; 641 642 private void resetLayoutTestController() { 643 mCanOpenWindows = false; 644 mDumpDatabaseCallbacks = false; 645 mIsGeolocationPermissionSet = false; 646 mPendingGeolocationPermissionCallbacks = null; 647 } 648 649 public void dumpAsText(boolean enablePixelTest) { 650 Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpAsText(" + enablePixelTest + ") called"); 651 /** TODO: Implement */ 652 if (enablePixelTest) { 653 Log.w(LOG_TAG, "enablePixelTest not implemented, switching to false"); 654 } 655 mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_AS_TEXT); 656 } 657 658 public void dumpChildFramesAsText() { 659 Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpChildFramesAsText() called"); 660 mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_CHILD_FRAMES_AS_TEXT); 661 } 662 663 public void dumpDatabaseCallbacks() { 664 Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpDatabaseCallbacks() called"); 665 mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_DATABASE_CALLBACKS); 666 } 667 668 public void notifyDone() { 669 Log.i(LOG_TAG, mCurrentTestRelativePath + ": notifyDone() called"); 670 mLayoutTestControllerHandler.sendEmptyMessage(MSG_NOTIFY_DONE); 671 } 672 673 public void overridePreference(String key, boolean value) { 674 Log.i(LOG_TAG, mCurrentTestRelativePath + ": overridePreference(" + key + ", " + value + 675 ") called"); 676 Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_OVERRIDE_PREFERENCE); 677 msg.getData().putString("key", key); 678 msg.getData().putBoolean("value", value); 679 msg.sendToTarget(); 680 } 681 682 public void setCanOpenWindows() { 683 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setCanOpenWindows() called"); 684 mLayoutTestControllerHandler.sendEmptyMessage(MSG_SET_CAN_OPEN_WINDOWS); 685 } 686 687 public void setGeolocationPermission(boolean allow) { 688 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setGeolocationPermission(" + allow + 689 ") called"); 690 Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_GEOLOCATION_PERMISSION); 691 msg.arg1 = allow ? 1 : 0; 692 msg.sendToTarget(); 693 } 694 695 public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha, 696 boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) { 697 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setMockDeviceOrientation(" + canProvideAlpha + 698 ", " + alpha + ", " + canProvideBeta + ", " + beta + ", " + canProvideGamma + 699 ", " + gamma + ")"); 700 mCurrentWebView.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, 701 canProvideGamma, gamma); 702 } 703 704 public void setXSSAuditorEnabled(boolean flag) { 705 Log.i(LOG_TAG, mCurrentTestRelativePath + ": setXSSAuditorEnabled(" + flag + ") called"); 706 Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_XSS_AUDITOR_ENABLED); 707 msg.arg1 = flag ? 1 : 0; 708 msg.sendToTarget(); 709 } 710 711 public void waitUntilDone() { 712 Log.i(LOG_TAG, mCurrentTestRelativePath + ": waitUntilDone() called"); 713 mLayoutTestControllerHandler.sendEmptyMessage(MSG_WAIT_UNTIL_DONE); 714 } 715} 716