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 &amp; {@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}