ViewDebug.java revision f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.view; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 20c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.util.DisplayMetrics; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 22105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.content.Context; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap; 24c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.graphics.Canvas; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment; 26c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.os.Debug; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedWriter; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileWriter; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.DataOutputStream; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStreamWriter; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedOutputStream; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.LinkedList; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.CountDownLatch; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.TimeUnit; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Target; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.ElementType; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Retention; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.RetentionPolicy; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Method; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.InvocationTargetException; 50c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport java.lang.reflect.AccessibleObject; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various debugging/tracing tools related to {@link View} and the view hierarchy. 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ViewDebug { 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view hierarchy tracing. Any invoker of 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_HIERARCHY = false; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view recycler tracing. Any invoker of 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])} should first 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_RECYCLER = false; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The system property of dynamic switch for capturing view information 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when it is set, we dump interested fields and methods for the view on focus 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String SYSTEM_PROPERTY_CAPTURE_VIEW = "debug.captureview"; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The system property of dynamic switch for capturing event information 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when it is set, we log key events, touch/motion and trackball events 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent"; 81c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped by 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view server. Only non-void methods with no arguments can be annotated 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * by this annotation. 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface ExportedProperty { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When resolveId is true, and if the annotated field/method return value 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is an int, the value is converted to an Android's resource name. 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the property's value must be transformed into an Android 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * resource name, false otherwise 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean resolveId() default false; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A mapping can be defined to map int values to specific strings. For 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance, View.getVisibility() returns 0, 4 or 8. However, these values 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * actually mean VISIBLE, INVISIBLE and GONE. A mapping can be used to see 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * these human readable values: 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.ExportedProperty(mapping = { 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "VISIBLE"), 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 4, to = "INVISIBLE"), 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 8, to = "GONE") 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * }) 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * public int getVisibility() { ... 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An array of int to String mappings 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.IntToString 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IntToString[] mapping() default { }; 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 121c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be defined to map array indices to specific strings. 122c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be used to see human readable values for the indices 123c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * of an array: 124c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 125c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 126c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.ExportedProperty(mapping = { 127c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "INVALID"), 128c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 1, to = "FIRST"), 129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 2, to = "SECOND") 130c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * }) 131c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * private int[] mElements; 132c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 134c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @return An array of int to String mappings 135c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see android.view.ViewDebug.IntToString 137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see #mapping() 138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project */ 139c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project IntToString[] indexMapping() default { }; 140c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 141c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project /** 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When deep export is turned on, this property is not dumped. Instead, the 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * properties contained in this property are dumped. Each child property 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is prefixed with the name of this property. 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the properties of this property should be dumped 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #prefix() 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean deepExport() default false; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The prefix to use on child properties when deep export is enabled 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a prefix as a String 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #deepExport() 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix() default ""; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines a mapping from an int value to a String. Such a mapping can be used 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in a @ExportedProperty to provide more meaningful values to the end user. 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.ExportedProperty 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.TYPE }) 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface IntToString { 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The original int value to map to a String. 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary int value. 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int from(); 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The String to use in place of the original int value. 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary non-null String. 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String to(); 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped when 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view is captured. Methods with this annotation must have no arguments 189f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * and must return a valid type of data. 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface CapturedViewProperty { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When retrieveReturn is true, we need to retrieve second level methods 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod() 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * we will set retrieveReturn = true on the annotation of 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * myView.getFirstLevelMethod() 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if we need the second level methods 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean retrieveReturn() default false; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null; 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Maximum delay in ms after which we stop trying to capture a View's drawing 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CAPTURE_TIMEOUT = 4000; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE"; 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_DUMP = "DUMP"; 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE"; 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT"; 214c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static final String REMOTE_PROFILE = "PROFILE"; 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> sFieldsForClasses; 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> sMethodsForClasses; 218c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static HashMap<AccessibleObject, ExportedProperty> sAnnotations; 219c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of hierarhcy trace to output to the hierarchy traces file. 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum HierarchyTraceType { 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE, 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD, 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD_IN_PARENT, 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project REQUEST_LAYOUT, 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_LAYOUT, 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_MEASURE, 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DRAW, 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BUILD_CACHE 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static BufferedWriter sHierarchyTraces; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static ViewRoot sHierarhcyRoot; 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sHierarchyTracePrefix; 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of recycler trace to output to the recycler traces file. 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum RecyclerTraceType { 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NEW_VIEW, 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BIND_VIEW, 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_ACTIVE_HEAP, 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_SCRAP_HEAP, 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_TO_ACTIVE_HEAP, 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_TO_SCRAP_HEAP, 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_FROM_ACTIVE_TO_SCRAP_HEAP 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class RecyclerTrace { 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int view; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public RecyclerTraceType type; 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int position; 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int indexOnScreen; 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View sRecyclerOwnerView; 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<View> sRecyclerViews; 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<RecyclerTrace> sRecyclerTraces; 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sRecyclerTracePrefix; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated Views. 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of Views instanciated in the current process. 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewInstanceCount() { 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return View.sInstanceCount; 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated ViewRoots. 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of ViewRoots instanciated in the current process. 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewRootInstanceCount() { 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ViewRoot.getInstanceCount(); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened recycler traces. The trace records the type of 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * recycler action performed on the supplied view as well as a number of parameters. 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param parameters parameters depending on the type of the trace 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, RecyclerTraceType type, int... parameters) { 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!sRecyclerViews.contains(view)) { 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.add(view); 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int index = sRecyclerViews.indexOf(view); 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RecyclerTrace trace = new RecyclerTrace(); 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.view = index; 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.type = type; 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.position = parameters[0]; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.indexOnScreen = parameters[1]; 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.add(trace); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view recycler of the specified view. The trace is identified by a prefix, 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-recycler/PREFIX.traces</code> and 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>. 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view recycler can be traced at the same time. After calling this method, any 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopRecyclerTracing()} is invoked before. 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Traces files are created only after {@link #stopRecyclerTracing()} is invoked. 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose recycler must be traced 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopRecyclerTracing() 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startRecyclerTracing(String prefix, View view) { 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView != null) { 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopRecyclerTracing() before running" + 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTracePrefix = prefix; 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = view; 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = new ArrayList<View>(); 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = new LinkedList<RecyclerTrace>(); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view recycer tracing. 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.traces</code> 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's recycler. 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.recycler</code> 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all of the views used by the recycler of the view supplied to 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startRecyclerTracing(String, View)}. 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #startRecyclerTracing(String, View) 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopRecyclerTracing() { 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startRecyclerTracing() before" + 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopRecyclerTracing()!"); 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 376c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump.mkdirs(); 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler"); 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final BufferedWriter out = new BufferedWriter(new FileWriter(recyclerDump), 8 * 1024); 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (View view : sRecyclerViews) { 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String name = view.getClass().getName(); 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(name); 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler content"); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces"); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final FileOutputStream file = new FileOutputStream(recyclerDump); 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final DataOutputStream out = new DataOutputStream(file); 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (RecyclerTrace trace : sRecyclerTraces) { 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.view); 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.type.ordinal()); 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.position); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.indexOnScreen); 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.flush(); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler traces"); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.clear(); 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = null; 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.clear(); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = null; 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = null; 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened traces file. The trace contains the class name 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and instance's hashcode of the specified view as well as the supplied trace type. 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, HierarchyTraceType type) { 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarchyTraces == null) { 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(type.name()); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(' '); 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(view.getClass().getName()); 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write('@'); 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(Integer.toHexString(view.hashCode())); 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.newLine(); 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping trace of type " + type + " for view " + view); 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix, 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> and 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>. 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view hierarchy can be traced at the same time. After calling this method, any 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopHierarchyTracing()} is invoked before. 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's hierarchy. 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose hierarchy must be traced 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopHierarchyTracing() 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startHierarchyTracing(String prefix, View view) { 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot != null) { 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopHierarchyTracing() before running" + 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 480c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, prefix + ".traces"); 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTracePrefix = prefix; 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarhcyRoot = (ViewRoot) view.getRootView().getParent(); 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view hierarchy tracing. This method closes the file 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>. 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code> 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing the view hierarchy of the view supplied to 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startHierarchyTracing(String, View)}. 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #startHierarchyTracing(String, View) 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopHierarchyTracing() { 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot == null || sHierarchyTraces == null) { 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startHierarchyTracing() before" + 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopHierarchyTracing()!"); 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.close(); 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not write view traces"); 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = null; 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 528c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree"); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out; 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = sHierarhcyRoot.getView(); 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy(group, out, 0); 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarhcyRoot = null; 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void dispatchCommand(View view, String command, String parameters, 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream clientStream) throws IOException { 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Paranoid but safe... 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view = view.getRootView(); 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) { 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dump(view, clientStream); 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String[] params = parameters.split(" "); 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) { 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project capture(view, clientStream, params[0]); 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) { 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(view, params[0]); 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) { 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(view, params[0]); 570c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) { 571c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project profile(view, clientStream, params[0]); 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 576c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static View findView(View root, String parameter) { 577c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by type/hashcode 578c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (parameter.indexOf('@') != -1) { 579c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String[] ids = parameter.split("@"); 580c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String className = ids[0]; 581c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int hashCode = Integer.parseInt(ids[1], 16); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 583c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project View view = root.getRootView(); 584c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view instanceof ViewGroup) { 585c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return findView((ViewGroup) view, className, hashCode); 586c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 587c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 588c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by id 589c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int id = root.getResources().getIdentifier(parameter, null, null); 590c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return root.getRootView().findViewById(id); 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void invalidate(View root, String parameter) { 597c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.postInvalidate(); 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void requestLayout(View root, String parameter) { 604c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project root.post(new Runnable() { 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.requestLayout(); 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 614c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void profile(View root, OutputStream clientStream, String parameter) 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 617c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 618c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project BufferedWriter out = null; 619c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 620c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024); 621c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 622c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view != null) { 623c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long durationMeasure = profileViewOperation(view, new ViewOperation<Void>() { 624c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public Void[] pre() { 625c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project forceLayout(view); 626c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return null; 627c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 628c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 629c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private void forceLayout(View view) { 630c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.forceLayout(); 631c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view instanceof ViewGroup) { 632c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ViewGroup group = (ViewGroup) view; 633c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int count = group.getChildCount(); 634c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int i = 0; i < count; i++) { 635c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project forceLayout(group.getChildAt(i)); 636c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 637c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 638c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 639c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 640c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run(Void... data) { 641c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec); 642c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 643c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 644c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void post(Void... data) { 645c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 646c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 647c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 648c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long durationLayout = profileViewOperation(view, new ViewOperation<Void>() { 649c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public Void[] pre() { 650c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return null; 651c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 652c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 653c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run(Void... data) { 654c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom); 655c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 656c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 657c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void post(Void... data) { 658c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 659c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 660c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 661c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long durationDraw = profileViewOperation(view, new ViewOperation<Object>() { 662c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public Object[] pre() { 663c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final DisplayMetrics metrics = view.getResources().getDisplayMetrics(); 664c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final Bitmap bitmap = Bitmap.createBitmap(metrics.widthPixels, 665ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project metrics.heightPixels, Bitmap.Config.RGB_565); 666c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final Canvas canvas = new Canvas(bitmap); 667c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return new Object[] { bitmap, canvas }; 668c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 669c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 670c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run(Object... data) { 671c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.draw((Canvas) data[1]); 672c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 673c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 674c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void post(Object... data) { 675c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ((Bitmap) data[0]).recycle(); 676c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 677c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 678c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 679c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(durationMeasure)); 680c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 681c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(durationLayout)); 682c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 683c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(durationDraw)); 684c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.newLine(); 685c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 686c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("-1 -1 -1"); 687c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.newLine(); 688c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 689c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Exception e) { 690c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project android.util.Log.w("View", "Problem profiling the view:", e); 691c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } finally { 692c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (out != null) { 693c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.close(); 694c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 695c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 696c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 697c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 698c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project interface ViewOperation<T> { 699c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] pre(); 700c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void run(T... data); 701c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void post(T... data); 702c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 703c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 704c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) { 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 706c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long[] duration = new long[1]; 707c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 708c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.post(new Runnable() { 709c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run() { 710c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 711c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] data = operation.pre(); 712c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project long start = Debug.threadCpuTimeNanos(); 713c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.run(data); 714c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project duration[0] = Debug.threadCpuTimeNanos() - start; 715c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.post(data); 716c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } finally { 717c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project latch.countDown(); 718c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 719c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 720c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 721c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 722c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 723c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); 724c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (InterruptedException e) { 725c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the profiling of the view " + view); 726c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 727c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return -1; 728c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 729c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 730c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return duration[0]; 731c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 732c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 733c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void capture(View root, final OutputStream clientStream, String parameter) 734c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 735c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 736c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View captureView = findView(root, parameter); 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (captureView != null) { 739c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Bitmap[] cache = new Bitmap[1]; 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project root.post(new Runnable() { 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 745958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 746958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Bitmap.Config.ARGB_8888, 0); 747958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e) { 748958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn try { 749958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 750958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Bitmap.Config.ARGB_4444, 0); 751958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e2) { 752958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Log.w("View", "Out of memory for bitmap"); 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.countDown(); 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cache[0] != null) { 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedOutputStream out = null; 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = new BufferedOutputStream(clientStream, 32 * 1024); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cache[0].compress(Bitmap.CompressFormat.PNG, 100, out); 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.flush(); 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out != null) { 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 773958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0].recycle(); 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 775958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } else { 776958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Log.w("View", "Failed to create capture bitmap!"); 777958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn clientStream.close(); 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 780c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the capture of the view " + captureView); 781c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dump(View root, OutputStream clientStream) throws IOException { 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out = null; 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024); 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = root.getRootView(); 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 793105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(group.getContext(), group, out, 0); 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write("DONE."); 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 797c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Exception e) { 798c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project android.util.Log.w("View", "Problem dumping the view:", e); 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out != null) { 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View findView(ViewGroup group, String className, int hashCode) { 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isRequestedView(group, className, hashCode)) { 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return group; 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View found = findView((ViewGroup) view, className, hashCode); 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (found != null) { 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return found; 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (isRequestedView(view, className, hashCode)) { 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view; 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean isRequestedView(View view, String className, int hashCode) { 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view.getClass().getName().equals(className) && view.hashCode() == hashCode; 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 831105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group, 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out, int level) { 833105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (!dumpViewWithProperties(context, group, out, level)) { 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 841105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1); 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 843105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewWithProperties(context, view, out, level + 1); 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 848105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static boolean dumpViewWithProperties(Context context, View view, 849105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, int level) { 850105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 859105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out); 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] getExportedPropertyFields(Class<?> klass) { 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sFieldsForClasses == null) { 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sFieldsForClasses = new HashMap<Class<?>, Field[]>(); 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 872c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 873c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 874c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 875c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = sFieldsForClasses; 877c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getDeclaredFields(); 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(ExportedProperty.class)) { 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 893c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project annotations.put(field, field.getAnnotation(ExportedProperty.class)); 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] getExportedPropertyMethods(Class<?> klass) { 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sMethodsForClasses == null) { 905c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sMethodsForClasses = new HashMap<Class<?>, Method[]>(100); 906c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 907c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 908c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 910c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = sMethodsForClasses; 912c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getDeclaredMethods(); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 926c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.isAnnotationPresent(ExportedProperty.class) && 927c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.getReturnType() != Void.class) { 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 930c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project annotations.put(method, method.getAnnotation(ExportedProperty.class)); 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 940105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 941105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out) throws IOException { 942105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 943105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out, ""); 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 946105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 947105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, String prefix) throws IOException { 948105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 952105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportFields(context, view, out, klass, prefix); 953105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportMethods(context, view, out, klass, prefix); 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project klass = klass.getSuperclass(); 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (klass != Object.class); 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 958105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportMethods(Context context, Object view, BufferedWriter out, 959105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = getExportedPropertyMethods(klass); 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: This should happen on the UI thread 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(view, (Object[]) null); 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (returnType == int.class) { 973c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(method); 974105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = (Integer) methodValue; 976105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project methodValue = resolveId(context, id); 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = (Integer) methodValue; 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mapped = false; 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapper = mapping[j]; 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapper.from() == intValue) { 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = mapper.to(); 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mapped = true; 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mapped) { 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = intValue; 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 997c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (returnType == int[].class) { 998c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(method); 999c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) methodValue; 1000c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String valuePrefix = prefix + method.getName() + '_'; 1001c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = "()"; 1002c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1003105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!returnType.isPrimitive()) { 1005c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(method); 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1007105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, methodValue, out, prefix + property.prefix()); 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1012c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, method.getName(), "()", methodValue); 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1019105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportFields(Context context, Object view, BufferedWriter out, 1020105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 1021105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = getExportedPropertyFields(klass); 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = null; 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> type = field.getType(); 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (type == int.class) { 1034c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(field); 1035105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = field.getInt(view); 1037105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project fieldValue = resolveId(context, id); 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = field.getInt(view); 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapped = mapping[j]; 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapped.from() == intValue) { 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = mapped.to(); 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = intValue; 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1056c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (type == int[].class) { 1057c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(field); 1058c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) field.get(view); 1059c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String valuePrefix = prefix + field.getName() + '_'; 1060c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = ""; 1061c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1062105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1063c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1064c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // We exit here! 1065c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return; 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!type.isPrimitive()) { 1067c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(field); 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1069105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, field.get(view), out, 1070105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project prefix + property.prefix()); 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = field.get(view); 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1079c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, field.getName(), "", fieldValue); 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1085c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeEntry(BufferedWriter out, String prefix, String name, 1086c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String suffix, Object value) throws IOException { 1087c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1088c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(prefix); 1089c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(name); 1090c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(suffix); 1091c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("="); 1092c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeValue(out, value); 1093c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 1094c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1095c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1096105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportUnrolledArray(Context context, BufferedWriter out, 1097c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ExportedProperty property, int[] array, String prefix, String suffix) 1098c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1099c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1100c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] indexMapping = property.indexMapping(); 1101c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasIndexMapping = indexMapping.length > 0; 1102c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1103c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] mapping = property.mapping(); 1104c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasMapping = mapping.length > 0; 1105c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1106105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final boolean resolveId = property.resolveId() && context != null; 1107c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int valuesCount = array.length; 1108c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1109c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int j = 0; j < valuesCount; j++) { 1110c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String name; 1111c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String value; 1112c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1113c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int intValue = array[j]; 1114c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1115c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = String.valueOf(j); 1116c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasIndexMapping) { 1117c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = indexMapping.length; 1118c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1119c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = indexMapping[k]; 1120c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == j) { 1121c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = mapped.to(); 1122c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1123c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1124c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1125c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1126c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1127c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project value = String.valueOf(intValue); 1128c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasMapping) { 1129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = mapping.length; 1130c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1131c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = mapping[k]; 1132c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == intValue) { 1133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project value = mapped.to(); 1134c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1135c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1139c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (resolveId) { 1140105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project value = (String) resolveId(context, intValue); 1141c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1142c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1143c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, name, suffix, value); 1144c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1145c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1146c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1147105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static Object resolveId(Context context, int id) { 1148c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Object fieldValue; 1149105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final Resources resources = context.getResources(); 1150c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (id >= 0) { 1151c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1152c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = resources.getResourceTypeName(id) + '/' + 1153c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project resources.getResourceEntryName(id); 1154c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Resources.NotFoundException e) { 1155c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "id/0x" + Integer.toHexString(id); 1156c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1157c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1158c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "NO_ID"; 1159c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1160c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return fieldValue; 1161c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1162c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1163c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeValue(BufferedWriter out, Object value) throws IOException { 1164c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (value != null) { 1165c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String output = value.toString().replace("\n", "\\n"); 1166c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(output.length())); 1167c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(","); 1168c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(output); 1169c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1170c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("4,null"); 1171c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1172c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1173c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dumpViewHierarchy(ViewGroup group, BufferedWriter out, int level) { 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!dumpView(group, out, level)) { 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy((ViewGroup) view, out, level + 1); 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpView(view, out, level + 1); 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean dumpView(Object view, BufferedWriter out, int level) { 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] capturedViewGetPropertyFields(Class<?> klass) { 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewFieldsForClasses == null) { 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>(); 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses; 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getFields(); 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(CapturedViewProperty.class)) { 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] capturedViewGetPropertyMethods(Class<?> klass) { 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewMethodsForClasses == null) { 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>(); 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses; 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getMethods(); 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.isAnnotationPresent(CapturedViewProperty.class) && 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.getReturnType() != Void.class) { 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String capturedViewExportMethods(Object obj, Class<?> klass, 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix) { 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = capturedViewGetPropertyMethods(klass); 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(obj, (Object[]) null); 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class); 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.retrieveReturn()) { 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we are interested in the second level data only 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#")); 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(method.getName()); 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("()="); 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methodValue != null) { 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String value = methodValue.toString().replace("\n", "\\n"); 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(value); 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("; "); 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //Exception IllegalAccess, it is OK here 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //Exception InvocationTarget, it is OK here 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) { 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = capturedViewGetPropertyFields(klass); 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = field.get(obj); 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(field.getName()); 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("="); 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue != null) { 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String value = fieldValue.toString().replace("\n", "\\n"); 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(value); 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(' '); 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //Exception IllegalAccess, it is OK here 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this field 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1346f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * Dump view info for id based instrument test generation 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (and possibly further data analysis). The results are dumped 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to the log. 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tag for log 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view for dump 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void dumpCapturedView(String tag, Object view) { 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(klass.getName() + ": "); 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportFields(view, klass, "")); 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportMethods(view, klass, "")); 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(tag, sb.toString()); 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1360