ViewDebug.java revision 95db2b20d7bc0aaf00b1d4418124f5cf0a755d74
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 19105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.content.Context; 20f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.content.res.Resources; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap; 22c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.graphics.Canvas; 23223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport android.graphics.Rect; 24c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.os.Debug; 25f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.os.Environment; 26f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.os.Looper; 27f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.os.Message; 289a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guyimport android.os.ParcelFileDescriptor; 29223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport android.os.RemoteException; 30648bee18a1ccd362445d562729250ff5910f16a0Romain Guyimport android.os.SystemClock; 31f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.util.DisplayMetrics; 32f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.util.Log; 33f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.util.Printer; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 35f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.BufferedOutputStream; 36f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.BufferedWriter; 37223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport java.io.ByteArrayOutputStream; 38f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.DataOutputStream; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 407eabe55db6b113f83c2cefcd06812648927de877Romain Guyimport java.io.FileDescriptor; 41f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.FileOutputStream; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileWriter; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 45f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.OutputStreamWriter; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.ElementType; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Retention; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.RetentionPolicy; 49f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.annotation.Target; 50f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.reflect.AccessibleObject; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.InvocationTargetException; 53f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.reflect.Method; 549a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guyimport java.nio.ByteBuffer; 559a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guyimport java.nio.ByteOrder; 569a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guyimport java.nio.channels.FileChannel; 57f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.ArrayList; 58f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.HashMap; 59f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.LinkedList; 60f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.List; 61648bee18a1ccd362445d562729250ff5910f16a0Romain Guyimport java.util.Map; 62f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.concurrent.CountDownLatch; 63f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.concurrent.TimeUnit; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various debugging/tracing tools related to {@link View} and the view hierarchy. 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ViewDebug { 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Log tag used to log errors related to the consistency of the view hierarchy. 7113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 7213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 7313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 7413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final String CONSISTENCY_LOG_TAG = "ViewConsistency"; 7513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 7613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 7713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Flag indicating the consistency check should check layout-related properties. 7813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 7913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 8013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 8113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final int CONSISTENCY_LAYOUT = 0x1; 8213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 8313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 8413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Flag indicating the consistency check should check drawing-related properties. 8513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 8613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 8713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 8813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static final int CONSISTENCY_DRAWING = 0x2; 8913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 9013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view hierarchy tracing. Any invoker of 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_HIERARCHY = false; 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables view recycler tracing. Any invoker of 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])} should first 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * check that this value is set to true as not to affect performance. 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_RECYCLER = false; 103a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles drawing times in the events log. 10613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 10713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 10813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 1095429e1d1026db8922478b715672e6c0703bbf4a9Romain Guy public static final boolean DEBUG_PROFILE_DRAWING = false; 11013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 11113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 11213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * Profiles layout times in the events log. 11313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * 11413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 11513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 1165429e1d1026db8922478b715672e6c0703bbf4a9Romain Guy public static final boolean DEBUG_PROFILE_LAYOUT = false; 11713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy 11813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy /** 1192c095f367779ef32130c72849936a2e3013c8492Christopher Tate * Enables detailed logging of drag/drop operations. 1202c095f367779ef32130c72849936a2e3013c8492Christopher Tate * @hide 1212c095f367779ef32130c72849936a2e3013c8492Christopher Tate */ 122994ef9296a00523de1df424b4b760b4416ead58bChristopher Tate public static final boolean DEBUG_DRAG = false; 1232c095f367779ef32130c72849936a2e3013c8492Christopher Tate 1242c095f367779ef32130c72849936a2e3013c8492Christopher Tate /** 1254e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown * Enables logging of factors that affect the latency and responsiveness of an application. 1264e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown * 1274e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown * Logs the relative difference between the time an event was created and the time it 1284e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown * was delivered. 1294e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown * 13095db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown * Logs the time spent waiting for Surface.lockCanvas(), Surface.unlockCanvasAndPost() 13195db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown * or eglSwapBuffers(). This is time that the event loop spends blocked and unresponsive. 13295db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown * Ideally, drawing and animations should be perfectly synchronized with VSYNC so that 13395db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown * dequeuing and queueing buffers is instantaneous. 1344e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown * 13595db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown * Logs the time spent in ViewRoot.performTraversals() and ViewRoot.performDraw(). 1364e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown * @hide 1374e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown */ 1384e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown public static final boolean DEBUG_LATENCY = false; 1394e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown 14095db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown /** @hide */ 14195db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown public static final String DEBUG_LATENCY_TAG = "ViewLatency"; 14295db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown 1434e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown /** 14413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <p>Enables or disables views consistency check. Even when this property is enabled, 14543a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato * view consistency checks happen only if {@link false} is set 14613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * to true. The value of this property can be configured externally in one of the 14713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * following files:</p> 14813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <ul> 14913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/system/debug.prop</li> 15013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/debug.prop</li> 15113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * <li>/data/debug.prop</li> 15213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * </ul> 15313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy * @hide 15413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy */ 15513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy @Debug.DebugProperty 15613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy public static boolean consistencyCheckEnabled = false; 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 ""; 255bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 256bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev /** 257bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * Specifies the category the property falls into, such as measurement, 258bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * layout, drawing, etc. 259bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * 260bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * @return the category as String 261bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev */ 262bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev String category() default ""; 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines a mapping from an int value to a String. Such a mapping can be used 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in a @ExportedProperty to provide more meaningful values to the end user. 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.ExportedProperty 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.TYPE }) 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface IntToString { 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The original int value to map to a String. 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary int value. 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int from(); 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The String to use in place of the original int value. 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary non-null String. 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String to(); 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 288809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 289809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 290809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * Defines a mapping from an flag to a String. Such a mapping can be used 291809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * in a @ExportedProperty to provide more meaningful values to the end user. 292809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 293809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @see android.view.ViewDebug.ExportedProperty 294809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 295809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Target({ ElementType.TYPE }) 296809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Retention(RetentionPolicy.RUNTIME) 297809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy public @interface FlagToString { 298809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 299809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The mask to apply to the original value. 300809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 301809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary int value. 302809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 303809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int mask(); 304809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 305809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 306809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The value to compare to the result of: 307809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <code>original value & {@link #mask()}</code>. 308809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 309809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary value. 310809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 311809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int equals(); 312809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 313809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 314809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The String to use in place of the original int value. 315809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 316809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary non-null String. 317809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 318809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy String name(); 319809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 320809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 321809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * Indicates whether to output the flag when the test is true, 322809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * or false. Defaults to true. 323809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 324809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy boolean outputIf() default true; 325809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 326809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped when 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view is captured. Methods with this annotation must have no arguments 330f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * and must return a valid type of data. 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface CapturedViewProperty { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 336a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * When retrieveReturn is true, we need to retrieve second level methods 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod() 338a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * we will set retrieveReturn = true on the annotation of 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * myView.getFirstLevelMethod() 340a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @return true if we need the second level methods 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 342a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy boolean retrieveReturn() default false; 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 344a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null; 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null; 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Maximum delay in ms after which we stop trying to capture a View's drawing 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CAPTURE_TIMEOUT = 4000; 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE"; 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_DUMP = "DUMP"; 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE"; 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT"; 355c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static final String REMOTE_PROFILE = "PROFILE"; 356223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS"; 357ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST"; 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> sFieldsForClasses; 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> sMethodsForClasses; 361c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static HashMap<AccessibleObject, ExportedProperty> sAnnotations; 362c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of hierarhcy trace to output to the hierarchy traces file. 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum HierarchyTraceType { 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE, 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD, 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD_IN_PARENT, 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project REQUEST_LAYOUT, 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_LAYOUT, 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_MEASURE, 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DRAW, 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BUILD_CACHE 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static BufferedWriter sHierarchyTraces; 3786dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn private static ViewRootImpl sHierarhcyRoot; 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sHierarchyTracePrefix; 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines the type of recycler trace to output to the recycler traces file. 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum RecyclerTraceType { 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NEW_VIEW, 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BIND_VIEW, 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_ACTIVE_HEAP, 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_SCRAP_HEAP, 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_TO_SCRAP_HEAP, 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_FROM_ACTIVE_TO_SCRAP_HEAP 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class RecyclerTrace { 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int view; 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public RecyclerTraceType type; 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int position; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int indexOnScreen; 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View sRecyclerOwnerView; 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<View> sRecyclerViews; 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static List<RecyclerTrace> sRecyclerTraces; 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String sRecyclerTracePrefix; 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 405f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy private static final ThreadLocal<LooperProfiler> sLooperProfilerStorage = 406f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy new ThreadLocal<LooperProfiler>(); 407f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated Views. 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of Views instanciated in the current process. 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewInstanceCount() { 416c21550a8d1dfc9e5359fe994cb48049a0bd4c82cBrian Carlstrom return Debug.countInstancesOfClass(View.class); 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 420c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato * Returns the number of instanciated ViewAncestors. 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 422c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato * @return The number of ViewAncestors instanciated in the current process. 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 42665b345fa22b878e141b8fd8ece9c208df00fa40fRomain Guy public static long getViewRootImplCount() { 4276dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn return Debug.countInstancesOfClass(ViewRootImpl.class); 428a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 431f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy * Starts profiling the looper associated with the current thread. 432f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy * You must call {@link #stopLooperProfiling} to end profiling 433f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy * and obtain the traces. Both methods must be invoked on the 434f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy * same thread. 435f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy * 4367eabe55db6b113f83c2cefcd06812648927de877Romain Guy * @hide 437f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy */ 4387eabe55db6b113f83c2cefcd06812648927de877Romain Guy public static void startLooperProfiling(String path, FileDescriptor fileDescriptor) { 439f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy if (sLooperProfilerStorage.get() == null) { 4407eabe55db6b113f83c2cefcd06812648927de877Romain Guy LooperProfiler profiler = new LooperProfiler(path, fileDescriptor); 441f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy sLooperProfilerStorage.set(profiler); 442f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy Looper.myLooper().setMessageLogging(profiler); 443f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 4447eabe55db6b113f83c2cefcd06812648927de877Romain Guy } 445f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 446f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy /** 447f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy * Stops profiling the looper associated with the current thread. 448f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy * 4497eabe55db6b113f83c2cefcd06812648927de877Romain Guy * @see #startLooperProfiling(String, java.io.FileDescriptor) 4507eabe55db6b113f83c2cefcd06812648927de877Romain Guy * 4517eabe55db6b113f83c2cefcd06812648927de877Romain Guy * @hide 452f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy */ 453f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy public static void stopLooperProfiling() { 454f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy LooperProfiler profiler = sLooperProfilerStorage.get(); 455f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy if (profiler != null) { 456f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy sLooperProfilerStorage.remove(); 457f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy Looper.myLooper().setMessageLogging(null); 458f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy profiler.save(); 459f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 460f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 461f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 462f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy private static class LooperProfiler implements Looper.Profiler, Printer { 463f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy private static final String LOG_TAG = "LooperProfiler"; 464f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 4659a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static final int TRACE_VERSION_NUMBER = 3; 4669a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static final int ACTION_EXIT_METHOD = 0x1; 4679a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static final int HEADER_SIZE = 32; 4689a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static final String HEADER_MAGIC = "SLOW"; 4699a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static final short HEADER_RECORD_SIZE = (short) 14; 4709a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 471648bee18a1ccd362445d562729250ff5910f16a0Romain Guy private final long mTraceWallStart; 472648bee18a1ccd362445d562729250ff5910f16a0Romain Guy private final long mTraceThreadStart; 473648bee18a1ccd362445d562729250ff5910f16a0Romain Guy 474f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy private final ArrayList<Entry> mTraces = new ArrayList<Entry>(512); 475f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 4769a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private final HashMap<String, Integer> mTraceNames = new HashMap<String, Integer>(32); 4779a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private int mTraceId = 0; 478648bee18a1ccd362445d562729250ff5910f16a0Romain Guy 4797eabe55db6b113f83c2cefcd06812648927de877Romain Guy private final String mPath; 4809a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private ParcelFileDescriptor mFileDescriptor; 4817eabe55db6b113f83c2cefcd06812648927de877Romain Guy 4827eabe55db6b113f83c2cefcd06812648927de877Romain Guy LooperProfiler(String path, FileDescriptor fileDescriptor) { 4837eabe55db6b113f83c2cefcd06812648927de877Romain Guy mPath = path; 4849a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy try { 4859a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy mFileDescriptor = ParcelFileDescriptor.dup(fileDescriptor); 4869a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } catch (IOException e) { 4879a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy Log.e(LOG_TAG, "Could not write trace file " + mPath, e); 4889a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy throw new RuntimeException(e); 4899a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 490648bee18a1ccd362445d562729250ff5910f16a0Romain Guy mTraceWallStart = SystemClock.currentTimeMicro(); 491648bee18a1ccd362445d562729250ff5910f16a0Romain Guy mTraceThreadStart = SystemClock.currentThreadTimeMicro(); 492f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 493f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 494f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy @Override 495f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy public void println(String x) { 496f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy // Ignore messages 497f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 498f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 499f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy @Override 500648bee18a1ccd362445d562729250ff5910f16a0Romain Guy public void profile(Message message, long wallStart, long wallTime, 501648bee18a1ccd362445d562729250ff5910f16a0Romain Guy long threadStart, long threadTime) { 502f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy Entry entry = new Entry(); 503648bee18a1ccd362445d562729250ff5910f16a0Romain Guy entry.traceId = getTraceId(message); 504f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy entry.wallStart = wallStart; 505f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy entry.wallTime = wallTime; 506648bee18a1ccd362445d562729250ff5910f16a0Romain Guy entry.threadStart = threadStart; 507f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy entry.threadTime = threadTime; 508f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 509f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy mTraces.add(entry); 510f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 511f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 5129a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private int getTraceId(Message message) { 513648bee18a1ccd362445d562729250ff5910f16a0Romain Guy String name = message.getTarget().getMessageName(message); 5149a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy Integer traceId = mTraceNames.get(name); 515648bee18a1ccd362445d562729250ff5910f16a0Romain Guy if (traceId == null) { 5169a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy traceId = mTraceId++ << 4; 517648bee18a1ccd362445d562729250ff5910f16a0Romain Guy mTraceNames.put(name, traceId); 518648bee18a1ccd362445d562729250ff5910f16a0Romain Guy } 519648bee18a1ccd362445d562729250ff5910f16a0Romain Guy return traceId; 520648bee18a1ccd362445d562729250ff5910f16a0Romain Guy } 521648bee18a1ccd362445d562729250ff5910f16a0Romain Guy 522f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy void save() { 523f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy // Don't block the UI thread 524f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy new Thread(new Runnable() { 525f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy @Override 526f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy public void run() { 527f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy saveTraces(); 528f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 5297eabe55db6b113f83c2cefcd06812648927de877Romain Guy }, "LooperProfiler[" + mPath + "]").start(); 530f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 531f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 532f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy private void saveTraces() { 5339a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy FileOutputStream fos = new FileOutputStream(mFileDescriptor.getFileDescriptor()); 534f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); 535f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 536f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy try { 5379a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy writeHeader(out, mTraceWallStart, mTraceNames, mTraces); 5389a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy out.flush(); 539648bee18a1ccd362445d562729250ff5910f16a0Romain Guy 5409a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy writeTraces(fos, out.size(), mTraceWallStart, mTraceThreadStart, mTraces); 541f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 5427eabe55db6b113f83c2cefcd06812648927de877Romain Guy Log.d(LOG_TAG, "Looper traces ready: " + mPath); 543f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } catch (IOException e) { 5449a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy Log.e(LOG_TAG, "Could not write trace file " + mPath, e); 545f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } finally { 546f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy try { 547f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy out.close(); 548f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } catch (IOException e) { 5499a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy Log.e(LOG_TAG, "Could not write trace file " + mPath, e); 5509a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 5519a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy try { 5529a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy mFileDescriptor.close(); 5539a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } catch (IOException e) { 5549a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy Log.e(LOG_TAG, "Could not write trace file " + mPath, e); 555f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 556f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 557f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 5589a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5599a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static void writeTraces(FileOutputStream out, long offset, long wallStart, 5609a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy long threadStart, ArrayList<Entry> entries) throws IOException { 5619a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5629a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy FileChannel channel = out.getChannel(); 5639a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5649a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy // Header 5659a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy ByteBuffer buffer = ByteBuffer.allocateDirect(HEADER_SIZE); 5669a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.put(HEADER_MAGIC.getBytes()); 5679a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); 5689a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putShort((short) TRACE_VERSION_NUMBER); // version 5699a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putShort((short) HEADER_SIZE); // offset to data 5709a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putLong(wallStart); // start time in usec 5719a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putShort(HEADER_RECORD_SIZE); // size of a record in bytes 5729a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy // padding to 32 bytes 5739a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy for (int i = 0; i < HEADER_SIZE - 18; i++) { 5749a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.put((byte) 0); 5759a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 5769a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5779a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.flip(); 5789a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy channel.position(offset).write(buffer); 5799a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5809a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer = ByteBuffer.allocateDirect(14).order(ByteOrder.LITTLE_ENDIAN); 5819a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy for (Entry entry : entries) { 5829a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putShort((short) 1); // we simulate only one thread 5839a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putInt(entry.traceId); // entering method 5849a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putInt((int) (entry.threadStart - threadStart)); 5859a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putInt((int) (entry.wallStart - wallStart)); 5869a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5879a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.flip(); 5889a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy channel.write(buffer); 5899a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.clear(); 5909a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5919a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putShort((short) 1); 5929a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putInt(entry.traceId | ACTION_EXIT_METHOD); // exiting method 5939a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putInt((int) (entry.threadStart + entry.threadTime - threadStart)); 5949a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.putInt((int) (entry.wallStart + entry.wallTime - wallStart)); 5959a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 5969a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.flip(); 5979a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy channel.write(buffer); 5989a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy buffer.clear(); 5999a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 6009a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6019a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy channel.close(); 6029a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 6039a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6049a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static void writeHeader(DataOutputStream out, long start, 6059a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy HashMap<String, Integer> names, ArrayList<Entry> entries) throws IOException { 6069a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6079a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy Entry last = entries.get(entries.size() - 1); 6089a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy long wallTotal = (last.wallStart + last.wallTime) - start; 6099a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6109a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy startSection("version", out); 6119a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addValue(null, Integer.toString(TRACE_VERSION_NUMBER), out); 6129a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addValue("data-file-overflow", "false", out); 6139a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addValue("clock", "dual", out); 6149a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addValue("elapsed-time-usec", Long.toString(wallTotal), out); 6159a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addValue("num-method-calls", Integer.toString(entries.size()), out); 6169a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addValue("clock-call-overhead-nsec", "1", out); 6179a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addValue("vm", "dalvik", out); 6189a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6199a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy startSection("threads", out); 6209a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addThreadId(1, "main", out); 6219a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6229a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy startSection("methods", out); 6239a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy addMethods(names, out); 6249a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6259a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy startSection("end", out); 626648bee18a1ccd362445d562729250ff5910f16a0Romain Guy } 6279a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6289a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static void addMethods(HashMap<String, Integer> names, DataOutputStream out) 6299a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy throws IOException { 6309a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6319a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy for (Map.Entry<String, Integer> name : names.entrySet()) { 6329a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy out.writeBytes(String.format("0x%08x\tEventQueue\t%s\t()V\tLooper\t-2\n", 6339a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy name.getValue(), name.getKey())); 6349a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 6359a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 6369a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6379a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static void addThreadId(int id, String name, DataOutputStream out) 6389a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy throws IOException { 639648bee18a1ccd362445d562729250ff5910f16a0Romain Guy 6409a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy out.writeBytes(Integer.toString(id) + '\t' + name + '\n'); 6419a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 6429a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6439a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static void addValue(String name, String value, DataOutputStream out) 6449a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy throws IOException { 6459a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6469a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy if (name != null) { 6479a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy out.writeBytes(name + "="); 6489a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 6499a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy out.writeBytes(value + '\n'); 6509a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy } 6519a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy 6529a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy private static void startSection(String name, DataOutputStream out) throws IOException { 6539a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy out.writeBytes("*" + name + '\n'); 654f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 655f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 656f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy static class Entry { 6579a8c5cefcab3d5dec6ff63f0e99553e1aa9a4af8Romain Guy int traceId; 658f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy long wallStart; 659f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy long wallTime; 660648bee18a1ccd362445d562729250ff5910f16a0Romain Guy long threadStart; 661f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy long threadTime; 662f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 663f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy } 664f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy 665f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guy /** 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened recycler traces. The trace records the type of 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * recycler action performed on the supplied view as well as a number of parameters. 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param parameters parameters depending on the type of the trace 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, RecyclerTraceType type, int... parameters) { 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!sRecyclerViews.contains(view)) { 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.add(view); 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int index = sRecyclerViews.indexOf(view); 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RecyclerTrace trace = new RecyclerTrace(); 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.view = index; 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.type = type; 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.position = parameters[0]; 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trace.indexOnScreen = parameters[1]; 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.add(trace); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view recycler of the specified view. The trace is identified by a prefix, 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-recycler/PREFIX.traces</code> and 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>. 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view recycler can be traced at the same time. After calling this method, any 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopRecyclerTracing()} is invoked before. 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Traces files are created only after {@link #stopRecyclerTracing()} is invoked. 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose recycler must be traced 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopRecyclerTracing() 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startRecyclerTracing(String prefix, View view) { 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView != null) { 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopRecyclerTracing() before running" + 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTracePrefix = prefix; 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = view; 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = new ArrayList<View>(); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = new LinkedList<RecyclerTrace>(); 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view recycer tracing. 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.traces</code> 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's recycler. 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.recycler</code> 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all of the views used by the recycler of the view supplied to 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startRecyclerTracing(String, View)}. 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_RECYCLER is false. 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #startRecyclerTracing(String, View) 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[]) 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopRecyclerTracing() { 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_RECYCLER) { 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sRecyclerOwnerView == null || sRecyclerViews == null) { 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startRecyclerTracing() before" + 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopRecyclerTracing()!"); 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 756c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump.mkdirs(); 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler"); 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final BufferedWriter out = new BufferedWriter(new FileWriter(recyclerDump), 8 * 1024); 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (View view : sRecyclerViews) { 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String name = view.getClass().getName(); 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(name); 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler content"); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces"); 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7781afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn if (recyclerDump.exists()) { 77988b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy //noinspection ResultOfMethodCallIgnored 7801afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn recyclerDump.delete(); 7811afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn } 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final FileOutputStream file = new FileOutputStream(recyclerDump); 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final DataOutputStream out = new DataOutputStream(file); 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (RecyclerTrace trace : sRecyclerTraces) { 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.view); 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.type.ordinal()); 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.position); 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(trace.indexOnScreen); 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.flush(); 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump recycler traces"); 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews.clear(); 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerViews = null; 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces.clear(); 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerTraces = null; 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sRecyclerOwnerView = null; 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Outputs a trace to the currently opened traces file. The trace contains the class name 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and instance's hashcode of the specified view as well as the supplied trace type. 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view to trace 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param type the type of the trace 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, HierarchyTraceType type) { 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarchyTraces == null) { 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(type.name()); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(' '); 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(view.getClass().getName()); 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write('@'); 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.write(Integer.toHexString(view.hashCode())); 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.newLine(); 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping trace of type " + type + " for view " + view); 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix, 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * used to build the traces files names: <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> and 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>. 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one view hierarchy can be traced at the same time. After calling this method, any 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other invocation will result in a <code>IllegalStateException</code> unless 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #stopHierarchyTracing()} is invoked before. 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing all the traces (or method calls) relative to the specified view's hierarchy. 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param prefix the traces files name prefix 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view the view whose hierarchy must be traced 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #stopHierarchyTracing() 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startHierarchyTracing(String prefix, View view) { 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot != null) { 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call stopHierarchyTracing() before running" + 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " a new trace!"); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 864c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, prefix + ".traces"); 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTracePrefix = prefix; 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8776dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn sHierarhcyRoot = (ViewRootImpl) view.getRootView().getParent(); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stops the current view hierarchy tracing. This method closes the file 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>. 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code> 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing the view hierarchy of the view supplied to 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #startHierarchyTracing(String, View)}. 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will return immediately if TRACE_HIERARCHY is false. 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 890a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @see #startHierarchyTracing(String, View) 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #trace(View, android.view.ViewDebug.HierarchyTraceType) 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopHierarchyTracing() { 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection PointlessBooleanExpression,ConstantConditions 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TRACE_HIERARCHY) { 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sHierarhcyRoot == null || sHierarchyTraces == null) { 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("You must call startHierarchyTracing() before" + 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " stopHierarchyTracing()!"); 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces.close(); 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not write view traces"); 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarchyTraces = null; 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); 912c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project //noinspection ResultOfMethodCallIgnored 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump.mkdirs(); 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree"); 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out; 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = sHierarhcyRoot.getView(); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy(group, out, 0); 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e("View", "Could not dump view hierarchy"); 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sHierarhcyRoot = null; 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 937a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void dispatchCommand(View view, String command, String parameters, 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream clientStream) throws IOException { 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Paranoid but safe... 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view = view.getRootView(); 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) { 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dump(view, clientStream); 946223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) { 947223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy captureLayers(view, new DataOutputStream(clientStream)); 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String[] params = parameters.split(" "); 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) { 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project capture(view, clientStream, params[0]); 952ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) { 953ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase outputDisplayList(view, params[0]); 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) { 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(view, params[0]); 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) { 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(view, params[0]); 958c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) { 959c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project profile(view, clientStream, params[0]); 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 964c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static View findView(View root, String parameter) { 965c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by type/hashcode 966c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (parameter.indexOf('@') != -1) { 967c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String[] ids = parameter.split("@"); 968c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String className = ids[0]; 969236092a36216c79507ec19eb207831810caced19Romain Guy final int hashCode = (int) Long.parseLong(ids[1], 16); 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 971c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project View view = root.getRootView(); 972c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view instanceof ViewGroup) { 973c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return findView((ViewGroup) view, className, hashCode); 974c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 975c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 976c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by id 977c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int id = root.getResources().getIdentifier(parameter, null, null); 978c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return root.getRootView().findViewById(id); 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void invalidate(View root, String parameter) { 985c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.postInvalidate(); 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void requestLayout(View root, String parameter) { 992c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project root.post(new Runnable() { 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.requestLayout(); 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1002c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void profile(View root, OutputStream clientStream, String parameter) 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1005c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 1006c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project BufferedWriter out = null; 1007c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1008c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024); 1009c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1010c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view != null) { 1011f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev profileViewAndChildren(view, out); 1012f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } else { 1013f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write("-1 -1 -1"); 1014f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 1015f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 1016f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write("DONE."); 1017f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 1018f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } catch (Exception e) { 1019f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev android.util.Log.w("View", "Problem profiling the view:", e); 1020f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } finally { 1021f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev if (out != null) { 1022f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.close(); 1023f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 1024f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 1025f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 1026c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1027f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev private static void profileViewAndChildren(final View view, BufferedWriter out) 1028f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev throws IOException { 1029c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev profileViewAndChildren(view, out, true); 1030c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1031f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev 1032c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev private static void profileViewAndChildren(final View view, BufferedWriter out, boolean root) 1033c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev throws IOException { 1034f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev 1035c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationMeasure = 1036c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev (root || (view.mPrivateFlags & View.MEASURED_DIMENSION_SET) != 0) ? profileViewOperation( 1037c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view, new ViewOperation<Void>() { 1038c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public Void[] pre() { 1039c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev forceLayout(view); 1040c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return null; 1041c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1042c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1043c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev private void forceLayout(View view) { 1044c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.forceLayout(); 1045c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev if (view instanceof ViewGroup) { 1046c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev ViewGroup group = (ViewGroup) view; 1047c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev final int count = group.getChildCount(); 1048c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev for (int i = 0; i < count; i++) { 1049c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev forceLayout(group.getChildAt(i)); 1050c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1051c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1052c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1053c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1054c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void run(Void... data) { 1055c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec); 1056c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1057c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1058c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void post(Void... data) { 1059c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1060c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }) 1061c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev : 0; 1062c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationLayout = 1063c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev (root || (view.mPrivateFlags & View.LAYOUT_REQUIRED) != 0) ? profileViewOperation( 1064c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view, new ViewOperation<Void>() { 1065c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public Void[] pre() { 1066c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return null; 1067c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1068c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1069c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void run(Void... data) { 1070c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom); 1071c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1072c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1073c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void post(Void... data) { 1074c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1075c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }) : 0; 1076c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationDraw = 1077bef337f516eafaee8f3891e22688b74388570317Konstantin Lopyrev (root || !view.willNotDraw() || (view.mPrivateFlags & View.DRAWN) != 0) ? profileViewOperation( 1078bef337f516eafaee8f3891e22688b74388570317Konstantin Lopyrev view, 1079c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev new ViewOperation<Object>() { 1080c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public Object[] pre() { 1081c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev final DisplayMetrics metrics = 1082daf98e941e140e8739458126640183b9f296a2abChet Haase (view != null && view.getResources() != null) ? 1083daf98e941e140e8739458126640183b9f296a2abChet Haase view.getResources().getDisplayMetrics() : null; 1084daf98e941e140e8739458126640183b9f296a2abChet Haase final Bitmap bitmap = metrics != null ? 1085c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev Bitmap.createBitmap(metrics.widthPixels, 1086daf98e941e140e8739458126640183b9f296a2abChet Haase metrics.heightPixels, Bitmap.Config.RGB_565) : null; 1087daf98e941e140e8739458126640183b9f296a2abChet Haase final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null; 1088c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return new Object[] { 1089c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev bitmap, canvas 1090c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }; 1091c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1092c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1093c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void run(Object... data) { 1094daf98e941e140e8739458126640183b9f296a2abChet Haase if (data[1] != null) { 1095daf98e941e140e8739458126640183b9f296a2abChet Haase view.draw((Canvas) data[1]); 1096daf98e941e140e8739458126640183b9f296a2abChet Haase } 1097c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1098c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 1099c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev public void post(Object... data) { 11006311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn if (data[1] != null) { 11016311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn ((Canvas) data[1]).setBitmap(null); 11026311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn } 1103daf98e941e140e8739458126640183b9f296a2abChet Haase if (data[0] != null) { 1104daf98e941e140e8739458126640183b9f296a2abChet Haase ((Bitmap) data[0]).recycle(); 1105daf98e941e140e8739458126640183b9f296a2abChet Haase } 1106c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1107c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev }) : 0; 1108f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationMeasure)); 1109f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(' '); 1110f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationLayout)); 1111f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(' '); 1112f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationDraw)); 1113f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 1114f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev if (view instanceof ViewGroup) { 1115f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev ViewGroup group = (ViewGroup) view; 1116f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev final int count = group.getChildCount(); 1117f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev for (int i = 0; i < count; i++) { 1118c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev profileViewAndChildren(group.getChildAt(i), out, false); 1119c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1120c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1121c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1122c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1123c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project interface ViewOperation<T> { 1124c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] pre(); 1125c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void run(T... data); 1126c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void post(T... data); 1127c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1128c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) { 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 1131c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long[] duration = new long[1]; 1132c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.post(new Runnable() { 1134c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run() { 1135c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] data = operation.pre(); 1137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project long start = Debug.threadCpuTimeNanos(); 113888b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy //noinspection unchecked 1139c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.run(data); 1140c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project duration[0] = Debug.threadCpuTimeNanos() - start; 114188b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy //noinspection unchecked 1142c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.post(data); 1143c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } finally { 1144c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project latch.countDown(); 1145c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1146c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1147c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 1148c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1149c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1150c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev if (!latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS)) { 1151c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev Log.w("View", "Could not complete the profiling of the view " + view); 1152c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return -1; 1153c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 1154c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (InterruptedException e) { 1155c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the profiling of the view " + view); 1156c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 1157c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return -1; 1158c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1159c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1160c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return duration[0]; 1161c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1162c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1163223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy private static void captureLayers(View root, final DataOutputStream clientStream) 1164223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy throws IOException { 1165223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1166223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy try { 1167223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Rect outRect = new Rect(); 1168223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy try { 1169223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy root.mAttachInfo.mSession.getDisplayFrame(root.mAttachInfo.mWindow, outRect); 1170223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } catch (RemoteException e) { 1171223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy // Ignore 1172223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1173223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1174223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(outRect.width()); 1175223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(outRect.height()); 1176223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 117765554f27855ce1764123604b061b10346f8b8404Romain Guy captureViewLayer(root, clientStream, true); 1178223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1179223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.write(2); 1180223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } finally { 1181223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.close(); 1182223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1183223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1184223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 118565554f27855ce1764123604b061b10346f8b8404Romain Guy private static void captureViewLayer(View view, DataOutputStream clientStream, boolean visible) 1186223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy throws IOException { 1187223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 118865554f27855ce1764123604b061b10346f8b8404Romain Guy final boolean localVisible = view.getVisibility() == View.VISIBLE && visible; 118965554f27855ce1764123604b061b10346f8b8404Romain Guy 1190223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if ((view.mPrivateFlags & View.SKIP_DRAW) != View.SKIP_DRAW) { 1191223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy final int id = view.getId(); 1192223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy String name = view.getClass().getSimpleName(); 1193223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (id != View.NO_ID) { 1194223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy name = resolveId(view.getContext(), id).toString(); 1195223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1196223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1197223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.write(1); 1198223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeUTF(name); 119965554f27855ce1764123604b061b10346f8b8404Romain Guy clientStream.writeByte(localVisible ? 1 : 0); 1200223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1201223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy int[] position = new int[2]; 1202223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy // XXX: Should happen on the UI thread 1203223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy view.getLocationInWindow(position); 1204223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1205223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(position[0]); 1206223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(position[1]); 1207223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.flush(); 1208223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1209223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap b = performViewCapture(view, true); 1210223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (b != null) { 1211223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(b.getWidth() * 1212223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy b.getHeight() * 2); 1213223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy b.compress(Bitmap.CompressFormat.PNG, 100, arrayOut); 1214223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(arrayOut.size()); 1215223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy arrayOut.writeTo(clientStream); 1216223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1217223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.flush(); 1218223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1219223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1220223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (view instanceof ViewGroup) { 1221223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy ViewGroup group = (ViewGroup) view; 1222223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy int count = group.getChildCount(); 1223223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1224223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy for (int i = 0; i < count; i++) { 122565554f27855ce1764123604b061b10346f8b8404Romain Guy captureViewLayer(group.getChildAt(i), clientStream, localVisible); 1226223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1227223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1228223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1229223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1230ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase private static void outputDisplayList(View root, String parameter) throws IOException { 1231ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase final View view = findView(root, parameter); 12326dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn view.getViewRootImpl().outputDisplayList(view); 1233ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase } 1234ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase 1235c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void capture(View root, final OutputStream clientStream, String parameter) 1236c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1237c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1238c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View captureView = findView(root, parameter); 1239223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap b = performViewCapture(captureView, false); 124043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev 124143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev if (b == null) { 1242223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Log.w("View", "Failed to create capture bitmap!"); 124343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev // Send an empty one so that it doesn't get stuck waiting for 124443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev // something. 124543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 124643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } 124743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev 124843b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev BufferedOutputStream out = null; 124943b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev try { 125043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out = new BufferedOutputStream(clientStream, 32 * 1024); 125143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b.compress(Bitmap.CompressFormat.PNG, 100, out); 125243b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out.flush(); 125343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } finally { 125443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev if (out != null) { 125543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out.close(); 125643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } 125743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b.recycle(); 1258223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 1259223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1261223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy private static Bitmap performViewCapture(final View captureView, final boolean skpiChildren) { 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (captureView != null) { 1263c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Bitmap[] cache = new Bitmap[1]; 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1266223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy captureView.post(new Runnable() { 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1269958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 1270223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap.Config.ARGB_8888, 0, skpiChildren); 1271958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e) { 127288b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy Log.w("View", "Out of memory for bitmap"); 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.countDown(); 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); 1281223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy return cache[0]; 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 1283c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the capture of the view " + captureView); 1284c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1287223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 1288223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy return null; 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dump(View root, OutputStream clientStream) throws IOException { 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out = null; 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 129438e951b62ed956501b11f0715e23e3bf70942f6dRomain Guy out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024); 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = root.getRootView(); 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 1298105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(group.getContext(), group, out, 0); 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write("DONE."); 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 1302c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Exception e) { 1303c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project android.util.Log.w("View", "Problem dumping the view:", e); 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out != null) { 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View findView(ViewGroup group, String className, int hashCode) { 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isRequestedView(group, className, hashCode)) { 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return group; 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View found = findView((ViewGroup) view, className, hashCode); 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (found != null) { 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return found; 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (isRequestedView(view, className, hashCode)) { 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view; 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean isRequestedView(View view, String className, int hashCode) { 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view.getClass().getName().equals(className) && view.hashCode() == hashCode; 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1336105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group, 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out, int level) { 1338105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (!dumpViewWithProperties(context, group, out, level)) { 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 1346105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1); 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1348105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewWithProperties(context, view, out, level + 1); 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1353105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static boolean dumpViewWithProperties(Context context, View view, 1354105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, int level) { 1355105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 1364105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out); 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] getExportedPropertyFields(Class<?> klass) { 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sFieldsForClasses == null) { 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sFieldsForClasses = new HashMap<Class<?>, Field[]>(); 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1377c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 1378c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 1379c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1380c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = sFieldsForClasses; 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getDeclaredFields(); 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(ExportedProperty.class)) { 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 139788b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy sAnnotations.put(field, field.getAnnotation(ExportedProperty.class)); 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] getExportedPropertyMethods(Class<?> klass) { 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sMethodsForClasses == null) { 1409c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sMethodsForClasses = new HashMap<Class<?>, Method[]>(100); 1410c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1411c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 1412c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1414c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = sMethodsForClasses; 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getDeclaredMethods(); 1424a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 1427a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final Method method = methods[i]; 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 1429c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.isAnnotationPresent(ExportedProperty.class) && 1430c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.getReturnType() != Void.class) { 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 143388b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy sAnnotations.put(method, method.getAnnotation(ExportedProperty.class)); 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out) throws IOException { 1445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out, ""); 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1450105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, String prefix) throws IOException { 1451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 1455105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportFields(context, view, out, klass, prefix); 1456105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportMethods(context, view, out, klass, prefix); 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project klass = klass.getSuperclass(); 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (klass != Object.class); 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1460a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1461105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportMethods(Context context, Object view, BufferedWriter out, 1462105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = getExportedPropertyMethods(klass); 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: This should happen on the UI thread 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(view, (Object[]) null); 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 1474bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev final ExportedProperty property = sAnnotations.get(method); 147591a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev String categoryPrefix = 147691a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev property.category().length() != 0 ? property.category() + ":" : ""; 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (returnType == int.class) { 1479bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 1480105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = (Integer) methodValue; 1482105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project methodValue = resolveId(context, id); 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1484809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1485809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1486809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = (Integer) methodValue; 148791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = 148891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev categoryPrefix + prefix + method.getName() + '_'; 1489809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1490809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1491809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = (Integer) methodValue; 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mapped = false; 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapper = mapping[j]; 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapper.from() == intValue) { 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = mapper.to(); 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mapped = true; 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mapped) { 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = intValue; 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1511c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (returnType == int[].class) { 1512c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) methodValue; 151391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = categoryPrefix + prefix + method.getName() + '_'; 1514c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = "()"; 1515c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1516105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1517bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 1518bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev // Probably want to return here, same as for fields. 1519bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev return; 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!returnType.isPrimitive()) { 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1522105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, methodValue, out, prefix + property.prefix()); 15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 152791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev writeEntry(out, categoryPrefix + prefix, method.getName(), "()", methodValue); 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1534105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportFields(Context context, Object view, BufferedWriter out, 1535105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 1536105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = getExportedPropertyFields(klass); 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 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = null; 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> type = field.getType(); 1547bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev final ExportedProperty property = sAnnotations.get(field); 154891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev String categoryPrefix = 154991a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev property.category().length() != 0 ? property.category() + ":" : ""; 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (type == int.class) { 1552bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 1553105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = field.getInt(view); 1555105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project fieldValue = resolveId(context, id); 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1557809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1558809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1559809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = field.getInt(view); 156091a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = 156191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev categoryPrefix + prefix + field.getName() + '_'; 1562809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1563809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1564809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = field.getInt(view); 15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapped = mapping[j]; 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapped.from() == intValue) { 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = mapped.to(); 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = intValue; 15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1582c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (type == int[].class) { 1583c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) field.get(view); 158491a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = categoryPrefix + prefix + field.getName() + '_'; 1585c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = ""; 1586c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1587105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1588c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1589c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // We exit here! 1590c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return; 15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!type.isPrimitive()) { 15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 159391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev dumpViewProperties(context, field.get(view), out, prefix 159491a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev + property.prefix()); 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = field.get(view); 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 160391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev writeEntry(out, categoryPrefix + prefix, field.getName(), "", fieldValue); 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1609c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeEntry(BufferedWriter out, String prefix, String name, 1610c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String suffix, Object value) throws IOException { 1611c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1612c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(prefix); 1613c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(name); 1614c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(suffix); 1615c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("="); 1616c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeValue(out, value); 1617c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 1618c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1619c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1620809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping, 1621809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int intValue, String prefix) throws IOException { 1622809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1623809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int count = mapping.length; 1624809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy for (int j = 0; j < count; j++) { 1625809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString flagMapping = mapping[j]; 1626809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final boolean ifTrue = flagMapping.outputIf(); 16275bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final int maskResult = intValue & flagMapping.mask(); 16285bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final boolean test = maskResult == flagMapping.equals(); 1629809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if ((test && ifTrue) || (!test && !ifTrue)) { 1630809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final String name = flagMapping.name(); 16315bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final String value = "0x" + Integer.toHexString(maskResult); 1632809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy writeEntry(out, prefix, name, "", value); 1633809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1634809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1635809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1636809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1637105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportUnrolledArray(Context context, BufferedWriter out, 1638c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ExportedProperty property, int[] array, String prefix, String suffix) 1639c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1640c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1641c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] indexMapping = property.indexMapping(); 1642c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasIndexMapping = indexMapping.length > 0; 1643c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1644c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] mapping = property.mapping(); 1645c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasMapping = mapping.length > 0; 1646c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1647105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final boolean resolveId = property.resolveId() && context != null; 1648c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int valuesCount = array.length; 1649c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1650c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int j = 0; j < valuesCount; j++) { 1651c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String name; 1652a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy String value = null; 1653c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1654c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int intValue = array[j]; 1655c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1656c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = String.valueOf(j); 1657c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasIndexMapping) { 1658c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = indexMapping.length; 1659c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1660c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = indexMapping[k]; 1661c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == j) { 1662c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = mapped.to(); 1663c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1664c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1665c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1666c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1667c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1668c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasMapping) { 1669c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = mapping.length; 1670c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1671c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = mapping[k]; 1672c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == intValue) { 1673c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project value = mapped.to(); 1674c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1675c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1676c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1677c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1678c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1679c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (resolveId) { 1680a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy if (value == null) value = (String) resolveId(context, intValue); 1681a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 1682a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy value = String.valueOf(intValue); 1683c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1684c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1685c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, name, suffix, value); 1686c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1687c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1688c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1689237c1ceea36024cf4194212e713806e3ce8a1c49Romain Guy static Object resolveId(Context context, int id) { 1690c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Object fieldValue; 1691105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final Resources resources = context.getResources(); 1692c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (id >= 0) { 1693c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1694c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = resources.getResourceTypeName(id) + '/' + 1695c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project resources.getResourceEntryName(id); 1696c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Resources.NotFoundException e) { 1697c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "id/0x" + Integer.toHexString(id); 1698c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1699c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1700c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "NO_ID"; 1701c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1702c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return fieldValue; 1703c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1704c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1705c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeValue(BufferedWriter out, Object value) throws IOException { 1706c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (value != null) { 1707c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String output = value.toString().replace("\n", "\\n"); 1708c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(String.valueOf(output.length())); 1709c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(","); 1710c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(output); 1711c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1712c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("4,null"); 1713c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1714c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1715c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void dumpViewHierarchy(ViewGroup group, BufferedWriter out, int level) { 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!dumpView(group, out, level)) { 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpViewHierarchy((ViewGroup) view, out, level + 1); 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dumpView(view, out, level + 1); 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean dumpView(Object view, BufferedWriter out, int level) { 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(view.getClass().getName()); 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] capturedViewGetPropertyFields(Class<?> klass) { 17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewFieldsForClasses == null) { 17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>(); 17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses; 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getFields(); 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(CapturedViewProperty.class)) { 17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] capturedViewGetPropertyMethods(Class<?> klass) { 17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewMethodsForClasses == null) { 17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>(); 17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses; 17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getMethods(); 1790a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 1793a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final Method method = methods[i]; 17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.isAnnotationPresent(CapturedViewProperty.class) && 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.getReturnType() != Void.class) { 17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1807a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1808a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy private static String capturedViewExportMethods(Object obj, Class<?> klass, 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix) { 18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1814a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = capturedViewGetPropertyMethods(klass); 18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(obj, (Object[]) null); 18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 1824a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class); 18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.retrieveReturn()) { 18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we are interested in the second level data only 18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#")); 1829a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(method.getName()); 18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("()="); 1833a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methodValue != null) { 1835a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final String value = methodValue.toString().replace("\n", "\\n"); 1836a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(value); 18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("; "); 18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 1843a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception IllegalAccess, it is OK here 18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 1846a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception InvocationTarget, it is OK here 18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this method 1848a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 1849a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) { 1854a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1858a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = capturedViewGetPropertyFields(klass); 18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = field.get(obj); 18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(field.getName()); 18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("="); 18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue != null) { 18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String value = fieldValue.toString().replace("\n", "\\n"); 18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(value); 18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(' '); 18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 1880a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception IllegalAccess, it is OK here 18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this field 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1886a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1888a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * Dump view info for id based instrument test generation 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (and possibly further data analysis). The results are dumped 1890a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * to the log. 18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tag for log 18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view for dump 18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1894a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy public static void dumpCapturedView(String tag, Object view) { 18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(klass.getName() + ": "); 18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportFields(view, klass, "")); 1898a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(capturedViewExportMethods(view, klass, "")); 1899a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy Log.d(tag, sb.toString()); 19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1902