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);
165dba37a78454da33c43921dd289df3b9e8080ed8aGuang Zhu            testRunOutput.putString("shortMsg", t.getMessage());
166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } finally {
167d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            long runTime = SystemClock.uptimeMillis() - startTime;
168d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            resultPrinter.print(testRunResult, runTime, testRunOutput);
16989f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov            automationWrapper.disconnect();
17048c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz            automationWrapper.setRunAsMonkey(false);
17189f6117cb1fbeab3770106cf54e05af1f597be81Svetoslav Ganov            mHandlerThread.quit();
172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // copy & pasted from com.android.commands.am.Am
176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private class FakeInstrumentationWatcher implements IInstrumentationWatcher {
177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
17848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final boolean mRawMode = true;
179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public IBinder asBinder() {
182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UnsupportedOperationException("I'm just a fake!");
183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            synchronized (this) {
188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // pretty printer mode?
189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String pretty = null;
190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (!mRawMode && results != null) {
191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
192e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (pretty != null) {
194e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.print(pretty);
195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                } else {
196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    if (results != null) {
197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        for (String key : results.keySet()) {
198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                            System.out.println("INSTRUMENTATION_STATUS: " + key + "="
199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                                    + results.get(key));
200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        }
201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    }
202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                notifyAll();
205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
208e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void instrumentationFinished(ComponentName name, int resultCode, Bundle results) {
210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            synchronized (this) {
211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // pretty printer mode?
212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String pretty = null;
213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (!mRawMode && results != null) {
214e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
215e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
216e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (pretty != null) {
217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.println(pretty);
218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                } else {
219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    if (results != null) {
220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        for (String key : results.keySet()) {
221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                            System.out.println("INSTRUMENTATION_RESULT: " + key + "="
222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                                    + results.get(key));
223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        }
224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    }
225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    System.out.println("INSTRUMENTATION_CODE: " + resultCode);
226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                notifyAll();
228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
232d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    private interface ResultReporter extends TestListener {
233d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void print(TestResult result, long runTime, Bundle testOutput);
234d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void printUnexpectedError(Throwable t);
235d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    }
236d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // Copy & pasted from InstrumentationTestRunner.WatcherResultPrinter
238d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    private class WatcherResultPrinter implements ResultReporter {
239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NUM_TOTAL = "numtests";
241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NAME_CLASS = "class";
242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NUM_CURRENT = "current";
243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NAME_TEST = "test";
244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_NUM_ITERATIONS = "numiterations";
245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_VALUE_ID = "UiAutomatorTestRunner";
246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final String REPORT_KEY_STACK = "stack";
247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final int REPORT_VALUE_RESULT_START = 1;
249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final int REPORT_VALUE_RESULT_ERROR = -1;
250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private static final int REPORT_VALUE_RESULT_FAILURE = -2;
251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        private final Bundle mResultTemplate;
253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Bundle mTestResult;
254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int mTestNum = 0;
255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int mTestResultCode = 0;
256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        String mTestClass = null;
257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
25848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final SimpleResultPrinter mPrinter;
25948c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final ByteArrayOutputStream mStream;
26048c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final PrintStream mWriter;
261d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public WatcherResultPrinter(int numTests) {
263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mResultTemplate = new Bundle();
264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mResultTemplate.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mResultTemplate.putInt(REPORT_KEY_NUM_TOTAL, numTests);
266d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
267d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mStream = new ByteArrayOutputStream();
268d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mWriter = new PrintStream(mStream);
269d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter = new SimpleResultPrinter(mWriter, false);
270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        /**
273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu         * send a status for the start of a each test, so long tests can be seen
274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu         * as "running"
275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu         */
276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void startTest(Test test) {
278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            String testClass = test.getClass().getName();
279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            String testName = ((TestCase) test).getName();
280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult = new Bundle(mResultTemplate);
281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_NAME_CLASS, testClass);
282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_NAME_TEST, testName);
283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putInt(REPORT_KEY_NUM_CURRENT, ++mTestNum);
284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // pretty printing
285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (testClass != null && !testClass.equals(mTestClass)) {
286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                        String.format("\n%s:", testClass));
288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestClass = testClass;
289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            } else {
290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "");
291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            Method testMethod = null;
294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            try {
295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                testMethod = test.getClass().getMethod(testName);
296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // Report total number of iterations, if test is repetitive
297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (testMethod.isAnnotationPresent(RepetitiveTest.class)) {
298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    int numIterations = testMethod.getAnnotation(RepetitiveTest.class)
299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                            .numIterations();
300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    mTestResult.putInt(REPORT_KEY_NUM_ITERATIONS, numIterations);
301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            } catch (NoSuchMethodException e) {
303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // ignore- the test with given name does not exist. Will be
304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // handled during test
305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                // execution
306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mAutomationSupport.sendStatus(REPORT_VALUE_RESULT_START, mTestResult);
309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResultCode = 0;
310d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
311d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.startTest(test);
312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void addError(Test test, Throwable t) {
316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResultCode = REPORT_VALUE_RESULT_ERROR;
318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // pretty printing
319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String.format("\nError in %s:\n%s",
321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
322d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
323d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.addError(test, t);
324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void addFailure(Test test, AssertionFailedError t) {
328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResultCode = REPORT_VALUE_RESULT_FAILURE;
330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // pretty printing
331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                String.format("\nFailure in %s:\n%s",
333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
334d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
335d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.addFailure(test, t);
336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        @Override
339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        public void endTest(Test test) {
340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (mTestResultCode == 0) {
341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ".");
342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mAutomationSupport.sendStatus(mTestResultCode, mTestResult);
344d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
345d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.endTest(test);
346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
34848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
349d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void print(TestResult result, long runTime, Bundle testOutput) {
350d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mPrinter.print(result, runTime, testOutput);
351d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            testOutput.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
352d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                  String.format("\nTest results for %s=%s",
353d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                  getClass().getSimpleName(),
354d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                  mStream.toString()));
355d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mWriter.close();
356d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mAutomationSupport.sendStatus(Activity.RESULT_OK, testOutput);
357d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        }
358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
35948c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
360d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void printUnexpectedError(Throwable t) {
361d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mWriter.println(String.format("Test run aborted due to unexpected exception: %s",
362d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                    t.getMessage()));
363d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            t.printStackTrace(mWriter);
364d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        }
365d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    }
366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
367d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    /**
368d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine     * Class that produces the same output as JUnit when running from command line. Can be
369d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine     * used when default UiAutomator output is too verbose.
370d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine     */
371d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine    private class SimpleResultPrinter extends ResultPrinter implements ResultReporter {
37248c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        private final boolean mFullOutput;
373d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public SimpleResultPrinter(PrintStream writer, boolean fullOutput) {
374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            super(writer);
375d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            mFullOutput = fullOutput;
376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
37848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
379d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void print(TestResult result, long runTime, Bundle testOutput) {
380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            printHeader(runTime);
381d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            if (mFullOutput) {
382d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                printErrors(result);
383d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                printFailures(result);
384d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            }
385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            printFooter(result);
386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
387d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine
38848c83ae3e5fc36138a412fc5854d543fffe80376Adam Momtaz        @Override
389d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        public void printUnexpectedError(Throwable t) {
390d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            if (mFullOutput) {
391d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                getWriter().printf("Test run aborted due to unexpected exeption: %s",
392d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                        t.getMessage());
393d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine                t.printStackTrace(getWriter());
394d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine            }
395d053117ad50d47a7f2b25be4303d945e4e9edd1eMaxim Siniavine        }
396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected TestCaseCollector getTestCaseCollector(ClassLoader classLoader) {
399bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine        return new TestCaseCollector(classLoader, getTestCaseFilter());
400bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine    }
401bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine
402bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine    /**
403bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     * Returns an object which determines if the class and its methods should be
404bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     * accepted into the test suite.
405bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     * @return
406bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine     */
407bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine    public UiAutomatorTestCaseFilter getTestCaseFilter() {
408bc81b387c8d6c464f9b2a0f4f6f3224270466181Maxim Siniavine        return new UiAutomatorTestCaseFilter();
409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected void addTestListener(TestListener listener) {
412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (!mTestListeners.contains(listener)) {
413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            mTestListeners.add(listener);
414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected void removeTestListener(TestListener listener) {
418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mTestListeners.remove(listener);
419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * subclass may override this method to perform further preparation
423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param testCase
425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected void prepareTestCase(TestCase testCase) {
427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        ((UiAutomatorTestCase)testCase).setAutomationSupport(mAutomationSupport);
428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        ((UiAutomatorTestCase)testCase).setUiDevice(mUiDevice);
429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        ((UiAutomatorTestCase)testCase).setParams(mParams);
430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu}
432