ViewDebug.java revision 13b907353f18215b52b5ceda24bbf520d91d72a1
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;
25223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport android.os.RemoteException;
26f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.util.DisplayMetrics;
27f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport android.util.Log;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.BufferedOutputStream;
30f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.BufferedWriter;
31223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guyimport java.io.ByteArrayOutputStream;
32f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.DataOutputStream;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream;
35f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.io.OutputStreamWriter;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.ElementType;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Retention;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.RetentionPolicy;
39f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.annotation.Target;
40f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.reflect.AccessibleObject;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.InvocationTargetException;
43f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.lang.reflect.Method;
44f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.ArrayList;
45f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.HashMap;
46f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.concurrent.CountDownLatch;
47f9284695e8c10dad4daf3d2c84f607483bcb56caRomain Guyimport java.util.concurrent.TimeUnit;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various debugging/tracing tools related to {@link View} and the view hierarchy.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ViewDebug {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This flag is now unused
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final boolean TRACE_HIERARCHY = false;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6013b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This flag is now unused
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final boolean TRACE_RECYCLER = false;
64a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
662c095f367779ef32130c72849936a2e3013c8492Christopher Tate     * Enables detailed logging of drag/drop operations.
672c095f367779ef32130c72849936a2e3013c8492Christopher Tate     * @hide
682c095f367779ef32130c72849936a2e3013c8492Christopher Tate     */
69994ef9296a00523de1df424b4b760b4416ead58bChristopher Tate    public static final boolean DEBUG_DRAG = false;
702c095f367779ef32130c72849936a2e3013c8492Christopher Tate
712c095f367779ef32130c72849936a2e3013c8492Christopher Tate    /**
724e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     * Enables logging of factors that affect the latency and responsiveness of an application.
734e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     *
744e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     * Logs the relative difference between the time an event was created and the time it
754e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     * was delivered.
764e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     *
7795db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown     * Logs the time spent waiting for Surface.lockCanvas(), Surface.unlockCanvasAndPost()
7895db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown     * or eglSwapBuffers().  This is time that the event loop spends blocked and unresponsive.
7995db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown     * Ideally, drawing and animations should be perfectly synchronized with VSYNC so that
8095db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown     * dequeuing and queueing buffers is instantaneous.
814e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     *
8295db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown     * Logs the time spent in ViewRoot.performTraversals() and ViewRoot.performDraw().
834e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     * @hide
844e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown     */
854e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown    public static final boolean DEBUG_LATENCY = false;
864e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown
8795db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown    /** @hide */
8895db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown    public static final String DEBUG_LATENCY_TAG = "ViewLatency";
8995db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
904e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown    /**
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This annotation can be used to mark fields and methods to be dumped by
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the view server. Only non-void methods with no arguments can be annotated
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * by this annotation.
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.FIELD, ElementType.METHOD })
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface ExportedProperty {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * When resolveId is true, and if the annotated field/method return value
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * is an int, the value is converted to an Android's resource name.
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the property's value must be transformed into an Android
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *         resource name, false otherwise
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean resolveId() default false;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * A mapping can be defined to map int values to specific strings. For
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * instance, View.getVisibility() returns 0, 4 or 8. However, these values
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * actually mean VISIBLE, INVISIBLE and GONE. A mapping can be used to see
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * these human readable values:
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <pre>
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @ViewDebug.ExportedProperty(mapping = {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 0, to = "VISIBLE"),
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 4, to = "INVISIBLE"),
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 8, to = "GONE")
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * })
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * public int getVisibility() { ...
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <pre>
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An array of int to String mappings
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @see android.view.ViewDebug.IntToString
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntToString[] mapping() default { };
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * A mapping can be defined to map array indices to specific strings.
130c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * A mapping can be used to see human readable values for the indices
131c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * of an array:
132c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * <pre>
134809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @ViewDebug.ExportedProperty(indexMapping = {
135c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 0, to = "INVALID"),
136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 1, to = "FIRST"),
137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 2, to = "SECOND")
138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * })
139c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * private int[] mElements;
140c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * <pre>
141c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
142c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @return An array of int to String mappings
143c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
144c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @see android.view.ViewDebug.IntToString
145c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @see #mapping()
146c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         */
147c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        IntToString[] indexMapping() default { };
148c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
149c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        /**
150809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * A flags mapping can be defined to map flags encoded in an integer to
151809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * specific strings. A mapping can be used to see human readable values
152809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * for the flags of an integer:
153809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
154809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <pre>
155809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @ViewDebug.ExportedProperty(flagMapping = {
156809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"),
157809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"),
158809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * })
159809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * private int mFlags;
160809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <pre>
161809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
162809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * A specified String is output when the following is true:
163a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         *
164809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An array of int to String mappings
165809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
166809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        FlagToString[] flagMapping() default { };
167809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
168809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * When deep export is turned on, this property is not dumped. Instead, the
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * properties contained in this property are dumped. Each child property
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * is prefixed with the name of this property.
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the properties of this property should be dumped
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
175a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * @see #prefix()
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean deepExport() default false;
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The prefix to use on child properties when deep export is enabled
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return a prefix as a String
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @see #deepExport()
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String prefix() default "";
187bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
188bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev        /**
189bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         * Specifies the category the property falls into, such as measurement,
190bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         * layout, drawing, etc.
191bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         *
192bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         * @return the category as String
193bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         */
194bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev        String category() default "";
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defines a mapping from an int value to a String. Such a mapping can be used
199f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa     * in an @ExportedProperty to provide more meaningful values to the end user.
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.view.ViewDebug.ExportedProperty
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.TYPE })
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface IntToString {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The original int value to map to a String.
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An arbitrary int value.
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int from();
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The String to use in place of the original int value.
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An arbitrary non-null String.
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String to();
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
220809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
221809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    /**
222f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa     * Defines a mapping from a flag to a String. Such a mapping can be used
223f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa     * in an @ExportedProperty to provide more meaningful values to the end user.
224809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     *
225809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     * @see android.view.ViewDebug.ExportedProperty
226809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     */
227809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    @Target({ ElementType.TYPE })
228809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    @Retention(RetentionPolicy.RUNTIME)
229809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    public @interface FlagToString {
230809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
231809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The mask to apply to the original value.
232809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
233809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary int value.
234809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
235809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        int mask();
236809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
237809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
238809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The value to compare to the result of:
239809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <code>original value &amp; {@link #mask()}</code>.
240809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
241809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary value.
242809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
243809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        int equals();
244809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
245809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
246809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The String to use in place of the original int value.
247809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
248809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary non-null String.
249809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
250809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        String name();
251809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
252809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
253809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * Indicates whether to output the flag when the test is true,
254809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * or false. Defaults to true.
255809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
256809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        boolean outputIf() default true;
257809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    }
258809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This annotation can be used to mark fields and methods to be dumped when
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the view is captured. Methods with this annotation must have no arguments
262f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler     * and must return a valid type of data.
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.FIELD, ElementType.METHOD })
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface CapturedViewProperty {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
268a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * When retrieveReturn is true, we need to retrieve second level methods
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod()
270a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * we will set retrieveReturn = true on the annotation of
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * myView.getFirstLevelMethod()
272a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * @return true if we need the second level methods
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
274a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        boolean retrieveReturn() default false;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
276a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Maximum delay in ms after which we stop trying to capture a View's drawing
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int CAPTURE_TIMEOUT = 4000;
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE";
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_DUMP = "DUMP";
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE";
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
287c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static final String REMOTE_PROFILE = "PROFILE";
288223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
289ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase    private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Field[]> sFieldsForClasses;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Method[]> sMethodsForClasses;
293c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static HashMap<AccessibleObject, ExportedProperty> sAnnotations;
294c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
29613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This enum is now unused
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
29813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public enum HierarchyTraceType {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE,
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE_CHILD,
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE_CHILD_IN_PARENT,
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        REQUEST_LAYOUT,
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ON_LAYOUT,
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ON_MEASURE,
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        DRAW,
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BUILD_CACHE
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
31113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This enum is now unused
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
31313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public enum RecyclerTraceType {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        NEW_VIEW,
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BIND_VIEW,
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        RECYCLE_FROM_ACTIVE_HEAP,
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        RECYCLE_FROM_SCRAP_HEAP,
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MOVE_TO_SCRAP_HEAP,
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MOVE_FROM_ACTIVE_TO_SCRAP_HEAP
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of instanciated Views.
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of Views instanciated in the current process.
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static long getViewInstanceCount() {
331c21550a8d1dfc9e5359fe994cb48049a0bd4c82cBrian Carlstrom        return Debug.countInstancesOfClass(View.class);
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
335c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato     * Returns the number of instanciated ViewAncestors.
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
337c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato     * @return The number of ViewAncestors instanciated in the current process.
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
34165b345fa22b878e141b8fd8ece9c208df00fa40fRomain Guy    public static long getViewRootImplCount() {
3426dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn        return Debug.countInstancesOfClass(ViewRootImpl.class);
343a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    }
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
34613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
34813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
34913b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings({ "UnusedParameters", "deprecation" })
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void trace(View view, RecyclerTraceType type, int... parameters) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
35713b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings("UnusedParameters")
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void startRecyclerTracing(String prefix, View view) {
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
36213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
36413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
36513b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings("UnusedParameters")
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stopRecyclerTracing() {
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
37013b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
37213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
37313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings({ "UnusedParameters", "deprecation" })
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void trace(View view, HierarchyTraceType type) {
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
37813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
38013b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
38113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings("UnusedParameters")
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void startHierarchyTracing(String prefix, View view) {
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
38613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
38813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stopHierarchyTracing() {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
391a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static void dispatchCommand(View view, String command, String parameters,
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OutputStream clientStream) throws IOException {
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Paranoid but safe...
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        view = view.getRootView();
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) {
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dump(view, clientStream);
400223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) {
401223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            captureLayers(view, new DataOutputStream(clientStream));
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final String[] params = parameters.split(" ");
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                capture(view, clientStream, params[0]);
406ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase            } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
407ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase                outputDisplayList(view, params[0]);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate(view, params[0]);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requestLayout(view, params[0]);
412c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) {
413c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                profile(view, clientStream, params[0]);
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
418c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static View findView(View root, String parameter) {
419c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        // Look by type/hashcode
420c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (parameter.indexOf('@') != -1) {
421c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final String[] ids = parameter.split("@");
422c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final String className = ids[0];
423236092a36216c79507ec19eb207831810caced19Romain Guy            final int hashCode = (int) Long.parseLong(ids[1], 16);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
425c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            View view = root.getRootView();
426c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (view instanceof ViewGroup) {
427c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                return findView((ViewGroup) view, className, hashCode);
428c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
429c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
430c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            // Look by id
431c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final int id = root.getResources().getIdentifier(parameter, null, null);
432c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            return root.getRootView().findViewById(id);
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void invalidate(View root, String parameter) {
439c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            view.postInvalidate();
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void requestLayout(View root, String parameter) {
446c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            root.post(new Runnable() {
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public void run() {
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    view.requestLayout();
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            });
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
456c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void profile(View root, OutputStream clientStream, String parameter)
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
460c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        BufferedWriter out = null;
461c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        try {
462c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024);
463c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
464c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (view != null) {
465f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                profileViewAndChildren(view, out);
466f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            } else {
467f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                out.write("-1 -1 -1");
468f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                out.newLine();
469f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            }
470f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            out.write("DONE.");
471f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            out.newLine();
472f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        } catch (Exception e) {
473f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            android.util.Log.w("View", "Problem profiling the view:", e);
474f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        } finally {
475f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            if (out != null) {
476f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                out.close();
477f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            }
478f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        }
479f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev    }
480c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
481f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev    private static void profileViewAndChildren(final View view, BufferedWriter out)
482f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            throws IOException {
483c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        profileViewAndChildren(view, out, true);
484c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev    }
485f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev
486c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev    private static void profileViewAndChildren(final View view, BufferedWriter out, boolean root)
487c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev            throws IOException {
488f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev
489c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        long durationMeasure =
490c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                (root || (view.mPrivateFlags & View.MEASURED_DIMENSION_SET) != 0) ? profileViewOperation(
491c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        view, new ViewOperation<Void>() {
492c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public Void[] pre() {
493c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                forceLayout(view);
494c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                return null;
495c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
496c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
497c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            private void forceLayout(View view) {
498c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                view.forceLayout();
499c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                if (view instanceof ViewGroup) {
500c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    ViewGroup group = (ViewGroup) view;
501c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    final int count = group.getChildCount();
502c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    for (int i = 0; i < count; i++) {
503c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                        forceLayout(group.getChildAt(i));
504c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    }
505c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                }
506c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
507c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
508c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void run(Void... data) {
509c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
510c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
511c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
512c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void post(Void... data) {
513c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
514c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        })
515c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        : 0;
516c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        long durationLayout =
517c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                (root || (view.mPrivateFlags & View.LAYOUT_REQUIRED) != 0) ? profileViewOperation(
518c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        view, new ViewOperation<Void>() {
519c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public Void[] pre() {
520c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                return null;
521c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
522c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
523c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void run(Void... data) {
524c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
525c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
526c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
527c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void post(Void... data) {
528c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
529c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        }) : 0;
530c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        long durationDraw =
531bef337f516eafaee8f3891e22688b74388570317Konstantin Lopyrev                (root || !view.willNotDraw() || (view.mPrivateFlags & View.DRAWN) != 0) ? profileViewOperation(
532bef337f516eafaee8f3891e22688b74388570317Konstantin Lopyrev                        view,
533c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        new ViewOperation<Object>() {
534c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public Object[] pre() {
535c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                final DisplayMetrics metrics =
536daf98e941e140e8739458126640183b9f296a2abChet Haase                                        (view != null && view.getResources() != null) ?
537daf98e941e140e8739458126640183b9f296a2abChet Haase                                                view.getResources().getDisplayMetrics() : null;
538daf98e941e140e8739458126640183b9f296a2abChet Haase                                final Bitmap bitmap = metrics != null ?
539c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                        Bitmap.createBitmap(metrics.widthPixels,
540daf98e941e140e8739458126640183b9f296a2abChet Haase                                                metrics.heightPixels, Bitmap.Config.RGB_565) : null;
541daf98e941e140e8739458126640183b9f296a2abChet Haase                                final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null;
542c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                return new Object[] {
543c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                        bitmap, canvas
544c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                };
545c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
546c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
547c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void run(Object... data) {
548daf98e941e140e8739458126640183b9f296a2abChet Haase                                if (data[1] != null) {
549daf98e941e140e8739458126640183b9f296a2abChet Haase                                    view.draw((Canvas) data[1]);
550daf98e941e140e8739458126640183b9f296a2abChet Haase                                }
551c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
552c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
553c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void post(Object... data) {
5546311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn                                if (data[1] != null) {
5556311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn                                    ((Canvas) data[1]).setBitmap(null);
5566311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn                                }
557daf98e941e140e8739458126640183b9f296a2abChet Haase                                if (data[0] != null) {
558daf98e941e140e8739458126640183b9f296a2abChet Haase                                    ((Bitmap) data[0]).recycle();
559daf98e941e140e8739458126640183b9f296a2abChet Haase                                }
560c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
561c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        }) : 0;
562f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(String.valueOf(durationMeasure));
563f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(' ');
564f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(String.valueOf(durationLayout));
565f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(' ');
566f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(String.valueOf(durationDraw));
567f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.newLine();
568f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        if (view instanceof ViewGroup) {
569f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            ViewGroup group = (ViewGroup) view;
570f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            final int count = group.getChildCount();
571f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            for (int i = 0; i < count; i++) {
572c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                profileViewAndChildren(group.getChildAt(i), out, false);
573c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
574c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
575c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
576c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
577c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    interface ViewOperation<T> {
578c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        T[] pre();
579c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        void run(T... data);
580c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        void post(T... data);
581c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
582c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
583c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final CountDownLatch latch = new CountDownLatch(1);
585c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final long[] duration = new long[1];
586c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
587c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        view.post(new Runnable() {
588c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            public void run() {
589c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                try {
590c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    T[] data = operation.pre();
591c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    long start = Debug.threadCpuTimeNanos();
59288b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                    //noinspection unchecked
593c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    operation.run(data);
594c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    duration[0] = Debug.threadCpuTimeNanos() - start;
59588b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                    //noinspection unchecked
596c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    operation.post(data);
597c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } finally {
598c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    latch.countDown();
599c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
600c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
601c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        });
602c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
603c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        try {
604c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev            if (!latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS)) {
605c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                Log.w("View", "Could not complete the profiling of the view " + view);
606c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                return -1;
607c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev            }
608c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } catch (InterruptedException e) {
609c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            Log.w("View", "Could not complete the profiling of the view " + view);
610c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            Thread.currentThread().interrupt();
611c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            return -1;
612c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
613c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
614c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        return duration[0];
615c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
616c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
617223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    private static void captureLayers(View root, final DataOutputStream clientStream)
618223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            throws IOException {
619223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
620223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        try {
621223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            Rect outRect = new Rect();
622223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            try {
623223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                root.mAttachInfo.mSession.getDisplayFrame(root.mAttachInfo.mWindow, outRect);
624223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            } catch (RemoteException e) {
625223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                // Ignore
626223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
627223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
628223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(outRect.width());
629223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(outRect.height());
630223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
63165554f27855ce1764123604b061b10346f8b8404Romain Guy            captureViewLayer(root, clientStream, true);
632223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
633223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.write(2);
634223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        } finally {
635223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.close();
636223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
637223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    }
638223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
63965554f27855ce1764123604b061b10346f8b8404Romain Guy    private static void captureViewLayer(View view, DataOutputStream clientStream, boolean visible)
640223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            throws IOException {
641223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
64265554f27855ce1764123604b061b10346f8b8404Romain Guy        final boolean localVisible = view.getVisibility() == View.VISIBLE && visible;
64365554f27855ce1764123604b061b10346f8b8404Romain Guy
644223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        if ((view.mPrivateFlags & View.SKIP_DRAW) != View.SKIP_DRAW) {
645223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            final int id = view.getId();
646223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            String name = view.getClass().getSimpleName();
647223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            if (id != View.NO_ID) {
648223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                name = resolveId(view.getContext(), id).toString();
649223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
650223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
651223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.write(1);
652223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeUTF(name);
65365554f27855ce1764123604b061b10346f8b8404Romain Guy            clientStream.writeByte(localVisible ? 1 : 0);
654223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
655223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            int[] position = new int[2];
656223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            // XXX: Should happen on the UI thread
657223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            view.getLocationInWindow(position);
658223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
659223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(position[0]);
660223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(position[1]);
661223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.flush();
662223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
663223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            Bitmap b = performViewCapture(view, true);
664223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            if (b != null) {
665223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(b.getWidth() *
666223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                        b.getHeight() * 2);
667223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                b.compress(Bitmap.CompressFormat.PNG, 100, arrayOut);
668223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                clientStream.writeInt(arrayOut.size());
669223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                arrayOut.writeTo(clientStream);
670223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
671223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.flush();
672223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
673223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
674223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        if (view instanceof ViewGroup) {
675223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            ViewGroup group = (ViewGroup) view;
676223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            int count = group.getChildCount();
677223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
678223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            for (int i = 0; i < count; i++) {
67965554f27855ce1764123604b061b10346f8b8404Romain Guy                captureViewLayer(group.getChildAt(i), clientStream, localVisible);
680223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
681223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
682223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    }
683223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
684ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase    private static void outputDisplayList(View root, String parameter) throws IOException {
685ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase        final View view = findView(root, parameter);
6866dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn        view.getViewRootImpl().outputDisplayList(view);
687ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase    }
688ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase
689c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void capture(View root, final OutputStream clientStream, String parameter)
690c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            throws IOException {
691c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
692c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View captureView = findView(root, parameter);
693223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        Bitmap b = performViewCapture(captureView, false);
69443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev
69543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        if (b == null) {
696223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            Log.w("View", "Failed to create capture bitmap!");
69743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            // Send an empty one so that it doesn't get stuck waiting for
69843b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            // something.
69943b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            b = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
70043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        }
70143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev
70243b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        BufferedOutputStream out = null;
70343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        try {
70443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            out = new BufferedOutputStream(clientStream, 32 * 1024);
70543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            b.compress(Bitmap.CompressFormat.PNG, 100, out);
70643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            out.flush();
70743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        } finally {
70843b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            if (out != null) {
70943b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev                out.close();
71043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            }
71143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            b.recycle();
712223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
713223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    }
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
715223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    private static Bitmap performViewCapture(final View captureView, final boolean skpiChildren) {
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (captureView != null) {
717c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final CountDownLatch latch = new CountDownLatch(1);
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Bitmap[] cache = new Bitmap[1];
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
720223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            captureView.post(new Runnable() {
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public void run() {
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
723958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                        cache[0] = captureView.createSnapshot(
724223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                                Bitmap.Config.ARGB_8888, 0, skpiChildren);
725958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                    } catch (OutOfMemoryError e) {
72688b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                        Log.w("View", "Out of memory for bitmap");
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } finally {
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        latch.countDown();
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            });
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS);
735223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                return cache[0];
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (InterruptedException e) {
737c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                Log.w("View", "Could not complete the capture of the view " + captureView);
738c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                Thread.currentThread().interrupt();
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
741223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
742223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        return null;
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void dump(View root, OutputStream clientStream) throws IOException {
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BufferedWriter out = null;
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
74838e951b62ed956501b11f0715e23e3bf70942f6dRomain Guy            out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024);
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View view = root.getRootView();
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ViewGroup group = (ViewGroup) view;
752105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewHierarchyWithProperties(group.getContext(), group, out, 0);
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write("DONE.");
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.newLine();
756c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } catch (Exception e) {
757c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            android.util.Log.w("View", "Problem dumping the view:", e);
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (out != null) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.close();
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static View findView(ViewGroup group, String className, int hashCode) {
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isRequestedView(group, className, hashCode)) {
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return group;
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = group.getChildCount();
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = group.getChildAt(i);
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View found = findView((ViewGroup) view, className, hashCode);
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (found != null) {
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return found;
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (isRequestedView(view, className, hashCode)) {
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return view;
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean isRequestedView(View view, String className, int hashCode) {
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
790105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group,
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            BufferedWriter out, int level) {
792105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (!dumpViewWithProperties(context, group, out, level)) {
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = group.getChildCount();
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = group.getChildAt(i);
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
800105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1);
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
802105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewWithProperties(context, view, out, level + 1);
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
807105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static boolean dumpViewWithProperties(Context context, View view,
808105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out, int level) {
809105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < level; i++) {
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.write(' ');
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(view.getClass().getName());
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write('@');
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(Integer.toHexString(view.hashCode()));
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(' ');
818105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            dumpViewProperties(context, view, out);
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.newLine();
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w("View", "Error while dumping hierarchy tree");
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Field[] getExportedPropertyFields(Class<?> klass) {
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sFieldsForClasses == null) {
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sFieldsForClasses = new HashMap<Class<?>, Field[]>();
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
831c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (sAnnotations == null) {
832c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
833c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
834c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Field[]> map = sFieldsForClasses;
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Field[] fields = map.get(klass);
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fields != null) {
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fields;
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Field> foundFields = new ArrayList<Field>();
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = klass.getDeclaredFields();
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (field.isAnnotationPresent(ExportedProperty.class)) {
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                field.setAccessible(true);
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundFields.add(field);
85188b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                sAnnotations.put(field, field.getAnnotation(ExportedProperty.class));
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = foundFields.toArray(new Field[foundFields.size()]);
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, fields);
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fields;
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Method[] getExportedPropertyMethods(Class<?> klass) {
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sMethodsForClasses == null) {
863c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sMethodsForClasses = new HashMap<Class<?>, Method[]>(100);
864c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
865c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (sAnnotations == null) {
866c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
868c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Method[]> map = sMethodsForClasses;
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Method[] methods = map.get(klass);
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (methods != null) {
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return methods;
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Method> foundMethods = new ArrayList<Method>();
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = klass.getDeclaredMethods();
878a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
881a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            final Method method = methods[i];
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (method.getParameterTypes().length == 0 &&
883c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    method.isAnnotationPresent(ExportedProperty.class) &&
884c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    method.getReturnType() != Void.class) {
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.setAccessible(true);
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundMethods.add(method);
88788b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                sAnnotations.put(method, method.getAnnotation(ExportedProperty.class));
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = foundMethods.toArray(new Method[foundMethods.size()]);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, methods);
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return methods;
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
897105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewProperties(Context context, Object view,
898105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out) throws IOException {
899105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
900105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        dumpViewProperties(context, view, out, "");
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
903105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewProperties(Context context, Object view,
904105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out, String prefix) throws IOException {
905105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Class<?> klass = view.getClass();
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        do {
909105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            exportFields(context, view, out, klass, prefix);
910105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            exportMethods(context, view, out, klass, prefix);
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            klass = klass.getSuperclass();
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } while (klass != Object.class);
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
914a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
915105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportMethods(Context context, Object view, BufferedWriter out,
916105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Class<?> klass, String prefix) throws IOException {
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Method[] methods = getExportedPropertyMethods(klass);
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Method method = methods[i];
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection EmptyCatchBlock
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // TODO: This should happen on the UI thread
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object methodValue = method.invoke(view, (Object[]) null);
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> returnType = method.getReturnType();
928bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                final ExportedProperty property = sAnnotations.get(method);
92991a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                String categoryPrefix =
93091a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                        property.category().length() != 0 ? property.category() + ":" : "";
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (returnType == int.class) {
933bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
934105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (property.resolveId() && context != null) {
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int id = (Integer) methodValue;
936105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        methodValue = resolveId(context, id);
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
938809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        final FlagToString[] flagsMapping = property.flagMapping();
939809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        if (flagsMapping.length > 0) {
940809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final int intValue = (Integer) methodValue;
94191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                            final String valuePrefix =
94291a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                                    categoryPrefix + prefix + method.getName() + '_';
943809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
944809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        }
945809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final IntToString[] mapping = property.mapping();
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mapping.length > 0) {
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            final int intValue = (Integer) methodValue;
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            boolean mapped = false;
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            int mappingCount = mapping.length;
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int j = 0; j < mappingCount; j++) {
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                final IntToString mapper = mapping[j];
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (mapper.from() == intValue) {
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    methodValue = mapper.to();
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    mapped = true;
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    break;
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (!mapped) {
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                methodValue = intValue;
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
965c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else if (returnType == int[].class) {
966c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final int[] array = (int[]) methodValue;
96791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                    final String valuePrefix = categoryPrefix + prefix + method.getName() + '_';
968c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String suffix = "()";
969c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
970105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
971bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
972bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                    // Probably want to return here, same as for fields.
973bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                    return;
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (!returnType.isPrimitive()) {
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (property.deepExport()) {
976105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        dumpViewProperties(context, methodValue, out, prefix + property.prefix());
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
98191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                writeEntry(out, categoryPrefix + prefix, method.getName(), "()", methodValue);
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (InvocationTargetException e) {
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
988105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportFields(Context context, Object view, BufferedWriter out,
989105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Class<?> klass, String prefix) throws IOException {
990105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = getExportedPropertyFields(klass);
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection EmptyCatchBlock
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object fieldValue = null;
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> type = field.getType();
1001bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                final ExportedProperty property = sAnnotations.get(field);
100291a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                String categoryPrefix =
100391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                        property.category().length() != 0 ? property.category() + ":" : "";
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type == int.class) {
1006bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
1007105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (property.resolveId() && context != null) {
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int id = field.getInt(view);
1009105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        fieldValue = resolveId(context, id);
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
1011809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        final FlagToString[] flagsMapping = property.flagMapping();
1012809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        if (flagsMapping.length > 0) {
1013809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final int intValue = field.getInt(view);
101491a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                            final String valuePrefix =
101591a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                                    categoryPrefix + prefix + field.getName() + '_';
1016809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
1017809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        }
1018809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final IntToString[] mapping = property.mapping();
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mapping.length > 0) {
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            final int intValue = field.getInt(view);
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            int mappingCount = mapping.length;
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int j = 0; j < mappingCount; j++) {
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                final IntToString mapped = mapping[j];
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (mapped.from() == intValue) {
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    fieldValue = mapped.to();
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    break;
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (fieldValue == null) {
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                fieldValue = intValue;
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1036c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else if (type == int[].class) {
1037c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final int[] array = (int[]) field.get(view);
103891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                    final String valuePrefix = categoryPrefix + prefix + field.getName() + '_';
1039c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String suffix = "";
1040c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1041105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
1042c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1043c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    // We exit here!
1044c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    return;
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (!type.isPrimitive()) {
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (property.deepExport()) {
104791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                        dumpViewProperties(context, field.get(view), out, prefix
104891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                                + property.prefix());
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fieldValue == null) {
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldValue = field.get(view);
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
105791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                writeEntry(out, categoryPrefix + prefix, field.getName(), "", fieldValue);
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1063c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void writeEntry(BufferedWriter out, String prefix, String name,
1064c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String suffix, Object value) throws IOException {
1065c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1066c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(prefix);
1067c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(name);
1068c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(suffix);
1069c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write("=");
1070c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        writeValue(out, value);
1071c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(' ');
1072c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1073c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1074809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping,
1075809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            int intValue, String prefix) throws IOException {
1076809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
1077809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        final int count = mapping.length;
1078809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        for (int j = 0; j < count; j++) {
1079809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final FlagToString flagMapping = mapping[j];
1080809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final boolean ifTrue = flagMapping.outputIf();
10815bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy            final int maskResult = intValue & flagMapping.mask();
10825bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy            final boolean test = maskResult == flagMapping.equals();
1083809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            if ((test && ifTrue) || (!test && !ifTrue)) {
1084809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                final String name = flagMapping.name();
10855bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy                final String value = "0x" + Integer.toHexString(maskResult);
1086809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                writeEntry(out, prefix, name, "", value);
1087809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            }
1088809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        }
1089809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    }
1090809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
1091105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportUnrolledArray(Context context, BufferedWriter out,
1092c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            ExportedProperty property, int[] array, String prefix, String suffix)
1093c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            throws IOException {
1094c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1095c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final IntToString[] indexMapping = property.indexMapping();
1096c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final boolean hasIndexMapping = indexMapping.length > 0;
1097c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1098c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final IntToString[] mapping = property.mapping();
1099c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final boolean hasMapping = mapping.length > 0;
1100c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1101105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        final boolean resolveId = property.resolveId() && context != null;
1102c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final int valuesCount = array.length;
1103c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1104c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        for (int j = 0; j < valuesCount; j++) {
1105c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String name;
1106a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            String value = null;
1107c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1108c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final int intValue = array[j];
1109c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1110c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            name = String.valueOf(j);
1111c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (hasIndexMapping) {
1112c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                int mappingCount = indexMapping.length;
1113c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                for (int k = 0; k < mappingCount; k++) {
1114c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final IntToString mapped = indexMapping[k];
1115c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    if (mapped.from() == j) {
1116c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        name = mapped.to();
1117c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        break;
1118c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
1119c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
1120c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1121c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1122c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (hasMapping) {
1123c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                int mappingCount = mapping.length;
1124c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                for (int k = 0; k < mappingCount; k++) {
1125c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final IntToString mapped = mapping[k];
1126c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    if (mapped.from() == intValue) {
1127c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        value = mapped.to();
1128c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        break;
1129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
1130c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
1131c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1132c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (resolveId) {
1134a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                if (value == null) value = (String) resolveId(context, intValue);
1135a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            } else {
1136a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                value = String.valueOf(intValue);
1137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1139c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            writeEntry(out, prefix, name, suffix, value);
1140c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1141c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1142c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1143237c1ceea36024cf4194212e713806e3ce8a1c49Romain Guy    static Object resolveId(Context context, int id) {
1144c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        Object fieldValue;
1145105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        final Resources resources = context.getResources();
1146c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (id >= 0) {
1147c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            try {
1148c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                fieldValue = resources.getResourceTypeName(id) + '/' +
1149c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        resources.getResourceEntryName(id);
1150c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            } catch (Resources.NotFoundException e) {
1151c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                fieldValue = "id/0x" + Integer.toHexString(id);
1152c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1153c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
1154c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            fieldValue = "NO_ID";
1155c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1156c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        return fieldValue;
1157c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1158c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1159c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void writeValue(BufferedWriter out, Object value) throws IOException {
1160c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (value != null) {
1161c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String output = value.toString().replace("\n", "\\n");
1162c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write(String.valueOf(output.length()));
1163c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write(",");
1164c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write(output);
1165c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
1166c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write("4,null");
1167c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1168c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1169c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Field[] capturedViewGetPropertyFields(Class<?> klass) {
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCapturedViewFieldsForClasses == null) {
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>();
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses;
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Field[] fields = map.get(klass);
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fields != null) {
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fields;
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Field> foundFields = new ArrayList<Field>();
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = klass.getFields();
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (field.isAnnotationPresent(CapturedViewProperty.class)) {
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                field.setAccessible(true);
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundFields.add(field);
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = foundFields.toArray(new Field[foundFields.size()]);
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, fields);
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fields;
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Method[] capturedViewGetPropertyMethods(Class<?> klass) {
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCapturedViewMethodsForClasses == null) {
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>();
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses;
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Method[] methods = map.get(klass);
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (methods != null) {
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return methods;
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Method> foundMethods = new ArrayList<Method>();
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = klass.getMethods();
1212a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
1215a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            final Method method = methods[i];
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (method.getParameterTypes().length == 0 &&
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    method.isAnnotationPresent(CapturedViewProperty.class) &&
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    method.getReturnType() != Void.class) {
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.setAccessible(true);
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundMethods.add(method);
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = foundMethods.toArray(new Method[foundMethods.size()]);
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, methods);
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return methods;
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1229a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
1230a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    private static String capturedViewExportMethods(Object obj, Class<?> klass,
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String prefix) {
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (obj == null) {
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "null";
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1236a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder();
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Method[] methods = capturedViewGetPropertyMethods(klass);
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Method method = methods[i];
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object methodValue = method.invoke(obj, (Object[]) null);
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> returnType = method.getReturnType();
1246a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class);
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (property.retrieveReturn()) {
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    //we are interested in the second level data only
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#"));
1251a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                } else {
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(prefix);
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(method.getName());
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("()=");
1255a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (methodValue != null) {
1257a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                        final String value = methodValue.toString().replace("\n", "\\n");
1258a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                        sb.append(value);
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sb.append("null");
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("; ");
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              } catch (IllegalAccessException e) {
1265a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                  //Exception IllegalAccess, it is OK here
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  //we simply ignore this method
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              } catch (InvocationTargetException e) {
1268a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                  //Exception InvocationTarget, it is OK here
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  //we simply ignore this method
1270a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy              }
1271a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        }
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) {
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (obj == null) {
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "null";
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1279a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder();
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = capturedViewGetPropertyFields(klass);
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object fieldValue = field.get(obj);
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(prefix);
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(field.getName());
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append("=");
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fieldValue != null) {
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final String value = fieldValue.toString().replace("\n", "\\n");
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(value);
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("null");
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(' ');
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
1301a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                //Exception IllegalAccess, it is OK here
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //we simply ignore this field
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1307a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1309a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     * Dump view info for id based instrument test generation
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (and possibly further data analysis). The results are dumped
1311a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     * to the log.
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param tag for log
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view for dump
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1315a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    public static void dumpCapturedView(String tag, Object view) {
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Class<?> klass = view.getClass();
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder(klass.getName() + ": ");
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(capturedViewExportFields(view, klass, ""));
1319a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        sb.append(capturedViewExportMethods(view, klass, ""));
1320a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        Log.d(tag, sb.toString());
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1323