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