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 Zhupackage com.android.uiautomator.core; 1718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 1818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.util.Log; 1918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 2018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.io.File; 2118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.io.FileNotFoundException; 2218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.io.PrintWriter; 2318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.text.SimpleDateFormat; 2418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.ArrayList; 2518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.Arrays; 2618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.Date; 2718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.List; 2818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.Locale; 2918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 3018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/** 3118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Class that creates traces of the calls to the UiAutomator API and outputs the 3218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * traces either to logcat or a logfile. Each public method in the UiAutomator 3318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * that needs to be traced should include a call to Tracer.trace in the 3418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * beginning. Tracing is turned off by defualt and needs to be enabled 3518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * explicitly. 3618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @hide 3718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 3818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupublic class Tracer { 3918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final String UNKNOWN_METHOD_STRING = "(unknown method)"; 4018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final String UIAUTOMATOR_PACKAGE = "com.android.uiautomator.core"; 4118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final int CALLER_LOCATION = 6; 4218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final int METHOD_TO_TRACE_LOCATION = 5; 4318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final int MIN_STACK_TRACE_LENGTH = 7; 4418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 4518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 4618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Enum that determines where the trace output goes. It can go to either 4718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * logcat, log file or both. 4818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 4918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public enum Mode { 5018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu NONE, 5118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu FILE, 5218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu LOGCAT, 5318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu ALL 5418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 5518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 5618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private interface TracerSink { 5718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void log(String message); 5818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 5918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void close(); 6018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 6118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 6218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private class FileSink implements TracerSink { 6318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private PrintWriter mOut; 6418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private SimpleDateFormat mDateFormat; 6518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 6618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public FileSink(File file) throws FileNotFoundException { 6718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mOut = new PrintWriter(file); 6818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); 6918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 7018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 7118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void log(String message) { 7218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mOut.printf("%s %s\n", mDateFormat.format(new Date()), message); 7318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 7418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 7518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void close() { 7618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mOut.close(); 7718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 7818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 7918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 8018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private class LogcatSink implements TracerSink { 8118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 8218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final String LOGCAT_TAG = "UiAutomatorTrace"; 8318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 8418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void log(String message) { 8518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.i(LOGCAT_TAG, message); 8618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 8718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 8818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void close() { 8918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // nothing is needed 9018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 9118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 9218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 9318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private Mode mCurrentMode = Mode.NONE; 9418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private List<TracerSink> mSinks = new ArrayList<TracerSink>(); 9518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private File mOutputFile; 9618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 9718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static Tracer mInstance = null; 9818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 9918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 10018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Returns a reference to an instance of the tracer. Useful to set the 10118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * parameters before the trace is collected. 10218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 10318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return 10418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 10518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public static Tracer getInstance() { 10618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (mInstance == null) { 10718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mInstance = new Tracer(); 10818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 10918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return mInstance; 11018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 11118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 11218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 11318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Sets where the trace output will go. Can be either be logcat or a file or 11418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * both. Setting this to NONE will turn off tracing. 11518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 11618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param mode 11718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 11818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void setOutputMode(Mode mode) { 11918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu closeSinks(); 12018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mCurrentMode = mode; 12118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu try { 12218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu switch (mode) { 12318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu case FILE: 12418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (mOutputFile == null) { 12518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new IllegalArgumentException("Please provide a filename before " + 12618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu "attempting write trace to a file"); 12718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 12818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mSinks.add(new FileSink(mOutputFile)); 12918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu break; 13018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu case LOGCAT: 13118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mSinks.add(new LogcatSink()); 13218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu break; 13318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu case ALL: 13418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mSinks.add(new LogcatSink()); 13518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (mOutputFile == null) { 13618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new IllegalArgumentException("Please provide a filename before " + 13718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu "attempting write trace to a file"); 13818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 13918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mSinks.add(new FileSink(mOutputFile)); 14018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu break; 14118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu default: 14218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu break; 14318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 14418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } catch (FileNotFoundException e) { 14518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.w("Tracer", "Could not open log file: " + e.getMessage()); 14618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 14718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 14818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 14918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private void closeSinks() { 15018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu for (TracerSink sink : mSinks) { 15118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu sink.close(); 15218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 15318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mSinks.clear(); 15418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 15518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 15618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 15718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Sets the name of the log file where tracing output will be written if the 15818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * tracer is set to write to a file. 15918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 16018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param filename name of the log file. 16118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 16218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void setOutputFilename(String filename) { 16318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mOutputFile = new File(filename); 16418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 16518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 16618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private void doTrace(Object[] arguments) { 16718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (mCurrentMode == Mode.NONE) { 16818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return; 16918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 17018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 17118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu String caller = getCaller(); 17218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (caller == null) { 17318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return; 17418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 17518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 17618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu log(String.format("%s (%s)", caller, join(", ", arguments))); 17718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 17818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 17918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private void log(String message) { 18018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu for (TracerSink sink : mSinks) { 18118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu sink.log(message); 18218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 18318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 18418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 18518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 18618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Queries whether the tracing is enabled. 18718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if tracing is enabled, false otherwise. 18818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 18918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isTracingEnabled() { 19018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return mCurrentMode != Mode.NONE; 19118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 19218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 19318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 19418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Public methods in the UiAutomator should call this function to generate a 19518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * trace. The trace will include the method thats is being called, it's 19618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * arguments and where in the user's code the method is called from. If a 19718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * public method is called internally from UIAutomator then this will not 19818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * output a trace entry. Only calls from outise the UiAutomator package will 19918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * produce output. 20018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 20118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Special note about array arguments. You can safely pass arrays of reference types 20218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * to this function. Like String[] or Integer[]. The trace function will print their 20318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * contents by calling toString() on each of the elements. This will not work for 20418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * array of primitive types like int[] or float[]. Before passing them to this function 20518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * convert them to arrays of reference types manually. Example: convert int[] to Integer[]. 20618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 20718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param arguments arguments of the method being traced. 20818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 20918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public static void trace(Object... arguments) { 21018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.getInstance().doTrace(arguments); 21118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 21218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 21318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static String join(String separator, Object[] strings) { 21418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (strings.length == 0) 21518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return ""; 21618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 21718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu StringBuilder builder = new StringBuilder(objectToString(strings[0])); 21818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu for (int i = 1; i < strings.length; i++) { 21918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu builder.append(separator); 22018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu builder.append(objectToString(strings[i])); 22118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 22218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return builder.toString(); 22318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 22418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 22518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 22618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Special toString method to handle arrays. If the argument is a normal object then this will 22718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * return normal output of obj.toString(). If the argument is an array this will return a 22818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * string representation of the elements of the array. 22918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 23018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * This method will not work for arrays of primitive types. Arrays of primitive types are 23118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * expected to be converted manually by the caller. If the array is not converter then 23218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * this function will only output "[...]" instead of the contents of the array. 23318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 23418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param obj object to convert to a string 23518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return String representation of the object. 23618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 23718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static String objectToString(Object obj) { 23818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (obj.getClass().isArray()) { 23918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (obj instanceof Object[]) { 24018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return Arrays.deepToString((Object[])obj); 24118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 24218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return "[...]"; 24318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 24418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 24518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return obj.toString(); 24618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 24718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 24818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 24918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 25018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * This method outputs which UiAutomator method was called and where in the 25118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * user code it was called from. If it can't deside which method is called 25218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * it will output "(unknown method)". If the method was called from inside 25318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the UiAutomator then it returns null. 25418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 25518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return name of the method called and where it was called from. Null if 25618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * method was called from inside UiAutomator. 25718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 25818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static String getCaller() { 25918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu StackTraceElement stackTrace[] = Thread.currentThread().getStackTrace(); 26018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (stackTrace.length < MIN_STACK_TRACE_LENGTH) { 26118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return UNKNOWN_METHOD_STRING; 26218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 26318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 26418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu StackTraceElement caller = stackTrace[METHOD_TO_TRACE_LOCATION]; 26518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu StackTraceElement previousCaller = stackTrace[CALLER_LOCATION]; 26618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 26718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (previousCaller.getClassName().startsWith(UIAUTOMATOR_PACKAGE)) { 26818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return null; 26918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 27118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int indexOfDot = caller.getClassName().lastIndexOf('.'); 27218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (indexOfDot < 0) { 27318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu indexOfDot = 0; 27418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 27618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (indexOfDot + 1 >= caller.getClassName().length()) { 27718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return UNKNOWN_METHOD_STRING; 27818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 28018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu String shortClassName = caller.getClassName().substring(indexOfDot + 1); 28118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return String.format("%s.%s from %s() at %s:%d", shortClassName, caller.getMethodName(), 28218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu previousCaller.getMethodName(), previousCaller.getFileName(), 28318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu previousCaller.getLineNumber()); 28418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 28518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu} 286