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 19e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guyimport android.util.Config; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 21c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.util.DisplayMetrics; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 23105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.content.Context; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap; 25c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.graphics.Canvas; 26223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport android.graphics.Rect; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment; 28c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.os.Debug; 29223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport android.os.RemoteException; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport java.io.ByteArrayOutputStream; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedWriter; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileWriter; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.DataOutputStream; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStreamWriter; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedOutputStream; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.LinkedList; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.CountDownLatch; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.TimeUnit; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Target; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.ElementType; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Retention; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.RetentionPolicy; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Method; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.InvocationTargetException; 54c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport java.lang.reflect.AccessibleObject; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various debugging/tracing tools related to {@link View} and the view hierarchy. 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ViewDebug { 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Log tag used to log errors related to the consistency of the view hierarchy. 6213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 6313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 6413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 6513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final String CONSISTENCY_LOG_TAG = "ViewConsistency"; 6613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 6713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 6813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Flag indicating the consistency check should check layout-related properties. 6913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 7013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 7113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 7213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final int CONSISTENCY_LAYOUT = 0x1; 7313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 7413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 7513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Flag indicating the consistency check should check drawing-related properties. 7613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 7713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 7813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 7913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final int CONSISTENCY_DRAWING = 0x2; 8013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 8113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view hierarchy tracing. Any invoker of 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_HIERARCHY = false; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view recycler tracing. Any invoker of 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])} should first 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_RECYCLER = false; 94a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 96cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Enables or disables motion events tracing. Any invoker of 97cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * {@link #trace(View, MotionEvent, MotionEventTraceType)} should first check 98cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * that this value is set to true as not to affect performance. 99cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 100cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 101cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 102cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static final boolean TRACE_MOTION_EVENTS = false; 103cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 104cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The system property of dynamic switch for capturing view information 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when it is set, we dump interested fields and methods for the view on focus 107a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy */ 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String SYSTEM_PROPERTY_CAPTURE_VIEW = "debug.captureview"; 109a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The system property of dynamic switch for capturing event information 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when it is set, we log key events, touch/motion and trackball events 113a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy */ 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent"; 115c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles drawing times in the events log. 11813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 11913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 12013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 12113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 12213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean profileDrawing = false; 12313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 12413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 12513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles layout times in the events log. 12613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 12713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 12813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 12913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 13013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean profileLayout = false; 13113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 13213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 13313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles real fps (times between draws) and displays the result. 13413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 13513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 13613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 13713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 13813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean showFps = false; 13913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 14013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 14113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <p>Enables or disables views consistency check. Even when this property is enabled, 14213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * view consistency checks happen only if {@link android.util.Config#DEBUG} is set 14313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * to true. The value of this property can be configured externally in one of the 14413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * following files:</p> 14513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <ul> 14613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/system/debug.prop</li> 14713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/debug.prop</li> 14813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/data/debug.prop</li> 14913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * </ul> 15013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 15113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 15213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 15313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean consistencyCheckEnabled = false; 15413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 15513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy static { 156e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy if (Config.DEBUG) { 157e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy Debug.setFieldsOn(ViewDebug.class, true); 158e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy } 15913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy } 16013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 16113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped by 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view server. Only non-void methods with no arguments can be annotated 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * by this annotation. 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface ExportedProperty { 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When resolveId is true, and if the annotated field/method return value 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is an int, the value is converted to an Android's resource name. 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the property's value must be transformed into an Android 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * resource name, false otherwise 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean resolveId() default false; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A mapping can be defined to map int values to specific strings. For 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance, View.getVisibility() returns 0, 4 or 8. However, these values 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * actually mean VISIBLE, INVISIBLE and GONE. A mapping can be used to see 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * these human readable values: 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.ExportedProperty(mapping = { 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "VISIBLE"), 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 4, to = "INVISIBLE"), 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 8, to = "GONE") 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * }) 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * public int getVisibility() { ... 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An array of int to String mappings 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.IntToString 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IntToString[] mapping() default { }; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 200c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be defined to map array indices to specific strings. 201c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be used to see human readable values for the indices 202c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * of an array: 203c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 204c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 205809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.ExportedProperty(indexMapping = { 206c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "INVALID"), 207c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 1, to = "FIRST"), 208c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 2, to = "SECOND") 209c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * }) 210c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * private int[] mElements; 211c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 212c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 213c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @return An array of int to String mappings 214c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 215c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see android.view.ViewDebug.IntToString 216c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see #mapping() 217c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project */ 218c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project IntToString[] indexMapping() default { }; 219c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 220c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project /** 221809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * A flags mapping can be defined to map flags encoded in an integer to 222809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * specific strings. A mapping can be used to see human readable values 223809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * for the flags of an integer: 224809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 225809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <pre> 226809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.ExportedProperty(flagMapping = { 227809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"), 228809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"), 229809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * }) 230809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * private int mFlags; 231809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <pre> 232809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 233809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * A specified String is output when the following is true: 234a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * 235809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An array of int to String mappings 236809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 237809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy FlagToString[] flagMapping() default { }; 238809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 239809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When deep export is turned on, this property is not dumped. Instead, the 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * properties contained in this property are dumped. Each child property 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is prefixed with the name of this property. 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the properties of this property should be dumped 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 246a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @see #prefix() 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean deepExport() default false; 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The prefix to use on child properties when deep export is enabled 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a prefix as a String 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #deepExport() 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix() default ""; 258bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 259bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev /** 260bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * Specifies the category the property falls into, such as measurement, 261bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * layout, drawing, etc. 262bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * 263bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * @return the category as String 264bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev */ 265bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev String category() default ""; 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines a mapping from an int value to a String. Such a mapping can be used 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in a @ExportedProperty to provide more meaningful values to the end user. 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.ExportedProperty 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.TYPE }) 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface IntToString { 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The original int value to map to a String. 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary int value. 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int from(); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The String to use in place of the original int value. 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary non-null String. 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String to(); 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 291809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 292809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 293809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * Defines a mapping from an flag to a String. Such a mapping can be used 294809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * in a @ExportedProperty to provide more meaningful values to the end user. 295809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 296809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @see android.view.ViewDebug.ExportedProperty 297809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 298809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Target({ ElementType.TYPE }) 299809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Retention(RetentionPolicy.RUNTIME) 300809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy public @interface FlagToString { 301809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 302809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The mask to apply to the original value. 303809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 304809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary int value. 305809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 306809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int mask(); 307809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 308809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 309809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The value to compare to the result of: 310809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <code>original value & {@link #mask()}</code>. 311809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 312809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary value. 313809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 314809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int equals(); 315809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 316809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 317809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The String to use in place of the original int value. 318809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 319809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary non-null String. 320809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 321809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy String name(); 322809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 323809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 324809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * Indicates whether to output the flag when the test is true, 325809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * or false. Defaults to true. 326809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 327809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy boolean outputIf() default true; 328809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 329809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped when 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view is captured. Methods with this annotation must have no arguments 333f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * and must return a valid type of data. 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface CapturedViewProperty { 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 339a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * When retrieveReturn is true, we need to retrieve second level methods 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod() 341a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * we will set retrieveReturn = true on the annotation of 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * myView.getFirstLevelMethod() 343a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @return true if we need the second level methods 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 345a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy boolean retrieveReturn() default false; 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 347a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null; 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null; 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Maximum delay in ms after which we stop trying to capture a View's drawing 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CAPTURE_TIMEOUT = 4000; 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE"; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_DUMP = "DUMP"; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE"; 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT"; 358c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static final String REMOTE_PROFILE = "PROFILE"; 359223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS"; 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> sFieldsForClasses; 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> sMethodsForClasses; 363c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static HashMap<AccessibleObject, ExportedProperty> sAnnotations; 364c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of hierarhcy trace to output to the hierarchy traces file. 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum HierarchyTraceType { 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE, 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD, 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD_IN_PARENT, 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project REQUEST_LAYOUT, 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_LAYOUT, 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_MEASURE, 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DRAW, 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BUILD_CACHE 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static BufferedWriter sHierarchyTraces; 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static ViewRoot sHierarhcyRoot; 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sHierarchyTracePrefix; 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of recycler trace to output to the recycler traces file. 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum RecyclerTraceType { 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NEW_VIEW, 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BIND_VIEW, 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_ACTIVE_HEAP, 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_SCRAP_HEAP, 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_TO_SCRAP_HEAP, 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_FROM_ACTIVE_TO_SCRAP_HEAP 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class RecyclerTrace { 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int view; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public RecyclerTraceType type; 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int position; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int indexOnScreen; 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View sRecyclerOwnerView; 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<View> sRecyclerViews; 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<RecyclerTrace> sRecyclerTraces; 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sRecyclerTracePrefix; 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 408cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Defines the type of motion events trace to output to the motion events traces file. 409cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 410cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 411cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 412cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public enum MotionEventTraceType { 413cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy DISPATCH, 414cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy ON_INTERCEPT, 415cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy ON_TOUCH 416cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 417cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 418cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy private static BufferedWriter sMotionEventTraces; 419cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy private static ViewRoot sMotionEventRoot; 420cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy private static String sMotionEventTracePrefix; 421cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 422cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated Views. 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of Views instanciated in the current process. 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewInstanceCount() { 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return View.sInstanceCount; 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated ViewRoots. 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of ViewRoots instanciated in the current process. 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewRootInstanceCount() { 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ViewRoot.getInstanceCount(); 442a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened recycler traces. The trace records the type of 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * recycler action performed on the supplied view as well as a number of parameters. 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param parameters parameters depending on the type of the trace 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, RecyclerTraceType type, int... parameters) { 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!sRecyclerViews.contains(view)) { 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.add(view); 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int index = sRecyclerViews.indexOf(view); 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RecyclerTrace trace = new RecyclerTrace(); 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.view = index; 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.type = type; 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.position = parameters[0]; 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.indexOnScreen = parameters[1]; 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.add(trace); 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view recycler of the specified view. The trace is identified by a prefix, 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-recycler/PREFIX.traces</code> and 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>. 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view recycler can be traced at the same time. After calling this method, any 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopRecyclerTracing()} is invoked before. 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Traces files are created only after {@link #stopRecyclerTracing()} is invoked. 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose recycler must be traced 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopRecyclerTracing() 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startRecyclerTracing(String prefix, View view) { 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView != null) { 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopRecyclerTracing() before running" + 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTracePrefix = prefix; 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = view; 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = new ArrayList<View>(); 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = new LinkedList<RecyclerTrace>(); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view recycer tracing. 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.traces</code> 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's recycler. 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.recycler</code> 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all of the views used by the recycler of the view supplied to 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startRecyclerTracing(String, View)}. 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #startRecyclerTracing(String, View) 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopRecyclerTracing() { 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startRecyclerTracing() before" + 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopRecyclerTracing()!"); 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 535c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump.mkdirs(); 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler"); 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final BufferedWriter out = new BufferedWriter(new FileWriter(recyclerDump), 8 * 1024); 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (View view : sRecyclerViews) { 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String name = view.getClass().getName(); 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(name); 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler content"); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces"); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5571afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn if (recyclerDump.exists()) { 5581afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn recyclerDump.delete(); 5591afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn } 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final FileOutputStream file = new FileOutputStream(recyclerDump); 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final DataOutputStream out = new DataOutputStream(file); 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (RecyclerTrace trace : sRecyclerTraces) { 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.view); 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.type.ordinal()); 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.position); 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.indexOnScreen); 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.flush(); 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler traces"); 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.clear(); 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = null; 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.clear(); 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = null; 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = null; 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened traces file. The trace contains the class name 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and instance's hashcode of the specified view as well as the supplied trace type. 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, HierarchyTraceType type) { 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarchyTraces == null) { 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(type.name()); 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(' '); 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(view.getClass().getName()); 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write('@'); 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(Integer.toHexString(view.hashCode())); 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.newLine(); 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping trace of type " + type + " for view " + view); 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix, 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> and 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>. 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view hierarchy can be traced at the same time. After calling this method, any 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopHierarchyTracing()} is invoked before. 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's hierarchy. 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose hierarchy must be traced 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopHierarchyTracing() 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startHierarchyTracing(String prefix, View view) { 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot != null) { 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopHierarchyTracing() before running" + 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 642c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, prefix + ".traces"); 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTracePrefix = prefix; 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarhcyRoot = (ViewRoot) view.getRootView().getParent(); 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view hierarchy tracing. This method closes the file 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>. 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code> 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing the view hierarchy of the view supplied to 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startHierarchyTracing(String, View)}. 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 668a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @see #startHierarchyTracing(String, View) 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopHierarchyTracing() { 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot == null || sHierarchyTraces == null) { 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startHierarchyTracing() before" + 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopHierarchyTracing()!"); 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.close(); 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not write view traces"); 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = null; 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 690c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree"); 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out; 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = sHierarhcyRoot.getView(); 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy(group, out, 0); 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarhcyRoot = null; 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 715a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 716cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 717cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Outputs a trace to the currently opened traces file. The trace contains the class name 718cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * and instance's hashcode of the specified view as well as the supplied trace type. 719cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 720cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param view the view to trace 721cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param event the event of the trace 722cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param type the type of the trace 723cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 724cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 725cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 726cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static void trace(View view, MotionEvent event, MotionEventTraceType type) { 727cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (sMotionEventTraces == null) { 728cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 729cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 730cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 731cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 732cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(type.name()); 733cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(' '); 734cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(event.getAction()); 735cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(' '); 736cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(view.getClass().getName()); 737cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write('@'); 738cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(Integer.toHexString(view.hashCode())); 739cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sHierarchyTraces.newLine(); 740cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 741cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.w("View", "Error while dumping trace of event " + event + " for view " + view); 742cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 743cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 744cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 745cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 746cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Starts tracing the motion events for the hierarchy of the specificy view. 747cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * The trace is identified by a prefix, used to build the traces files names: 748cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * <code>/EXTERNAL/motion-events/PREFIX.traces</code> and 749cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * <code>/EXTERNAL/motion-events/PREFIX.tree</code>. 750cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 751cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Only one view hierarchy can be traced at the same time. After calling this method, any 752cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * other invocation will result in a <code>IllegalStateException</code> unless 753cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * {@link #stopMotionEventTracing()} is invoked before. 754cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 755cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.traces</code> 756cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * containing all the traces (or method calls) relative to the specified view's hierarchy. 757cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 758cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * This method will return immediately if TRACE_HIERARCHY is false. 759cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 760cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param prefix the traces files name prefix 761cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param view the view whose hierarchy must be traced 762cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 763cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #stopMotionEventTracing() 764cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) 765cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 766cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 767cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 768cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static void startMotionEventTracing(String prefix, View view) { 769cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection PointlessBooleanExpression,ConstantConditions 770cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (!TRACE_MOTION_EVENTS) { 771cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 772cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 773cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 774cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (sMotionEventRoot != null) { 775cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy throw new IllegalStateException("You must call stopMotionEventTracing() before running" + 776cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy " a new trace!"); 777cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 778cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 779cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); 780cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection ResultOfMethodCallIgnored 781cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump.mkdirs(); 782cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 783cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump = new File(hierarchyDump, prefix + ".traces"); 784cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTracePrefix = prefix; 785cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 786cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 787cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces = new BufferedWriter(new FileWriter(hierarchyDump), 32 * 1024); 788cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 789cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not dump view hierarchy"); 790cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 791cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 792cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 793cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventRoot = (ViewRoot) view.getRootView().getParent(); 794cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 795cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 796cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 797cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Stops the current motion events tracing. This method closes the file 798cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * <code>/EXTERNAL/motion-events/PREFIX.traces</code>. 799cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 800cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.tree</code> 801cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * containing the view hierarchy of the view supplied to 802cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * {@link #startMotionEventTracing(String, View)}. 803cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 804cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * This method will return immediately if TRACE_HIERARCHY is false. 805cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 806cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #startMotionEventTracing(String, View) 807cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) 808cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 809cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 810cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 811cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static void stopMotionEventTracing() { 812cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection PointlessBooleanExpression,ConstantConditions 813cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (!TRACE_MOTION_EVENTS) { 814cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 815cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 816cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 817cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (sMotionEventRoot == null || sMotionEventTraces == null) { 818cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy throw new IllegalStateException("You must call startMotionEventTracing() before" + 819cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy " stopMotionEventTracing()!"); 820cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 821cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 822cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 823cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.close(); 824cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 825cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not write view traces"); 826cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 827cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces = null; 828cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 829cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); 830cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection ResultOfMethodCallIgnored 831cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump.mkdirs(); 832cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump = new File(hierarchyDump, sMotionEventTracePrefix + ".tree"); 833cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 834cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy BufferedWriter out; 835cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 836cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 837cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 838cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not dump view hierarchy"); 839cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 840cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 841cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 842cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy View view = sMotionEventRoot.getView(); 843cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (view instanceof ViewGroup) { 844cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy ViewGroup group = (ViewGroup) view; 845cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy dumpViewHierarchy(group, out, 0); 846cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 847cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy out.close(); 848cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 849cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not dump view hierarchy"); 850cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 851cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 852cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 853cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sHierarhcyRoot = null; 854cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 855cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void dispatchCommand(View view, String command, String parameters, 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream clientStream) throws IOException { 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Paranoid but safe... 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view = view.getRootView(); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) { 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dump(view, clientStream); 864223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) { 865223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy captureLayers(view, new DataOutputStream(clientStream)); 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String[] params = parameters.split(" "); 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) { 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project capture(view, clientStream, params[0]); 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) { 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(view, params[0]); 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) { 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(view, params[0]); 874c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) { 875c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project profile(view, clientStream, params[0]); 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 880c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static View findView(View root, String parameter) { 881c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by type/hashcode 882c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (parameter.indexOf('@') != -1) { 883c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String[] ids = parameter.split("@"); 884c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String className = ids[0]; 885236092a36216c79507ec19eb207831810caced19Romain Guy final int hashCode = (int) Long.parseLong(ids[1], 16); 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 887c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project View view = root.getRootView(); 888c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view instanceof ViewGroup) { 889c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return findView((ViewGroup) view, className, hashCode); 890c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 891c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 892c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by id 893c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int id = root.getResources().getIdentifier(parameter, null, null); 894c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return root.getRootView().findViewById(id); 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void invalidate(View root, String parameter) { 901c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.postInvalidate(); 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void requestLayout(View root, String parameter) { 908c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project root.post(new Runnable() { 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.requestLayout(); 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 918c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void profile(View root, OutputStream clientStream, String parameter) 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 921c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 922c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project BufferedWriter out = null; 923c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 924c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024); 925c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 926c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view != null) { 927f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev profileViewAndChildren(view, out); 928f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } else { 929f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write("-1 -1 -1"); 930f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 931f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 932f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write("DONE."); 933f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 934f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } catch (Exception e) { 935f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev android.util.Log.w("View", "Problem profiling the view:", e); 936f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } finally { 937f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev if (out != null) { 938f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.close(); 939f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 940f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 941f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 942c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 943f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev private static void profileViewAndChildren(final View view, BufferedWriter out) 944f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev throws IOException { 945c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev profileViewAndChildren(view, out, true); 946c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 947f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev 948c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev private static void profileViewAndChildren(final View view, BufferedWriter out, boolean root) 949c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev throws IOException { 950f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev 951c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationMeasure = 952c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev (root || (view.mPrivateFlags & View.MEASURED_DIMENSION_SET) != 0) ? profileViewOperation( 953c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view, new ViewOperation<Void>() { 954c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public Void[] pre() { 955c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev forceLayout(view); 956c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return null; 957c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 958c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 959c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev private void forceLayout(View view) { 960c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.forceLayout(); 961c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev if (view instanceof ViewGroup) { 962c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev ViewGroup group = (ViewGroup) view; 963c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev final int count = group.getChildCount(); 964c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev for (int i = 0; i < count; i++) { 965c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev forceLayout(group.getChildAt(i)); 966c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 967c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 968c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 969c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 970c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void run(Void... data) { 971c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec); 972c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 973c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 974c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void post(Void... data) { 975c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 976c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }) 977c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev : 0; 978c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationLayout = 979c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev (root || (view.mPrivateFlags & View.LAYOUT_REQUIRED) != 0) ? profileViewOperation( 980c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view, new ViewOperation<Void>() { 981c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public Void[] pre() { 982c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return null; 983c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 984c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 985c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void run(Void... data) { 986c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom); 987c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 988c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 989c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void post(Void... data) { 990c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 991c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }) : 0; 992c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationDraw = 993bef337f516eafaee8f3891e22688b74388570317Konstantin Lopyrev (root || !view.willNotDraw() || (view.mPrivateFlags & View.DRAWN) != 0) ? profileViewOperation( 994bef337f516eafaee8f3891e22688b74388570317Konstantin Lopyrev view, 995c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev new ViewOperation<Object>() { 996c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public Object[] pre() { 997c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev final DisplayMetrics metrics = 998c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.getResources().getDisplayMetrics(); 999c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev final Bitmap bitmap = 1000c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev Bitmap.createBitmap(metrics.widthPixels, 1001c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev metrics.heightPixels, Bitmap.Config.RGB_565); 1002c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev final Canvas canvas = new Canvas(bitmap); 1003c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return new Object[] { 1004c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev bitmap, canvas 1005c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }; 1006c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1007c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1008c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void run(Object... data) { 1009c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.draw((Canvas) data[1]); 1010c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1011c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1012c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void post(Object... data) { 1013c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev ((Bitmap) data[0]).recycle(); 1014c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1015c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }) : 0; 1016f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationMeasure)); 1017f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(' '); 1018f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationLayout)); 1019f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(' '); 1020f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationDraw)); 1021f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 1022f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev if (view instanceof ViewGroup) { 1023f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev ViewGroup group = (ViewGroup) view; 1024f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev final int count = group.getChildCount(); 1025f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev for (int i = 0; i < count; i++) { 1026c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev profileViewAndChildren(group.getChildAt(i), out, false); 1027c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1028c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1029c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1030c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1031c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project interface ViewOperation<T> { 1032c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] pre(); 1033c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void run(T... data); 1034c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void post(T... data); 1035c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1036c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1037c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) { 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 1039c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long[] duration = new long[1]; 1040c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1041c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.post(new Runnable() { 1042c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run() { 1043c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1044c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] data = operation.pre(); 1045c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project long start = Debug.threadCpuTimeNanos(); 1046c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.run(data); 1047c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project duration[0] = Debug.threadCpuTimeNanos() - start; 1048c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.post(data); 1049c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } finally { 1050c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project latch.countDown(); 1051c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1052c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1053c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 1054c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1055c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1056c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev if (!latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS)) { 1057c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev Log.w("View", "Could not complete the profiling of the view " + view); 1058c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return -1; 1059c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1060c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (InterruptedException e) { 1061c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the profiling of the view " + view); 1062c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 1063c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return -1; 1064c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1065c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1066c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return duration[0]; 1067c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1068c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1069223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy private static void captureLayers(View root, final DataOutputStream clientStream) 1070223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy throws IOException { 1071223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1072223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy try { 1073223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Rect outRect = new Rect(); 1074223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy try { 1075223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy root.mAttachInfo.mSession.getDisplayFrame(root.mAttachInfo.mWindow, outRect); 1076223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } catch (RemoteException e) { 1077223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy // Ignore 1078223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1079223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1080223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(outRect.width()); 1081223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(outRect.height()); 1082223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 108365554f27855ce1764123604b061b10346f8b8404Romain Guy captureViewLayer(root, clientStream, true); 1084223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1085223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.write(2); 1086223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } finally { 1087223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.close(); 1088223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1089223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1090223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 109165554f27855ce1764123604b061b10346f8b8404Romain Guy private static void captureViewLayer(View view, DataOutputStream clientStream, boolean visible) 1092223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy throws IOException { 1093223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 109465554f27855ce1764123604b061b10346f8b8404Romain Guy final boolean localVisible = view.getVisibility() == View.VISIBLE && visible; 109565554f27855ce1764123604b061b10346f8b8404Romain Guy 1096223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if ((view.mPrivateFlags & View.SKIP_DRAW) != View.SKIP_DRAW) { 1097223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy final int id = view.getId(); 1098223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy String name = view.getClass().getSimpleName(); 1099223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (id != View.NO_ID) { 1100223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy name = resolveId(view.getContext(), id).toString(); 1101223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1102223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1103223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.write(1); 1104223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeUTF(name); 110565554f27855ce1764123604b061b10346f8b8404Romain Guy clientStream.writeByte(localVisible ? 1 : 0); 1106223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1107223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy int[] position = new int[2]; 1108223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy // XXX: Should happen on the UI thread 1109223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy view.getLocationInWindow(position); 1110223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1111223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(position[0]); 1112223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(position[1]); 1113223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.flush(); 1114223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1115223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap b = performViewCapture(view, true); 1116223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (b != null) { 1117223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(b.getWidth() * 1118223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy b.getHeight() * 2); 1119223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy b.compress(Bitmap.CompressFormat.PNG, 100, arrayOut); 1120223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(arrayOut.size()); 1121223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy arrayOut.writeTo(clientStream); 1122223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1123223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.flush(); 1124223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1125223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1126223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (view instanceof ViewGroup) { 1127223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy ViewGroup group = (ViewGroup) view; 1128223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy int count = group.getChildCount(); 1129223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1130223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy for (int i = 0; i < count; i++) { 113165554f27855ce1764123604b061b10346f8b8404Romain Guy captureViewLayer(group.getChildAt(i), clientStream, localVisible); 1132223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1133223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1134223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1135223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void capture(View root, final OutputStream clientStream, String parameter) 1137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1139c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View captureView = findView(root, parameter); 1140223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap b = performViewCapture(captureView, false); 114143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev 114243b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev if (b == null) { 1143223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Log.w("View", "Failed to create capture bitmap!"); 114443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev // Send an empty one so that it doesn't get stuck waiting for 114543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev // something. 114643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 114743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } 114843b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev 114943b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev BufferedOutputStream out = null; 115043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev try { 115143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out = new BufferedOutputStream(clientStream, 32 * 1024); 115243b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b.compress(Bitmap.CompressFormat.PNG, 100, out); 115343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out.flush(); 115443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } finally { 115543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev if (out != null) { 115643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out.close(); 115743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } 115843b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b.recycle(); 1159223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1160223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1162223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy private static Bitmap performViewCapture(final View captureView, final boolean skpiChildren) { 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (captureView != null) { 1164c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Bitmap[] cache = new Bitmap[1]; 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1167223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy captureView.post(new Runnable() { 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1170958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 1171223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap.Config.ARGB_8888, 0, skpiChildren); 1172958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e) { 1173958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn try { 1174958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 1175223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap.Config.ARGB_4444, 0, skpiChildren); 1176958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e2) { 1177958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Log.w("View", "Out of memory for bitmap"); 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.countDown(); 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); 1187223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy return cache[0]; 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 1189c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the capture of the view " + captureView); 1190c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1193223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1194223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy return null; 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dump(View root, OutputStream clientStream) throws IOException { 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out = null; 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 120038e951b62ed956501b11f0715e23e3bf70942f6dRomain Guy out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024); 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = root.getRootView(); 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 1204105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(group.getContext(), group, out, 0); 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write("DONE."); 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 1208c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Exception e) { 1209c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project android.util.Log.w("View", "Problem dumping the view:", e); 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out != null) { 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View findView(ViewGroup group, String className, int hashCode) { 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isRequestedView(group, className, hashCode)) { 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return group; 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View found = findView((ViewGroup) view, className, hashCode); 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (found != null) { 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return found; 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (isRequestedView(view, className, hashCode)) { 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view; 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean isRequestedView(View view, String className, int hashCode) { 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view.getClass().getName().equals(className) && view.hashCode() == hashCode; 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1242105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group, 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out, int level) { 1244105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (!dumpViewWithProperties(context, group, out, level)) { 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 1252105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1); 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1254105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewWithProperties(context, view, out, level + 1); 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1259105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static boolean dumpViewWithProperties(Context context, View view, 1260105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, int level) { 1261105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 1270105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out); 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] getExportedPropertyFields(Class<?> klass) { 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sFieldsForClasses == null) { 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sFieldsForClasses = new HashMap<Class<?>, Field[]>(); 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1283c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 1284c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 1285c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1286c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = sFieldsForClasses; 1288c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getDeclaredFields(); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(ExportedProperty.class)) { 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 1304c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project annotations.put(field, field.getAnnotation(ExportedProperty.class)); 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] getExportedPropertyMethods(Class<?> klass) { 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sMethodsForClasses == null) { 1316c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sMethodsForClasses = new HashMap<Class<?>, Method[]>(100); 1317c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1318c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 1319c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1321c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = sMethodsForClasses; 1323c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getDeclaredMethods(); 1332a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 1335a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final Method method = methods[i]; 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 1337c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.isAnnotationPresent(ExportedProperty.class) && 1338c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.getReturnType() != Void.class) { 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 1341c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project annotations.put(method, method.getAnnotation(ExportedProperty.class)); 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1351105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1352105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out) throws IOException { 1353105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1354105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out, ""); 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1357105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1358105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, String prefix) throws IOException { 1359105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 1363105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportFields(context, view, out, klass, prefix); 1364105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportMethods(context, view, out, klass, prefix); 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project klass = klass.getSuperclass(); 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (klass != Object.class); 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1368a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportMethods(Context context, Object view, BufferedWriter out, 1370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = getExportedPropertyMethods(klass); 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: This should happen on the UI thread 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(view, (Object[]) null); 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 1382bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev final ExportedProperty property = sAnnotations.get(method); 138391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev String categoryPrefix = 138491a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev property.category().length() != 0 ? property.category() + ":" : ""; 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (returnType == int.class) { 1387bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 1388105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = (Integer) methodValue; 1390105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project methodValue = resolveId(context, id); 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1392809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1393809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1394809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = (Integer) methodValue; 139591a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = 139691a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev categoryPrefix + prefix + method.getName() + '_'; 1397809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1398809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1399809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = (Integer) methodValue; 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mapped = false; 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapper = mapping[j]; 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapper.from() == intValue) { 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = mapper.to(); 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mapped = true; 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mapped) { 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = intValue; 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1419c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (returnType == int[].class) { 1420c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) methodValue; 142191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = categoryPrefix + prefix + method.getName() + '_'; 1422c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = "()"; 1423c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1425bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 1426bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev // Probably want to return here, same as for fields. 1427bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev return; 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!returnType.isPrimitive()) { 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1430105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, methodValue, out, prefix + property.prefix()); 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 143591a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev writeEntry(out, categoryPrefix + prefix, method.getName(), "()", methodValue); 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportFields(Context context, Object view, BufferedWriter out, 1443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 1444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = getExportedPropertyFields(klass); 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = null; 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> type = field.getType(); 1455bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev final ExportedProperty property = sAnnotations.get(field); 145691a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev String categoryPrefix = 145791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev property.category().length() != 0 ? property.category() + ":" : ""; 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (type == int.class) { 1460bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 1461105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = field.getInt(view); 1463105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project fieldValue = resolveId(context, id); 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1465809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1466809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1467809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = field.getInt(view); 146891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = 146991a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev categoryPrefix + prefix + field.getName() + '_'; 1470809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1471809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1472809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = field.getInt(view); 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapped = mapping[j]; 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapped.from() == intValue) { 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = mapped.to(); 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = intValue; 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1490c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (type == int[].class) { 1491c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) field.get(view); 149291a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = categoryPrefix + prefix + field.getName() + '_'; 1493c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = ""; 1494c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1495105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1496c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1497c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // We exit here! 1498c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return; 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!type.isPrimitive()) { 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 150191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev dumpViewProperties(context, field.get(view), out, prefix 150291a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev + property.prefix()); 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = field.get(view); 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 151191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev writeEntry(out, categoryPrefix + prefix, field.getName(), "", fieldValue); 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1517c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeEntry(BufferedWriter out, String prefix, String name, 1518c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String suffix, Object value) throws IOException { 1519c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1520c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(prefix); 1521c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(name); 1522c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(suffix); 1523c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("="); 1524c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeValue(out, value); 1525c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 1526c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1527c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1528809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping, 1529809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int intValue, String prefix) throws IOException { 1530809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1531809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int count = mapping.length; 1532809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy for (int j = 0; j < count; j++) { 1533809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString flagMapping = mapping[j]; 1534809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final boolean ifTrue = flagMapping.outputIf(); 15355bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final int maskResult = intValue & flagMapping.mask(); 15365bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final boolean test = maskResult == flagMapping.equals(); 1537809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if ((test && ifTrue) || (!test && !ifTrue)) { 1538809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final String name = flagMapping.name(); 15395bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final String value = "0x" + Integer.toHexString(maskResult); 1540809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy writeEntry(out, prefix, name, "", value); 1541809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1542809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1543809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1544809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1545105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportUnrolledArray(Context context, BufferedWriter out, 1546c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ExportedProperty property, int[] array, String prefix, String suffix) 1547c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1548c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1549c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] indexMapping = property.indexMapping(); 1550c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasIndexMapping = indexMapping.length > 0; 1551c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1552c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] mapping = property.mapping(); 1553c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasMapping = mapping.length > 0; 1554c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1555105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final boolean resolveId = property.resolveId() && context != null; 1556c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int valuesCount = array.length; 1557c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1558c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int j = 0; j < valuesCount; j++) { 1559c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String name; 1560a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy String value = null; 1561c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1562c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int intValue = array[j]; 1563c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1564c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = String.valueOf(j); 1565c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasIndexMapping) { 1566c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = indexMapping.length; 1567c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1568c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = indexMapping[k]; 1569c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == j) { 1570c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = mapped.to(); 1571c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1572c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1573c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1574c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1575c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1576c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasMapping) { 1577c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = mapping.length; 1578c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1579c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = mapping[k]; 1580c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == intValue) { 1581c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project value = mapped.to(); 1582c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1583c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1584c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1585c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1586c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1587c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (resolveId) { 1588a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy if (value == null) value = (String) resolveId(context, intValue); 1589a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 1590a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy value = String.valueOf(intValue); 1591c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1592c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1593c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, name, suffix, value); 1594c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1595c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1596c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1597237c1ceea36024cf4194212e713806e3ce8a1c49Romain Guy static Object resolveId(Context context, int id) { 1598c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Object fieldValue; 1599105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final Resources resources = context.getResources(); 1600c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (id >= 0) { 1601c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1602c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = resources.getResourceTypeName(id) + '/' + 1603c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project resources.getResourceEntryName(id); 1604c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Resources.NotFoundException e) { 1605c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "id/0x" + Integer.toHexString(id); 1606c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1607c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1608c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "NO_ID"; 1609c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1610c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return fieldValue; 1611c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1612c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1613c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeValue(BufferedWriter out, Object value) throws IOException { 1614c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (value != null) { 1615c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String output = value.toString().replace("\n", "\\n"); 1616c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(output.length())); 1617c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(","); 1618c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(output); 1619c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1620c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("4,null"); 1621c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1622c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1623c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dumpViewHierarchy(ViewGroup group, BufferedWriter out, int level) { 16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!dumpView(group, out, level)) { 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy((ViewGroup) view, out, level + 1); 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpView(view, out, level + 1); 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean dumpView(Object view, BufferedWriter out, int level) { 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] capturedViewGetPropertyFields(Class<?> klass) { 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewFieldsForClasses == null) { 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>(); 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses; 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getFields(); 16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(CapturedViewProperty.class)) { 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] capturedViewGetPropertyMethods(Class<?> klass) { 16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewMethodsForClasses == null) { 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>(); 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses; 16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getMethods(); 1698a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 1701a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final Method method = methods[i]; 17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.isAnnotationPresent(CapturedViewProperty.class) && 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.getReturnType() != Void.class) { 17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1715a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1716a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy private static String capturedViewExportMethods(Object obj, Class<?> klass, 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix) { 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1722a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = capturedViewGetPropertyMethods(klass); 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(obj, (Object[]) null); 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 1732a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class); 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.retrieveReturn()) { 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we are interested in the second level data only 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#")); 1737a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(method.getName()); 17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("()="); 1741a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methodValue != null) { 1743a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final String value = methodValue.toString().replace("\n", "\\n"); 1744a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(value); 17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("; "); 17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 1751a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception IllegalAccess, it is OK here 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 1754a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception InvocationTarget, it is OK here 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 1756a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 1757a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) { 1762a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1766a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = capturedViewGetPropertyFields(klass); 17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = field.get(obj); 17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(field.getName()); 17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("="); 17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue != null) { 17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String value = fieldValue.toString().replace("\n", "\\n"); 17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(value); 17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(' '); 17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 1788a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception IllegalAccess, it is OK here 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this field 17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1794a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1796a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * Dump view info for id based instrument test generation 17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (and possibly further data analysis). The results are dumped 1798a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * to the log. 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tag for log 18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view for dump 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1802a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy public static void dumpCapturedView(String tag, Object view) { 18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(klass.getName() + ": "); 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportFields(view, klass, "")); 1806a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(capturedViewExportMethods(view, klass, "")); 1807a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy Log.d(tag, sb.toString()); 18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1810