118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/*
218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Copyright (C) 2012 The Android Open Source Project
318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *
418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * you may not use this file except in compliance with the License.
618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * You may obtain a copy of the License at
718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *
818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *
1018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Unless required by applicable law or agreed to in writing, software
1118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
1218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See the License for the specific language governing permissions and
1418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * limitations under the License.
1518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */
1618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
1718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupackage com.android.uiautomator.testrunner;
1818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
1918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.app.Activity;
2018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.app.IInstrumentationWatcher;
2118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.app.Instrumentation;
2218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.content.ComponentName;
2318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.os.Bundle;
2418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.os.Debug;
2518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.os.HandlerThread;
2618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.os.IBinder;
2718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.os.SystemClock;
2818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.test.RepetitiveTest;
2918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.util.Log;
3018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
3118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport com.android.uiautomator.core.ShellUiAutomatorBridge;
3218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport com.android.uiautomator.core.Tracer;
3318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport com.android.uiautomator.core.UiAutomationShellWrapper;
3418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport com.android.uiautomator.core.UiDevice;
3518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
3618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.io.ByteArrayOutputStream;
3718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.io.PrintStream;
3818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.lang.Thread.UncaughtExceptionHandler;
3918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.lang.reflect.Method;
4018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.ArrayList;
4118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.List;
4218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
4318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.framework.AssertionFailedError;
4418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.framework.Test;
4518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.framework.TestCase;
4618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.framework.TestListener;
4718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.framework.TestResult;
4818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.runner.BaseTestRunner;
4918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.textui.ResultPrinter;
5018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
5118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/**
5218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @hide
5318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */
5418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupublic class UiAutomatorTestRunner {
5518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
5618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private static final String LOGTAG = UiAutomatorTestRunner.class.getSimpleName();
5718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private static final int EXIT_OK = 0;
5818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private static final int EXIT_EXCEPTION = -1;
5918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
6018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private static final String HANDLER_THREAD_NAME = "UiAutomatorHandlerThread";
6118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
6218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private boolean mDebug;
6318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private boolean mMonkey;
6418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private Bundle mParams = null;
6518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private UiDevice mUiDevice;
6618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private List<String> mTestClasses = null;
6718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private final FakeInstrumentationWatcher mWatcher = new FakeInstrumentationWatcher();
6818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private final IAutomationSupport mAutomationSupport = new IAutomationSupport() {
6918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
7018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void sendStatus(int resultCode, Bundle status) {
7118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mWatcher.instrumentationStatus(null, resultCode, status);
7218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
7318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    };
7418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private final List<TestListener> mTestListeners = new ArrayList<TestListener>();
7518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
7618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private HandlerThread mHandlerThread;
7718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
7818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public void run(List<String> testClasses, Bundle params, boolean debug, boolean monkey) {
7918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
8018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            @Override
8118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            public void uncaughtException(Thread thread, Throwable ex) {
8218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                Log.e(LOGTAG, "uncaught exception", ex);
8318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                Bundle results = new Bundle();
8418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                results.putString("shortMsg", ex.getClass().getName());
8518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                results.putString("longMsg", ex.getMessage());
8618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                mWatcher.instrumentationFinished(null, 0, results);
8718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                // bailing on uncaught exception
8818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                System.exit(EXIT_EXCEPTION);
8918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
9018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        });
9118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
9218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mTestClasses = testClasses;
9318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mParams = params;
9418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mDebug = debug;
9518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mMonkey = monkey;
9618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        start();
9718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        System.exit(EXIT_OK);
9818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
9918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
10018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
10118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Called after all test classes are in place, ready to test
10218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
10318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    protected void start() {
10418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        TestCaseCollector collector = getTestCaseCollector(this.getClass().getClassLoader());
10518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        try {
10618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            collector.addTestClasses(mTestClasses);
10718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        } catch (ClassNotFoundException e) {
10818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // will be caught by uncaught handler
10918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            throw new RuntimeException(e.getMessage(), e);
11018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
11118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        if (mDebug) {
11218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            Debug.waitForDebugger();
11318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
11418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
11518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mHandlerThread.setDaemon(true);
11618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mHandlerThread.start();
11718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        UiAutomationShellWrapper automationWrapper = new UiAutomationShellWrapper();
11818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        automationWrapper.connect();
11918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
12018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        long startTime = SystemClock.uptimeMillis();
12118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        TestResult testRunResult = new TestResult();
12218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        ResultReporter resultPrinter;
12318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        String outputFormat = mParams.getString("outputFormat");
12418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        List<TestCase> testCases = collector.getTestCases();
12518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        Bundle testRunOutput = new Bundle();
12618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        if ("simple".equals(outputFormat)) {
12718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            resultPrinter = new SimpleResultPrinter(System.out, true);
12818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        } else {
12918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            resultPrinter = new WatcherResultPrinter(testCases.size());
13018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
13118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        try {
13218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            automationWrapper.setRunAsMonkey(mMonkey);
13318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mUiDevice = UiDevice.getInstance();
13418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mUiDevice.initialize(new ShellUiAutomatorBridge(automationWrapper.getUiAutomation()));
13518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
13618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            String traceType = mParams.getString("traceOutputMode");
13718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            if(traceType != null) {
13818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                Tracer.Mode mode = Tracer.Mode.valueOf(Tracer.Mode.class, traceType);
13918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                if (mode == Tracer.Mode.FILE || mode == Tracer.Mode.ALL) {
14018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    String filename = mParams.getString("traceLogFilename");
14118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    if (filename == null) {
14218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                        throw new RuntimeException("Name of log file not specified. " +
14318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                                "Please specify it using traceLogFilename parameter");
14418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    }
14518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    Tracer.getInstance().setOutputFilename(filename);
14618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                }
14718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                Tracer.getInstance().setOutputMode(mode);
14818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
14918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
15018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // add test listeners
15118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            testRunResult.addListener(resultPrinter);
15218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // add all custom listeners
15318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            for (TestListener listener : mTestListeners) {
15418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                testRunResult.addListener(listener);
15518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
15618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
15718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // run tests for realz!
15818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            for (TestCase testCase : testCases) {
15918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                prepareTestCase(testCase);
16018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                testCase.run(testRunResult);
16118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
16218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        } catch (Throwable t) {
16318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // catch all exceptions so a more verbose error message can be outputted
16418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            resultPrinter.printUnexpectedError(t);
16518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            testRunOutput.putString("shortMsg", t.getMessage());
16618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        } finally {
16718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            long runTime = SystemClock.uptimeMillis() - startTime;
16818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            resultPrinter.print(testRunResult, runTime, testRunOutput);
16918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            automationWrapper.disconnect();
17018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            automationWrapper.setRunAsMonkey(false);
17118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mHandlerThread.quit();
17218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
17318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
17418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
17518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    // copy & pasted from com.android.commands.am.Am
17618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private class FakeInstrumentationWatcher implements IInstrumentationWatcher {
17718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
17818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private final boolean mRawMode = true;
17918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
18018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
18118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public IBinder asBinder() {
18218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            throw new UnsupportedOperationException("I'm just a fake!");
18318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
18418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
18518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
18618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
18718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            synchronized (this) {
18818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                // pretty printer mode?
18918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                String pretty = null;
19018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                if (!mRawMode && results != null) {
19118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
19218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                }
19318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                if (pretty != null) {
19418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    System.out.print(pretty);
19518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                } else {
19618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    if (results != null) {
19718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                        for (String key : results.keySet()) {
19818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                            System.out.println("INSTRUMENTATION_STATUS: " + key + "="
19918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                                    + results.get(key));
20018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                        }
20118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    }
20218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
20318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                }
20418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                notifyAll();
20518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
20618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
20718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
20818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
20918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void instrumentationFinished(ComponentName name, int resultCode, Bundle results) {
21018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            synchronized (this) {
21118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                // pretty printer mode?
21218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                String pretty = null;
21318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                if (!mRawMode && results != null) {
21418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
21518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                }
21618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                if (pretty != null) {
21718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    System.out.println(pretty);
21818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                } else {
21918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    if (results != null) {
22018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                        for (String key : results.keySet()) {
22118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                            System.out.println("INSTRUMENTATION_RESULT: " + key + "="
22218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                                    + results.get(key));
22318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                        }
22418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    }
22518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    System.out.println("INSTRUMENTATION_CODE: " + resultCode);
22618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                }
22718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                notifyAll();
22818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
22918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
23018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
23118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
23218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private interface ResultReporter extends TestListener {
23318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void print(TestResult result, long runTime, Bundle testOutput);
23418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void printUnexpectedError(Throwable t);
23518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
23618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
23718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    // Copy & pasted from InstrumentationTestRunner.WatcherResultPrinter
23818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private class WatcherResultPrinter implements ResultReporter {
23918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
24018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final String REPORT_KEY_NUM_TOTAL = "numtests";
24118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final String REPORT_KEY_NAME_CLASS = "class";
24218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final String REPORT_KEY_NUM_CURRENT = "current";
24318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final String REPORT_KEY_NAME_TEST = "test";
24418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final String REPORT_KEY_NUM_ITERATIONS = "numiterations";
24518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final String REPORT_VALUE_ID = "UiAutomatorTestRunner";
24618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final String REPORT_KEY_STACK = "stack";
24718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
24818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final int REPORT_VALUE_RESULT_START = 1;
24918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final int REPORT_VALUE_RESULT_ERROR = -1;
25018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private static final int REPORT_VALUE_RESULT_FAILURE = -2;
25118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
25218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private final Bundle mResultTemplate;
25318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        Bundle mTestResult;
25418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        int mTestNum = 0;
25518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        int mTestResultCode = 0;
25618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        String mTestClass = null;
25718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
25818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private final SimpleResultPrinter mPrinter;
25918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private final ByteArrayOutputStream mStream;
26018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private final PrintStream mWriter;
26118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
26218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public WatcherResultPrinter(int numTests) {
26318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mResultTemplate = new Bundle();
26418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mResultTemplate.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
26518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mResultTemplate.putInt(REPORT_KEY_NUM_TOTAL, numTests);
26618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
26718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mStream = new ByteArrayOutputStream();
26818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mWriter = new PrintStream(mStream);
26918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mPrinter = new SimpleResultPrinter(mWriter, false);
27018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
27118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
27218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        /**
27318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         * send a status for the start of a each test, so long tests can be seen
27418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         * as "running"
27518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         */
27618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
27718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void startTest(Test test) {
27818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            String testClass = test.getClass().getName();
27918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            String testName = ((TestCase) test).getName();
28018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult = new Bundle(mResultTemplate);
28118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult.putString(REPORT_KEY_NAME_CLASS, testClass);
28218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult.putString(REPORT_KEY_NAME_TEST, testName);
28318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult.putInt(REPORT_KEY_NUM_CURRENT, ++mTestNum);
28418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // pretty printing
28518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            if (testClass != null && !testClass.equals(mTestClass)) {
28618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
28718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                        String.format("\n%s:", testClass));
28818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                mTestClass = testClass;
28918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            } else {
29018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "");
29118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
29218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
29318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            Method testMethod = null;
29418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            try {
29518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                testMethod = test.getClass().getMethod(testName);
29618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                // Report total number of iterations, if test is repetitive
29718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                if (testMethod.isAnnotationPresent(RepetitiveTest.class)) {
29818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    int numIterations = testMethod.getAnnotation(RepetitiveTest.class)
29918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                            .numIterations();
30018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    mTestResult.putInt(REPORT_KEY_NUM_ITERATIONS, numIterations);
30118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                }
30218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            } catch (NoSuchMethodException e) {
30318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                // ignore- the test with given name does not exist. Will be
30418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                // handled during test
30518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                // execution
30618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
30718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
30818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mAutomationSupport.sendStatus(REPORT_VALUE_RESULT_START, mTestResult);
30918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResultCode = 0;
31018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
31118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mPrinter.startTest(test);
31218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
31318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
31418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
31518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void addError(Test test, Throwable t) {
31618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
31718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResultCode = REPORT_VALUE_RESULT_ERROR;
31818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // pretty printing
31918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
32018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                String.format("\nError in %s:\n%s",
32118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
32218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
32318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mPrinter.addError(test, t);
32418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
32518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
32618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
32718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void addFailure(Test test, AssertionFailedError t) {
32818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
32918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResultCode = REPORT_VALUE_RESULT_FAILURE;
33018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            // pretty printing
33118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
33218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                String.format("\nFailure in %s:\n%s",
33318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
33418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
33518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mPrinter.addFailure(test, t);
33618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
33718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
33818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
33918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void endTest(Test test) {
34018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            if (mTestResultCode == 0) {
34118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ".");
34218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
34318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mAutomationSupport.sendStatus(mTestResultCode, mTestResult);
34418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
34518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mPrinter.endTest(test);
34618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
34718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
34818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
34918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void print(TestResult result, long runTime, Bundle testOutput) {
35018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mPrinter.print(result, runTime, testOutput);
35118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            testOutput.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
35218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                  String.format("\nTest results for %s=%s",
35318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                  getClass().getSimpleName(),
35418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                  mStream.toString()));
35518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mWriter.close();
35618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mAutomationSupport.sendStatus(Activity.RESULT_OK, testOutput);
35718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
35818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
35918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
36018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void printUnexpectedError(Throwable t) {
36118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mWriter.println(String.format("Test run aborted due to unexpected exception: %s",
36218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    t.getMessage()));
36318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            t.printStackTrace(mWriter);
36418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
36518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
36618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
36718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
36818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Class that produces the same output as JUnit when running from command line. Can be
36918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * used when default UiAutomator output is too verbose.
37018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
37118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private class SimpleResultPrinter extends ResultPrinter implements ResultReporter {
37218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        private final boolean mFullOutput;
37318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public SimpleResultPrinter(PrintStream writer, boolean fullOutput) {
37418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            super(writer);
37518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mFullOutput = fullOutput;
37618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
37718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
37818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
37918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void print(TestResult result, long runTime, Bundle testOutput) {
38018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            printHeader(runTime);
38118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            if (mFullOutput) {
38218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                printErrors(result);
38318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                printFailures(result);
38418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
38518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            printFooter(result);
38618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
38718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
38818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        @Override
38918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public void printUnexpectedError(Throwable t) {
39018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            if (mFullOutput) {
39118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                getWriter().printf("Test run aborted due to unexpected exeption: %s",
39218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                        t.getMessage());
39318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                t.printStackTrace(getWriter());
39418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
39518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
39618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
39718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
39818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    protected TestCaseCollector getTestCaseCollector(ClassLoader classLoader) {
39918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        return new TestCaseCollector(classLoader, getTestCaseFilter());
40018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
40118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
40218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
40318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Returns an object which determines if the class and its methods should be
40418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * accepted into the test suite.
40518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @return
40618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
40718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public UiAutomatorTestCaseFilter getTestCaseFilter() {
40818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        return new UiAutomatorTestCaseFilter();
40918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
41018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
41118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    protected void addTestListener(TestListener listener) {
41218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        if (!mTestListeners.contains(listener)) {
41318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestListeners.add(listener);
41418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
41518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
41618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
41718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    protected void removeTestListener(TestListener listener) {
41818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mTestListeners.remove(listener);
41918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
42018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
42118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
42218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * subclass may override this method to perform further preparation
42318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *
42418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @param testCase
42518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
42618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    protected void prepareTestCase(TestCase testCase) {
42718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        ((UiAutomatorTestCase)testCase).setAutomationSupport(mAutomationSupport);
42818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        ((UiAutomatorTestCase)testCase).setUiDevice(mUiDevice);
42918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        ((UiAutomatorTestCase)testCase).setParams(mParams);
43018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
43118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu}
432