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