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