ViewDebug.java revision cf635ae7c65de34f62a41cd330f25f4ee9ddc95b
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; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment; 27c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.os.Debug; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedWriter; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileWriter; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.DataOutputStream; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStreamWriter; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedOutputStream; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.LinkedList; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.CountDownLatch; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.TimeUnit; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Target; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.ElementType; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Retention; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.RetentionPolicy; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Method; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.InvocationTargetException; 51c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport java.lang.reflect.AccessibleObject; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various debugging/tracing tools related to {@link View} and the view hierarchy. 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ViewDebug { 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Log tag used to log errors related to the consistency of the view hierarchy. 5913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 6013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 6113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 6213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final String CONSISTENCY_LOG_TAG = "ViewConsistency"; 6313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 6413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 6513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Flag indicating the consistency check should check layout-related properties. 6613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 6713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 6813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 6913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final int CONSISTENCY_LAYOUT = 0x1; 7013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 7113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 7213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Flag indicating the consistency check should check drawing-related properties. 7313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 7413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 7513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 7613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final int CONSISTENCY_DRAWING = 0x2; 7713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 7813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view hierarchy tracing. Any invoker of 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_HIERARCHY = false; 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view recycler tracing. Any invoker of 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])} should first 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_RECYCLER = false; 91a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 93cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Enables or disables motion events tracing. Any invoker of 94cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * {@link #trace(View, MotionEvent, MotionEventTraceType)} should first check 95cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * that this value is set to true as not to affect performance. 96cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 97cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 98cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 99cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static final boolean TRACE_MOTION_EVENTS = false; 100cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 101cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The system property of dynamic switch for capturing view information 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when it is set, we dump interested fields and methods for the view on focus 104a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy */ 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String SYSTEM_PROPERTY_CAPTURE_VIEW = "debug.captureview"; 106a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The system property of dynamic switch for capturing event information 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when it is set, we log key events, touch/motion and trackball events 110a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy */ 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent"; 112c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles drawing times in the events log. 11513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 11613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 11713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 11813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 11913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean profileDrawing = false; 12013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 12113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 12213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles layout times in the events log. 12313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 12413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 12513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 12613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 12713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean profileLayout = false; 12813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 12913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 13013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles real fps (times between draws) and displays the result. 13113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 13213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 13313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 13413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 13513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean showFps = false; 13613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 13713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 13813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <p>Enables or disables views consistency check. Even when this property is enabled, 13913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * view consistency checks happen only if {@link android.util.Config#DEBUG} is set 14013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * to true. The value of this property can be configured externally in one of the 14113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * following files:</p> 14213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <ul> 14313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/system/debug.prop</li> 14413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/debug.prop</li> 14513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/data/debug.prop</li> 14613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * </ul> 14713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 14813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 14913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 15013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean consistencyCheckEnabled = false; 15113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 15213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy static { 153e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy if (Config.DEBUG) { 154e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy Debug.setFieldsOn(ViewDebug.class, true); 155e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy } 15613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy } 15713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 15813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped by 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view server. Only non-void methods with no arguments can be annotated 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * by this annotation. 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface ExportedProperty { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When resolveId is true, and if the annotated field/method return value 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is an int, the value is converted to an Android's resource name. 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the property's value must be transformed into an Android 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * resource name, false otherwise 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean resolveId() default false; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A mapping can be defined to map int values to specific strings. For 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance, View.getVisibility() returns 0, 4 or 8. However, these values 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * actually mean VISIBLE, INVISIBLE and GONE. A mapping can be used to see 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * these human readable values: 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.ExportedProperty(mapping = { 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "VISIBLE"), 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 4, to = "INVISIBLE"), 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 8, to = "GONE") 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * }) 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * public int getVisibility() { ... 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An array of int to String mappings 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.IntToString 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IntToString[] mapping() default { }; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 197c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be defined to map array indices to specific strings. 198c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be used to see human readable values for the indices 199c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * of an array: 200c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 201c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 202809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.ExportedProperty(indexMapping = { 203c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "INVALID"), 204c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 1, to = "FIRST"), 205c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 2, to = "SECOND") 206c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * }) 207c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * private int[] mElements; 208c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 209c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 210c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @return An array of int to String mappings 211c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 212c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see android.view.ViewDebug.IntToString 213c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see #mapping() 214c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project */ 215c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project IntToString[] indexMapping() default { }; 216c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 217c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project /** 218809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * A flags mapping can be defined to map flags encoded in an integer to 219809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * specific strings. A mapping can be used to see human readable values 220809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * for the flags of an integer: 221809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 222809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <pre> 223809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.ExportedProperty(flagMapping = { 224809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"), 225809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"), 226809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * }) 227809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * private int mFlags; 228809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <pre> 229809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 230809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * A specified String is output when the following is true: 231a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * 232809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An array of int to String mappings 233809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 234809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy FlagToString[] flagMapping() default { }; 235809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 236809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When deep export is turned on, this property is not dumped. Instead, the 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * properties contained in this property are dumped. Each child property 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is prefixed with the name of this property. 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the properties of this property should be dumped 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 243a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @see #prefix() 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean deepExport() default false; 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The prefix to use on child properties when deep export is enabled 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a prefix as a String 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #deepExport() 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix() default ""; 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines a mapping from an int value to a String. Such a mapping can be used 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in a @ExportedProperty to provide more meaningful values to the end user. 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.ExportedProperty 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.TYPE }) 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface IntToString { 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The original int value to map to a String. 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary int value. 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int from(); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The String to use in place of the original int value. 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary non-null String. 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String to(); 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 280809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 281809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 282809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * Defines a mapping from an flag to a String. Such a mapping can be used 283809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * in a @ExportedProperty to provide more meaningful values to the end user. 284809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 285809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @see android.view.ViewDebug.ExportedProperty 286809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 287809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Target({ ElementType.TYPE }) 288809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Retention(RetentionPolicy.RUNTIME) 289809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy public @interface FlagToString { 290809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 291809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The mask to apply to the original value. 292809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 293809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary int value. 294809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 295809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int mask(); 296809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 297809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 298809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The value to compare to the result of: 299809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <code>original value & {@link #mask()}</code>. 300809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 301809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary value. 302809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 303809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int equals(); 304809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 305809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 306809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The String to use in place of the original int value. 307809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 308809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary non-null String. 309809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 310809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy String name(); 311809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 312809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 313809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * Indicates whether to output the flag when the test is true, 314809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * or false. Defaults to true. 315809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 316809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy boolean outputIf() default true; 317809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 318809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped when 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view is captured. Methods with this annotation must have no arguments 322f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * and must return a valid type of data. 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface CapturedViewProperty { 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 328a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * When retrieveReturn is true, we need to retrieve second level methods 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod() 330a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * we will set retrieveReturn = true on the annotation of 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * myView.getFirstLevelMethod() 332a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @return true if we need the second level methods 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 334a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy boolean retrieveReturn() default false; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 336a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null; 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null; 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Maximum delay in ms after which we stop trying to capture a View's drawing 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CAPTURE_TIMEOUT = 4000; 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE"; 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_DUMP = "DUMP"; 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE"; 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT"; 347c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static final String REMOTE_PROFILE = "PROFILE"; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> sFieldsForClasses; 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> sMethodsForClasses; 351c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static HashMap<AccessibleObject, ExportedProperty> sAnnotations; 352c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of hierarhcy trace to output to the hierarchy traces file. 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum HierarchyTraceType { 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE, 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD, 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD_IN_PARENT, 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project REQUEST_LAYOUT, 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_LAYOUT, 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_MEASURE, 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DRAW, 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BUILD_CACHE 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static BufferedWriter sHierarchyTraces; 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static ViewRoot sHierarhcyRoot; 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sHierarchyTracePrefix; 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of recycler trace to output to the recycler traces file. 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum RecyclerTraceType { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NEW_VIEW, 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BIND_VIEW, 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_ACTIVE_HEAP, 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_SCRAP_HEAP, 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_TO_SCRAP_HEAP, 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_FROM_ACTIVE_TO_SCRAP_HEAP 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class RecyclerTrace { 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int view; 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public RecyclerTraceType type; 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int position; 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int indexOnScreen; 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View sRecyclerOwnerView; 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<View> sRecyclerViews; 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<RecyclerTrace> sRecyclerTraces; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sRecyclerTracePrefix; 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 396cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Defines the type of motion events trace to output to the motion events traces file. 397cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 398cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 399cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 400cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public enum MotionEventTraceType { 401cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy DISPATCH, 402cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy ON_INTERCEPT, 403cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy ON_TOUCH 404cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 405cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 406cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy private static BufferedWriter sMotionEventTraces; 407cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy private static ViewRoot sMotionEventRoot; 408cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy private static String sMotionEventTracePrefix; 409cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 410cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated Views. 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of Views instanciated in the current process. 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewInstanceCount() { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return View.sInstanceCount; 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated ViewRoots. 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of ViewRoots instanciated in the current process. 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewRootInstanceCount() { 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ViewRoot.getInstanceCount(); 430a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened recycler traces. The trace records the type of 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * recycler action performed on the supplied view as well as a number of parameters. 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param parameters parameters depending on the type of the trace 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, RecyclerTraceType type, int... parameters) { 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!sRecyclerViews.contains(view)) { 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.add(view); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int index = sRecyclerViews.indexOf(view); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RecyclerTrace trace = new RecyclerTrace(); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.view = index; 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.type = type; 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.position = parameters[0]; 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.indexOnScreen = parameters[1]; 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.add(trace); 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view recycler of the specified view. The trace is identified by a prefix, 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-recycler/PREFIX.traces</code> and 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>. 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view recycler can be traced at the same time. After calling this method, any 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopRecyclerTracing()} is invoked before. 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Traces files are created only after {@link #stopRecyclerTracing()} is invoked. 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose recycler must be traced 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopRecyclerTracing() 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startRecyclerTracing(String prefix, View view) { 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView != null) { 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopRecyclerTracing() before running" + 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTracePrefix = prefix; 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = view; 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = new ArrayList<View>(); 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = new LinkedList<RecyclerTrace>(); 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view recycer tracing. 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.traces</code> 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's recycler. 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.recycler</code> 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all of the views used by the recycler of the view supplied to 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startRecyclerTracing(String, View)}. 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #startRecyclerTracing(String, View) 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopRecyclerTracing() { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startRecyclerTracing() before" + 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopRecyclerTracing()!"); 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 523c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump.mkdirs(); 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler"); 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final BufferedWriter out = new BufferedWriter(new FileWriter(recyclerDump), 8 * 1024); 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (View view : sRecyclerViews) { 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String name = view.getClass().getName(); 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(name); 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler content"); 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces"); 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final FileOutputStream file = new FileOutputStream(recyclerDump); 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final DataOutputStream out = new DataOutputStream(file); 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (RecyclerTrace trace : sRecyclerTraces) { 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.view); 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.type.ordinal()); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.position); 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.indexOnScreen); 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.flush(); 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler traces"); 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.clear(); 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = null; 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.clear(); 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = null; 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = null; 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened traces file. The trace contains the class name 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and instance's hashcode of the specified view as well as the supplied trace type. 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, HierarchyTraceType type) { 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarchyTraces == null) { 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(type.name()); 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(' '); 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(view.getClass().getName()); 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write('@'); 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(Integer.toHexString(view.hashCode())); 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.newLine(); 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping trace of type " + type + " for view " + view); 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix, 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> and 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>. 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view hierarchy can be traced at the same time. After calling this method, any 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopHierarchyTracing()} is invoked before. 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's hierarchy. 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose hierarchy must be traced 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopHierarchyTracing() 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startHierarchyTracing(String prefix, View view) { 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot != null) { 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopHierarchyTracing() before running" + 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 627c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, prefix + ".traces"); 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTracePrefix = prefix; 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarhcyRoot = (ViewRoot) view.getRootView().getParent(); 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view hierarchy tracing. This method closes the file 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>. 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code> 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing the view hierarchy of the view supplied to 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startHierarchyTracing(String, View)}. 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 653a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @see #startHierarchyTracing(String, View) 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopHierarchyTracing() { 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot == null || sHierarchyTraces == null) { 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startHierarchyTracing() before" + 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopHierarchyTracing()!"); 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.close(); 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not write view traces"); 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = null; 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 675c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree"); 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out; 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = sHierarhcyRoot.getView(); 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy(group, out, 0); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarhcyRoot = null; 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 700a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 701cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 702cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Outputs a trace to the currently opened traces file. The trace contains the class name 703cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * and instance's hashcode of the specified view as well as the supplied trace type. 704cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 705cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param view the view to trace 706cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param event the event of the trace 707cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param type the type of the trace 708cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 709cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 710cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 711cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static void trace(View view, MotionEvent event, MotionEventTraceType type) { 712cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (sMotionEventTraces == null) { 713cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 714cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 715cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 716cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 717cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(type.name()); 718cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(' '); 719cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(event.getAction()); 720cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(' '); 721cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(view.getClass().getName()); 722cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write('@'); 723cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.write(Integer.toHexString(view.hashCode())); 724cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sHierarchyTraces.newLine(); 725cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 726cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.w("View", "Error while dumping trace of event " + event + " for view " + view); 727cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 728cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 729cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 730cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 731cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Starts tracing the motion events for the hierarchy of the specificy view. 732cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * The trace is identified by a prefix, used to build the traces files names: 733cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * <code>/EXTERNAL/motion-events/PREFIX.traces</code> and 734cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * <code>/EXTERNAL/motion-events/PREFIX.tree</code>. 735cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 736cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Only one view hierarchy can be traced at the same time. After calling this method, any 737cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * other invocation will result in a <code>IllegalStateException</code> unless 738cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * {@link #stopMotionEventTracing()} is invoked before. 739cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 740cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.traces</code> 741cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * containing all the traces (or method calls) relative to the specified view's hierarchy. 742cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 743cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * This method will return immediately if TRACE_HIERARCHY is false. 744cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 745cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param prefix the traces files name prefix 746cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @param view the view whose hierarchy must be traced 747cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 748cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #stopMotionEventTracing() 749cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) 750cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 751cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 752cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 753cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static void startMotionEventTracing(String prefix, View view) { 754cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection PointlessBooleanExpression,ConstantConditions 755cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (!TRACE_MOTION_EVENTS) { 756cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 757cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 758cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 759cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (sMotionEventRoot != null) { 760cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy throw new IllegalStateException("You must call stopMotionEventTracing() before running" + 761cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy " a new trace!"); 762cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 763cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 764cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); 765cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection ResultOfMethodCallIgnored 766cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump.mkdirs(); 767cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 768cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump = new File(hierarchyDump, prefix + ".traces"); 769cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTracePrefix = prefix; 770cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 771cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 772cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces = new BufferedWriter(new FileWriter(hierarchyDump), 32 * 1024); 773cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 774cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not dump view hierarchy"); 775cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 776cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 777cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 778cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventRoot = (ViewRoot) view.getRootView().getParent(); 779cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 780cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 781cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy /** 782cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Stops the current motion events tracing. This method closes the file 783cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * <code>/EXTERNAL/motion-events/PREFIX.traces</code>. 784cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 785cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.tree</code> 786cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * containing the view hierarchy of the view supplied to 787cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * {@link #startMotionEventTracing(String, View)}. 788cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 789cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * This method will return immediately if TRACE_HIERARCHY is false. 790cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 791cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #startMotionEventTracing(String, View) 792cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) 793cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * 794cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy * @hide 795cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy */ 796cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy public static void stopMotionEventTracing() { 797cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection PointlessBooleanExpression,ConstantConditions 798cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (!TRACE_MOTION_EVENTS) { 799cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 800cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 801cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 802cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (sMotionEventRoot == null || sMotionEventTraces == null) { 803cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy throw new IllegalStateException("You must call startMotionEventTracing() before" + 804cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy " stopMotionEventTracing()!"); 805cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 806cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 807cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 808cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces.close(); 809cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 810cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not write view traces"); 811cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 812cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sMotionEventTraces = null; 813cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 814cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); 815cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy //noinspection ResultOfMethodCallIgnored 816cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump.mkdirs(); 817cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy hierarchyDump = new File(hierarchyDump, sMotionEventTracePrefix + ".tree"); 818cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 819cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy BufferedWriter out; 820cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 821cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 822cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 823cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not dump view hierarchy"); 824cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy return; 825cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 826cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 827cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy View view = sMotionEventRoot.getView(); 828cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy if (view instanceof ViewGroup) { 829cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy ViewGroup group = (ViewGroup) view; 830cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy dumpViewHierarchy(group, out, 0); 831cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy try { 832cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy out.close(); 833cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } catch (IOException e) { 834cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy Log.e("View", "Could not dump view hierarchy"); 835cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 836cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 837cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 838cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy sHierarhcyRoot = null; 839cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy } 840cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void dispatchCommand(View view, String command, String parameters, 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream clientStream) throws IOException { 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Paranoid but safe... 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view = view.getRootView(); 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) { 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dump(view, clientStream); 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String[] params = parameters.split(" "); 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) { 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project capture(view, clientStream, params[0]); 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) { 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(view, params[0]); 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) { 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(view, params[0]); 857c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) { 858c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project profile(view, clientStream, params[0]); 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 863c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static View findView(View root, String parameter) { 864c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by type/hashcode 865c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (parameter.indexOf('@') != -1) { 866c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String[] ids = parameter.split("@"); 867c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String className = ids[0]; 868236092a36216c79507ec19eb207831810caced19Romain Guy final int hashCode = (int) Long.parseLong(ids[1], 16); 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 870c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project View view = root.getRootView(); 871c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view instanceof ViewGroup) { 872c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return findView((ViewGroup) view, className, hashCode); 873c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 874c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 875c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by id 876c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int id = root.getResources().getIdentifier(parameter, null, null); 877c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return root.getRootView().findViewById(id); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void invalidate(View root, String parameter) { 884c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.postInvalidate(); 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void requestLayout(View root, String parameter) { 891c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project root.post(new Runnable() { 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.requestLayout(); 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 901c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void profile(View root, OutputStream clientStream, String parameter) 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 904c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 905c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project BufferedWriter out = null; 906c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 907c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024); 908c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 909c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view != null) { 910c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long durationMeasure = profileViewOperation(view, new ViewOperation<Void>() { 911c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public Void[] pre() { 912c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project forceLayout(view); 913c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return null; 914c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 915c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 916c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private void forceLayout(View view) { 917c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.forceLayout(); 918c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view instanceof ViewGroup) { 919c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ViewGroup group = (ViewGroup) view; 920c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int count = group.getChildCount(); 921c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int i = 0; i < count; i++) { 922c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project forceLayout(group.getChildAt(i)); 923c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 924c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 925c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 926c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 927c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run(Void... data) { 928c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec); 929c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 930c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 931c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void post(Void... data) { 932c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 933c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 934c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 935c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long durationLayout = profileViewOperation(view, new ViewOperation<Void>() { 936c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public Void[] pre() { 937c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return null; 938c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 939c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 940c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run(Void... data) { 941c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom); 942c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 943c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 944c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void post(Void... data) { 945c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 946c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 947c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 948c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long durationDraw = profileViewOperation(view, new ViewOperation<Object>() { 949c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public Object[] pre() { 950c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final DisplayMetrics metrics = view.getResources().getDisplayMetrics(); 951c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final Bitmap bitmap = Bitmap.createBitmap(metrics.widthPixels, 952ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project metrics.heightPixels, Bitmap.Config.RGB_565); 953c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final Canvas canvas = new Canvas(bitmap); 954c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return new Object[] { bitmap, canvas }; 955c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 956c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 957c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run(Object... data) { 958c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.draw((Canvas) data[1]); 959c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 960c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 961c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void post(Object... data) { 962c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ((Bitmap) data[0]).recycle(); 963c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 964c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 965c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 966c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(durationMeasure)); 967c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 968c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(durationLayout)); 969c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 970c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(durationDraw)); 971c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.newLine(); 972c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 973c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("-1 -1 -1"); 974c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.newLine(); 975c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 976c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Exception e) { 977c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project android.util.Log.w("View", "Problem profiling the view:", e); 978c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } finally { 979c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (out != null) { 980c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.close(); 981c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 982c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 983c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 984c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 985c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project interface ViewOperation<T> { 986c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] pre(); 987c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void run(T... data); 988c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void post(T... data); 989c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 990c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 991c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) { 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 993c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long[] duration = new long[1]; 994c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 995c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.post(new Runnable() { 996c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run() { 997c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 998c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] data = operation.pre(); 999c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project long start = Debug.threadCpuTimeNanos(); 1000c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.run(data); 1001c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project duration[0] = Debug.threadCpuTimeNanos() - start; 1002c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.post(data); 1003c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } finally { 1004c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project latch.countDown(); 1005c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1006c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1007c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 1008c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1009c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1010c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); 1011c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (InterruptedException e) { 1012c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the profiling of the view " + view); 1013c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 1014c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return -1; 1015c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1016c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1017c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return duration[0]; 1018c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1019c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1020c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void capture(View root, final OutputStream clientStream, String parameter) 1021c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1022c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1023c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View captureView = findView(root, parameter); 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (captureView != null) { 1026c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Bitmap[] cache = new Bitmap[1]; 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project root.post(new Runnable() { 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1032958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 1033958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Bitmap.Config.ARGB_8888, 0); 1034958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e) { 1035958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn try { 1036958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 1037958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Bitmap.Config.ARGB_4444, 0); 1038958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e2) { 1039958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Log.w("View", "Out of memory for bitmap"); 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.countDown(); 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cache[0] != null) { 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedOutputStream out = null; 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = new BufferedOutputStream(clientStream, 32 * 1024); 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cache[0].compress(Bitmap.CompressFormat.PNG, 100, out); 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.flush(); 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out != null) { 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1060958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0].recycle(); 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1062958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } else { 1063958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn Log.w("View", "Failed to create capture bitmap!"); 1064958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn clientStream.close(); 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 1067c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the capture of the view " + captureView); 1068c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dump(View root, OutputStream clientStream) throws IOException { 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out = null; 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 107638e951b62ed956501b11f0715e23e3bf70942f6dRomain Guy out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024); 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = root.getRootView(); 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 1080105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(group.getContext(), group, out, 0); 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write("DONE."); 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 1084c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Exception e) { 1085c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project android.util.Log.w("View", "Problem dumping the view:", e); 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out != null) { 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View findView(ViewGroup group, String className, int hashCode) { 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isRequestedView(group, className, hashCode)) { 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return group; 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View found = findView((ViewGroup) view, className, hashCode); 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (found != null) { 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return found; 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (isRequestedView(view, className, hashCode)) { 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view; 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean isRequestedView(View view, String className, int hashCode) { 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view.getClass().getName().equals(className) && view.hashCode() == hashCode; 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1118105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group, 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out, int level) { 1120105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (!dumpViewWithProperties(context, group, out, level)) { 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 1128105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1); 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1130105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewWithProperties(context, view, out, level + 1); 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1135105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static boolean dumpViewWithProperties(Context context, View view, 1136105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, int level) { 1137105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 1146105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out); 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] getExportedPropertyFields(Class<?> klass) { 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sFieldsForClasses == null) { 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sFieldsForClasses = new HashMap<Class<?>, Field[]>(); 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1159c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 1160c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 1161c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1162c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = sFieldsForClasses; 1164c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getDeclaredFields(); 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(ExportedProperty.class)) { 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 1180c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project annotations.put(field, field.getAnnotation(ExportedProperty.class)); 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] getExportedPropertyMethods(Class<?> klass) { 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sMethodsForClasses == null) { 1192c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sMethodsForClasses = new HashMap<Class<?>, Method[]>(100); 1193c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1194c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 1195c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1197c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = sMethodsForClasses; 1199c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations; 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getDeclaredMethods(); 1208a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 1211a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final Method method = methods[i]; 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 1213c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.isAnnotationPresent(ExportedProperty.class) && 1214c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.getReturnType() != Void.class) { 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 1217c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project annotations.put(method, method.getAnnotation(ExportedProperty.class)); 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1227105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1228105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out) throws IOException { 1229105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1230105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out, ""); 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1233105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1234105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, String prefix) throws IOException { 1235105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 1239105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportFields(context, view, out, klass, prefix); 1240105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportMethods(context, view, out, klass, prefix); 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project klass = klass.getSuperclass(); 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (klass != Object.class); 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1244a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1245105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportMethods(Context context, Object view, BufferedWriter out, 1246105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = getExportedPropertyMethods(klass); 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: This should happen on the UI thread 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(view, (Object[]) null); 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (returnType == int.class) { 1260c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(method); 1261105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = (Integer) methodValue; 1263105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project methodValue = resolveId(context, id); 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1265809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1266809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1267809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = (Integer) methodValue; 1268809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final String valuePrefix = prefix + method.getName() + '_'; 1269809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1270809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1271809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = (Integer) methodValue; 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mapped = false; 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapper = mapping[j]; 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapper.from() == intValue) { 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = mapper.to(); 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mapped = true; 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mapped) { 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = intValue; 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1291c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (returnType == int[].class) { 1292c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(method); 1293c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) methodValue; 1294c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String valuePrefix = prefix + method.getName() + '_'; 1295c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = "()"; 1296c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1297105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!returnType.isPrimitive()) { 1299c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(method); 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1301105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, methodValue, out, prefix + property.prefix()); 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1306c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, method.getName(), "()", methodValue); 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1313105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportFields(Context context, Object view, BufferedWriter out, 1314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 1315105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = getExportedPropertyFields(klass); 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = null; 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> type = field.getType(); 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (type == int.class) { 1328c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(field); 1329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = field.getInt(view); 1331105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project fieldValue = resolveId(context, id); 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1333809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1334809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1335809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = field.getInt(view); 1336809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final String valuePrefix = prefix + field.getName() + '_'; 1337809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1338809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1339809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = field.getInt(view); 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapped = mapping[j]; 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapped.from() == intValue) { 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = mapped.to(); 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = intValue; 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1357c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (type == int[].class) { 1358c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(field); 1359c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) field.get(view); 1360c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String valuePrefix = prefix + field.getName() + '_'; 1361c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = ""; 1362c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1363105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1364c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1365c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // We exit here! 1366c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return; 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!type.isPrimitive()) { 1368c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final ExportedProperty property = sAnnotations.get(field); 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, field.get(view), out, 1371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project prefix + property.prefix()); 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = field.get(view); 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1380c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, field.getName(), "", fieldValue); 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1386c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeEntry(BufferedWriter out, String prefix, String name, 1387c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String suffix, Object value) throws IOException { 1388c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1389c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(prefix); 1390c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(name); 1391c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(suffix); 1392c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("="); 1393c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeValue(out, value); 1394c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 1395c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1396c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1397809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping, 1398809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int intValue, String prefix) throws IOException { 1399809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1400809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int count = mapping.length; 1401809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy for (int j = 0; j < count; j++) { 1402809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString flagMapping = mapping[j]; 1403809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final boolean ifTrue = flagMapping.outputIf(); 14045bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final int maskResult = intValue & flagMapping.mask(); 14055bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final boolean test = maskResult == flagMapping.equals(); 1406809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if ((test && ifTrue) || (!test && !ifTrue)) { 1407809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final String name = flagMapping.name(); 14085bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final String value = "0x" + Integer.toHexString(maskResult); 1409809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy writeEntry(out, prefix, name, "", value); 1410809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1411809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1412809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1413809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1414105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportUnrolledArray(Context context, BufferedWriter out, 1415c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ExportedProperty property, int[] array, String prefix, String suffix) 1416c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1417c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1418c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] indexMapping = property.indexMapping(); 1419c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasIndexMapping = indexMapping.length > 0; 1420c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1421c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] mapping = property.mapping(); 1422c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasMapping = mapping.length > 0; 1423c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final boolean resolveId = property.resolveId() && context != null; 1425c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int valuesCount = array.length; 1426c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1427c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int j = 0; j < valuesCount; j++) { 1428c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String name; 1429a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy String value = null; 1430c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1431c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int intValue = array[j]; 1432c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1433c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = String.valueOf(j); 1434c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasIndexMapping) { 1435c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = indexMapping.length; 1436c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1437c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = indexMapping[k]; 1438c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == j) { 1439c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = mapped.to(); 1440c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1441c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1442c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1443c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1444c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1445c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasMapping) { 1446c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = mapping.length; 1447c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1448c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = mapping[k]; 1449c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == intValue) { 1450c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project value = mapped.to(); 1451c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1452c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1453c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1454c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1455c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1456c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (resolveId) { 1457a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy if (value == null) value = (String) resolveId(context, intValue); 1458a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 1459a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy value = String.valueOf(intValue); 1460c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1461c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1462c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, name, suffix, value); 1463c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1464c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1465c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1466237c1ceea36024cf4194212e713806e3ce8a1c49Romain Guy static Object resolveId(Context context, int id) { 1467c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Object fieldValue; 1468105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final Resources resources = context.getResources(); 1469c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (id >= 0) { 1470c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1471c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = resources.getResourceTypeName(id) + '/' + 1472c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project resources.getResourceEntryName(id); 1473c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Resources.NotFoundException e) { 1474c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "id/0x" + Integer.toHexString(id); 1475c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1476c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1477c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "NO_ID"; 1478c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1479c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return fieldValue; 1480c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1481c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1482c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeValue(BufferedWriter out, Object value) throws IOException { 1483c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (value != null) { 1484c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String output = value.toString().replace("\n", "\\n"); 1485c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(output.length())); 1486c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(","); 1487c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(output); 1488c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1489c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("4,null"); 1490c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1491c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1492c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dumpViewHierarchy(ViewGroup group, BufferedWriter out, int level) { 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!dumpView(group, out, level)) { 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy((ViewGroup) view, out, level + 1); 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpView(view, out, level + 1); 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean dumpView(Object view, BufferedWriter out, int level) { 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] capturedViewGetPropertyFields(Class<?> klass) { 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewFieldsForClasses == null) { 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>(); 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses; 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getFields(); 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(CapturedViewProperty.class)) { 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] capturedViewGetPropertyMethods(Class<?> klass) { 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewMethodsForClasses == null) { 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>(); 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses; 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getMethods(); 1567a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 1570a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final Method method = methods[i]; 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.isAnnotationPresent(CapturedViewProperty.class) && 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.getReturnType() != Void.class) { 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1584a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1585a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy private static String capturedViewExportMethods(Object obj, Class<?> klass, 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix) { 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1591a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = capturedViewGetPropertyMethods(klass); 15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(obj, (Object[]) null); 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 1601a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class); 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.retrieveReturn()) { 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we are interested in the second level data only 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#")); 1606a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(method.getName()); 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("()="); 1610a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methodValue != null) { 1612a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final String value = methodValue.toString().replace("\n", "\\n"); 1613a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(value); 16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("; "); 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 1620a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception IllegalAccess, it is OK here 16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 1623a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception InvocationTarget, it is OK here 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 1625a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 1626a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) { 1631a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1635a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = capturedViewGetPropertyFields(klass); 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = field.get(obj); 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(field.getName()); 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("="); 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue != null) { 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String value = fieldValue.toString().replace("\n", "\\n"); 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(value); 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(' '); 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 1657a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception IllegalAccess, it is OK here 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this field 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1663a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1665a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * Dump view info for id based instrument test generation 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (and possibly further data analysis). The results are dumped 1667a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * to the log. 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tag for log 16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view for dump 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1671a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy public static void dumpCapturedView(String tag, Object view) { 16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(klass.getName() + ": "); 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportFields(view, klass, "")); 1675a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(capturedViewExportMethods(view, klass, "")); 1676a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy Log.d(tag, sb.toString()); 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1679