TestShellActivity.java revision f92bd42a702af7047ac4bd7c95b4a82973b7a79d
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 android.app.Activity; 20import android.app.AlertDialog; 21import android.content.DialogInterface; 22import android.content.Intent; 23import android.content.DialogInterface.OnClickListener; 24import android.graphics.Bitmap; 25import android.net.http.SslError; 26import android.os.Bundle; 27import android.os.Handler; 28import android.os.Message; 29import android.util.Log; 30import android.view.ViewGroup; 31import android.webkit.HttpAuthHandler; 32import android.webkit.JsPromptResult; 33import android.webkit.JsResult; 34import android.webkit.SslErrorHandler; 35import android.webkit.WebChromeClient; 36import android.webkit.WebSettings; 37import android.webkit.WebView; 38import android.webkit.WebViewClient; 39import android.widget.LinearLayout; 40 41import java.io.BufferedReader; 42import java.io.File; 43import java.io.FileOutputStream; 44import java.io.FileReader; 45import java.io.IOException; 46import java.util.Vector; 47 48public class TestShellActivity extends Activity implements LayoutTestController { 49 50 static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP} 51 52 public class AsyncHandler extends Handler { 53 @Override 54 public void handleMessage(Message msg) { 55 if (msg.what == MSG_TIMEOUT) { 56 mTimedOut = true; 57 if(mCallback != null) 58 mCallback.timedOut(mWebView.getUrl()); 59 requestWebKitData(); 60 return; 61 } else if (msg.what == MSG_WEBKIT_DATA) { 62 TestShellActivity.this.dump(mTimedOut, (String)msg.obj); 63 return; 64 } 65 66 super.handleMessage(msg); 67 } 68 } 69 70 public void requestWebKitData() { 71 Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA); 72 73 if (mRequestedWebKitData) 74 throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl()); 75 76 mRequestedWebKitData = true; 77 switch (mDumpDataType) { 78 case DUMP_AS_TEXT: 79 mWebView.documentAsText(callback); 80 break; 81 case EXT_REPR: 82 mWebView.externalRepresentation(callback); 83 break; 84 default: 85 finished(); 86 break; 87 } 88 } 89 90 @Override 91 protected void onCreate(Bundle icicle) { 92 super.onCreate(icicle); 93 94 LinearLayout contentView = new LinearLayout(this); 95 contentView.setOrientation(LinearLayout.VERTICAL); 96 setContentView(contentView); 97 98 mWebView = new WebView(this); 99 mWebView.getSettings().setJavaScriptEnabled(true); 100 mWebView.setWebChromeClient(mChromeClient); 101 mWebView.setWebViewClient(new WebViewClient(){ 102 103 @Override 104 public void onPageFinished(WebView view, String url) { 105 Log.v(LOGTAG, "onPageFinished, url=" + url); 106 super.onPageFinished(view, url); 107 } 108 109 @Override 110 public void onPageStarted(WebView view, String url, Bitmap favicon) { 111 Log.v(LOGTAG, "onPageStarted, url=" + url); 112 super.onPageStarted(view, url, favicon); 113 } 114 115 @Override 116 public void onReceivedError(WebView view, int errorCode, String description, 117 String failingUrl) { 118 Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode 119 + ", desc=" + description + ", url=" + failingUrl); 120 super.onReceivedError(view, errorCode, description, failingUrl); 121 } 122 123 @Override 124 public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, 125 String host, String realm) { 126 handler.cancel(); 127 } 128 129 @Override 130 public void onReceivedSslError(WebView view, SslErrorHandler handler, 131 SslError error) { 132 handler.proceed(); 133 } 134 135 }); 136 mEventSender = new WebViewEventSender(mWebView); 137 mCallbackProxy = new CallbackProxy(mEventSender, this); 138 139 mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController"); 140 mWebView.addJavascriptInterface(mCallbackProxy, "eventSender"); 141 contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f)); 142 143 mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); 144 145 mHandler = new AsyncHandler(); 146 147 Intent intent = getIntent(); 148 if (intent != null) { 149 executeIntent(intent); 150 } 151 } 152 153 @Override 154 protected void onNewIntent(Intent intent) { 155 super.onNewIntent(intent); 156 executeIntent(intent); 157 } 158 159 private void executeIntent(Intent intent) { 160 resetTestStatus(); 161 if (!Intent.ACTION_VIEW.equals(intent.getAction())) { 162 return; 163 } 164 165 mTestUrl = intent.getStringExtra(TEST_URL); 166 if (mTestUrl == null) { 167 mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST); 168 if(mUiAutoTestPath != null) { 169 beginUiAutoTest(); 170 } 171 return; 172 } 173 174 mResultFile = intent.getStringExtra(RESULT_FILE); 175 mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0); 176 177 Log.v(LOGTAG, " Loading " + mTestUrl); 178 mWebView.loadUrl(mTestUrl); 179 180 if (mTimeoutInMillis > 0) { 181 // Create a timeout timer 182 Message m = mHandler.obtainMessage(MSG_TIMEOUT); 183 mHandler.sendMessageDelayed(m, mTimeoutInMillis); 184 } 185 } 186 187 private void beginUiAutoTest() { 188 try { 189 mTestListReader = new BufferedReader( 190 new FileReader(mUiAutoTestPath)); 191 } catch (IOException ioe) { 192 Log.e(LOGTAG, "Failed to open test list for read.", ioe); 193 finishUiAutoTest(); 194 return; 195 } 196 moveToNextTest(); 197 } 198 199 private void finishUiAutoTest() { 200 try { 201 if(mTestListReader != null) 202 mTestListReader.close(); 203 } catch (IOException ioe) { 204 Log.w(LOGTAG, "Failed to close test list file.", ioe); 205 } 206 finished(); 207 } 208 209 private void moveToNextTest() { 210 String url = null; 211 try { 212 url = mTestListReader.readLine(); 213 } catch (IOException ioe) { 214 Log.e(LOGTAG, "Failed to read next test.", ioe); 215 finishUiAutoTest(); 216 return; 217 } 218 if (url == null) { 219 mUiAutoTestPath = null; 220 finishUiAutoTest(); 221 AlertDialog.Builder builder = new AlertDialog.Builder(this); 222 builder.setMessage("All tests finished. Exit?") 223 .setCancelable(false) 224 .setPositiveButton("Yes", new OnClickListener(){ 225 public void onClick(DialogInterface dialog, int which) { 226 TestShellActivity.this.finish(); 227 } 228 }) 229 .setNegativeButton("No", new OnClickListener(){ 230 public void onClick(DialogInterface dialog, int which) { 231 dialog.cancel(); 232 } 233 }); 234 builder.create().show(); 235 return; 236 } 237 url = "file://" + url; 238 Intent intent = new Intent(Intent.ACTION_VIEW); 239 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 240 intent.putExtra(TestShellActivity.TEST_URL, url); 241 intent.putExtra(TIMEOUT_IN_MILLIS, 10000); 242 executeIntent(intent); 243 } 244 245 @Override 246 protected void onStop() { 247 super.onStop(); 248 mWebView.stopLoading(); 249 } 250 251 @Override 252 protected void onDestroy() { 253 super.onDestroy(); 254 mWebView.destroy(); 255 mWebView = null; 256 } 257 258 @Override 259 public void onLowMemory() { 260 super.onLowMemory(); 261 Log.e(LOGTAG, "Low memory, kill self"); 262 System.exit(1); 263 } 264 265 // Dump the page 266 public void dump(boolean timeout, String webkitData) { 267 if (mResultFile == null || mResultFile.length() == 0) { 268 finished(); 269 return; 270 } 271 272 try { 273 File parentDir = new File(mResultFile).getParentFile(); 274 if (!parentDir.exists()) { 275 parentDir.mkdirs(); 276 } 277 278 FileOutputStream os = new FileOutputStream(mResultFile); 279 if (timeout) { 280 Log.w("Layout test: Timeout", mResultFile); 281 os.write(TIMEOUT_STR.getBytes()); 282 os.write('\n'); 283 } 284 if (mDumpTitleChanges) 285 os.write(mTitleChanges.toString().getBytes()); 286 if (mDialogStrings != null) 287 os.write(mDialogStrings.toString().getBytes()); 288 mDialogStrings = null; 289 if (webkitData != null) 290 os.write(webkitData.getBytes()); 291 os.flush(); 292 os.close(); 293 } catch (IOException ex) { 294 Log.e(LOGTAG, "Cannot write to " + mResultFile + ", " + ex.getMessage()); 295 } 296 297 finished(); 298 } 299 300 public void setCallback(TestShellCallback callback) { 301 mCallback = callback; 302 } 303 304 public void finished() { 305 if (mUiAutoTestPath != null) { 306 //don't really finish here 307 moveToNextTest(); 308 } else { 309 if (mCallback != null) { 310 mCallback.finished(); 311 } 312 } 313 } 314 315 public void setDefaultDumpDataType(DumpDataType defaultDumpDataType) { 316 mDefaultDumpDataType = defaultDumpDataType; 317 } 318 319 // ....................................... 320 // LayoutTestController Functions 321 public void dumpAsText() { 322 mDumpDataType = DumpDataType.DUMP_AS_TEXT; 323 if (mWebView != null) { 324 String url = mWebView.getUrl(); 325 Log.v(LOGTAG, "dumpAsText called: "+url); 326 } 327 } 328 329 public void waitUntilDone() { 330 mWaitUntilDone = true; 331 String url = mWebView.getUrl(); 332 Log.v(LOGTAG, "waitUntilDone called: " + url); 333 } 334 335 public void notifyDone() { 336 String url = mWebView.getUrl(); 337 Log.v(LOGTAG, "notifyDone called: " + url); 338 if (mWaitUntilDone) { 339 mWaitUntilDone = false; 340 mChromeClient.onProgressChanged(mWebView, 100); 341 } 342 } 343 344 public void display() { 345 mWebView.invalidate(); 346 } 347 348 public void clearBackForwardList() { 349 mWebView.clearHistory(); 350 351 } 352 353 public void dumpBackForwardList() { 354 //printf("\n============== Back Forward List ==============\n"); 355 // mWebHistory 356 //printf("===============================================\n"); 357 358 } 359 360 public void dumpChildFrameScrollPositions() { 361 // TODO Auto-generated method stub 362 363 } 364 365 public void dumpEditingCallbacks() { 366 // TODO Auto-generated method stub 367 368 } 369 370 public void dumpSelectionRect() { 371 // TODO Auto-generated method stub 372 373 } 374 375 public void dumpTitleChanges() { 376 if (!mDumpTitleChanges) { 377 mTitleChanges = new StringBuffer(); 378 } 379 mDumpTitleChanges = true; 380 } 381 382 public void keepWebHistory() { 383 if (!mKeepWebHistory) { 384 mWebHistory = new Vector(); 385 } 386 mKeepWebHistory = true; 387 } 388 389 public void queueBackNavigation(int howfar) { 390 // TODO Auto-generated method stub 391 392 } 393 394 public void queueForwardNavigation(int howfar) { 395 // TODO Auto-generated method stub 396 397 } 398 399 public void queueLoad(String Url, String frameTarget) { 400 // TODO Auto-generated method stub 401 402 } 403 404 public void queueReload() { 405 mWebView.reload(); 406 } 407 408 public void queueScript(String scriptToRunInCurrentContext) { 409 mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext); 410 } 411 412 public void repaintSweepHorizontally() { 413 // TODO Auto-generated method stub 414 415 } 416 417 public void setAcceptsEditing(boolean b) { 418 // TODO Auto-generated method stub 419 420 } 421 422 public void setMainFrameIsFirstResponder(boolean b) { 423 // TODO Auto-generated method stub 424 425 } 426 427 public void setWindowIsKey(boolean b) { 428 // This is meant to show/hide the window. The best I can find 429 // is setEnabled() 430 mWebView.setEnabled(b); 431 } 432 433 public void testRepaint() { 434 mWebView.invalidate(); 435 } 436 437 private final WebChromeClient mChromeClient = new WebChromeClient() { 438 @Override 439 public void onProgressChanged(WebView view, int newProgress) { 440 if (newProgress == 100) { 441 if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) { 442 String url = mWebView.getUrl(); 443 Log.v(LOGTAG, "Finished: "+ url); 444 mHandler.removeMessages(MSG_TIMEOUT); 445 requestWebKitData(); 446 } else { 447 String url = mWebView.getUrl(); 448 if (mTimedOut) { 449 Log.v(LOGTAG, "Timed out before finishing: " + url); 450 } else if (mWaitUntilDone) { 451 Log.v(LOGTAG, "Waiting for notifyDone: " + url); 452 } else if (mRequestedWebKitData) { 453 Log.v(LOGTAG, "Requested webkit data ready: " + url); 454 } 455 } 456 } 457 } 458 459 @Override 460 public void onReceivedTitle(WebView view, String title) { 461 if (title.length() > 30) 462 title = "..."+title.substring(title.length()-30); 463 setTitle(title); 464 if (mDumpTitleChanges) { 465 mTitleChanges.append("TITLE CHANGED: "); 466 mTitleChanges.append(title); 467 mTitleChanges.append("\n"); 468 } 469 } 470 471 @Override 472 public boolean onJsAlert(WebView view, String url, String message, 473 JsResult result) { 474 if (mDialogStrings == null) { 475 mDialogStrings = new StringBuffer(); 476 } 477 mDialogStrings.append("ALERT: "); 478 mDialogStrings.append(message); 479 mDialogStrings.append('\n'); 480 result.confirm(); 481 return true; 482 } 483 484 @Override 485 public boolean onJsConfirm(WebView view, String url, String message, 486 JsResult result) { 487 if (mDialogStrings == null) { 488 mDialogStrings = new StringBuffer(); 489 } 490 mDialogStrings.append("CONFIRM: "); 491 mDialogStrings.append(message); 492 mDialogStrings.append('\n'); 493 result.confirm(); 494 return true; 495 } 496 497 @Override 498 public boolean onJsPrompt(WebView view, String url, String message, 499 String defaultValue, JsPromptResult result) { 500 if (mDialogStrings == null) { 501 mDialogStrings = new StringBuffer(); 502 } 503 mDialogStrings.append("PROMPT: "); 504 mDialogStrings.append(message); 505 mDialogStrings.append(", default text: "); 506 mDialogStrings.append(defaultValue); 507 mDialogStrings.append('\n'); 508 result.confirm(); 509 return true; 510 } 511 }; 512 513 private void resetTestStatus() { 514 mWaitUntilDone = false; 515 mDumpDataType = mDefaultDumpDataType; 516 mTimedOut = false; 517 mDumpTitleChanges = false; 518 mRequestedWebKitData = false; 519 mEventSender.resetMouse(); 520 } 521 522 private WebView mWebView; 523 private WebViewEventSender mEventSender; 524 private AsyncHandler mHandler; 525 private TestShellCallback mCallback; 526 527 private CallbackProxy mCallbackProxy; 528 529 private String mTestUrl; 530 private String mResultFile; 531 private int mTimeoutInMillis; 532 private String mUiAutoTestPath; 533 private BufferedReader mTestListReader; 534 535 // States 536 private boolean mTimedOut; 537 private boolean mRequestedWebKitData; 538 private boolean mFinishedRunning; 539 540 // Layout test controller variables. 541 private DumpDataType mDumpDataType; 542 private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR; 543 private boolean mWaitUntilDone; 544 private boolean mDumpTitleChanges; 545 private StringBuffer mTitleChanges; 546 private StringBuffer mDialogStrings; 547 private boolean mKeepWebHistory; 548 private Vector mWebHistory; 549 550 static final String TIMEOUT_STR = "**Test timeout"; 551 552 static final int MSG_TIMEOUT = 0; 553 static final int MSG_WEBKIT_DATA = 1; 554 555 static final String LOGTAG="TestShell"; 556 557 static final String TEST_URL = "TestUrl"; 558 static final String RESULT_FILE = "ResultFile"; 559 static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis"; 560 static final String UI_AUTO_TEST = "UiAutoTest"; 561} 562