LayoutTestsExecutor.java revision 2c38de8436fefb5c2834d843ab3520474bc3a35a
1/*
2 * Copyright (C) 2010 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.dumprendertree2;
18
19import android.app.Activity;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.ServiceConnection;
24import android.net.Uri;
25import android.os.Bundle;
26import android.os.Environment;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Message;
30import android.os.Messenger;
31import android.os.PowerManager;
32import android.os.Process;
33import android.os.RemoteException;
34import android.os.PowerManager.WakeLock;
35import android.util.Log;
36import android.view.Window;
37import android.webkit.ConsoleMessage;
38import android.webkit.HttpAuthHandler;
39import android.webkit.JsPromptResult;
40import android.webkit.JsResult;
41import android.webkit.WebChromeClient;
42import android.webkit.WebSettings;
43import android.webkit.WebView;
44import android.webkit.WebViewClient;
45import android.webkit.GeolocationPermissions;
46import android.webkit.WebStorage.QuotaUpdater;
47
48import java.io.File;
49import java.lang.Thread.UncaughtExceptionHandler;
50import java.net.MalformedURLException;
51import java.net.URL;
52import java.util.HashMap;
53import java.util.Iterator;
54import java.util.List;
55import java.util.Map;
56
57/**
58 * This activity executes the test. It contains WebView and logic of LayoutTestController
59 * functions. It runs in a separate process and sends the results of running the test
60 * to ManagerService. The reason why is to handle crashing (test that crashes brings down
61 * whole process with it).
62 */
63public class LayoutTestsExecutor extends Activity {
64
65    private enum CurrentState {
66        IDLE,
67        RENDERING_PAGE,
68        WAITING_FOR_ASYNCHRONOUS_TEST,
69        OBTAINING_RESULT;
70
71        public boolean isRunningState() {
72            return this == CurrentState.RENDERING_PAGE ||
73                    this == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST;
74        }
75    }
76
77    private static final String LOG_TAG = "LayoutTestExecutor";
78
79    public static final String EXTRA_TESTS_LIST = "TestsList";
80    public static final String EXTRA_TEST_INDEX = "TestIndex";
81
82    private static final int MSG_ACTUAL_RESULT_OBTAINED = 0;
83    private static final int MSG_TEST_TIMED_OUT = 1;
84
85    private static final int DEFAULT_TIME_OUT_MS = 15 * 1000;
86
87    /** A list of tests that remain to run since last crash */
88    private List<String> mTestsList;
89
90    /**
91     * This is a number of currently running test. It is 0-based and doesn't reset after
92     * the crash. Initial index is passed to LayoutTestsExecuter in the intent that starts
93     * it.
94     */
95    private int mCurrentTestIndex;
96
97    /** The total number of tests to run, doesn't reset after crash */
98    private int mTotalTestCount;
99
100    private WebView mCurrentWebView;
101    private String mCurrentTestRelativePath;
102    private String mCurrentTestUri;
103    private CurrentState mCurrentState = CurrentState.IDLE;
104
105    private boolean mCurrentTestTimedOut;
106    private AbstractResult mCurrentResult;
107    private AdditionalTextOutput mCurrentAdditionalTextOutput;
108
109    private LayoutTestController mLayoutTestController = new LayoutTestController(this);
110    private boolean mCanOpenWindows;
111    private boolean mDumpDatabaseCallbacks;
112    private boolean mIsGeolocationPermissionSet;
113    private boolean mGeolocationPermission;
114    private Map<GeolocationPermissions.Callback, String> mPendingGeolocationPermissionCallbacks;
115
116    private EventSender mEventSender = new EventSender();
117
118    private WakeLock mScreenDimLock;
119
120    /** COMMUNICATION WITH ManagerService */
121
122    private Messenger mManagerServiceMessenger;
123
124    private ServiceConnection mServiceConnection = new ServiceConnection() {
125
126        @Override
127        public void onServiceConnected(ComponentName name, IBinder service) {
128            mManagerServiceMessenger = new Messenger(service);
129            startTests();
130        }
131
132        @Override
133        public void onServiceDisconnected(ComponentName name) {
134            /** TODO */
135        }
136    };
137
138    private final Handler mResultHandler = new Handler() {
139        @Override
140        public void handleMessage(Message msg) {
141            switch (msg.what) {
142                case MSG_ACTUAL_RESULT_OBTAINED:
143                    onActualResultsObtained();
144                    break;
145
146                case MSG_TEST_TIMED_OUT:
147                    onTestTimedOut();
148                    break;
149
150                default:
151                    break;
152            }
153        }
154    };
155
156    /** WEBVIEW CONFIGURATION */
157
158    private WebViewClient mWebViewClient = new WebViewClient() {
159        @Override
160        public void onPageFinished(WebView view, String url) {
161            /** Some tests fire up many page loads, we don't want to detect them */
162            if (!url.equals(mCurrentTestUri)) {
163                return;
164            }
165
166            if (mCurrentState == CurrentState.RENDERING_PAGE) {
167                onTestFinished();
168            }
169        }
170
171         @Override
172         public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
173                 String host, String realm) {
174             if (handler.useHttpAuthUsernamePassword() && view != null) {
175                 String[] credentials = view.getHttpAuthUsernamePassword(host, realm);
176                 if (credentials != null && credentials.length == 2) {
177                     handler.proceed(credentials[0], credentials[1]);
178                     return;
179                 }
180             }
181             handler.cancel();
182         }
183    };
184
185    private WebChromeClient mWebChromeClient = new WebChromeClient() {
186        @Override
187        public void onExceededDatabaseQuota(String url, String databaseIdentifier,
188                long currentQuota, long estimatedSize, long totalUsedQuota,
189                QuotaUpdater quotaUpdater) {
190            /** TODO: This should be recorded as part of the text result */
191            /** TODO: The quota should also probably be reset somehow for every test? */
192            if (mDumpDatabaseCallbacks) {
193                getCurrentAdditionalTextOutput().appendExceededDbQuotaMessage(url,
194                        databaseIdentifier);
195            }
196            quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024);
197        }
198
199        @Override
200        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
201            getCurrentAdditionalTextOutput().appendJsAlert(message);
202            result.confirm();
203            return true;
204        }
205
206        @Override
207        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
208            getCurrentAdditionalTextOutput().appendJsConfirm(message);
209            result.confirm();
210            return true;
211        }
212
213        @Override
214        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
215                JsPromptResult result) {
216            getCurrentAdditionalTextOutput().appendJsPrompt(message, defaultValue);
217            result.confirm();
218            return true;
219        }
220
221        @Override
222        public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
223            getCurrentAdditionalTextOutput().appendConsoleMessage(consoleMessage);
224            return true;
225        }
226
227        @Override
228        public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
229                Message resultMsg) {
230            WebView.WebViewTransport transport = (WebView.WebViewTransport)resultMsg.obj;
231            /** By default windows cannot be opened, so just send null back. */
232            WebView newWindowWebView = null;
233
234            if (mCanOpenWindows) {
235                /**
236                 * We never display the new window, just create the view and allow it's content to
237                 * execute and be recorded by the executor.
238                 */
239                newWindowWebView = new WebView(LayoutTestsExecutor.this);
240                setupWebView(newWindowWebView);
241            }
242
243            transport.setWebView(newWindowWebView);
244            resultMsg.sendToTarget();
245            return true;
246        }
247
248        @Override
249        public void onGeolocationPermissionsShowPrompt(String origin,
250                GeolocationPermissions.Callback callback) {
251            if (mIsGeolocationPermissionSet) {
252                callback.invoke(origin, mGeolocationPermission, false);
253                return;
254            }
255            if (mPendingGeolocationPermissionCallbacks == null) {
256                mPendingGeolocationPermissionCallbacks =
257                        new HashMap<GeolocationPermissions.Callback, String>();
258            }
259            mPendingGeolocationPermissionCallbacks.put(callback, origin);
260        }
261    };
262
263    /** IMPLEMENTATION */
264
265    @Override
266    protected void onCreate(Bundle savedInstanceState) {
267        super.onCreate(savedInstanceState);
268
269        /**
270         * It detects the crash by catching all the uncaught exceptions. However, we
271         * still have to kill the process, because after catching the exception the
272         * activity remains in a strange state, where intents don't revive it.
273         * However, we send the message to the service to speed up the rebooting
274         * (we don't have to wait for time-out to kick in).
275         */
276        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
277            @Override
278            public void uncaughtException(Thread thread, Throwable e) {
279                Log.w(LOG_TAG,
280                        "onTestCrashed(): " + mCurrentTestRelativePath + " thread=" + thread, e);
281
282                try {
283                    Message serviceMsg =
284                            Message.obtain(null, ManagerService.MSG_CURRENT_TEST_CRASHED);
285
286                    mManagerServiceMessenger.send(serviceMsg);
287                } catch (RemoteException e2) {
288                    Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e2);
289                }
290
291                Process.killProcess(Process.myPid());
292            }
293        });
294
295        requestWindowFeature(Window.FEATURE_PROGRESS);
296
297        Intent intent = getIntent();
298        mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST);
299        mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1);
300        mTotalTestCount = mCurrentTestIndex + mTestsList.size();
301
302        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
303        mScreenDimLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK
304                | PowerManager.ON_AFTER_RELEASE, "WakeLock in LayoutTester");
305        mScreenDimLock.acquire();
306
307        bindService(new Intent(this, ManagerService.class), mServiceConnection,
308                Context.BIND_AUTO_CREATE);
309    }
310
311    private void reset() {
312        WebView previousWebView = mCurrentWebView;
313
314        resetLayoutTestController();
315
316        mCurrentTestTimedOut = false;
317        mCurrentResult = null;
318        mCurrentAdditionalTextOutput = null;
319
320        mCurrentWebView = new WebView(this);
321        setupWebView(mCurrentWebView);
322
323        mEventSender.reset(mCurrentWebView);
324
325        setContentView(mCurrentWebView);
326        if (previousWebView != null) {
327            Log.d(LOG_TAG + "::reset", "previousWebView != null");
328            previousWebView.destroy();
329        }
330    }
331
332    private void setupWebView(WebView webView) {
333        webView.setWebViewClient(mWebViewClient);
334        webView.setWebChromeClient(mWebChromeClient);
335        webView.addJavascriptInterface(mLayoutTestController, "layoutTestController");
336        webView.addJavascriptInterface(mEventSender, "eventSender");
337
338        /**
339         * Setting a touch interval of -1 effectively disables the optimisation in WebView
340         * that stops repeated touch events flooding WebCore. The Event Sender only sends a
341         * single event rather than a stream of events (like what would generally happen in
342         * a real use of touch events in a WebView)  and so if the WebView drops the event,
343         * the test will fail as the test expects one callback for every touch it synthesizes.
344         */
345        webView.setTouchInterval(-1);
346
347        webView.clearCache(true);
348
349        WebSettings webViewSettings = webView.getSettings();
350        webViewSettings.setAppCacheEnabled(true);
351        webViewSettings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
352        webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE);
353        webViewSettings.setJavaScriptEnabled(true);
354        webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true);
355        webViewSettings.setSupportMultipleWindows(true);
356        webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
357        webViewSettings.setDatabaseEnabled(true);
358        webViewSettings.setDatabasePath(getDir("databases", 0).getAbsolutePath());
359        webViewSettings.setDomStorageEnabled(true);
360        webViewSettings.setWorkersEnabled(false);
361        webViewSettings.setXSSAuditorEnabled(false);
362
363        // This is asynchronous, but it gets processed by WebCore before it starts loading pages.
364        mCurrentWebView.useMockDeviceOrientation();
365    }
366
367    private void startTests() {
368        try {
369            Message serviceMsg =
370                    Message.obtain(null, ManagerService.MSG_FIRST_TEST);
371
372            Bundle bundle = new Bundle();
373            if (!mTestsList.isEmpty()) {
374                bundle.putString("firstTest", mTestsList.get(0));
375                bundle.putInt("index", mCurrentTestIndex);
376            }
377
378            serviceMsg.setData(bundle);
379            mManagerServiceMessenger.send(serviceMsg);
380        } catch (RemoteException e) {
381            Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e);
382        }
383
384        runNextTest();
385    }
386
387    private void runNextTest() {
388        assert mCurrentState == CurrentState.IDLE : "mCurrentState = " + mCurrentState.name();
389
390        if (mTestsList.isEmpty()) {
391            onAllTestsFinished();
392            return;
393        }
394
395        mCurrentTestRelativePath = mTestsList.remove(0);
396
397        Log.i(LOG_TAG, "runNextTest(): Start: " + mCurrentTestRelativePath +
398                " (" + mCurrentTestIndex + ")");
399
400        mCurrentTestUri = FileFilter.getUrl(mCurrentTestRelativePath).toString();
401
402        reset();
403
404        /** Start time-out countdown and the test */
405        mCurrentState = CurrentState.RENDERING_PAGE;
406        mResultHandler.sendEmptyMessageDelayed(MSG_TEST_TIMED_OUT, DEFAULT_TIME_OUT_MS);
407        mCurrentWebView.loadUrl(mCurrentTestUri);
408    }
409
410    private void onTestTimedOut() {
411        assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name();
412
413        Log.w(LOG_TAG, "onTestTimedOut(): " + mCurrentTestRelativePath);
414        mCurrentTestTimedOut = true;
415
416        /**
417         * While it is theoretically possible that the test times out because
418         * of webview becoming unresponsive, it is very unlikely. Therefore it's
419         * assumed that obtaining results (that calls various webview methods)
420         * will not itself hang.
421         */
422        obtainActualResultsFromWebView();
423    }
424
425    private void onTestFinished() {
426        assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name();
427
428        Log.i(LOG_TAG, "onTestFinished(): " + mCurrentTestRelativePath);
429        obtainActualResultsFromWebView();
430    }
431
432    private void obtainActualResultsFromWebView() {
433        /**
434         * If the result has not been set by the time the test finishes we create
435         * a default type of result.
436         */
437        if (mCurrentResult == null) {
438            /** TODO: Default type should be RenderTreeResult. We don't support it now. */
439            mCurrentResult = new TextResult(mCurrentTestRelativePath);
440        }
441
442        mCurrentState = CurrentState.OBTAINING_RESULT;
443
444        mCurrentResult.obtainActualResults(mCurrentWebView,
445                mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED));
446    }
447
448    private void onActualResultsObtained() {
449        assert mCurrentState == CurrentState.OBTAINING_RESULT
450                : "mCurrentState = " + mCurrentState.name();
451
452        Log.i(LOG_TAG, "onActualResultsObtained(): " + mCurrentTestRelativePath);
453        mCurrentState = CurrentState.IDLE;
454
455        mResultHandler.removeMessages(MSG_TEST_TIMED_OUT);
456        reportResultToService();
457        mCurrentTestIndex++;
458        updateProgressBar();
459        runNextTest();
460    }
461
462    private void reportResultToService() {
463        if (mCurrentAdditionalTextOutput != null) {
464            mCurrentResult.setAdditionalTextOutputString(mCurrentAdditionalTextOutput.toString());
465        }
466
467        try {
468            Message serviceMsg =
469                    Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS);
470
471            Bundle bundle = mCurrentResult.getBundle();
472            bundle.putInt("testIndex", mCurrentTestIndex);
473            if (mCurrentTestTimedOut) {
474                bundle.putString("resultCode", AbstractResult.ResultCode.FAIL_TIMED_OUT.name());
475            }
476            if (!mTestsList.isEmpty()) {
477                bundle.putString("nextTest", mTestsList.get(0));
478            }
479
480            serviceMsg.setData(bundle);
481            mManagerServiceMessenger.send(serviceMsg);
482        } catch (RemoteException e) {
483            Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e);
484        }
485    }
486
487    private void updateProgressBar() {
488        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
489                mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount);
490        setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " +
491                "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")");
492    }
493
494    private void onAllTestsFinished() {
495        mScreenDimLock.release();
496
497        try {
498            Message serviceMsg =
499                    Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED);
500            mManagerServiceMessenger.send(serviceMsg);
501        } catch (RemoteException e) {
502            Log.e(LOG_TAG, "mCurrentTestRelativePath=" + mCurrentTestRelativePath, e);
503        }
504
505        unbindService(mServiceConnection);
506    }
507
508    private AdditionalTextOutput getCurrentAdditionalTextOutput() {
509        if (mCurrentAdditionalTextOutput == null) {
510            mCurrentAdditionalTextOutput = new AdditionalTextOutput();
511        }
512        return mCurrentAdditionalTextOutput;
513    }
514
515    /** LAYOUT TEST CONTROLLER */
516
517    private static final int MSG_WAIT_UNTIL_DONE = 0;
518    private static final int MSG_NOTIFY_DONE = 1;
519    private static final int MSG_DUMP_AS_TEXT = 2;
520    private static final int MSG_DUMP_CHILD_FRAMES_AS_TEXT = 3;
521    private static final int MSG_SET_CAN_OPEN_WINDOWS = 4;
522    private static final int MSG_DUMP_DATABASE_CALLBACKS = 5;
523    private static final int MSG_SET_GEOLOCATION_PERMISSION = 6;
524    private static final int MSG_OVERRIDE_PREFERENCE = 7;
525    private static final int MSG_SET_XSS_AUDITOR_ENABLED = 8;
526
527    /** String constants for use with layoutTestController.overridePreference() */
528    private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED =
529            "WebKitOfflineWebApplicationCacheEnabled";
530
531    Handler mLayoutTestControllerHandler = new Handler() {
532        @Override
533        public void handleMessage(Message msg) {
534            assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name();
535
536            switch (msg.what) {
537                case MSG_DUMP_AS_TEXT:
538                    if (mCurrentResult == null) {
539                        mCurrentResult = new TextResult(mCurrentTestRelativePath);
540                    }
541                    assert mCurrentResult instanceof TextResult
542                            : "mCurrentResult instanceof" + mCurrentResult.getClass().getName();
543                    break;
544
545                case MSG_DUMP_CHILD_FRAMES_AS_TEXT:
546                    /** If dumpAsText was not called we assume that the result should be text */
547                    if (mCurrentResult == null) {
548                        mCurrentResult = new TextResult(mCurrentTestRelativePath);
549                    }
550
551                    assert mCurrentResult instanceof TextResult
552                            : "mCurrentResult instanceof" + mCurrentResult.getClass().getName();
553
554                    ((TextResult)mCurrentResult).setDumpChildFramesAsText(true);
555                    break;
556
557                case MSG_DUMP_DATABASE_CALLBACKS:
558                    mDumpDatabaseCallbacks = true;
559                    break;
560
561                case MSG_NOTIFY_DONE:
562                    if (mCurrentState == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST) {
563                        onTestFinished();
564                    }
565                    break;
566
567                case MSG_OVERRIDE_PREFERENCE:
568                    /**
569                     * TODO: We should look up the correct WebView for the frame which
570                     * called the layoutTestController method. Currently, we just use the
571                     * WebView for the main frame. EventSender suffers from the same
572                     * problem.
573                     */
574                    if (msg.getData().getString("key").equals(
575                            WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) {
576                        mCurrentWebView.getSettings().setAppCacheEnabled(msg.getData().getBoolean(
577                                "value"));
578                    } else {
579                        Log.w(LOG_TAG, "MSG_OVERRIDE_PREFERENCE: unsupported preference!");
580                    }
581                    break;
582
583                case MSG_SET_CAN_OPEN_WINDOWS:
584                    mCanOpenWindows = true;
585                    break;
586
587                case MSG_SET_GEOLOCATION_PERMISSION:
588                    mIsGeolocationPermissionSet = true;
589                    mGeolocationPermission = msg.arg1 == 1;
590
591                    if (mPendingGeolocationPermissionCallbacks != null) {
592                        Iterator<GeolocationPermissions.Callback> iter =
593                                mPendingGeolocationPermissionCallbacks.keySet().iterator();
594                        while (iter.hasNext()) {
595                            GeolocationPermissions.Callback callback = iter.next();
596                            String origin = mPendingGeolocationPermissionCallbacks.get(callback);
597                            callback.invoke(origin, mGeolocationPermission, false);
598                        }
599                        mPendingGeolocationPermissionCallbacks = null;
600                    }
601                    break;
602
603                case MSG_SET_XSS_AUDITOR_ENABLED:
604                    mCurrentWebView.getSettings().setXSSAuditorEnabled(msg.arg1 == 1);
605                    break;
606
607                case MSG_WAIT_UNTIL_DONE:
608                    mCurrentState = CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST;
609                    break;
610
611                default:
612                    assert false : "msg.what=" + msg.what;
613                    break;
614            }
615        }
616    };
617
618    private void resetLayoutTestController() {
619        mCanOpenWindows = false;
620        mDumpDatabaseCallbacks = false;
621        mIsGeolocationPermissionSet = false;
622        mPendingGeolocationPermissionCallbacks = null;
623    }
624
625    public void dumpAsText(boolean enablePixelTest) {
626        Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpAsText(" + enablePixelTest + ") called");
627        /** TODO: Implement */
628        if (enablePixelTest) {
629            Log.w(LOG_TAG, "enablePixelTest not implemented, switching to false");
630        }
631        mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_AS_TEXT);
632    }
633
634    public void dumpChildFramesAsText() {
635        Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpChildFramesAsText() called");
636        mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_CHILD_FRAMES_AS_TEXT);
637    }
638
639    public void dumpDatabaseCallbacks() {
640        Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpDatabaseCallbacks() called");
641        mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_DATABASE_CALLBACKS);
642    }
643
644    public void notifyDone() {
645        Log.i(LOG_TAG, mCurrentTestRelativePath + ": notifyDone() called");
646        mLayoutTestControllerHandler.sendEmptyMessage(MSG_NOTIFY_DONE);
647    }
648
649    public void overridePreference(String key, boolean value) {
650        Log.i(LOG_TAG, mCurrentTestRelativePath + ": overridePreference(" + key + ", " + value +
651        ") called");
652        Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_OVERRIDE_PREFERENCE);
653        msg.getData().putString("key", key);
654        msg.getData().putBoolean("value", value);
655        msg.sendToTarget();
656    }
657
658    public void setCanOpenWindows() {
659        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setCanOpenWindows() called");
660        mLayoutTestControllerHandler.sendEmptyMessage(MSG_SET_CAN_OPEN_WINDOWS);
661    }
662
663    public void setGeolocationPermission(boolean allow) {
664        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setGeolocationPermission(" + allow +
665                ") called");
666        Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_GEOLOCATION_PERMISSION);
667        msg.arg1 = allow ? 1 : 0;
668        msg.sendToTarget();
669    }
670
671    public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
672            boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
673        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setMockDeviceOrientation(" + canProvideAlpha +
674                ", " + alpha + ", " + canProvideBeta + ", " + beta + ", " + canProvideGamma +
675                ", " + gamma + ")");
676        mCurrentWebView.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta,
677                canProvideGamma, gamma);
678    }
679
680    public void setXSSAuditorEnabled(boolean flag) {
681        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setXSSAuditorEnabled(" + flag + ") called");
682        Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_XSS_AUDITOR_ENABLED);
683        msg.arg1 = flag ? 1 : 0;
684        msg.sendToTarget();
685    }
686
687    public void waitUntilDone() {
688        Log.i(LOG_TAG, mCurrentTestRelativePath + ": waitUntilDone() called");
689        mLayoutTestControllerHandler.sendEmptyMessage(MSG_WAIT_UNTIL_DONE);
690    }
691}
692