ViewDebug.java revision 97723b2eb415d044d8dcee6a5ee3a2a3fb607b15
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    /**
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This annotation can be used to mark fields and methods to be dumped by
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the view server. Only non-void methods with no arguments can be annotated
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * by this annotation.
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.FIELD, ElementType.METHOD })
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface ExportedProperty {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * When resolveId is true, and if the annotated field/method return value
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * is an int, the value is converted to an Android's resource name.
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the property's value must be transformed into an Android
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *         resource name, false otherwise
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean resolveId() default false;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * A mapping can be defined to map int values to specific strings. For
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * instance, View.getVisibility() returns 0, 4 or 8. However, these values
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * actually mean VISIBLE, INVISIBLE and GONE. A mapping can be used to see
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * these human readable values:
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <pre>
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @ViewDebug.ExportedProperty(mapping = {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 0, to = "VISIBLE"),
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 4, to = "INVISIBLE"),
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 8, to = "GONE")
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * })
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * public int getVisibility() { ...
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <pre>
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An array of int to String mappings
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @see android.view.ViewDebug.IntToString
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntToString[] mapping() default { };
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
110c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * A mapping can be defined to map array indices to specific strings.
111c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * A mapping can be used to see human readable values for the indices
112c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * of an array:
113c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
114c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * <pre>
115809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @ViewDebug.ExportedProperty(indexMapping = {
116c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 0, to = "INVALID"),
117c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 1, to = "FIRST"),
118c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 2, to = "SECOND")
119c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * })
120c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * private int[] mElements;
121c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * <pre>
122c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
123c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @return An array of int to String mappings
124c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
125c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @see android.view.ViewDebug.IntToString
126c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @see #mapping()
127c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         */
128c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        IntToString[] indexMapping() default { };
129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
130c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        /**
131809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * A flags mapping can be defined to map flags encoded in an integer to
132809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * specific strings. A mapping can be used to see human readable values
133809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * for the flags of an integer:
134809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
135809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <pre>
136809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @ViewDebug.ExportedProperty(flagMapping = {
137809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"),
138809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"),
139809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * })
140809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * private int mFlags;
141809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <pre>
142809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
143809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * A specified String is output when the following is true:
144a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         *
145809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An array of int to String mappings
146809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
147809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        FlagToString[] flagMapping() default { };
148809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
149809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * When deep export is turned on, this property is not dumped. Instead, the
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * properties contained in this property are dumped. Each child property
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * is prefixed with the name of this property.
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the properties of this property should be dumped
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
156a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * @see #prefix()
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean deepExport() default false;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The prefix to use on child properties when deep export is enabled
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return a prefix as a String
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @see #deepExport()
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String prefix() default "";
168bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
169bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev        /**
170bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         * Specifies the category the property falls into, such as measurement,
171bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         * layout, drawing, etc.
172bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         *
173bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         * @return the category as String
174bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev         */
175bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev        String category() default "";
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defines a mapping from an int value to a String. Such a mapping can be used
180f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa     * in an @ExportedProperty to provide more meaningful values to the end user.
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.view.ViewDebug.ExportedProperty
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.TYPE })
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface IntToString {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The original int value to map to a String.
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An arbitrary int value.
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int from();
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The String to use in place of the original int value.
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An arbitrary non-null String.
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String to();
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
201809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
202809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    /**
203f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa     * Defines a mapping from a flag to a String. Such a mapping can be used
204f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa     * in an @ExportedProperty to provide more meaningful values to the end user.
205809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     *
206809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     * @see android.view.ViewDebug.ExportedProperty
207809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     */
208809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    @Target({ ElementType.TYPE })
209809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    @Retention(RetentionPolicy.RUNTIME)
210809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    public @interface FlagToString {
211809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
212809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The mask to apply to the original value.
213809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
214809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary int value.
215809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
216809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        int mask();
217809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
218809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
219809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The value to compare to the result of:
220809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <code>original value &amp; {@link #mask()}</code>.
221809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
222809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary value.
223809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
224809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        int equals();
225809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
226809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
227809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The String to use in place of the original int value.
228809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
229809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary non-null String.
230809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
231809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        String name();
232809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
233809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
234809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * Indicates whether to output the flag when the test is true,
235809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * or false. Defaults to true.
236809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
237809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        boolean outputIf() default true;
238809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    }
239809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This annotation can be used to mark fields and methods to be dumped when
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the view is captured. Methods with this annotation must have no arguments
243f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler     * and must return a valid type of data.
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.FIELD, ElementType.METHOD })
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface CapturedViewProperty {
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
249a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * When retrieveReturn is true, we need to retrieve second level methods
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod()
251a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * we will set retrieveReturn = true on the annotation of
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * myView.getFirstLevelMethod()
253a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * @return true if we need the second level methods
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
255a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        boolean retrieveReturn() default false;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
257a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
258926cf56676d760579573470c7848dbf119a86779John Reck    /**
259926cf56676d760579573470c7848dbf119a86779John Reck     * Allows a View to inject custom children into HierarchyViewer. For example,
260926cf56676d760579573470c7848dbf119a86779John Reck     * WebView uses this to add its internal layer tree as a child to itself
261926cf56676d760579573470c7848dbf119a86779John Reck     * @hide
262926cf56676d760579573470c7848dbf119a86779John Reck     */
263926cf56676d760579573470c7848dbf119a86779John Reck    public interface HierarchyHandler {
264926cf56676d760579573470c7848dbf119a86779John Reck        /**
265926cf56676d760579573470c7848dbf119a86779John Reck         * Dumps custom children to hierarchy viewer.
266f2361156c4aee3dad26f25c410fcf255656922d1John Reck         * See ViewDebug.dumpViewWithProperties(Context, View, BufferedWriter, int)
267926cf56676d760579573470c7848dbf119a86779John Reck         * for the format
268926cf56676d760579573470c7848dbf119a86779John Reck         *
269926cf56676d760579573470c7848dbf119a86779John Reck         * An empty implementation should simply do nothing
270926cf56676d760579573470c7848dbf119a86779John Reck         *
271926cf56676d760579573470c7848dbf119a86779John Reck         * @param out The output writer
272926cf56676d760579573470c7848dbf119a86779John Reck         * @param level The indentation level
273926cf56676d760579573470c7848dbf119a86779John Reck         */
274926cf56676d760579573470c7848dbf119a86779John Reck        public void dumpViewHierarchyWithProperties(BufferedWriter out, int level);
275926cf56676d760579573470c7848dbf119a86779John Reck
276926cf56676d760579573470c7848dbf119a86779John Reck        /**
277926cf56676d760579573470c7848dbf119a86779John Reck         * Returns a View to enable grabbing screenshots from custom children
278926cf56676d760579573470c7848dbf119a86779John Reck         * returned in dumpViewHierarchyWithProperties.
279926cf56676d760579573470c7848dbf119a86779John Reck         *
280926cf56676d760579573470c7848dbf119a86779John Reck         * @param className The className of the view to find
281926cf56676d760579573470c7848dbf119a86779John Reck         * @param hashCode The hashCode of the view to find
282926cf56676d760579573470c7848dbf119a86779John Reck         * @return the View to capture from, or null if not found
283926cf56676d760579573470c7848dbf119a86779John Reck         */
284926cf56676d760579573470c7848dbf119a86779John Reck        public View findHierarchyView(String className, int hashCode);
285926cf56676d760579573470c7848dbf119a86779John Reck    }
286926cf56676d760579573470c7848dbf119a86779John Reck
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Maximum delay in ms after which we stop trying to capture a View's drawing
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int CAPTURE_TIMEOUT = 4000;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE";
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_DUMP = "DUMP";
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE";
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
297c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static final String REMOTE_PROFILE = "PROFILE";
298223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
299ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase    private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Field[]> sFieldsForClasses;
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Method[]> sMethodsForClasses;
303c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static HashMap<AccessibleObject, ExportedProperty> sAnnotations;
304c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This enum is now unused
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public enum HierarchyTraceType {
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE,
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE_CHILD,
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE_CHILD_IN_PARENT,
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        REQUEST_LAYOUT,
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ON_LAYOUT,
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ON_MEASURE,
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        DRAW,
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BUILD_CACHE
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
32113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This enum is now unused
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
32313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public enum RecyclerTraceType {
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        NEW_VIEW,
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BIND_VIEW,
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        RECYCLE_FROM_ACTIVE_HEAP,
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        RECYCLE_FROM_SCRAP_HEAP,
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MOVE_TO_SCRAP_HEAP,
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MOVE_FROM_ACTIVE_TO_SCRAP_HEAP
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of instanciated Views.
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of Views instanciated in the current process.
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static long getViewInstanceCount() {
341c21550a8d1dfc9e5359fe994cb48049a0bd4c82cBrian Carlstrom        return Debug.countInstancesOfClass(View.class);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
345c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato     * Returns the number of instanciated ViewAncestors.
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
347c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato     * @return The number of ViewAncestors instanciated in the current process.
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35165b345fa22b878e141b8fd8ece9c208df00fa40fRomain Guy    public static long getViewRootImplCount() {
3526dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn        return Debug.countInstancesOfClass(ViewRootImpl.class);
353a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
35813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
35913b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings({ "UnusedParameters", "deprecation" })
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void trace(View view, RecyclerTraceType type, int... parameters) {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
36413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
36613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
36713b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings("UnusedParameters")
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void startRecyclerTracing(String prefix, View view) {
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
37213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
37413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
37513b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings("UnusedParameters")
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stopRecyclerTracing() {
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
38013b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
38213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
38313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings({ "UnusedParameters", "deprecation" })
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void trace(View view, HierarchyTraceType type) {
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
38813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
39013b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
39113b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @SuppressWarnings("UnusedParameters")
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void startHierarchyTracing(String prefix, View view) {
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
39613b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy     * @deprecated This method is now unused and invoking it is a no-op
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
39813b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy    @Deprecated
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stopHierarchyTracing() {
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
401a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static void dispatchCommand(View view, String command, String parameters,
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OutputStream clientStream) throws IOException {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Paranoid but safe...
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        view = view.getRootView();
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dump(view, clientStream);
410223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        } else if (REMOTE_COMMAND_CAPTURE_LAYERS.equalsIgnoreCase(command)) {
411223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            captureLayers(view, new DataOutputStream(clientStream));
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final String[] params = parameters.split(" ");
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                capture(view, clientStream, params[0]);
416ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase            } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
417ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase                outputDisplayList(view, params[0]);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate(view, params[0]);
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requestLayout(view, params[0]);
422c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) {
423c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                profile(view, clientStream, params[0]);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
428c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static View findView(View root, String parameter) {
429c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        // Look by type/hashcode
430c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (parameter.indexOf('@') != -1) {
431c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final String[] ids = parameter.split("@");
432c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final String className = ids[0];
433236092a36216c79507ec19eb207831810caced19Romain Guy            final int hashCode = (int) Long.parseLong(ids[1], 16);
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
435c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            View view = root.getRootView();
436c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (view instanceof ViewGroup) {
437c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                return findView((ViewGroup) view, className, hashCode);
438c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
439c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
440c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            // Look by id
441c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final int id = root.getResources().getIdentifier(parameter, null, null);
442c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            return root.getRootView().findViewById(id);
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void invalidate(View root, String parameter) {
449c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            view.postInvalidate();
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void requestLayout(View root, String parameter) {
456c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            root.post(new Runnable() {
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public void run() {
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    view.requestLayout();
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            });
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
466c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void profile(View root, OutputStream clientStream, String parameter)
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
470c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        BufferedWriter out = null;
471c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        try {
472c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024);
473c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
474c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (view != null) {
475f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                profileViewAndChildren(view, out);
476f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            } else {
477f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                out.write("-1 -1 -1");
478f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                out.newLine();
479f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            }
480f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            out.write("DONE.");
481f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            out.newLine();
482f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        } catch (Exception e) {
483f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            android.util.Log.w("View", "Problem profiling the view:", e);
484f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        } finally {
485f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            if (out != null) {
486f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev                out.close();
487f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            }
488f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        }
489f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev    }
490c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
491f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev    private static void profileViewAndChildren(final View view, BufferedWriter out)
492f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            throws IOException {
493c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        profileViewAndChildren(view, out, true);
494c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev    }
495f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev
496c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev    private static void profileViewAndChildren(final View view, BufferedWriter out, boolean root)
497c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev            throws IOException {
498f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev
499c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        long durationMeasure =
5004702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn                (root || (view.mPrivateFlags & View.PFLAG_MEASURED_DIMENSION_SET) != 0)
5014702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn                ? profileViewOperation(view, new ViewOperation<Void>() {
502c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public Void[] pre() {
503c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                forceLayout(view);
504c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                return null;
505c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
506c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
507c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            private void forceLayout(View view) {
508c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                view.forceLayout();
509c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                if (view instanceof ViewGroup) {
510c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    ViewGroup group = (ViewGroup) view;
511c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    final int count = group.getChildCount();
512c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    for (int i = 0; i < count; i++) {
513c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                        forceLayout(group.getChildAt(i));
514c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                    }
515c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                }
516c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
517c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
518c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void run(Void... data) {
519c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
520c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
521c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
522c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void post(Void... data) {
523c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
524c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        })
525c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        : 0;
526c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        long durationLayout =
5274702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn                (root || (view.mPrivateFlags & View.PFLAG_LAYOUT_REQUIRED) != 0)
5284702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn                ? profileViewOperation(view, new ViewOperation<Void>() {
529c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public Void[] pre() {
530c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                return null;
531c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
532c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
533c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void run(Void... data) {
534c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
535c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
536c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
537c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void post(Void... data) {
538c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
539c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        }) : 0;
540c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev        long durationDraw =
5414702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn                (root || !view.willNotDraw() || (view.mPrivateFlags & View.PFLAG_DRAWN) != 0)
5424702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn                ? profileViewOperation(view, new ViewOperation<Object>() {
543c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public Object[] pre() {
544c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                final DisplayMetrics metrics =
545daf98e941e140e8739458126640183b9f296a2abChet Haase                                        (view != null && view.getResources() != null) ?
546daf98e941e140e8739458126640183b9f296a2abChet Haase                                                view.getResources().getDisplayMetrics() : null;
547daf98e941e140e8739458126640183b9f296a2abChet Haase                                final Bitmap bitmap = metrics != null ?
548dde331cebd87982faded6818ad5f9927ff994c96Dianne Hackborn                                        Bitmap.createBitmap(metrics, metrics.widthPixels,
549daf98e941e140e8739458126640183b9f296a2abChet Haase                                                metrics.heightPixels, Bitmap.Config.RGB_565) : null;
550daf98e941e140e8739458126640183b9f296a2abChet Haase                                final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null;
551c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                return new Object[] {
552c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                        bitmap, canvas
553c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                                };
554c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
555c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
556c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void run(Object... data) {
557daf98e941e140e8739458126640183b9f296a2abChet Haase                                if (data[1] != null) {
558daf98e941e140e8739458126640183b9f296a2abChet Haase                                    view.draw((Canvas) data[1]);
559daf98e941e140e8739458126640183b9f296a2abChet Haase                                }
560c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
561c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev
562c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            public void post(Object... data) {
5636311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn                                if (data[1] != null) {
5646311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn                                    ((Canvas) data[1]).setBitmap(null);
5656311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn                                }
566daf98e941e140e8739458126640183b9f296a2abChet Haase                                if (data[0] != null) {
567daf98e941e140e8739458126640183b9f296a2abChet Haase                                    ((Bitmap) data[0]).recycle();
568daf98e941e140e8739458126640183b9f296a2abChet Haase                                }
569c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                            }
570c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                        }) : 0;
571f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(String.valueOf(durationMeasure));
572f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(' ');
573f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(String.valueOf(durationLayout));
574f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(' ');
575f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.write(String.valueOf(durationDraw));
576f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        out.newLine();
577f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev        if (view instanceof ViewGroup) {
578f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            ViewGroup group = (ViewGroup) view;
579f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            final int count = group.getChildCount();
580f8e1219cf8992a22d6c48c2c70d4fbbccc2494f6Konstantin Lopyrev            for (int i = 0; i < count; i++) {
581c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                profileViewAndChildren(group.getChildAt(i), out, false);
582c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
583c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
584c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
585c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
586c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    interface ViewOperation<T> {
587c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        T[] pre();
588c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        void run(T... data);
589c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        void post(T... data);
590c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
591c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
592c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) {
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final CountDownLatch latch = new CountDownLatch(1);
594c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final long[] duration = new long[1];
595c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
596c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        view.post(new Runnable() {
597c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            public void run() {
598c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                try {
599c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    T[] data = operation.pre();
600c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    long start = Debug.threadCpuTimeNanos();
60188b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                    //noinspection unchecked
602c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    operation.run(data);
603c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    duration[0] = Debug.threadCpuTimeNanos() - start;
60488b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                    //noinspection unchecked
605c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    operation.post(data);
606c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } finally {
607c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    latch.countDown();
608c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
609c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
610c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        });
611c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
612c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        try {
613c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev            if (!latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS)) {
614c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                Log.w("View", "Could not complete the profiling of the view " + view);
615c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev                return -1;
616c6dc45700bf0c18708b0ad2f695ea85fadcbf131Konstantin Lopyrev            }
617c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } catch (InterruptedException e) {
618c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            Log.w("View", "Could not complete the profiling of the view " + view);
619c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            Thread.currentThread().interrupt();
620c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            return -1;
621c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
622c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
623c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        return duration[0];
624c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
625c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
626223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    private static void captureLayers(View root, final DataOutputStream clientStream)
627223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            throws IOException {
628223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
629223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        try {
630223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            Rect outRect = new Rect();
631223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            try {
632223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                root.mAttachInfo.mSession.getDisplayFrame(root.mAttachInfo.mWindow, outRect);
633223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            } catch (RemoteException e) {
634223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                // Ignore
635223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
636223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
637223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(outRect.width());
638223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(outRect.height());
639223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
64065554f27855ce1764123604b061b10346f8b8404Romain Guy            captureViewLayer(root, clientStream, true);
641223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
642223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.write(2);
643223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        } finally {
644223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.close();
645223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
646223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    }
647223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
64865554f27855ce1764123604b061b10346f8b8404Romain Guy    private static void captureViewLayer(View view, DataOutputStream clientStream, boolean visible)
649223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            throws IOException {
650223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
65165554f27855ce1764123604b061b10346f8b8404Romain Guy        final boolean localVisible = view.getVisibility() == View.VISIBLE && visible;
65265554f27855ce1764123604b061b10346f8b8404Romain Guy
6534702a856973a553deb82f71b1d3b6c3db5dbf4baDianne Hackborn        if ((view.mPrivateFlags & View.PFLAG_SKIP_DRAW) != View.PFLAG_SKIP_DRAW) {
654223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            final int id = view.getId();
655223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            String name = view.getClass().getSimpleName();
656223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            if (id != View.NO_ID) {
657223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                name = resolveId(view.getContext(), id).toString();
658223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
659223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
660223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.write(1);
661223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeUTF(name);
66265554f27855ce1764123604b061b10346f8b8404Romain Guy            clientStream.writeByte(localVisible ? 1 : 0);
663223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
664223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            int[] position = new int[2];
665223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            // XXX: Should happen on the UI thread
666223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            view.getLocationInWindow(position);
667223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
668223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(position[0]);
669223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.writeInt(position[1]);
670223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.flush();
671223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
672223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            Bitmap b = performViewCapture(view, true);
673223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            if (b != null) {
674223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(b.getWidth() *
675223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                        b.getHeight() * 2);
676223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                b.compress(Bitmap.CompressFormat.PNG, 100, arrayOut);
677223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                clientStream.writeInt(arrayOut.size());
678223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                arrayOut.writeTo(clientStream);
679223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
680223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            clientStream.flush();
681223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
682223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
683223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        if (view instanceof ViewGroup) {
684223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            ViewGroup group = (ViewGroup) view;
685223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            int count = group.getChildCount();
686223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
687223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            for (int i = 0; i < count; i++) {
68865554f27855ce1764123604b061b10346f8b8404Romain Guy                captureViewLayer(group.getChildAt(i), clientStream, localVisible);
689223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            }
690223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
691223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    }
692223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
693ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase    private static void outputDisplayList(View root, String parameter) throws IOException {
694ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase        final View view = findView(root, parameter);
6956dd005b48138708762bfade0081d031a2a4a3822Dianne Hackborn        view.getViewRootImpl().outputDisplayList(view);
696ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase    }
697ed30fd8e9a2d65ee5c8520de55b0089c219f390cChet Haase
698c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void capture(View root, final OutputStream clientStream, String parameter)
699c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            throws IOException {
700c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
701c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View captureView = findView(root, parameter);
702223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        Bitmap b = performViewCapture(captureView, false);
70343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev
70443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        if (b == null) {
705223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            Log.w("View", "Failed to create capture bitmap!");
70643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            // Send an empty one so that it doesn't get stuck waiting for
70743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            // something.
708dde331cebd87982faded6818ad5f9927ff994c96Dianne Hackborn            b = Bitmap.createBitmap(root.getResources().getDisplayMetrics(),
709dde331cebd87982faded6818ad5f9927ff994c96Dianne Hackborn                    1, 1, Bitmap.Config.ARGB_8888);
71043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        }
71143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev
71243b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        BufferedOutputStream out = null;
71343b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        try {
71443b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            out = new BufferedOutputStream(clientStream, 32 * 1024);
71543b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            b.compress(Bitmap.CompressFormat.PNG, 100, out);
71643b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            out.flush();
71743b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev        } finally {
71843b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            if (out != null) {
71943b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev                out.close();
72043b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            }
72143b9b48f792e0b1b166af7f7fb6a32172e7f11c2Konstantin Lopyrev            b.recycle();
722223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        }
723223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    }
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
725223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy    private static Bitmap performViewCapture(final View captureView, final boolean skpiChildren) {
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (captureView != null) {
727c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final CountDownLatch latch = new CountDownLatch(1);
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Bitmap[] cache = new Bitmap[1];
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
730223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy            captureView.post(new Runnable() {
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public void run() {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
733958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                        cache[0] = captureView.createSnapshot(
734223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                                Bitmap.Config.ARGB_8888, 0, skpiChildren);
735958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                    } catch (OutOfMemoryError e) {
73688b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                        Log.w("View", "Out of memory for bitmap");
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } finally {
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        latch.countDown();
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            });
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS);
745223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy                return cache[0];
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (InterruptedException e) {
747c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                Log.w("View", "Could not complete the capture of the view " + captureView);
748c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                Thread.currentThread().interrupt();
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
751223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy
752223ff5c0586adbbd1d6d57a3a4d176222e8b7434Romain Guy        return null;
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void dump(View root, OutputStream clientStream) throws IOException {
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BufferedWriter out = null;
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
75838e951b62ed956501b11f0715e23e3bf70942f6dRomain Guy            out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024);
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View view = root.getRootView();
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ViewGroup group = (ViewGroup) view;
762105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewHierarchyWithProperties(group.getContext(), group, out, 0);
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write("DONE.");
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.newLine();
766c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } catch (Exception e) {
767c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            android.util.Log.w("View", "Problem dumping the view:", e);
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (out != null) {
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.close();
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static View findView(ViewGroup group, String className, int hashCode) {
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isRequestedView(group, className, hashCode)) {
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return group;
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = group.getChildCount();
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = group.getChildAt(i);
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View found = findView((ViewGroup) view, className, hashCode);
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (found != null) {
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return found;
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (isRequestedView(view, className, hashCode)) {
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return view;
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
791926cf56676d760579573470c7848dbf119a86779John Reck            if (view instanceof HierarchyHandler) {
792926cf56676d760579573470c7848dbf119a86779John Reck                final View found = ((HierarchyHandler)view)
793926cf56676d760579573470c7848dbf119a86779John Reck                        .findHierarchyView(className, hashCode);
794926cf56676d760579573470c7848dbf119a86779John Reck                if (found != null) {
795926cf56676d760579573470c7848dbf119a86779John Reck                    return found;
796926cf56676d760579573470c7848dbf119a86779John Reck                }
797926cf56676d760579573470c7848dbf119a86779John Reck            }
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean isRequestedView(View view, String className, int hashCode) {
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
807105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group,
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            BufferedWriter out, int level) {
809105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (!dumpViewWithProperties(context, group, out, level)) {
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = group.getChildCount();
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = group.getChildAt(i);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
817105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1);
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
819105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewWithProperties(context, view, out, level + 1);
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
822926cf56676d760579573470c7848dbf119a86779John Reck        if (group instanceof HierarchyHandler) {
823926cf56676d760579573470c7848dbf119a86779John Reck            ((HierarchyHandler)group).dumpViewHierarchyWithProperties(out, level + 1);
824926cf56676d760579573470c7848dbf119a86779John Reck        }
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
827105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static boolean dumpViewWithProperties(Context context, View view,
828105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out, int level) {
829105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < level; i++) {
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.write(' ');
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(view.getClass().getName());
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write('@');
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(Integer.toHexString(view.hashCode()));
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(' ');
838105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            dumpViewProperties(context, view, out);
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.newLine();
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w("View", "Error while dumping hierarchy tree");
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Field[] getExportedPropertyFields(Class<?> klass) {
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sFieldsForClasses == null) {
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sFieldsForClasses = new HashMap<Class<?>, Field[]>();
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
851c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (sAnnotations == null) {
852c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
853c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
854c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Field[]> map = sFieldsForClasses;
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Field[] fields = map.get(klass);
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fields != null) {
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fields;
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Field> foundFields = new ArrayList<Field>();
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = klass.getDeclaredFields();
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (field.isAnnotationPresent(ExportedProperty.class)) {
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                field.setAccessible(true);
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundFields.add(field);
87188b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                sAnnotations.put(field, field.getAnnotation(ExportedProperty.class));
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = foundFields.toArray(new Field[foundFields.size()]);
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, fields);
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fields;
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Method[] getExportedPropertyMethods(Class<?> klass) {
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sMethodsForClasses == null) {
883c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sMethodsForClasses = new HashMap<Class<?>, Method[]>(100);
884c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
885c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (sAnnotations == null) {
886c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
888c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Method[]> map = sMethodsForClasses;
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Method[] methods = map.get(klass);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (methods != null) {
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return methods;
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Method> foundMethods = new ArrayList<Method>();
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = klass.getDeclaredMethods();
898a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
901a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            final Method method = methods[i];
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (method.getParameterTypes().length == 0 &&
903c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    method.isAnnotationPresent(ExportedProperty.class) &&
904c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    method.getReturnType() != Void.class) {
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.setAccessible(true);
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundMethods.add(method);
90788b4f153e2be863d79f4d7f68af95e0f9375e4ecRomain Guy                sAnnotations.put(method, method.getAnnotation(ExportedProperty.class));
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = foundMethods.toArray(new Method[foundMethods.size()]);
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, methods);
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return methods;
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
917105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewProperties(Context context, Object view,
918105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out) throws IOException {
919105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
920105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        dumpViewProperties(context, view, out, "");
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
923105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewProperties(Context context, Object view,
924105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out, String prefix) throws IOException {
925105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Class<?> klass = view.getClass();
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        do {
929105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            exportFields(context, view, out, klass, prefix);
930105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            exportMethods(context, view, out, klass, prefix);
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            klass = klass.getSuperclass();
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } while (klass != Object.class);
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
934a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
935105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportMethods(Context context, Object view, BufferedWriter out,
936105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Class<?> klass, String prefix) throws IOException {
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Method[] methods = getExportedPropertyMethods(klass);
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Method method = methods[i];
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection EmptyCatchBlock
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // TODO: This should happen on the UI thread
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object methodValue = method.invoke(view, (Object[]) null);
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> returnType = method.getReturnType();
948bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                final ExportedProperty property = sAnnotations.get(method);
94991a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                String categoryPrefix =
95091a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                        property.category().length() != 0 ? property.category() + ":" : "";
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (returnType == int.class) {
953bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
954105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (property.resolveId() && context != null) {
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int id = (Integer) methodValue;
956105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        methodValue = resolveId(context, id);
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
958809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        final FlagToString[] flagsMapping = property.flagMapping();
959809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        if (flagsMapping.length > 0) {
960809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final int intValue = (Integer) methodValue;
96191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                            final String valuePrefix =
96291a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                                    categoryPrefix + prefix + method.getName() + '_';
963809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
964809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        }
965809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final IntToString[] mapping = property.mapping();
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mapping.length > 0) {
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            final int intValue = (Integer) methodValue;
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            boolean mapped = false;
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            int mappingCount = mapping.length;
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int j = 0; j < mappingCount; j++) {
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                final IntToString mapper = mapping[j];
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (mapper.from() == intValue) {
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    methodValue = mapper.to();
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    mapped = true;
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    break;
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (!mapped) {
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                methodValue = intValue;
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
985c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else if (returnType == int[].class) {
986c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final int[] array = (int[]) methodValue;
98791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                    final String valuePrefix = categoryPrefix + prefix + method.getName() + '_';
988c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String suffix = "()";
989c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
990105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
991bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
992bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                    // Probably want to return here, same as for fields.
993bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                    return;
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (!returnType.isPrimitive()) {
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (property.deepExport()) {
996105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        dumpViewProperties(context, methodValue, out, prefix + property.prefix());
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
100191a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                writeEntry(out, categoryPrefix + prefix, method.getName(), "()", methodValue);
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (InvocationTargetException e) {
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1008105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportFields(Context context, Object view, BufferedWriter out,
1009105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Class<?> klass, String prefix) throws IOException {
1010105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = getExportedPropertyFields(klass);
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection EmptyCatchBlock
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object fieldValue = null;
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> type = field.getType();
1021bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev                final ExportedProperty property = sAnnotations.get(field);
102291a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                String categoryPrefix =
102391a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                        property.category().length() != 0 ? property.category() + ":" : "";
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type == int.class) {
1026bea95162ca25bd00b0479d93739b6283795c3986Konstantin Lopyrev
1027105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (property.resolveId() && context != null) {
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int id = field.getInt(view);
1029105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        fieldValue = resolveId(context, id);
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
1031809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        final FlagToString[] flagsMapping = property.flagMapping();
1032809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        if (flagsMapping.length > 0) {
1033809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final int intValue = field.getInt(view);
103491a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                            final String valuePrefix =
103591a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                                    categoryPrefix + prefix + field.getName() + '_';
1036809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
1037809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        }
1038809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final IntToString[] mapping = property.mapping();
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mapping.length > 0) {
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            final int intValue = field.getInt(view);
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            int mappingCount = mapping.length;
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int j = 0; j < mappingCount; j++) {
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                final IntToString mapped = mapping[j];
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (mapped.from() == intValue) {
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    fieldValue = mapped.to();
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    break;
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (fieldValue == null) {
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                fieldValue = intValue;
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1056c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else if (type == int[].class) {
1057c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final int[] array = (int[]) field.get(view);
105891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                    final String valuePrefix = categoryPrefix + prefix + field.getName() + '_';
1059c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String suffix = "";
1060c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1061105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
1062c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1063c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    // We exit here!
1064c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    return;
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (!type.isPrimitive()) {
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (property.deepExport()) {
106791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                        dumpViewProperties(context, field.get(view), out, prefix
106891a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                                + property.prefix());
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fieldValue == null) {
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldValue = field.get(view);
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
107791a7f5fef8a9fc496acef23f513cb48139e8dff5Konstantin Lopyrev                writeEntry(out, categoryPrefix + prefix, field.getName(), "", fieldValue);
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1083c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void writeEntry(BufferedWriter out, String prefix, String name,
1084c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String suffix, Object value) throws IOException {
1085c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1086c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(prefix);
1087c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(name);
1088c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(suffix);
1089c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write("=");
1090c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        writeValue(out, value);
1091c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(' ');
1092c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1093c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1094809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping,
1095809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            int intValue, String prefix) throws IOException {
1096809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
1097809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        final int count = mapping.length;
1098809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        for (int j = 0; j < count; j++) {
1099809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final FlagToString flagMapping = mapping[j];
1100809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final boolean ifTrue = flagMapping.outputIf();
11015bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy            final int maskResult = intValue & flagMapping.mask();
11025bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy            final boolean test = maskResult == flagMapping.equals();
1103809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            if ((test && ifTrue) || (!test && !ifTrue)) {
1104809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                final String name = flagMapping.name();
11055bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy                final String value = "0x" + Integer.toHexString(maskResult);
1106809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                writeEntry(out, prefix, name, "", value);
1107809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            }
1108809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        }
1109809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    }
1110809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
1111105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportUnrolledArray(Context context, BufferedWriter out,
1112c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            ExportedProperty property, int[] array, String prefix, String suffix)
1113c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            throws IOException {
1114c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1115c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final IntToString[] indexMapping = property.indexMapping();
1116c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final boolean hasIndexMapping = indexMapping.length > 0;
1117c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1118c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final IntToString[] mapping = property.mapping();
1119c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final boolean hasMapping = mapping.length > 0;
1120c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1121105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        final boolean resolveId = property.resolveId() && context != null;
1122c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final int valuesCount = array.length;
1123c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1124c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        for (int j = 0; j < valuesCount; j++) {
1125c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String name;
1126a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            String value = null;
1127c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1128c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final int intValue = array[j];
1129c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1130c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            name = String.valueOf(j);
1131c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (hasIndexMapping) {
1132c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                int mappingCount = indexMapping.length;
1133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                for (int k = 0; k < mappingCount; k++) {
1134c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final IntToString mapped = indexMapping[k];
1135c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    if (mapped.from() == j) {
1136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        name = mapped.to();
1137c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        break;
1138c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
1139c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
1140c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1141c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1142c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (hasMapping) {
1143c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                int mappingCount = mapping.length;
1144c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                for (int k = 0; k < mappingCount; k++) {
1145c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final IntToString mapped = mapping[k];
1146c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    if (mapped.from() == intValue) {
1147c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        value = mapped.to();
1148c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        break;
1149c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
1150c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
1151c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1152c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1153c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (resolveId) {
1154a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                if (value == null) value = (String) resolveId(context, intValue);
1155a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            } else {
1156a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                value = String.valueOf(intValue);
1157c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1158c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1159c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            writeEntry(out, prefix, name, suffix, value);
1160c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1161c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1162c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1163237c1ceea36024cf4194212e713806e3ce8a1c49Romain Guy    static Object resolveId(Context context, int id) {
1164c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        Object fieldValue;
1165105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        final Resources resources = context.getResources();
1166c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (id >= 0) {
1167c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            try {
1168c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                fieldValue = resources.getResourceTypeName(id) + '/' +
1169c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        resources.getResourceEntryName(id);
1170c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            } catch (Resources.NotFoundException e) {
1171c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                fieldValue = "id/0x" + Integer.toHexString(id);
1172c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1173c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
1174c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            fieldValue = "NO_ID";
1175c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1176c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        return fieldValue;
1177c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1178c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1179c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void writeValue(BufferedWriter out, Object value) throws IOException {
1180c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (value != null) {
118197723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy            String output = "[EXCEPTION]";
118297723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy            try {
118397723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy                output = value.toString().replace("\n", "\\n");
118497723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy            } finally {
118597723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy                out.write(String.valueOf(output.length()));
118697723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy                out.write(",");
118797723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy                out.write(output);
118897723b2eb415d044d8dcee6a5ee3a2a3fb607b15Romain Guy            }
1189c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
1190c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write("4,null");
1191c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1192c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1193c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Field[] capturedViewGetPropertyFields(Class<?> klass) {
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCapturedViewFieldsForClasses == null) {
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>();
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses;
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Field[] fields = map.get(klass);
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fields != null) {
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fields;
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Field> foundFields = new ArrayList<Field>();
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = klass.getFields();
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (field.isAnnotationPresent(CapturedViewProperty.class)) {
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                field.setAccessible(true);
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundFields.add(field);
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = foundFields.toArray(new Field[foundFields.size()]);
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, fields);
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fields;
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Method[] capturedViewGetPropertyMethods(Class<?> klass) {
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCapturedViewMethodsForClasses == null) {
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>();
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses;
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Method[] methods = map.get(klass);
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (methods != null) {
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return methods;
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Method> foundMethods = new ArrayList<Method>();
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = klass.getMethods();
1236a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
1239a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            final Method method = methods[i];
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (method.getParameterTypes().length == 0 &&
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    method.isAnnotationPresent(CapturedViewProperty.class) &&
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    method.getReturnType() != Void.class) {
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.setAccessible(true);
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundMethods.add(method);
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = foundMethods.toArray(new Method[foundMethods.size()]);
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, methods);
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return methods;
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1253a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
1254a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    private static String capturedViewExportMethods(Object obj, Class<?> klass,
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String prefix) {
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (obj == null) {
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "null";
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1260a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder();
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Method[] methods = capturedViewGetPropertyMethods(klass);
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Method method = methods[i];
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object methodValue = method.invoke(obj, (Object[]) null);
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> returnType = method.getReturnType();
1270a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class);
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (property.retrieveReturn()) {
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    //we are interested in the second level data only
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#"));
1275a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                } else {
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(prefix);
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(method.getName());
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("()=");
1279a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (methodValue != null) {
1281a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                        final String value = methodValue.toString().replace("\n", "\\n");
1282a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                        sb.append(value);
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sb.append("null");
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("; ");
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              } catch (IllegalAccessException e) {
1289a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                  //Exception IllegalAccess, it is OK here
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  //we simply ignore this method
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              } catch (InvocationTargetException e) {
1292a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                  //Exception InvocationTarget, it is OK here
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  //we simply ignore this method
1294a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy              }
1295a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        }
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) {
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (obj == null) {
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "null";
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1303a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder();
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = capturedViewGetPropertyFields(klass);
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object fieldValue = field.get(obj);
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(prefix);
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(field.getName());
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append("=");
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fieldValue != null) {
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final String value = fieldValue.toString().replace("\n", "\\n");
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(value);
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("null");
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(' ');
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
1325a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                //Exception IllegalAccess, it is OK here
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //we simply ignore this field
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1331a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1333a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     * Dump view info for id based instrument test generation
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (and possibly further data analysis). The results are dumped
1335a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     * to the log.
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param tag for log
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view for dump
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1339a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    public static void dumpCapturedView(String tag, Object view) {
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Class<?> klass = view.getClass();
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder(klass.getName() + ": ");
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(capturedViewExportFields(view, klass, ""));
1343a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        sb.append(capturedViewExportMethods(view, klass, ""));
1344a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        Log.d(tag, sb.toString());
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1347