UiAutomatorTestRunner.java revision 71aebfa11443a9a04777cde3d9c7e29cdbb5d447
1e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/*
2e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Copyright (C) 2012 The Android Open Source Project
3e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
4e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
5e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you may not use this file except in compliance with the License.
6e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * You may obtain a copy of the License at
7e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
8e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
9e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
10e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Unless required by applicable law or agreed to in writing, software
11e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
12e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * See the License for the specific language governing permissions and
14e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * limitations under the License.
15e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */
16e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
17e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupackage com.android.uiautomator.testrunner;
18e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
19e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.app.Activity;
20e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.app.IInstrumentationWatcher;
21e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.app.Instrumentation;
22e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.content.ComponentName;
23e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.Bundle;
24e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.Debug;
2589f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganovimport android.os.HandlerThread;
26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.IBinder;
27d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavineimport android.os.SystemClock;
28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.test.RepetitiveTest;
29e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log;
30e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
31cd08ab4b0d19e68cc1cf18396cb9076e828c1a63Guang Zhuimport com.android.uiautomator.core.ShellUiAutomatorBridge;
32f406deb12db531785300f04e219fef28ef60b126Maxim Siniavineimport com.android.uiautomator.core.Tracer;
3389f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganovimport com.android.uiautomator.core.UiAutomationShellWrapper;
34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport com.android.uiautomator.core.UiDevice;
35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
3648c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtazimport java.io.ByteArrayOutputStream;
3748c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtazimport java.io.PrintStream;
3848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtazimport java.lang.Thread.UncaughtExceptionHandler;
3948c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtazimport java.lang.reflect.Method;
4048c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtazimport java.util.ArrayList;
4148c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtazimport java.util.List;
4248c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz
43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport junit.framework.AssertionFailedError;
44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport junit.framework.Test;
45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport junit.framework.TestCase;
46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport junit.framework.TestListener;
47e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport junit.framework.TestResult;
48e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport junit.runner.BaseTestRunner;
49e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport junit.textui.ResultPrinter;
50e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
51ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu/**
52ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu * @hide
53ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu */
54e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiAutomatorTestRunner {
55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final String LOGTAG = UiAutomatorTestRunner.class.getSimpleName();
57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final int EXIT_OK = 0;
58e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final int EXIT_EXCEPTION = -1;
59e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
6089f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov    private static final String HANDLER_THREAD_NAME = "UiAutomatorHandlerThread";
6189f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov
62e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private boolean mDebug;
6348c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz    private boolean mMonkey;
64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private Bundle mParams = null;
65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private UiDevice mUiDevice;
66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private List<String> mTestClasses = null;
6748c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz    private final FakeInstrumentationWatcher mWatcher = new FakeInstrumentationWatcher();
6848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz    private final IAutomationSupport mAutomationSupport = new IAutomationSupport() {
69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void sendStatus(int resultCode, Bundle status) {
71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mWatcher.instrumentationStatus(null, resultCode, status);
72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
73e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    };
7448c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz    private final List<TestListener> mTestListeners = new ArrayList<TestListener>();
75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
7689f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov    private HandlerThread mHandlerThread;
7789f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov
7848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz    public void run(List<String> testClasses, Bundle params, boolean debug, boolean monkey) {
79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            @Override
81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            public void uncaughtException(Thread thread, Throwable ex) {
82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                Log.e(LOGTAG, "uncaught exception", ex);
83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                Bundle results = new Bundle();
84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                results.putString("shortMsg", ex.getClass().getName());
85e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                results.putString("longMsg", ex.getMessage());
86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mWatcher.instrumentationFinished(null, 0, results);
87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // bailing on uncaught exception
88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                System.exit(EXIT_EXCEPTION);
89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        });
91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mTestClasses = testClasses;
93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mParams = params;
94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mDebug = debug;
9548c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        mMonkey = monkey;
96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        start();
97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        System.exit(EXIT_OK);
98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Called after all test classes are in place, ready to test
102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected void start() {
104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        TestCaseCollector collector = getTestCaseCollector(this.getClass().getClassLoader());
105e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        try {
106e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            collector.addTestClasses(mTestClasses);
107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } catch (ClassNotFoundException e) {
108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // will be caught by uncaught handler
109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new RuntimeException(e.getMessage(), e);
110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (mDebug) {
112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            Debug.waitForDebugger();
113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
11489f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov        mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
11589f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov        mHandlerThread.setDaemon(true);
11689f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov        mHandlerThread.start();
11789f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov        UiAutomationShellWrapper automationWrapper = new UiAutomationShellWrapper();
11889f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov        automationWrapper.connect();
119f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine
12071aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz        long startTime = SystemClock.uptimeMillis();
121d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        TestResult testRunResult = new TestResult();
122d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        ResultReporter resultPrinter;
123d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        String outputFormat = mParams.getString("outputFormat");
12471aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz        List<TestCase> testCases = collector.getTestCases();
12571aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz        Bundle testRunOutput = new Bundle();
126d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        if ("simple".equals(outputFormat)) {
127d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            resultPrinter = new SimpleResultPrinter(System.out, true);
128d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        } else {
129d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            resultPrinter = new WatcherResultPrinter(testCases.size());
130d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        }
131d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        try {
13271aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz            automationWrapper.setRunAsMonkey(mMonkey);
13371aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz            mUiDevice = UiDevice.getInstance();
13471aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz            mUiDevice.initialize(new ShellUiAutomatorBridge(automationWrapper.getUiAutomation()));
13571aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz
13671aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz            String traceType = mParams.getString("traceOutputMode");
13771aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz            if(traceType != null) {
13871aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                Tracer.Mode mode = Tracer.Mode.valueOf(Tracer.Mode.class, traceType);
13971aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                if (mode == Tracer.Mode.FILE || mode == Tracer.Mode.ALL) {
14071aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                    String filename = mParams.getString("traceLogFilename");
14171aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                    if (filename == null) {
14271aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                        throw new RuntimeException("Name of log file not specified. " +
14371aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                                "Please specify it using traceLogFilename parameter");
14471aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                    }
14571aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                    Tracer.getInstance().setOutputFilename(filename);
14671aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                }
14771aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz                Tracer.getInstance().setOutputMode(mode);
14871aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz            }
14971aebfa11443a9a04777cde3d9c7e29cdbb5d447Adam Momtaz
150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // add test listeners
151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            testRunResult.addListener(resultPrinter);
152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // add all custom listeners
153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            for (TestListener listener : mTestListeners) {
154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                testRunResult.addListener(listener);
155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // run tests for realz!
158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            for (TestCase testCase : testCases) {
159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                prepareTestCase(testCase);
160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                testCase.run(testRunResult);
161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } catch (Throwable t) {
163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // catch all exceptions so a more verbose error message can be outputted
164d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            resultPrinter.printUnexpectedError(t);
165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } finally {
166d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            long runTime = SystemClock.uptimeMillis() - startTime;
167d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            resultPrinter.print(testRunResult, runTime, testRunOutput);
16889f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov            automationWrapper.disconnect();
16948c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz            automationWrapper.setRunAsMonkey(false);
17089f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov            mHandlerThread.quit();
171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // copy & pasted from com.android.commands.am.Am
175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private class FakeInstrumentationWatcher implements IInstrumentationWatcher {
176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
17748c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final boolean mRawMode = true;
178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public IBinder asBinder() {
181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UnsupportedOperationException("I'm just a fake!");
182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            synchronized (this) {
187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // pretty printer mode?
188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String pretty = null;
189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (!mRawMode && results != null) {
190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
192e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (pretty != null) {
193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.print(pretty);
194e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                } else {
195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    if (results != null) {
196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        for (String key : results.keySet()) {
197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                            System.out.println("INSTRUMENTATION_STATUS: " + key + "="
198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                                    + results.get(key));
199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        }
200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    }
201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                notifyAll();
204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
208e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void instrumentationFinished(ComponentName name, int resultCode, Bundle results) {
209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            synchronized (this) {
210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // pretty printer mode?
211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String pretty = null;
212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (!mRawMode && results != null) {
213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
214e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
215e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (pretty != null) {
216e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.println(pretty);
217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                } else {
218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    if (results != null) {
219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        for (String key : results.keySet()) {
220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                            System.out.println("INSTRUMENTATION_RESULT: " + key + "="
221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                                    + results.get(key));
222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        }
223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    }
224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.println("INSTRUMENTATION_CODE: " + resultCode);
225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                notifyAll();
227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
231d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    private interface ResultReporter extends TestListener {
232d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void print(TestResult result, long runTime, Bundle testOutput);
233d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void printUnexpectedError(Throwable t);
234d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    }
235d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // Copy & pasted from InstrumentationTestRunner.WatcherResultPrinter
237d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    private class WatcherResultPrinter implements ResultReporter {
238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NUM_TOTAL = "numtests";
240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NAME_CLASS = "class";
241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NUM_CURRENT = "current";
242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NAME_TEST = "test";
243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NUM_ITERATIONS = "numiterations";
244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_VALUE_ID = "UiAutomatorTestRunner";
245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_STACK = "stack";
246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final int REPORT_VALUE_RESULT_START = 1;
248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final int REPORT_VALUE_RESULT_ERROR = -1;
249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final int REPORT_VALUE_RESULT_FAILURE = -2;
250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private final Bundle mResultTemplate;
252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Bundle mTestResult;
253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int mTestNum = 0;
254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int mTestResultCode = 0;
255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        String mTestClass = null;
256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
25748c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final SimpleResultPrinter mPrinter;
25848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final ByteArrayOutputStream mStream;
25948c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final PrintStream mWriter;
260d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public WatcherResultPrinter(int numTests) {
262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mResultTemplate = new Bundle();
263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mResultTemplate.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mResultTemplate.putInt(REPORT_KEY_NUM_TOTAL, numTests);
265d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
266d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mStream = new ByteArrayOutputStream();
267d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mWriter = new PrintStream(mStream);
268d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter = new SimpleResultPrinter(mWriter, false);
269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        /**
272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu         * send a status for the start of a each test, so long tests can be seen
273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu         * as "running"
274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu         */
275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void startTest(Test test) {
277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            String testClass = test.getClass().getName();
278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            String testName = ((TestCase) test).getName();
279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult = new Bundle(mResultTemplate);
280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_NAME_CLASS, testClass);
281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_NAME_TEST, testName);
282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putInt(REPORT_KEY_NUM_CURRENT, ++mTestNum);
283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // pretty printing
284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (testClass != null && !testClass.equals(mTestClass)) {
285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        String.format("\n%s:", testClass));
287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestClass = testClass;
288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            } else {
289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "");
290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            Method testMethod = null;
293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            try {
294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                testMethod = test.getClass().getMethod(testName);
295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // Report total number of iterations, if test is repetitive
296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (testMethod.isAnnotationPresent(RepetitiveTest.class)) {
297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    int numIterations = testMethod.getAnnotation(RepetitiveTest.class)
298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                            .numIterations();
299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    mTestResult.putInt(REPORT_KEY_NUM_ITERATIONS, numIterations);
300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            } catch (NoSuchMethodException e) {
302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // ignore- the test with given name does not exist. Will be
303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // handled during test
304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // execution
305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mAutomationSupport.sendStatus(REPORT_VALUE_RESULT_START, mTestResult);
308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResultCode = 0;
309d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
310d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.startTest(test);
311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void addError(Test test, Throwable t) {
315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResultCode = REPORT_VALUE_RESULT_ERROR;
317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // pretty printing
318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String.format("\nError in %s:\n%s",
320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
321d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
322d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.addError(test, t);
323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void addFailure(Test test, AssertionFailedError t) {
327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResultCode = REPORT_VALUE_RESULT_FAILURE;
329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // pretty printing
330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String.format("\nFailure in %s:\n%s",
332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
333d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
334d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.addFailure(test, t);
335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void endTest(Test test) {
339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (mTestResultCode == 0) {
340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ".");
341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mAutomationSupport.sendStatus(mTestResultCode, mTestResult);
343d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
344d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.endTest(test);
345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
34748c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
348d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void print(TestResult result, long runTime, Bundle testOutput) {
349d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.print(result, runTime, testOutput);
350d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            testOutput.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
351d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                  String.format("\nTest results for %s=%s",
352d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                  getClass().getSimpleName(),
353d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                  mStream.toString()));
354d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mWriter.close();
355d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mAutomationSupport.sendStatus(Activity.RESULT_OK, testOutput);
356d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        }
357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
35848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
359d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void printUnexpectedError(Throwable t) {
360d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mWriter.println(String.format("Test run aborted due to unexpected exception: %s",
361d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                    t.getMessage()));
362d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            t.printStackTrace(mWriter);
363d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        }
364d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    }
365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
366d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    /**
367d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine     * Class that produces the same output as JUnit when running from command line. Can be
368d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine     * used when default UiAutomator output is too verbose.
369d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine     */
370d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    private class SimpleResultPrinter extends ResultPrinter implements ResultReporter {
37148c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final boolean mFullOutput;
372d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public SimpleResultPrinter(PrintStream writer, boolean fullOutput) {
373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            super(writer);
374d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mFullOutput = fullOutput;
375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
37748c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
378d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void print(TestResult result, long runTime, Bundle testOutput) {
379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            printHeader(runTime);
380d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            if (mFullOutput) {
381d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                printErrors(result);
382d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                printFailures(result);
383d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            }
384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            printFooter(result);
385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
386d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
38748c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
388d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void printUnexpectedError(Throwable t) {
389d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            if (mFullOutput) {
390d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                getWriter().printf("Test run aborted due to unexpected exeption: %s",
391d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                        t.getMessage());
392d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                t.printStackTrace(getWriter());
393d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            }
394d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        }
395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected TestCaseCollector getTestCaseCollector(ClassLoader classLoader) {
398bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine        return new TestCaseCollector(classLoader, getTestCaseFilter());
399bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine    }
400bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine
401bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine    /**
402bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     * Returns an object which determines if the class and its methods should be
403bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     * accepted into the test suite.
404bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     * @return
405bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     */
406bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine    public UiAutomatorTestCaseFilter getTestCaseFilter() {
407bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine        return new UiAutomatorTestCaseFilter();
408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected void addTestListener(TestListener listener) {
411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (!mTestListeners.contains(listener)) {
412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestListeners.add(listener);
413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected void removeTestListener(TestListener listener) {
417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mTestListeners.remove(listener);
418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * subclass may override this method to perform further preparation
422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param testCase
424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected void prepareTestCase(TestCase testCase) {
426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        ((UiAutomatorTestCase)testCase).setAutomationSupport(mAutomationSupport);
427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        ((UiAutomatorTestCase)testCase).setUiDevice(mUiDevice);
428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        ((UiAutomatorTestCase)testCase).setParams(mParams);
429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu}
431