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