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; 2597e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsenimport android.os.Handler; 26223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport android.os.RemoteException; 27f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.util.DisplayMetrics; 28f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.util.Log; 29042ad633bc68bdda2bb0c50216706d73575a5992Jon Mirandaimport android.util.TypedValue; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.BufferedOutputStream; 32f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.BufferedWriter; 33223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport java.io.ByteArrayOutputStream; 34f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.DataOutputStream; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 37f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.OutputStreamWriter; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.ElementType; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Retention; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.RetentionPolicy; 41f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.annotation.Target; 42f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.reflect.AccessibleObject; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.InvocationTargetException; 45f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.reflect.Method; 46f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.ArrayList; 47f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.HashMap; 4897e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsenimport java.util.concurrent.Callable; 4997e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsenimport java.util.concurrent.CancellationException; 50f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.concurrent.CountDownLatch; 5197e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsenimport java.util.concurrent.ExecutionException; 5297e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsenimport java.util.concurrent.FutureTask; 5397e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsenimport java.util.concurrent.TimeoutException; 54f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.concurrent.TimeUnit; 55f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamyimport java.util.concurrent.atomic.AtomicReference; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various debugging/tracing tools related to {@link View} and the view hierarchy. 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ViewDebug { 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This flag is now unused 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_HIERARCHY = false; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This flag is now unused 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7013b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final boolean TRACE_RECYCLER = false; 72a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 742c095f367779ef32130c72849936a2e3013c8492Christopher Tate * Enables detailed logging of drag/drop operations. 752c095f367779ef32130c72849936a2e3013c8492Christopher Tate * @hide 762c095f367779ef32130c72849936a2e3013c8492Christopher Tate */ 77994ef9296a00523de1df424b4b760b4416ead58bChristopher Tate public static final boolean DEBUG_DRAG = false; 782c095f367779ef32130c72849936a2e3013c8492Christopher Tate 792c095f367779ef32130c72849936a2e3013c8492Christopher Tate /** 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped by 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view server. Only non-void methods with no arguments can be annotated 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * by this annotation. 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface ExportedProperty { 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When resolveId is true, and if the annotated field/method return value 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is an int, the value is converted to an Android's resource name. 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the property's value must be transformed into an Android 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * resource name, false otherwise 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean resolveId() default false; 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A mapping can be defined to map int values to specific strings. For 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance, View.getVisibility() returns 0, 4 or 8. However, these values 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * actually mean VISIBLE, INVISIBLE and GONE. A mapping can be used to see 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * these human readable values: 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.ExportedProperty(mapping = { 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "VISIBLE"), 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 4, to = "INVISIBLE"), 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @ViewDebug.IntToString(from = 8, to = "GONE") 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * }) 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * public int getVisibility() { ... 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An array of int to String mappings 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.IntToString 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IntToString[] mapping() default { }; 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 118c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be defined to map array indices to specific strings. 119c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * A mapping can be used to see human readable values for the indices 120c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * of an array: 121c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 122c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 123809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.ExportedProperty(indexMapping = { 124c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 0, to = "INVALID"), 125c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 1, to = "FIRST"), 126c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @ViewDebug.IntToString(from = 2, to = "SECOND") 127c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * }) 128c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * private int[] mElements; 129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * <pre> 130c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 131c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @return An array of int to String mappings 132c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * 133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see android.view.ViewDebug.IntToString 134c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * @see #mapping() 135c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project */ 136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project IntToString[] indexMapping() default { }; 137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project /** 139809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * A flags mapping can be defined to map flags encoded in an integer to 140809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * specific strings. A mapping can be used to see human readable values 141809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * for the flags of an integer: 142809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 143809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <pre> 144809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.ExportedProperty(flagMapping = { 145809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"), 146809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"), 147809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * }) 148809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * private int mFlags; 149809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <pre> 150809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 151809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * A specified String is output when the following is true: 152a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * 153809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An array of int to String mappings 154809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 155809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy FlagToString[] flagMapping() default { }; 156809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 157809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When deep export is turned on, this property is not dumped. Instead, the 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * properties contained in this property are dumped. Each child property 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is prefixed with the name of this property. 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the properties of this property should be dumped 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 164a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @see #prefix() 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean deepExport() default false; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The prefix to use on child properties when deep export is enabled 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a prefix as a String 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #deepExport() 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix() default ""; 176bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 177bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev /** 178bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * Specifies the category the property falls into, such as measurement, 179bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * layout, drawing, etc. 180bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * 181bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev * @return the category as String 182bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev */ 183bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev String category() default ""; 1844597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 1854597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda /** 1864597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda * Indicates whether or not to format an {@code int} or {@code byte} value as a hex string. 1874597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda * 1884597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda * @return true if the supported values should be formatted as a hex string. 1894597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda */ 1904597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda boolean formatToHexString() default false; 191836c0a8b949d71293c996761691e065f0651acefJon Miranda 192836c0a8b949d71293c996761691e065f0651acefJon Miranda /** 193836c0a8b949d71293c996761691e065f0651acefJon Miranda * Indicates whether or not the key to value mappings are held in adjacent indices. 194836c0a8b949d71293c996761691e065f0651acefJon Miranda * 195836c0a8b949d71293c996761691e065f0651acefJon Miranda * Note: Applies only to fields and methods that return String[]. 196836c0a8b949d71293c996761691e065f0651acefJon Miranda * 197836c0a8b949d71293c996761691e065f0651acefJon Miranda * @return true if the key to value mappings are held in adjacent indices. 198836c0a8b949d71293c996761691e065f0651acefJon Miranda */ 199836c0a8b949d71293c996761691e065f0651acefJon Miranda boolean hasAdjacentMapping() default false; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Defines a mapping from an int value to a String. Such a mapping can be used 204f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa * in an @ExportedProperty to provide more meaningful values to the end user. 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.view.ViewDebug.ExportedProperty 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.TYPE }) 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface IntToString { 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The original int value to map to a String. 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary int value. 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int from(); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The String to use in place of the original int value. 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return An arbitrary non-null String. 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String to(); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 225809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 226809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 227f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa * Defines a mapping from a flag to a String. Such a mapping can be used 228f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa * in an @ExportedProperty to provide more meaningful values to the end user. 229809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 230809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @see android.view.ViewDebug.ExportedProperty 231809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 232809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Target({ ElementType.TYPE }) 233809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy @Retention(RetentionPolicy.RUNTIME) 234809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy public @interface FlagToString { 235809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 236809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The mask to apply to the original value. 237809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 238809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary int value. 239809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 240809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int mask(); 241809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 242809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 243809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The value to compare to the result of: 244809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * <code>original value & {@link #mask()}</code>. 245809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 246809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary value. 247809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 248809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int equals(); 249809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 250809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 251809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * The String to use in place of the original int value. 252809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * 253809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * @return An arbitrary non-null String. 254809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 255809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy String name(); 256809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 257809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy /** 258809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * Indicates whether to output the flag when the test is true, 259809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy * or false. Defaults to true. 260809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy */ 261809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy boolean outputIf() default true; 262809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 263809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This annotation can be used to mark fields and methods to be dumped when 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the view is captured. Methods with this annotation must have no arguments 267f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * and must return a valid type of data. 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Target({ ElementType.FIELD, ElementType.METHOD }) 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Retention(RetentionPolicy.RUNTIME) 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public @interface CapturedViewProperty { 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 273a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * When retrieveReturn is true, we need to retrieve second level methods 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod() 275a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * we will set retrieveReturn = true on the annotation of 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * myView.getFirstLevelMethod() 277a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * @return true if we need the second level methods 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 279a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy boolean retrieveReturn() default false; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 281a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 282926cf56676d760579573470c7848dbf119a86779John Reck /** 283926cf56676d760579573470c7848dbf119a86779John Reck * Allows a View to inject custom children into HierarchyViewer. For example, 284926cf56676d760579573470c7848dbf119a86779John Reck * WebView uses this to add its internal layer tree as a child to itself 285926cf56676d760579573470c7848dbf119a86779John Reck * @hide 286926cf56676d760579573470c7848dbf119a86779John Reck */ 287926cf56676d760579573470c7848dbf119a86779John Reck public interface HierarchyHandler { 288926cf56676d760579573470c7848dbf119a86779John Reck /** 289926cf56676d760579573470c7848dbf119a86779John Reck * Dumps custom children to hierarchy viewer. 290f2361156c4aee3dad26f25c410fcf255656922d1John Reck * See ViewDebug.dumpViewWithProperties(Context, View, BufferedWriter, int) 291926cf56676d760579573470c7848dbf119a86779John Reck * for the format 292926cf56676d760579573470c7848dbf119a86779John Reck * 293926cf56676d760579573470c7848dbf119a86779John Reck * An empty implementation should simply do nothing 294926cf56676d760579573470c7848dbf119a86779John Reck * 295926cf56676d760579573470c7848dbf119a86779John Reck * @param out The output writer 296926cf56676d760579573470c7848dbf119a86779John Reck * @param level The indentation level 297926cf56676d760579573470c7848dbf119a86779John Reck */ 298926cf56676d760579573470c7848dbf119a86779John Reck public void dumpViewHierarchyWithProperties(BufferedWriter out, int level); 299926cf56676d760579573470c7848dbf119a86779John Reck 300926cf56676d760579573470c7848dbf119a86779John Reck /** 301926cf56676d760579573470c7848dbf119a86779John Reck * Returns a View to enable grabbing screenshots from custom children 302926cf56676d760579573470c7848dbf119a86779John Reck * returned in dumpViewHierarchyWithProperties. 303926cf56676d760579573470c7848dbf119a86779John Reck * 304926cf56676d760579573470c7848dbf119a86779John Reck * @param className The className of the view to find 305926cf56676d760579573470c7848dbf119a86779John Reck * @param hashCode The hashCode of the view to find 306926cf56676d760579573470c7848dbf119a86779John Reck * @return the View to capture from, or null if not found 307926cf56676d760579573470c7848dbf119a86779John Reck */ 308926cf56676d760579573470c7848dbf119a86779John Reck public View findHierarchyView(String className, int hashCode); 309926cf56676d760579573470c7848dbf119a86779John Reck } 310926cf56676d760579573470c7848dbf119a86779John Reck 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null; 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null; 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Maximum delay in ms after which we stop trying to capture a View's drawing 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CAPTURE_TIMEOUT = 4000; 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE"; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_DUMP = "DUMP"; 319042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda private static final String REMOTE_COMMAND_DUMP_THEME = "DUMP_THEME"; 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE"; 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT"; 322c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static final String REMOTE_PROFILE = "PROFILE"; 323223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS"; 324ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST"; 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Field[]> sFieldsForClasses; 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static HashMap<Class<?>, Method[]> sMethodsForClasses; 328c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static HashMap<AccessibleObject, ExportedProperty> sAnnotations; 329c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 33113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This enum is now unused 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 33313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum HierarchyTraceType { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE, 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD, 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project INVALIDATE_CHILD_IN_PARENT, 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project REQUEST_LAYOUT, 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_LAYOUT, 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ON_MEASURE, 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DRAW, 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BUILD_CACHE 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 34613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This enum is now unused 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 34813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum RecyclerTraceType { 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NEW_VIEW, 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BIND_VIEW, 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_ACTIVE_HEAP, 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RECYCLE_FROM_SCRAP_HEAP, 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_TO_SCRAP_HEAP, 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MOVE_FROM_ACTIVE_TO_SCRAP_HEAP 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of instanciated Views. 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of Views instanciated in the current process. 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getViewInstanceCount() { 366c21550a8d1dfc9e5359fe994cb48049a0bd4c82cBrian Carlstrom return Debug.countInstancesOfClass(View.class); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 370c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato * Returns the number of instanciated ViewAncestors. 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 372c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato * @return The number of ViewAncestors instanciated in the current process. 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 37665b345fa22b878e141b8fd8ece9c208df00fa40fRomain Guy public static long getViewRootImplCount() { 3776dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn return Debug.countInstancesOfClass(ViewRootImpl.class); 378a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 38113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This method is now unused and invoking it is a no-op 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 38313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 38413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @SuppressWarnings({ "UnusedParameters", "deprecation" }) 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, RecyclerTraceType type, int... parameters) { 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 38913b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This method is now unused and invoking it is a no-op 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 39113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 39213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @SuppressWarnings("UnusedParameters") 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startRecyclerTracing(String prefix, View view) { 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 39713b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This method is now unused and invoking it is a no-op 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 39913b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 40013b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @SuppressWarnings("UnusedParameters") 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopRecyclerTracing() { 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 40513b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This method is now unused and invoking it is a no-op 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 40713b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 40813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @SuppressWarnings({ "UnusedParameters", "deprecation" }) 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void trace(View view, HierarchyTraceType type) { 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 41313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This method is now unused and invoking it is a no-op 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 41513b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 41613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @SuppressWarnings("UnusedParameters") 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startHierarchyTracing(String prefix, View view) { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 42113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy * @deprecated This method is now unused and invoking it is a no-op 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 42313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy @Deprecated 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopHierarchyTracing() { 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 426a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void dispatchCommand(View view, String command, String parameters, 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream clientStream) throws IOException { 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Paranoid but safe... 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view = view.getRootView(); 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) { 434945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy dump(view, false, true, clientStream); 435042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } else if (REMOTE_COMMAND_DUMP_THEME.equalsIgnoreCase(command)) { 436042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda dumpTheme(view, clientStream); 437223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) { 438223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy captureLayers(view, new DataOutputStream(clientStream)); 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String[] params = parameters.split(" "); 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) { 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project capture(view, clientStream, params[0]); 443ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) { 444ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase outputDisplayList(view, params[0]); 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) { 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(view, params[0]); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) { 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(view, params[0]); 449c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) { 450c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project profile(view, clientStream, params[0]); 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 455945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy /** @hide */ 456945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy public static View findView(View root, String parameter) { 457c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by type/hashcode 458c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (parameter.indexOf('@') != -1) { 459c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String[] ids = parameter.split("@"); 460c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String className = ids[0]; 461236092a36216c79507ec19eb207831810caced19Romain Guy final int hashCode = (int) Long.parseLong(ids[1], 16); 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 463c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project View view = root.getRootView(); 464c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view instanceof ViewGroup) { 465c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return findView((ViewGroup) view, className, hashCode); 466c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 467c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 468c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // Look by id 469c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int id = root.getResources().getIdentifier(parameter, null, null); 470c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return root.getRootView().findViewById(id); 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void invalidate(View root, String parameter) { 477c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.postInvalidate(); 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void requestLayout(View root, String parameter) { 484c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project root.post(new Runnable() { 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.requestLayout(); 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 494c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void profile(View root, OutputStream clientStream, String parameter) 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 497c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View view = findView(root, parameter); 498c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project BufferedWriter out = null; 499c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 500c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024); 501c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 502c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (view != null) { 503f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev profileViewAndChildren(view, out); 504f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } else { 505f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write("-1 -1 -1"); 506f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 507f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 508f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write("DONE."); 509f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 510f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } catch (Exception e) { 511f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev android.util.Log.w("View", "Problem profiling the view:", e); 512f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } finally { 513f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev if (out != null) { 514f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.close(); 515f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 516f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 517f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev } 518c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 519945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy /** @hide */ 520945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy public static void profileViewAndChildren(final View view, BufferedWriter out) 521f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev throws IOException { 522c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev profileViewAndChildren(view, out, true); 523c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 524f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev 525c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev private static void profileViewAndChildren(final View view, BufferedWriter out, boolean root) 526c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev throws IOException { 527f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev 528c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationMeasure = 5294702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn (root || (view.mPrivateFlags & View.PFLAG_MEASURED_DIMENSION_SET) != 0) 5304597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda ? profileViewOperation(view, new ViewOperation<Void>() { 5314597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public Void[] pre() { 5324597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda forceLayout(view); 5334597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda return null; 5344597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 535c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 5364597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda private void forceLayout(View view) { 5374597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda view.forceLayout(); 5384597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda if (view instanceof ViewGroup) { 5394597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda ViewGroup group = (ViewGroup) view; 5404597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda final int count = group.getChildCount(); 5414597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda for (int i = 0; i < count; i++) { 5424597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda forceLayout(group.getChildAt(i)); 543c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 5444597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 5454597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 546c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 5474597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public void run(Void... data) { 5484597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec); 5494597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 550c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 5514597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public void post(Void... data) { 5524597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 5534597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda }) 554c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev : 0; 555c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationLayout = 5564702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn (root || (view.mPrivateFlags & View.PFLAG_LAYOUT_REQUIRED) != 0) 5574597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda ? profileViewOperation(view, new ViewOperation<Void>() { 5584597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public Void[] pre() { 5594597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda return null; 5604597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 561c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 5624597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public void run(Void... data) { 5634597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom); 5644597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 565c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 5664597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public void post(Void... data) { 5674597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 5684597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda }) : 0; 569c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev long durationDraw = 5704702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn (root || !view.willNotDraw() || (view.mPrivateFlags & View.PFLAG_DRAWN) != 0) 5714597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda ? profileViewOperation(view, new ViewOperation<Object>() { 5724597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public Object[] pre() { 5734597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda final DisplayMetrics metrics = 5744597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda (view != null && view.getResources() != null) ? 5754597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda view.getResources().getDisplayMetrics() : null; 5764597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda final Bitmap bitmap = metrics != null ? 5774597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda Bitmap.createBitmap(metrics, metrics.widthPixels, 5784597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda metrics.heightPixels, Bitmap.Config.RGB_565) : null; 5794597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null; 5804597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda return new Object[] { 5814597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda bitmap, canvas 5824597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda }; 5834597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 584c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 5854597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public void run(Object... data) { 5864597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda if (data[1] != null) { 5874597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda view.draw((Canvas) data[1]); 5884597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 5894597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 590c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev 5914597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public void post(Object... data) { 5924597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda if (data[1] != null) { 5934597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda ((Canvas) data[1]).setBitmap(null); 5944597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 5954597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda if (data[0] != null) { 5964597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda ((Bitmap) data[0]).recycle(); 5974597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 5984597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 5994597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda }) : 0; 600f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationMeasure)); 601f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(' '); 602f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationLayout)); 603f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(' '); 604f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.write(String.valueOf(durationDraw)); 605f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev out.newLine(); 606f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev if (view instanceof ViewGroup) { 607f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev ViewGroup group = (ViewGroup) view; 608f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev final int count = group.getChildCount(); 609f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev for (int i = 0; i < count; i++) { 610c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev profileViewAndChildren(group.getChildAt(i), out, false); 611c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 612c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 613c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 614c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 615c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project interface ViewOperation<T> { 616c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] pre(); 617c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void run(T... data); 618c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project void post(T... data); 619c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 620c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 621c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) { 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 623c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final long[] duration = new long[1]; 624c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 625c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project view.post(new Runnable() { 626c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void run() { 627c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 628c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project T[] data = operation.pre(); 629c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project long start = Debug.threadCpuTimeNanos(); 63088b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy //noinspection unchecked 631c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.run(data); 632c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project duration[0] = Debug.threadCpuTimeNanos() - start; 63388b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy //noinspection unchecked 634c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project operation.post(data); 635c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } finally { 636c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project latch.countDown(); 637c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 638c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 639c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project }); 640c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 641c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 642c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev if (!latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS)) { 643c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev Log.w("View", "Could not complete the profiling of the view " + view); 644c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev return -1; 645c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev } 646c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (InterruptedException e) { 647c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the profiling of the view " + view); 648c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 649c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return -1; 650c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 651c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 652c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return duration[0]; 653c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 654c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 655945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy /** @hide */ 656945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy public static void captureLayers(View root, final DataOutputStream clientStream) 657223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy throws IOException { 658223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 659223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy try { 660223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Rect outRect = new Rect(); 661223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy try { 662223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy root.mAttachInfo.mSession.getDisplayFrame(root.mAttachInfo.mWindow, outRect); 663223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } catch (RemoteException e) { 664223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy // Ignore 665223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 6664597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 667223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(outRect.width()); 668223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(outRect.height()); 6694597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 67065554f27855ce1764123604b061b10346f8b8404Romain Guy captureViewLayer(root, clientStream, true); 6714597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 672223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.write(2); 673223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } finally { 674223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.close(); 675223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 676223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 677223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 67865554f27855ce1764123604b061b10346f8b8404Romain Guy private static void captureViewLayer(View view, DataOutputStream clientStream, boolean visible) 679223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy throws IOException { 680223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 68165554f27855ce1764123604b061b10346f8b8404Romain Guy final boolean localVisible = view.getVisibility() == View.VISIBLE && visible; 68265554f27855ce1764123604b061b10346f8b8404Romain Guy 6834702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn if ((view.mPrivateFlags & View.PFLAG_SKIP_DRAW) != View.PFLAG_SKIP_DRAW) { 684223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy final int id = view.getId(); 685223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy String name = view.getClass().getSimpleName(); 686223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (id != View.NO_ID) { 687223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy name = resolveId(view.getContext(), id).toString(); 688223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 6894597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 690223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.write(1); 691223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeUTF(name); 69265554f27855ce1764123604b061b10346f8b8404Romain Guy clientStream.writeByte(localVisible ? 1 : 0); 6934597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 694223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy int[] position = new int[2]; 695223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy // XXX: Should happen on the UI thread 696223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy view.getLocationInWindow(position); 6974597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 698223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(position[0]); 699223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(position[1]); 700223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.flush(); 7014597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 702223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap b = performViewCapture(view, true); 703223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (b != null) { 704223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(b.getWidth() * 705223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy b.getHeight() * 2); 706223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy b.compress(Bitmap.CompressFormat.PNG, 100, arrayOut); 707223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.writeInt(arrayOut.size()); 708223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy arrayOut.writeTo(clientStream); 709223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 710223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy clientStream.flush(); 711223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 712223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 713223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy if (view instanceof ViewGroup) { 714223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy ViewGroup group = (ViewGroup) view; 715223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy int count = group.getChildCount(); 716223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 717223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy for (int i = 0; i < count; i++) { 71865554f27855ce1764123604b061b10346f8b8404Romain Guy captureViewLayer(group.getChildAt(i), clientStream, localVisible); 719223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 720223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 72168bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase 72268bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase if (view.mOverlay != null) { 72368bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase ViewGroup overlayContainer = view.getOverlay().mOverlayViewGroup; 72468bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase captureViewLayer(overlayContainer, clientStream, localVisible); 72568bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } 726223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 727223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy 728ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase private static void outputDisplayList(View root, String parameter) throws IOException { 729ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase final View view = findView(root, parameter); 7306dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn view.getViewRootImpl().outputDisplayList(view); 731ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase } 732ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase 733945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy /** @hide */ 734945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy public static void outputDisplayList(View root, View target) { 735945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy root.getViewRootImpl().outputDisplayList(target); 736945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy } 737945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy 738c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void capture(View root, final OutputStream clientStream, String parameter) 739c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 740c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 741c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final View captureView = findView(root, parameter); 742945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy capture(root, clientStream, captureView); 743945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy } 744945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy 745945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy /** @hide */ 746945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy public static void capture(View root, final OutputStream clientStream, View captureView) 747945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy throws IOException { 748223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Bitmap b = performViewCapture(captureView, false); 74943b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev 75043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev if (b == null) { 751223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy Log.w("View", "Failed to create capture bitmap!"); 75243b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev // Send an empty one so that it doesn't get stuck waiting for 75343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev // something. 754dde331cebd87982faded6818ad5f9927ff994c96Dianne Hackborn b = Bitmap.createBitmap(root.getResources().getDisplayMetrics(), 755dde331cebd87982faded6818ad5f9927ff994c96Dianne Hackborn 1, 1, Bitmap.Config.ARGB_8888); 75643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } 75743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev 75843b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev BufferedOutputStream out = null; 75943b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev try { 76043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out = new BufferedOutputStream(clientStream, 32 * 1024); 76143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b.compress(Bitmap.CompressFormat.PNG, 100, out); 76243b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out.flush(); 76343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } finally { 76443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev if (out != null) { 76543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev out.close(); 76643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev } 76743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev b.recycle(); 768223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 769223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy } 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 77168bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase private static Bitmap performViewCapture(final View captureView, final boolean skipChildren) { 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (captureView != null) { 773c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final CountDownLatch latch = new CountDownLatch(1); 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Bitmap[] cache = new Bitmap[1]; 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 776223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy captureView.post(new Runnable() { 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 779958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn cache[0] = captureView.createSnapshot( 78068bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase Bitmap.Config.ARGB_8888, 0, skipChildren); 781958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn } catch (OutOfMemoryError e) { 78288b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy Log.w("View", "Out of memory for bitmap"); 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.countDown(); 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS); 791223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy return cache[0]; 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 793c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w("View", "Could not complete the capture of the view " + captureView); 794c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Thread.currentThread().interrupt(); 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7974597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 798223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy return null; 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 801945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy /** 802945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy * Dumps the view hierarchy starting from the given view. 803945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy * @hide 804945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy */ 805945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy public static void dump(View root, boolean skipChildren, boolean includeProperties, 806945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy OutputStream clientStream) throws IOException { 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedWriter out = null; 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 80938e951b62ed956501b11f0715e23e3bf70942f6dRomain Guy out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024); 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view = root.getRootView(); 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ViewGroup group = (ViewGroup) view; 813945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy dumpViewHierarchy(group.getContext(), group, out, 0, 814945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy skipChildren, includeProperties); 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write("DONE."); 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 818c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Exception e) { 819c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project android.util.Log.w("View", "Problem dumping the view:", e); 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out != null) { 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.close(); 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 827042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda /** 828042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * Dumps the theme attributes from the given View. 829042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * @hide 830042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda */ 831042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda public static void dumpTheme(View view, OutputStream clientStream) throws IOException { 832042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda BufferedWriter out = null; 833042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda try { 834042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024); 835042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda String[] attributes = getStyleAttributesDump(view.getContext().getResources(), 836042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda view.getContext().getTheme()); 837042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda if (attributes != null) { 838042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda for (int i = 0; i < attributes.length; i += 2) { 839042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda if (attributes[i] != null) { 840042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda out.write(attributes[i] + "\n"); 841042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda out.write(attributes[i + 1] + "\n"); 842042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 843042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 844042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 845042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda out.write("DONE."); 846042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda out.newLine(); 847042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } catch (Exception e) { 848042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda android.util.Log.w("View", "Problem dumping View Theme:", e); 849042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } finally { 850042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda if (out != null) { 851042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda out.close(); 852042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 853042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 854042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 855042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda 856042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda /** 857042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * Gets the style attributes from the {@link Resources.Theme}. For debugging only. 858042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * 859042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * @param resources Resources to resolve attributes from. 860042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * @param theme Theme to dump. 861042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * @return a String array containing pairs of adjacent Theme attribute data: name followed by 862042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * its value. 863042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * 864042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda * @hide 865042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda */ 866042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda private static String[] getStyleAttributesDump(Resources resources, Resources.Theme theme) { 867042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda TypedValue outValue = new TypedValue(); 868042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda String nullString = "null"; 869042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda int i = 0; 870042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda int[] attributes = theme.getAllAttributes(); 871042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda String[] data = new String[attributes.length * 2]; 872042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda for (int attributeId : attributes) { 873042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda try { 874042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda data[i] = resources.getResourceName(attributeId); 875042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda data[i + 1] = theme.resolveAttribute(attributeId, outValue, true) ? 876042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda outValue.coerceToString().toString() : nullString; 877042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda i += 2; 8787c744bdbf35aedbdde3a5ff9f2374e91f16f3641Jon Miranda 8797c744bdbf35aedbdde3a5ff9f2374e91f16f3641Jon Miranda // attempt to replace reference data with its name 8807c744bdbf35aedbdde3a5ff9f2374e91f16f3641Jon Miranda if (outValue.type == TypedValue.TYPE_REFERENCE) { 8817c744bdbf35aedbdde3a5ff9f2374e91f16f3641Jon Miranda data[i - 1] = resources.getResourceName(outValue.resourceId); 8827c744bdbf35aedbdde3a5ff9f2374e91f16f3641Jon Miranda } 883042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } catch (Resources.NotFoundException e) { 884042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda // ignore resources we can't resolve 885042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 886042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 887042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda return data; 888042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda } 889042ad633bc68bdda2bb0c50216706d73575a5992Jon Miranda 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static View findView(ViewGroup group, String className, int hashCode) { 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isRequestedView(group, className, hashCode)) { 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return group; 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View found = findView((ViewGroup) view, className, hashCode); 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (found != null) { 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return found; 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (isRequestedView(view, className, hashCode)) { 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return view; 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 90668bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase if (view.mOverlay != null) { 90768bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase final View found = findView((ViewGroup) view.mOverlay.mOverlayViewGroup, 90868bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase className, hashCode); 90968bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase if (found != null) { 91068bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase return found; 91168bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } 91268bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } 913926cf56676d760579573470c7848dbf119a86779John Reck if (view instanceof HierarchyHandler) { 914926cf56676d760579573470c7848dbf119a86779John Reck final View found = ((HierarchyHandler)view) 915926cf56676d760579573470c7848dbf119a86779John Reck .findHierarchyView(className, hashCode); 916926cf56676d760579573470c7848dbf119a86779John Reck if (found != null) { 917926cf56676d760579573470c7848dbf119a86779John Reck return found; 918926cf56676d760579573470c7848dbf119a86779John Reck } 919926cf56676d760579573470c7848dbf119a86779John Reck } 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean isRequestedView(View view, String className, int hashCode) { 92568bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase if (view.hashCode() == hashCode) { 92668bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase String viewClassName = view.getClass().getName(); 92768bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase if (className.equals("ViewOverlay")) { 92868bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase return viewClassName.equals("android.view.ViewOverlay$OverlayViewGroup"); 92968bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } else { 93068bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase return className.equals(viewClassName); 93168bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } 93268bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } 93368bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase return false; 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 936945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy private static void dumpViewHierarchy(Context context, ViewGroup group, 937945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy BufferedWriter out, int level, boolean skipChildren, boolean includeProperties) { 938945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy if (!dumpView(context, group, out, level, includeProperties)) { 939945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy return; 940945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy } 941945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy 942945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy if (skipChildren) { 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = group.getChildCount(); 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final View view = group.getChildAt(i); 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view instanceof ViewGroup) { 950945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy dumpViewHierarchy(context, (ViewGroup) view, out, level + 1, skipChildren, 951945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy includeProperties); 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 953945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy dumpView(context, view, out, level + 1, includeProperties); 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 95568bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase if (view.mOverlay != null) { 95668bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase ViewOverlay overlay = view.getOverlay(); 95768bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase ViewGroup overlayContainer = overlay.mOverlayViewGroup; 95868bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase dumpViewHierarchy(context, overlayContainer, out, level + 2, skipChildren, 95968bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase includeProperties); 96068bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 962926cf56676d760579573470c7848dbf119a86779John Reck if (group instanceof HierarchyHandler) { 963926cf56676d760579573470c7848dbf119a86779John Reck ((HierarchyHandler)group).dumpViewHierarchyWithProperties(out, level + 1); 964926cf56676d760579573470c7848dbf119a86779John Reck } 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 967945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy private static boolean dumpView(Context context, View view, 968945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy BufferedWriter out, int level, boolean includeProperties) { 969105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < level; i++) { 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 97468bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase String className = view.getClass().getName(); 97568bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase if (className.equals("android.view.ViewOverlay$OverlayViewGroup")) { 97668bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase className = "ViewOverlay"; 97768bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase } 97868bf5bd3858684dbaa79f265943d7adaba982e85Chet Haase out.write(className); 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write('@'); 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(Integer.toHexString(view.hashCode())); 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.write(' '); 982945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy if (includeProperties) { 983945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy dumpViewProperties(context, view, out); 984945bfb6068d4ac1414a37a3ebe4dc4d02383e38eSiva Velusamy } 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.newLine(); 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w("View", "Error while dumping hierarchy tree"); 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] getExportedPropertyFields(Class<?> klass) { 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sFieldsForClasses == null) { 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sFieldsForClasses = new HashMap<Class<?>, Field[]>(); 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 997c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 998c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 999c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1000c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = sFieldsForClasses; 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 100899562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final ArrayList<Field> declaredFields = new ArrayList(); 1009721fc2adf4d4d5b890b12cb2067db10e78888abaAlan Viverette klass.getDeclaredFieldsUnchecked(false, declaredFields); 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 101199562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final ArrayList<Field> foundFields = new ArrayList<Field>(); 101299562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final int count = declaredFields.size(); 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 101499562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final Field field = declaredFields.get(i); 101599562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette 101699562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette // Ensure the field type can be resolved. 101799562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette try { 101899562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette field.getType(); 101999562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette } catch (NoClassDefFoundError e) { 102099562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette continue; 102199562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette } 102299562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(ExportedProperty.class)) { 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 102688b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy sAnnotations.put(field, field.getAnnotation(ExportedProperty.class)); 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] getExportedPropertyMethods(Class<?> klass) { 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sMethodsForClasses == null) { 1038c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sMethodsForClasses = new HashMap<Class<?>, Method[]>(100); 1039c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1040c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (sAnnotations == null) { 1041c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512); 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1043c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = sMethodsForClasses; 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 105199562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final ArrayList<Method> declaredMethods = new ArrayList(); 1052721fc2adf4d4d5b890b12cb2067db10e78888abaAlan Viverette klass.getDeclaredMethodsUnchecked(false, declaredMethods); 1053a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 105499562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final ArrayList<Method> foundMethods = new ArrayList<Method>(); 105599562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final int count = declaredMethods.size(); 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 105799562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette final Method method = declaredMethods.get(i); 105899562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette 105999562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette // Ensure the method return and parameter types can be resolved. 106099562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette try { 106199562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette method.getReturnType(); 106299562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette method.getParameterTypes(); 106399562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette } catch (NoClassDefFoundError e) { 106499562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette continue; 106599562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette } 106699562fbbb40c72722468e5dc8c84b3e28494a20fAlan Viverette 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 1068c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.isAnnotationPresent(ExportedProperty.class) && 1069c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project method.getReturnType() != Void.class) { 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 107288b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy sAnnotations.put(method, method.getAnnotation(ExportedProperty.class)); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1082105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1083105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out) throws IOException { 1084105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1085105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, view, out, ""); 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1088105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void dumpViewProperties(Context context, Object view, 1089105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BufferedWriter out, String prefix) throws IOException { 1090105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1091dfab363807b3b44be4032e410f016e0a0d018426Romain Guy if (view == null) { 1092dfab363807b3b44be4032e410f016e0a0d018426Romain Guy out.write(prefix + "=4,null "); 1093dfab363807b3b44be4032e410f016e0a0d018426Romain Guy return; 1094dfab363807b3b44be4032e410f016e0a0d018426Romain Guy } 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1096dfab363807b3b44be4032e410f016e0a0d018426Romain Guy Class<?> klass = view.getClass(); 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 1098105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportFields(context, view, out, klass, prefix); 1099105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportMethods(context, view, out, klass, prefix); 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project klass = klass.getSuperclass(); 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (klass != Object.class); 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1103a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 110497e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen private static Object callMethodOnAppropriateTheadBlocking(final Method method, 110597e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen final Object object) throws IllegalAccessException, InvocationTargetException, 110697e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen TimeoutException { 110797e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen if (!(object instanceof View)) { 110897e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen return method.invoke(object, (Object[]) null); 110997e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } 111097e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen 111197e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen final View view = (View) object; 111297e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen Callable<Object> callable = new Callable<Object>() { 11134597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda @Override 11144597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda public Object call() throws IllegalAccessException, InvocationTargetException { 11154597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda return method.invoke(view, (Object[]) null); 11164597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 111797e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen }; 111897e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen FutureTask<Object> future = new FutureTask<Object>(callable); 111997e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen // Try to use the handler provided by the view 112097e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen Handler handler = view.getHandler(); 112197e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen // Fall back on using the main thread 112297e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen if (handler == null) { 112397e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen handler = new Handler(android.os.Looper.getMainLooper()); 112497e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } 112597e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen handler.post(future); 112697e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen while (true) { 112797e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen try { 112897e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen return future.get(CAPTURE_TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS); 112997e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } catch (ExecutionException e) { 113097e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen Throwable t = e.getCause(); 113197e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen if (t instanceof IllegalAccessException) { 113297e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen throw (IllegalAccessException)t; 113397e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } 113497e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen if (t instanceof InvocationTargetException) { 113597e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen throw (InvocationTargetException)t; 113697e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } 113797e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen throw new RuntimeException("Unexpected exception", t); 113897e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } catch (InterruptedException e) { 113997e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen // Call get again 114097e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } catch (CancellationException e) { 114197e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen throw new RuntimeException("Unexpected cancellation exception", e); 114297e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } 114397e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } 114497e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } 114597e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen 11464597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda private static String formatIntToHexString(int value) { 11474597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda return "0x" + Integer.toHexString(value).toUpperCase(); 11484597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 11494597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 1150105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportMethods(Context context, Object view, BufferedWriter out, 1151105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = getExportedPropertyMethods(klass); 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 115997e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen Object methodValue = callMethodOnAppropriateTheadBlocking(method, view); 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 1161bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev final ExportedProperty property = sAnnotations.get(method); 116291a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev String categoryPrefix = 116391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev property.category().length() != 0 ? property.category() + ":" : ""; 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (returnType == int.class) { 1166105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = (Integer) methodValue; 1168105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project methodValue = resolveId(context, id); 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1170809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1171809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1172809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = (Integer) methodValue; 117391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = 117491a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev categoryPrefix + prefix + method.getName() + '_'; 1175809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1176809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1177809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = (Integer) methodValue; 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mapped = false; 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapper = mapping[j]; 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapper.from() == intValue) { 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = mapper.to(); 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mapped = true; 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mapped) { 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methodValue = intValue; 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1197c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (returnType == int[].class) { 1198c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) methodValue; 119991a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = categoryPrefix + prefix + method.getName() + '_'; 1200c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = "()"; 1201c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1202105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1203bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev 120448520210958b07d99791779abd52ba8034f3aa21Jon Miranda continue; 1205836c0a8b949d71293c996761691e065f0651acefJon Miranda } else if (returnType == String[].class) { 1206836c0a8b949d71293c996761691e065f0651acefJon Miranda final String[] array = (String[]) methodValue; 1207836c0a8b949d71293c996761691e065f0651acefJon Miranda if (property.hasAdjacentMapping() && array != null) { 1208836c0a8b949d71293c996761691e065f0651acefJon Miranda for (int j = 0; j < array.length; j += 2) { 1209836c0a8b949d71293c996761691e065f0651acefJon Miranda if (array[j] != null) { 1210836c0a8b949d71293c996761691e065f0651acefJon Miranda writeEntry(out, categoryPrefix + prefix, array[j], "()", 1211836c0a8b949d71293c996761691e065f0651acefJon Miranda array[j + 1] == null ? "null" : array[j + 1]); 1212836c0a8b949d71293c996761691e065f0651acefJon Miranda } 1213836c0a8b949d71293c996761691e065f0651acefJon Miranda 1214836c0a8b949d71293c996761691e065f0651acefJon Miranda } 1215836c0a8b949d71293c996761691e065f0651acefJon Miranda } 1216836c0a8b949d71293c996761691e065f0651acefJon Miranda 1217836c0a8b949d71293c996761691e065f0651acefJon Miranda continue; 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!returnType.isPrimitive()) { 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1220105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project dumpViewProperties(context, methodValue, out, prefix + property.prefix()); 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 122591a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev writeEntry(out, categoryPrefix + prefix, method.getName(), "()", methodValue); 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InvocationTargetException e) { 122897e8f6280484e3cde946b242982a0ddf95dae70eKristian Monsen } catch (TimeoutException e) { 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1233105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportFields(Context context, Object view, BufferedWriter out, 1234105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Class<?> klass, String prefix) throws IOException { 1235105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = getExportedPropertyFields(klass); 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //noinspection EmptyCatchBlock 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = null; 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> type = field.getType(); 1246bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev final ExportedProperty property = sAnnotations.get(field); 124791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev String categoryPrefix = 124891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev property.category().length() != 0 ? property.category() + ":" : ""; 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1250b365f91688dc081b3bcea82377ce0e94c09124ffFabrice Di Meglio if (type == int.class || type == byte.class) { 1251105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (property.resolveId() && context != null) { 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int id = field.getInt(view); 1253105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project fieldValue = resolveId(context, id); 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1255809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString[] flagsMapping = property.flagMapping(); 1256809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if (flagsMapping.length > 0) { 1257809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int intValue = field.getInt(view); 125891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = 125991a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev categoryPrefix + prefix + field.getName() + '_'; 1260809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); 1261809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1262809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString[] mapping = property.mapping(); 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapping.length > 0) { 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int intValue = field.getInt(view); 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mappingCount = mapping.length; 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mappingCount; j++) { 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final IntToString mapped = mapping[j]; 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mapped.from() == intValue) { 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = mapped.to(); 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = intValue; 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12794597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda 12804597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda if (property.formatToHexString()) { 12814597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda fieldValue = field.get(view); 12824597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda if (type == int.class) { 12834597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda fieldValue = formatIntToHexString((Integer) fieldValue); 12844597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } else if (type == byte.class) { 12854597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda fieldValue = "0x" + Byte.toHexString((Byte) fieldValue, true); 12864597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 12874597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1289c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else if (type == int[].class) { 1290c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int[] array = (int[]) field.get(view); 129191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev final String valuePrefix = categoryPrefix + prefix + field.getName() + '_'; 1292c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final String suffix = ""; 1293c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1294105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project exportUnrolledArray(context, out, property, array, valuePrefix, suffix); 1295c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 129648520210958b07d99791779abd52ba8034f3aa21Jon Miranda continue; 1297836c0a8b949d71293c996761691e065f0651acefJon Miranda } else if (type == String[].class) { 1298836c0a8b949d71293c996761691e065f0651acefJon Miranda final String[] array = (String[]) field.get(view); 1299836c0a8b949d71293c996761691e065f0651acefJon Miranda if (property.hasAdjacentMapping() && array != null) { 1300836c0a8b949d71293c996761691e065f0651acefJon Miranda for (int j = 0; j < array.length; j += 2) { 1301836c0a8b949d71293c996761691e065f0651acefJon Miranda if (array[j] != null) { 1302836c0a8b949d71293c996761691e065f0651acefJon Miranda writeEntry(out, categoryPrefix + prefix, array[j], "", 1303836c0a8b949d71293c996761691e065f0651acefJon Miranda array[j + 1] == null ? "null" : array[j + 1]); 1304836c0a8b949d71293c996761691e065f0651acefJon Miranda } 1305836c0a8b949d71293c996761691e065f0651acefJon Miranda } 1306836c0a8b949d71293c996761691e065f0651acefJon Miranda } 1307836c0a8b949d71293c996761691e065f0651acefJon Miranda 1308836c0a8b949d71293c996761691e065f0651acefJon Miranda continue; 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!type.isPrimitive()) { 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.deepExport()) { 1311dfab363807b3b44be4032e410f016e0a0d018426Romain Guy dumpViewProperties(context, field.get(view), out, prefix + 1312dfab363807b3b44be4032e410f016e0a0d018426Romain Guy property.prefix()); 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue == null) { 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fieldValue = field.get(view); 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 132191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev writeEntry(out, categoryPrefix + prefix, field.getName(), "", fieldValue); 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1327c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeEntry(BufferedWriter out, String prefix, String name, 1328c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String suffix, Object value) throws IOException { 1329c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1330c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(prefix); 1331c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(name); 1332c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(suffix); 1333c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("="); 1334c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeValue(out, value); 1335c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write(' '); 1336c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1337c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1338809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping, 1339809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy int intValue, String prefix) throws IOException { 1340809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1341809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final int count = mapping.length; 1342809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy for (int j = 0; j < count; j++) { 1343809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final FlagToString flagMapping = mapping[j]; 1344809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final boolean ifTrue = flagMapping.outputIf(); 13455bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final int maskResult = intValue & flagMapping.mask(); 13465bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy final boolean test = maskResult == flagMapping.equals(); 1347809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy if ((test && ifTrue) || (!test && !ifTrue)) { 1348809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy final String name = flagMapping.name(); 13494597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda final String value = formatIntToHexString(maskResult); 1350809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy writeEntry(out, prefix, name, "", value); 1351809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1352809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1353809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy } 1354809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy 1355105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static void exportUnrolledArray(Context context, BufferedWriter out, 1356c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project ExportedProperty property, int[] array, String prefix, String suffix) 1357c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project throws IOException { 1358c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1359c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] indexMapping = property.indexMapping(); 1360c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasIndexMapping = indexMapping.length > 0; 1361c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1362c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString[] mapping = property.mapping(); 1363c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final boolean hasMapping = mapping.length > 0; 1364c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1365105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final boolean resolveId = property.resolveId() && context != null; 1366c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int valuesCount = array.length; 1367c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1368c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int j = 0; j < valuesCount; j++) { 1369c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project String name; 1370a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy String value = null; 1371c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1372c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final int intValue = array[j]; 1373c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1374c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = String.valueOf(j); 1375c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasIndexMapping) { 1376c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = indexMapping.length; 1377c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1378c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = indexMapping[k]; 1379c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == j) { 1380c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project name = mapped.to(); 1381c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1382c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1383c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1384c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1385c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1386c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (hasMapping) { 1387c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mappingCount = mapping.length; 1388c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project for (int k = 0; k < mappingCount; k++) { 1389c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project final IntToString mapped = mapping[k]; 1390c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mapped.from() == intValue) { 1391c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project value = mapped.to(); 1392c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project break; 1393c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1394c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1395c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1396c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1397c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (resolveId) { 1398a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy if (value == null) value = (String) resolveId(context, intValue); 1399a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 1400a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy value = String.valueOf(intValue); 1401c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1402c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1403c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project writeEntry(out, prefix, name, suffix, value); 1404c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1405c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1406c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1407237c1ceea36024cf4194212e713806e3ce8a1c49Romain Guy static Object resolveId(Context context, int id) { 1408c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Object fieldValue; 1409105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project final Resources resources = context.getResources(); 1410c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (id >= 0) { 1411c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project try { 1412c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = resources.getResourceTypeName(id) + '/' + 1413c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project resources.getResourceEntryName(id); 1414c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } catch (Resources.NotFoundException e) { 14154597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda fieldValue = "id/" + formatIntToHexString(id); 1416c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1417c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1418c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project fieldValue = "NO_ID"; 1419c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1420c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return fieldValue; 1421c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1422c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1423c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project private static void writeValue(BufferedWriter out, Object value) throws IOException { 1424c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (value != null) { 142597723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy String output = "[EXCEPTION]"; 142697723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy try { 142797723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy output = value.toString().replace("\n", "\\n"); 142897723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy } finally { 142997723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy out.write(String.valueOf(output.length())); 143097723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy out.write(","); 143197723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy out.write(output); 143297723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy } 1433c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 1434c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project out.write("4,null"); 1435c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1436c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 1437c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Field[] capturedViewGetPropertyFields(Class<?> klass) { 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewFieldsForClasses == null) { 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>(); 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses; 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field[] fields = map.get(klass); 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields != null) { 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Field> foundFields = new ArrayList<Field>(); 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = klass.getFields(); 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (field.isAnnotationPresent(CapturedViewProperty.class)) { 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project field.setAccessible(true); 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundFields.add(field); 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields = foundFields.toArray(new Field[foundFields.size()]); 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, fields); 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fields; 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Method[] capturedViewGetPropertyMethods(Class<?> klass) { 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCapturedViewMethodsForClasses == null) { 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>(); 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses; 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method[] methods = map.get(klass); 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methods != null) { 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Method> foundMethods = new ArrayList<Method>(); 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = klass.getMethods(); 1480a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 1483a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final Method method = methods[i]; 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (method.getParameterTypes().length == 0 && 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.isAnnotationPresent(CapturedViewProperty.class) && 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.getReturnType() != Void.class) { 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project method.setAccessible(true); 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foundMethods.add(method); 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project methods = foundMethods.toArray(new Method[foundMethods.size()]); 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(klass, methods); 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return methods; 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1497a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 1498a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy private static String capturedViewExportMethods(Object obj, Class<?> klass, 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prefix) { 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1504a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method[] methods = capturedViewGetPropertyMethods(klass); 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = methods.length; 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Method method = methods[i]; 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object methodValue = method.invoke(obj, (Object[]) null); 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Class<?> returnType = method.getReturnType(); 1514a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class); 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (property.retrieveReturn()) { 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we are interested in the second level data only 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#")); 1519a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } else { 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(method.getName()); 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("()="); 1523a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (methodValue != null) { 1525a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy final String value = methodValue.toString().replace("\n", "\\n"); 1526a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(value); 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("; "); 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15324597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } catch (IllegalAccessException e) { 15334597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda //Exception IllegalAccess, it is OK here 15344597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda //we simply ignore this method 15354597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } catch (InvocationTargetException e) { 15364597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda //Exception InvocationTarget, it is OK here 15374597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda //we simply ignore this method 15384597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda } 1539a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy } 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) { 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (obj == null) { 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "null"; 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1547a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field[] fields = capturedViewGetPropertyFields(klass); 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = fields.length; 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Field field = fields[i]; 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object fieldValue = field.get(obj); 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(prefix); 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(field.getName()); 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("="); 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fieldValue != null) { 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String value = fieldValue.toString().replace("\n", "\\n"); 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(value); 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append("null"); 15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(' '); 15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalAccessException e) { 1569a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy //Exception IllegalAccess, it is OK here 15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //we simply ignore this field 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sb.toString(); 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1575a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1577a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * Dump view info for id based instrument test generation 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (and possibly further data analysis). The results are dumped 1579a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy * to the log. 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tag for log 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param view for dump 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1583a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy public static void dumpCapturedView(String tag, Object view) { 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class<?> klass = view.getClass(); 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(klass.getName() + ": "); 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(capturedViewExportFields(view, klass, "")); 1587a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy sb.append(capturedViewExportMethods(view, klass, "")); 1588a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy Log.d(tag, sb.toString()); 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1590f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1591f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy /** 1592f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy * Invoke a particular method on given view. 1593f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy * The given method is always invoked on the UI thread. The caller thread will stall until the 1594f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy * method invocation is complete. Returns an object equal to the result of the method 1595f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy * invocation, null if the method is declared to return void 1596f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy * @throws Exception if the method invocation caused any exception 1597f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy * @hide 1598f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy */ 1599f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy public static Object invokeViewMethod(final View view, final Method method, 1600f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy final Object[] args) { 1601f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy final CountDownLatch latch = new CountDownLatch(1); 1602f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy final AtomicReference<Object> result = new AtomicReference<Object>(); 1603f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy final AtomicReference<Throwable> exception = new AtomicReference<Throwable>(); 1604f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1605f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy view.post(new Runnable() { 1606f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy @Override 1607f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy public void run() { 1608f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy try { 1609f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy result.set(method.invoke(view, args)); 1610f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } catch (InvocationTargetException e) { 1611f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy exception.set(e.getCause()); 1612f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } catch (Exception e) { 1613f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy exception.set(e); 1614f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 1615f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1616f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy latch.countDown(); 1617f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 1618f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy }); 1619f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1620f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy try { 1621f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy latch.await(); 1622f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } catch (InterruptedException e) { 1623f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy throw new RuntimeException(e); 1624f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 1625f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1626f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy if (exception.get() != null) { 1627f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy throw new RuntimeException(exception.get()); 1628f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 1629f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1630f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy return result.get(); 1631f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 1632f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1633f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy /** 1634f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy * @hide 1635f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy */ 1636f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy public static void setLayoutParameter(final View view, final String param, final int value) 1637f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy throws NoSuchFieldException, IllegalAccessException { 1638f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy final ViewGroup.LayoutParams p = view.getLayoutParams(); 1639f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy final Field f = p.getClass().getField(param); 1640f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy if (f.getType() != int.class) { 1641f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy throw new RuntimeException("Only integer layout parameters can be set. Field " 16424597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda + param + " is of type " + f.getType().getSimpleName()); 1643f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 1644f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1645f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy f.set(p, Integer.valueOf(value)); 1646f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy 1647f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy view.post(new Runnable() { 1648f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy @Override 1649f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy public void run() { 1650f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy view.setLayoutParams(p); 1651f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 1652f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy }); 1653f9455fafb690f23cee9cc9a59bfb68f31e695990Siva Velusamy } 16544597e9806948256e82b9f1cdaa7019cbbd912668Jon Miranda}