TestShellActivity.java revision be1304f0c2c96be1876c2bd38d319f46e135536f
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 com.android.dumprendertree; 18 19import com.android.dumprendertree.forwarder.ForwardService; 20 21import android.app.Activity; 22import android.app.AlertDialog; 23import android.content.Context; 24import android.content.DialogInterface; 25import android.content.Intent; 26import android.content.DialogInterface.OnClickListener; 27import android.graphics.Bitmap; 28import android.graphics.Canvas; 29import android.graphics.Bitmap.CompressFormat; 30import android.graphics.Bitmap.Config; 31import android.net.http.SslError; 32import android.os.Bundle; 33import android.os.Handler; 34import android.os.Message; 35import android.util.Log; 36import android.view.ViewGroup; 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.WebStorage; 47import android.webkit.WebView; 48import android.webkit.WebViewClient; 49import android.widget.LinearLayout; 50 51import java.io.BufferedReader; 52import java.io.File; 53import java.io.FileOutputStream; 54import java.io.FileReader; 55import java.io.IOException; 56import java.net.MalformedURLException; 57import java.net.URL; 58import java.util.HashMap; 59import java.util.Map; 60import java.util.Vector; 61 62public class TestShellActivity extends Activity implements LayoutTestController { 63 64 static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP} 65 66 // String constants for use with layoutTestController.overridePreferences 67 private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED = "WebKitOfflineWebApplicationCacheEnabled"; 68 69 public class AsyncHandler extends Handler { 70 @Override 71 public void handleMessage(Message msg) { 72 if (msg.what == MSG_TIMEOUT) { 73 mTimedOut = true; 74 if (mCallback != null) 75 mCallback.timedOut(mWebView.getUrl()); 76 if (!mRequestedWebKitData) { 77 requestWebKitData(); 78 } else { 79 // if timed out and webkit data has been dumped before 80 // finish directly 81 finished(); 82 } 83 return; 84 } else if (msg.what == MSG_WEBKIT_DATA) { 85 TestShellActivity.this.dump(mTimedOut, (String)msg.obj); 86 return; 87 } 88 89 super.handleMessage(msg); 90 } 91 } 92 93 public void requestWebKitData() { 94 Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA); 95 96 if (mRequestedWebKitData) 97 throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl()); 98 99 mRequestedWebKitData = true; 100 Log.v(LOGTAG, "message sent to WebView to dump text."); 101 switch (mDumpDataType) { 102 case DUMP_AS_TEXT: 103 callback.arg1 = mDumpTopFrameAsText ? 1 : 0; 104 callback.arg2 = mDumpChildFramesAsText ? 1 : 0; 105 mWebView.documentAsText(callback); 106 break; 107 case EXT_REPR: 108 mWebView.externalRepresentation(callback); 109 break; 110 default: 111 finished(); 112 break; 113 } 114 } 115 116 public void clearCache() { 117 mWebView.freeMemory(); 118 } 119 120 @Override 121 protected void onCreate(Bundle icicle) { 122 super.onCreate(icicle); 123 requestWindowFeature(Window.FEATURE_PROGRESS); 124 125 LinearLayout contentView = new LinearLayout(this); 126 contentView.setOrientation(LinearLayout.VERTICAL); 127 setContentView(contentView); 128 129 mWebView = new WebView(this); 130 mEventSender = new WebViewEventSender(mWebView); 131 mCallbackProxy = new CallbackProxy(mEventSender, this); 132 133 mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController"); 134 mWebView.addJavascriptInterface(mCallbackProxy, "eventSender"); 135 setupWebViewForLayoutTests(mWebView, mCallbackProxy); 136 137 contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0f)); 138 139 mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); 140 141 // Expose window.gc function to JavaScript. JSC build exposes 142 // this function by default, but V8 requires the flag to turn it on. 143 // WebView::setJsFlags is noop in JSC build. 144 mWebView.setJsFlags("--expose_gc"); 145 146 mHandler = new AsyncHandler(); 147 148 Intent intent = getIntent(); 149 if (intent != null) { 150 executeIntent(intent); 151 } 152 } 153 154 @Override 155 protected void onNewIntent(Intent intent) { 156 super.onNewIntent(intent); 157 executeIntent(intent); 158 } 159 160 private void executeIntent(Intent intent) { 161 resetTestStatus(); 162 if (!Intent.ACTION_VIEW.equals(intent.getAction())) { 163 return; 164 } 165 166 mTotalTestCount = intent.getIntExtra(TOTAL_TEST_COUNT, mTotalTestCount); 167 mCurrentTestNumber = intent.getIntExtra(CURRENT_TEST_NUMBER, mCurrentTestNumber); 168 169 mTestUrl = intent.getStringExtra(TEST_URL); 170 if (mTestUrl == null) { 171 mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST); 172 if(mUiAutoTestPath != null) { 173 beginUiAutoTest(); 174 } 175 return; 176 } 177 178 mResultFile = intent.getStringExtra(RESULT_FILE); 179 mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0); 180 mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false); 181 mSaveImagePath = intent.getStringExtra(SAVE_IMAGE); 182 setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount); 183 float ratio = (float)mCurrentTestNumber / mTotalTestCount; 184 int progress = (int)(ratio * Window.PROGRESS_END); 185 getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress); 186 187 Log.v(LOGTAG, " Loading " + mTestUrl); 188 mWebView.loadUrl(mTestUrl); 189 190 if (mTimeoutInMillis > 0) { 191 // Create a timeout timer 192 Message m = mHandler.obtainMessage(MSG_TIMEOUT); 193 mHandler.sendMessageDelayed(m, mTimeoutInMillis); 194 } 195 } 196 197 private void beginUiAutoTest() { 198 try { 199 mTestListReader = new BufferedReader( 200 new FileReader(mUiAutoTestPath)); 201 } catch (IOException ioe) { 202 Log.e(LOGTAG, "Failed to open test list for read.", ioe); 203 finishUiAutoTest(); 204 return; 205 } 206 moveToNextTest(); 207 } 208 209 private void finishUiAutoTest() { 210 try { 211 if(mTestListReader != null) 212 mTestListReader.close(); 213 } catch (IOException ioe) { 214 Log.w(LOGTAG, "Failed to close test list file.", ioe); 215 } 216 ForwardService.getForwardService().stopForwardService(); 217 finished(); 218 } 219 220 private void moveToNextTest() { 221 String url = null; 222 try { 223 url = mTestListReader.readLine(); 224 } catch (IOException ioe) { 225 Log.e(LOGTAG, "Failed to read next test.", ioe); 226 finishUiAutoTest(); 227 return; 228 } 229 if (url == null) { 230 mUiAutoTestPath = null; 231 finishUiAutoTest(); 232 AlertDialog.Builder builder = new AlertDialog.Builder(this); 233 builder.setMessage("All tests finished. Exit?") 234 .setCancelable(false) 235 .setPositiveButton("Yes", new OnClickListener(){ 236 public void onClick(DialogInterface dialog, int which) { 237 TestShellActivity.this.finish(); 238 } 239 }) 240 .setNegativeButton("No", new OnClickListener(){ 241 public void onClick(DialogInterface dialog, int which) { 242 dialog.cancel(); 243 } 244 }); 245 builder.create().show(); 246 return; 247 } 248 Intent intent = new Intent(Intent.ACTION_VIEW); 249 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 250 intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url)); 251 intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, ++mCurrentTestNumber); 252 intent.putExtra(TIMEOUT_IN_MILLIS, 10000); 253 executeIntent(intent); 254 } 255 256 @Override 257 protected void onStop() { 258 super.onStop(); 259 mWebView.stopLoading(); 260 } 261 262 @Override 263 protected void onDestroy() { 264 super.onDestroy(); 265 mWebView.destroy(); 266 mWebView = null; 267 } 268 269 @Override 270 public void onLowMemory() { 271 super.onLowMemory(); 272 Log.e(LOGTAG, "Low memory, clearing caches"); 273 mWebView.freeMemory(); 274 } 275 276 // Dump the page 277 public void dump(boolean timeout, String webkitData) { 278 mDumpWebKitData = true; 279 if (mResultFile == null || mResultFile.length() == 0) { 280 finished(); 281 return; 282 } 283 284 try { 285 File parentDir = new File(mResultFile).getParentFile(); 286 if (!parentDir.exists()) { 287 parentDir.mkdirs(); 288 } 289 290 FileOutputStream os = new FileOutputStream(mResultFile); 291 if (timeout) { 292 Log.w("Layout test: Timeout", mResultFile); 293 os.write(TIMEOUT_STR.getBytes()); 294 os.write('\n'); 295 } 296 if (mDumpTitleChanges) 297 os.write(mTitleChanges.toString().getBytes()); 298 if (mDialogStrings != null) 299 os.write(mDialogStrings.toString().getBytes()); 300 mDialogStrings = null; 301 if (mDatabaseCallbackStrings != null) 302 os.write(mDatabaseCallbackStrings.toString().getBytes()); 303 mDatabaseCallbackStrings = null; 304 if (mConsoleMessages != null) 305 os.write(mConsoleMessages.toString().getBytes()); 306 mConsoleMessages = null; 307 if (webkitData != null) 308 os.write(webkitData.getBytes()); 309 os.flush(); 310 os.close(); 311 } catch (IOException ex) { 312 Log.e(LOGTAG, "Cannot write to " + mResultFile + ", " + ex.getMessage()); 313 } 314 315 finished(); 316 } 317 318 public void setCallback(TestShellCallback callback) { 319 mCallback = callback; 320 } 321 322 public boolean finished() { 323 if (canMoveToNextTest()) { 324 mHandler.removeMessages(MSG_TIMEOUT); 325 if (mUiAutoTestPath != null) { 326 //don't really finish here 327 moveToNextTest(); 328 } else { 329 if (mCallback != null) { 330 mCallback.finished(); 331 } 332 } 333 return true; 334 } 335 return false; 336 } 337 338 public void setDefaultDumpDataType(DumpDataType defaultDumpDataType) { 339 mDefaultDumpDataType = defaultDumpDataType; 340 } 341 342 // ....................................... 343 // LayoutTestController Functions 344 public void dumpAsText() { 345 mDumpDataType = DumpDataType.DUMP_AS_TEXT; 346 mDumpTopFrameAsText = true; 347 if (mWebView != null) { 348 String url = mWebView.getUrl(); 349 Log.v(LOGTAG, "dumpAsText called: "+url); 350 } 351 } 352 353 public void dumpChildFramesAsText() { 354 mDumpDataType = DumpDataType.DUMP_AS_TEXT; 355 mDumpChildFramesAsText = true; 356 if (mWebView != null) { 357 String url = mWebView.getUrl(); 358 Log.v(LOGTAG, "dumpChildFramesAsText called: "+url); 359 } 360 } 361 362 public void waitUntilDone() { 363 mWaitUntilDone = true; 364 String url = mWebView.getUrl(); 365 Log.v(LOGTAG, "waitUntilDone called: " + url); 366 } 367 368 public void notifyDone() { 369 String url = mWebView.getUrl(); 370 Log.v(LOGTAG, "notifyDone called: " + url); 371 if (mWaitUntilDone) { 372 mWaitUntilDone = false; 373 if (!mRequestedWebKitData && !mTimedOut && !finished()) { 374 requestWebKitData(); 375 } 376 } 377 } 378 379 public void display() { 380 mWebView.invalidate(); 381 } 382 383 public void clearBackForwardList() { 384 mWebView.clearHistory(); 385 386 } 387 388 public void dumpBackForwardList() { 389 //printf("\n============== Back Forward List ==============\n"); 390 // mWebHistory 391 //printf("===============================================\n"); 392 393 } 394 395 public void dumpChildFrameScrollPositions() { 396 // TODO Auto-generated method stub 397 398 } 399 400 public void dumpEditingCallbacks() { 401 // TODO Auto-generated method stub 402 403 } 404 405 public void dumpSelectionRect() { 406 // TODO Auto-generated method stub 407 408 } 409 410 public void dumpTitleChanges() { 411 if (!mDumpTitleChanges) { 412 mTitleChanges = new StringBuffer(); 413 } 414 mDumpTitleChanges = true; 415 } 416 417 public void keepWebHistory() { 418 if (!mKeepWebHistory) { 419 mWebHistory = new Vector(); 420 } 421 mKeepWebHistory = true; 422 } 423 424 public void queueBackNavigation(int howfar) { 425 // TODO Auto-generated method stub 426 427 } 428 429 public void queueForwardNavigation(int howfar) { 430 // TODO Auto-generated method stub 431 432 } 433 434 public void queueLoad(String Url, String frameTarget) { 435 // TODO Auto-generated method stub 436 437 } 438 439 public void queueReload() { 440 mWebView.reload(); 441 } 442 443 public void queueScript(String scriptToRunInCurrentContext) { 444 mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext); 445 } 446 447 public void repaintSweepHorizontally() { 448 // TODO Auto-generated method stub 449 450 } 451 452 public void setAcceptsEditing(boolean b) { 453 // TODO Auto-generated method stub 454 455 } 456 457 public void setMainFrameIsFirstResponder(boolean b) { 458 // TODO Auto-generated method stub 459 460 } 461 462 public void setWindowIsKey(boolean b) { 463 // This is meant to show/hide the window. The best I can find 464 // is setEnabled() 465 mWebView.setEnabled(b); 466 } 467 468 public void testRepaint() { 469 mWebView.invalidate(); 470 } 471 472 public void dumpDatabaseCallbacks() { 473 Log.v(LOGTAG, "dumpDatabaseCallbacks called."); 474 mDumpDatabaseCallbacks = true; 475 } 476 477 public void setCanOpenWindows() { 478 Log.v(LOGTAG, "setCanOpenWindows called."); 479 mCanOpenWindows = true; 480 } 481 482 /** 483 * Sets the Geolocation permission state to be used for all future requests. 484 */ 485 public void setGeolocationPermission(boolean allow) { 486 mGeolocationPermissionSet = true; 487 mGeolocationPermission = allow; 488 } 489 490 public void overridePreference(String key, boolean value) { 491 // TODO: We should look up the correct WebView for the frame which 492 // called the layoutTestController method. Currently, we just use the 493 // WebView for the main frame. EventSender suffers from the same 494 // problem. 495 if (key.equals(WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) { 496 mWebView.getSettings().setAppCacheEnabled(value); 497 } 498 } 499 500 public void setXSSAuditorEnabled (boolean flag) { 501 mWebView.getSettings().setXSSAuditorEnabled(flag); 502 } 503 504 private final WebViewClient mViewClient = new WebViewClient(){ 505 @Override 506 public void onPageFinished(WebView view, String url) { 507 Log.v(LOGTAG, "onPageFinished, url=" + url); 508 mPageFinished = true; 509 // get page draw time 510 if (FsUtils.isTestPageUrl(url)) { 511 if (mGetDrawtime) { 512 long[] times = new long[DRAW_RUNS]; 513 times = getDrawWebViewTime(mWebView, DRAW_RUNS); 514 FsUtils.writeDrawTime(DRAW_TIME_LOG, url, times); 515 } 516 if (mSaveImagePath != null) { 517 String name = FsUtils.getLastSegmentInPath(url); 518 drawPageToFile(mSaveImagePath + "/" + name + ".png", mWebView); 519 } 520 } 521 522 // Calling finished() will check if we've met all the conditions for completing 523 // this test and move to the next one if we are ready. Otherwise we ask WebCore to 524 // dump the page. 525 if (finished()) { 526 return; 527 } 528 529 if (!mWaitUntilDone && !mRequestedWebKitData && !mTimedOut) { 530 requestWebKitData(); 531 } else { 532 if (mWaitUntilDone) { 533 Log.v(LOGTAG, "page finished loading but waiting for notifyDone to be called: " + url); 534 } 535 536 if (mRequestedWebKitData) { 537 Log.v(LOGTAG, "page finished loading but webkit data has already been requested: " + url); 538 } 539 540 if (mTimedOut) { 541 Log.v(LOGTAG, "page finished loading but already timed out: " + url); 542 } 543 } 544 545 super.onPageFinished(view, url); 546 } 547 548 @Override 549 public void onPageStarted(WebView view, String url, Bitmap favicon) { 550 Log.v(LOGTAG, "onPageStarted, url=" + url); 551 mPageFinished = false; 552 super.onPageStarted(view, url, favicon); 553 } 554 555 @Override 556 public void onReceivedError(WebView view, int errorCode, String description, 557 String failingUrl) { 558 Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode 559 + ", desc=" + description + ", url=" + failingUrl); 560 super.onReceivedError(view, errorCode, description, failingUrl); 561 } 562 563 @Override 564 public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, 565 String host, String realm) { 566 if (handler.useHttpAuthUsernamePassword() && view != null) { 567 String[] credentials = view.getHttpAuthUsernamePassword(host, realm); 568 if (credentials != null && credentials.length == 2) { 569 handler.proceed(credentials[0], credentials[1]); 570 return; 571 } 572 } 573 handler.cancel(); 574 } 575 576 @Override 577 public void onReceivedSslError(WebView view, SslErrorHandler handler, 578 SslError error) { 579 handler.proceed(); 580 } 581 }; 582 583 584 private final WebChromeClient mChromeClient = new WebChromeClient() { 585 @Override 586 public void onReceivedTitle(WebView view, String title) { 587 setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount + ": "+ title); 588 if (mDumpTitleChanges) { 589 mTitleChanges.append("TITLE CHANGED: "); 590 mTitleChanges.append(title); 591 mTitleChanges.append("\n"); 592 } 593 } 594 595 @Override 596 public boolean onJsAlert(WebView view, String url, String message, 597 JsResult result) { 598 if (mDialogStrings == null) { 599 mDialogStrings = new StringBuffer(); 600 } 601 mDialogStrings.append("ALERT: "); 602 mDialogStrings.append(message); 603 mDialogStrings.append('\n'); 604 result.confirm(); 605 return true; 606 } 607 608 @Override 609 public boolean onJsConfirm(WebView view, String url, String message, 610 JsResult result) { 611 if (mDialogStrings == null) { 612 mDialogStrings = new StringBuffer(); 613 } 614 mDialogStrings.append("CONFIRM: "); 615 mDialogStrings.append(message); 616 mDialogStrings.append('\n'); 617 result.confirm(); 618 return true; 619 } 620 621 @Override 622 public boolean onJsPrompt(WebView view, String url, String message, 623 String defaultValue, JsPromptResult result) { 624 if (mDialogStrings == null) { 625 mDialogStrings = new StringBuffer(); 626 } 627 mDialogStrings.append("PROMPT: "); 628 mDialogStrings.append(message); 629 mDialogStrings.append(", default text: "); 630 mDialogStrings.append(defaultValue); 631 mDialogStrings.append('\n'); 632 result.confirm(); 633 return true; 634 } 635 636 @Override 637 public boolean onJsTimeout() { 638 Log.v(LOGTAG, "JavaScript timeout"); 639 return false; 640 } 641 642 @Override 643 public void onExceededDatabaseQuota(String url_str, 644 String databaseIdentifier, long currentQuota, 645 long estimatedSize, long totalUsedQuota, 646 WebStorage.QuotaUpdater callback) { 647 if (mDumpDatabaseCallbacks) { 648 if (mDatabaseCallbackStrings == null) { 649 mDatabaseCallbackStrings = new StringBuffer(); 650 } 651 652 String protocol = ""; 653 String host = ""; 654 int port = 0; 655 656 try { 657 URL url = new URL(url_str); 658 protocol = url.getProtocol(); 659 host = url.getHost(); 660 if (url.getPort() > -1) { 661 port = url.getPort(); 662 } 663 } catch (MalformedURLException e) {} 664 665 String databaseCallbackString = 666 "UI DELEGATE DATABASE CALLBACK: " + 667 "exceededDatabaseQuotaForSecurityOrigin:{" + protocol + 668 ", " + host + ", " + port + "} database:" + 669 databaseIdentifier + "\n"; 670 Log.v(LOGTAG, "LOG: "+databaseCallbackString); 671 mDatabaseCallbackStrings.append(databaseCallbackString); 672 } 673 // Give 5MB more quota. 674 callback.updateQuota(currentQuota + 1024 * 1024 * 5); 675 } 676 677 /** 678 * Instructs the client to show a prompt to ask the user to set the 679 * Geolocation permission state for the specified origin. 680 */ 681 @Override 682 public void onGeolocationPermissionsShowPrompt(String origin, 683 GeolocationPermissions.Callback callback) { 684 if (mGeolocationPermissionSet) { 685 callback.invoke(origin, mGeolocationPermission, false); 686 } 687 } 688 689 @Override 690 public boolean onConsoleMessage(ConsoleMessage consoleMessage) { 691 String msg = "CONSOLE MESSAGE: line " + consoleMessage.lineNumber() + ": " 692 + consoleMessage.message() + "\n"; 693 if (mConsoleMessages == null) { 694 mConsoleMessages = new StringBuffer(); 695 } 696 mConsoleMessages.append(msg); 697 Log.v(LOGTAG, "LOG: " + msg); 698 // the rationale here is that if there's an error of either type, and the test was 699 // waiting for "notifyDone" signal to finish, then there's no point in waiting 700 // anymore because the JS execution is already terminated at this point and a 701 // "notifyDone" will never come out so it's just wasting time till timeout kicks in 702 if (msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:") 703 && mWaitUntilDone) { 704 Log.w(LOGTAG, "Terminating test case on uncaught ReferenceError or TypeError."); 705 mHandler.postDelayed(new Runnable() { 706 public void run() { 707 notifyDone(); 708 } 709 }, 500); 710 } 711 return true; 712 } 713 714 @Override 715 public boolean onCreateWindow(WebView view, boolean dialog, 716 boolean userGesture, Message resultMsg) { 717 if (!mCanOpenWindows) { 718 // We can't open windows, so just send null back. 719 WebView.WebViewTransport transport = 720 (WebView.WebViewTransport) resultMsg.obj; 721 transport.setWebView(null); 722 resultMsg.sendToTarget(); 723 return true; 724 } 725 726 // We never display the new window, just create the view and 727 // allow it's content to execute and be recorded by the test 728 // runner. 729 730 HashMap<String, Object> jsIfaces = new HashMap<String, Object>(); 731 jsIfaces.put("layoutTestController", mCallbackProxy); 732 jsIfaces.put("eventSender", mCallbackProxy); 733 WebView newWindowView = new NewWindowWebView(TestShellActivity.this, jsIfaces); 734 setupWebViewForLayoutTests(newWindowView, mCallbackProxy); 735 WebView.WebViewTransport transport = 736 (WebView.WebViewTransport) resultMsg.obj; 737 transport.setWebView(newWindowView); 738 resultMsg.sendToTarget(); 739 return true; 740 } 741 742 @Override 743 public void onCloseWindow(WebView view) { 744 view.destroy(); 745 } 746 }; 747 748 private static class NewWindowWebView extends WebView { 749 public NewWindowWebView(Context context, Map<String, Object> jsIfaces) { 750 super(context, null, 0, jsIfaces); 751 } 752 } 753 754 private void resetTestStatus() { 755 mWaitUntilDone = false; 756 mDumpDataType = mDefaultDumpDataType; 757 mDumpTopFrameAsText = false; 758 mDumpChildFramesAsText = false; 759 mTimedOut = false; 760 mDumpTitleChanges = false; 761 mRequestedWebKitData = false; 762 mDumpDatabaseCallbacks = false; 763 mCanOpenWindows = false; 764 mEventSender.resetMouse(); 765 mEventSender.clearTouchPoints(); 766 mEventSender.clearTouchMetaState(); 767 mPageFinished = false; 768 mDumpWebKitData = false; 769 mGetDrawtime = false; 770 mSaveImagePath = null; 771 setDefaultWebSettings(mWebView); 772 } 773 774 private long[] getDrawWebViewTime(WebView view, int count) { 775 if (count == 0) 776 return null; 777 long[] ret = new long[count]; 778 long start; 779 Canvas canvas = new Canvas(); 780 Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Config.ARGB_8888); 781 canvas.setBitmap(bitmap); 782 for (int i = 0; i < count; i++) { 783 start = System.currentTimeMillis(); 784 view.draw(canvas); 785 ret[i] = System.currentTimeMillis() - start; 786 } 787 return ret; 788 } 789 790 private void drawPageToFile(String fileName, WebView view) { 791 Canvas canvas = new Canvas(); 792 Bitmap bitmap = Bitmap.createBitmap(view.getContentWidth(), view.getContentHeight(), 793 Config.ARGB_8888); 794 canvas.setBitmap(bitmap); 795 view.drawPage(canvas); 796 try { 797 FileOutputStream fos = new FileOutputStream(fileName); 798 if(!bitmap.compress(CompressFormat.PNG, 90, fos)) { 799 Log.w(LOGTAG, "Failed to compress and save image."); 800 } 801 } catch (IOException ioe) { 802 Log.e(LOGTAG, "", ioe); 803 } 804 bitmap.recycle(); 805 } 806 807 private boolean canMoveToNextTest() { 808 return (mDumpWebKitData && mPageFinished && !mWaitUntilDone) || mTimedOut; 809 } 810 811 private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) { 812 if (webview == null) { 813 return; 814 } 815 816 setDefaultWebSettings(webview); 817 818 webview.setWebChromeClient(mChromeClient); 819 webview.setWebViewClient(mViewClient); 820 // Setting a touch interval of -1 effectively disables the optimisation in WebView 821 // that stops repeated touch events flooding WebCore. The Event Sender only sends a 822 // single event rather than a stream of events (like what would generally happen in 823 // a real use of touch events in a WebView) and so if the WebView drops the event, 824 // the test will fail as the test expects one callback for every touch it synthesizes. 825 webview.setTouchInterval(-1); 826 } 827 828 public void setDefaultWebSettings(WebView webview) { 829 WebSettings settings = webview.getSettings(); 830 settings.setAppCacheEnabled(true); 831 settings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); 832 settings.setAppCacheMaxSize(Long.MAX_VALUE); 833 settings.setJavaScriptEnabled(true); 834 settings.setJavaScriptCanOpenWindowsAutomatically(true); 835 settings.setSupportMultipleWindows(true); 836 settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); 837 settings.setDatabaseEnabled(true); 838 settings.setDatabasePath(getDir("databases",0).getAbsolutePath()); 839 settings.setDomStorageEnabled(true); 840 settings.setWorkersEnabled(false); 841 settings.setXSSAuditorEnabled(false); 842 } 843 844 private WebView mWebView; 845 private WebViewEventSender mEventSender; 846 private AsyncHandler mHandler; 847 private TestShellCallback mCallback; 848 849 private CallbackProxy mCallbackProxy; 850 851 private String mTestUrl; 852 private String mResultFile; 853 private int mTimeoutInMillis; 854 private String mUiAutoTestPath; 855 private String mSaveImagePath; 856 private BufferedReader mTestListReader; 857 private boolean mGetDrawtime; 858 private int mTotalTestCount; 859 private int mCurrentTestNumber; 860 861 // States 862 private boolean mTimedOut; 863 private boolean mRequestedWebKitData; 864 private boolean mFinishedRunning; 865 866 // Layout test controller variables. 867 private DumpDataType mDumpDataType; 868 private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR; 869 private boolean mDumpTopFrameAsText; 870 private boolean mDumpChildFramesAsText; 871 private boolean mWaitUntilDone; 872 private boolean mDumpTitleChanges; 873 private StringBuffer mTitleChanges; 874 private StringBuffer mDialogStrings; 875 private boolean mKeepWebHistory; 876 private Vector mWebHistory; 877 private boolean mDumpDatabaseCallbacks; 878 private StringBuffer mDatabaseCallbackStrings; 879 private StringBuffer mConsoleMessages; 880 private boolean mCanOpenWindows; 881 882 private boolean mPageFinished = false; 883 private boolean mDumpWebKitData = false; 884 885 static final String TIMEOUT_STR = "**Test timeout"; 886 887 static final int MSG_TIMEOUT = 0; 888 static final int MSG_WEBKIT_DATA = 1; 889 890 static final String LOGTAG="TestShell"; 891 892 static final String TEST_URL = "TestUrl"; 893 static final String RESULT_FILE = "ResultFile"; 894 static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis"; 895 static final String UI_AUTO_TEST = "UiAutoTest"; 896 static final String GET_DRAW_TIME = "GetDrawTime"; 897 static final String SAVE_IMAGE = "SaveImage"; 898 static final String TOTAL_TEST_COUNT = "TestCount"; 899 static final String CURRENT_TEST_NUMBER = "TestNumber"; 900 901 static final int DRAW_RUNS = 5; 902 static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt"; 903 904 private boolean mGeolocationPermissionSet; 905 private boolean mGeolocationPermission; 906} 907