ViewDebug.java revision cf635ae7c65de34f62a41cd330f25f4ee9ddc95b
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
19e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guyimport android.util.Config;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
21c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.util.DisplayMetrics;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
23105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.content.Context;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap;
25c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.graphics.Canvas;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment;
27c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport android.os.Debug;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedWriter;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileWriter;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.DataOutputStream;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStreamWriter;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedOutputStream;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.LinkedList;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.CountDownLatch;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.TimeUnit;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Target;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.ElementType;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.Retention;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.annotation.RetentionPolicy;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Method;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.InvocationTargetException;
51c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport java.lang.reflect.AccessibleObject;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various debugging/tracing tools related to {@link View} and the view hierarchy.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ViewDebug {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * Log tag used to log errors related to the consistency of the view hierarchy.
5913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *
6013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * @hide
6113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     */
6213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    public static final String CONSISTENCY_LOG_TAG = "ViewConsistency";
6313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
6413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    /**
6513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * Flag indicating the consistency check should check layout-related properties.
6613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *
6713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * @hide
6813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     */
6913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    public static final int CONSISTENCY_LAYOUT = 0x1;
7013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
7113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    /**
7213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * Flag indicating the consistency check should check drawing-related properties.
7313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *
7413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * @hide
7513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     */
7613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    public static final int CONSISTENCY_DRAWING = 0x2;
7713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
7813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    /**
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables view hierarchy tracing. Any invoker of
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * check that this value is set to true as not to affect performance.
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final boolean TRACE_HIERARCHY = false;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables view recycler tracing. Any invoker of
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])} should first
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * check that this value is set to true as not to affect performance.
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final boolean TRACE_RECYCLER = false;
91a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
93cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Enables or disables motion events tracing. Any invoker of
94cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * {@link #trace(View, MotionEvent, MotionEventTraceType)} should first check
95cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * that this value is set to true as not to affect performance.
96cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
97cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @hide
98cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     */
99cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    public static final boolean TRACE_MOTION_EVENTS = false;
100cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
101cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    /**
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The system property of dynamic switch for capturing view information
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * when it is set, we dump interested fields and methods for the view on focus
104a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     */
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final String SYSTEM_PROPERTY_CAPTURE_VIEW = "debug.captureview";
106a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The system property of dynamic switch for capturing event information
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * when it is set, we log key events, touch/motion and trackball events
110a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     */
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent";
112c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * Profiles drawing times in the events log.
11513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *
11613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * @hide
11713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     */
11813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    @Debug.DebugProperty
11913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    public static boolean profileDrawing = false;
12013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
12113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    /**
12213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * Profiles layout times in the events log.
12313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *
12413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * @hide
12513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     */
12613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    @Debug.DebugProperty
12713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    public static boolean profileLayout = false;
12813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
12913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    /**
13013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * Profiles real fps (times between draws) and displays the result.
13113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *
13213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * @hide
13313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     */
13413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    @Debug.DebugProperty
13513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    public static boolean showFps = false;
13613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
13713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    /**
13813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * <p>Enables or disables views consistency check. Even when this property is enabled,
13913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * view consistency checks happen only if {@link android.util.Config#DEBUG} is set
14013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * to true. The value of this property can be configured externally in one of the
14113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * following files:</p>
14213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * <ul>
14313922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *  <li>/system/debug.prop</li>
14413922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *  <li>/debug.prop</li>
14513922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     *  <li>/data/debug.prop</li>
14613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * </ul>
14713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     * @hide
14813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy     */
14913922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    @Debug.DebugProperty
15013922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    public static boolean consistencyCheckEnabled = false;
15113922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
15213922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    static {
153e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy        if (Config.DEBUG) {
154e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy	        Debug.setFieldsOn(ViewDebug.class, true);
155e551dc76bcde0e114b06e876eeb1d5f9d367fddfRomain Guy	    }
15613922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    }
15713922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy
15813922e03037d71a538f24ddf61c0b61bb4eb5af0Romain Guy    /**
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This annotation can be used to mark fields and methods to be dumped by
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the view server. Only non-void methods with no arguments can be annotated
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * by this annotation.
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.FIELD, ElementType.METHOD })
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface ExportedProperty {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * When resolveId is true, and if the annotated field/method return value
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * is an int, the value is converted to an Android's resource name.
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the property's value must be transformed into an Android
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *         resource name, false otherwise
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean resolveId() default false;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * A mapping can be defined to map int values to specific strings. For
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * instance, View.getVisibility() returns 0, 4 or 8. However, these values
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * actually mean VISIBLE, INVISIBLE and GONE. A mapping can be used to see
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * these human readable values:
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <pre>
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @ViewDebug.ExportedProperty(mapping = {
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 0, to = "VISIBLE"),
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 4, to = "INVISIBLE"),
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     @ViewDebug.IntToString(from = 8, to = "GONE")
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * })
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * public int getVisibility() { ...
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <pre>
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An array of int to String mappings
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @see android.view.ViewDebug.IntToString
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntToString[] mapping() default { };
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
197c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * A mapping can be defined to map array indices to specific strings.
198c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * A mapping can be used to see human readable values for the indices
199c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * of an array:
200c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
201c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * <pre>
202809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @ViewDebug.ExportedProperty(indexMapping = {
203c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 0, to = "INVALID"),
204c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 1, to = "FIRST"),
205c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *     @ViewDebug.IntToString(from = 2, to = "SECOND")
206c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * })
207c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * private int[] mElements;
208c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * <pre>
209c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
210c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @return An array of int to String mappings
211c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         *
212c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @see android.view.ViewDebug.IntToString
213c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         * @see #mapping()
214c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project         */
215c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        IntToString[] indexMapping() default { };
216c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
217c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        /**
218809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * A flags mapping can be defined to map flags encoded in an integer to
219809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * specific strings. A mapping can be used to see human readable values
220809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * for the flags of an integer:
221809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
222809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <pre>
223809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @ViewDebug.ExportedProperty(flagMapping = {
224809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"),
225809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"),
226809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * })
227809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * private int mFlags;
228809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <pre>
229809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
230809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * A specified String is output when the following is true:
231a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         *
232809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An array of int to String mappings
233809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
234809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        FlagToString[] flagMapping() default { };
235809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
236809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * When deep export is turned on, this property is not dumped. Instead, the
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * properties contained in this property are dumped. Each child property
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * is prefixed with the name of this property.
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the properties of this property should be dumped
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
243a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * @see #prefix()
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean deepExport() default false;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The prefix to use on child properties when deep export is enabled
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return a prefix as a String
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @see #deepExport()
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String prefix() default "";
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defines a mapping from an int value to a String. Such a mapping can be used
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in a @ExportedProperty to provide more meaningful values to the end user.
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.view.ViewDebug.ExportedProperty
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.TYPE })
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface IntToString {
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The original int value to map to a String.
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An arbitrary int value.
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int from();
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The String to use in place of the original int value.
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return An arbitrary non-null String.
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String to();
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
280809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
281809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    /**
282809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     * Defines a mapping from an flag to a String. Such a mapping can be used
283809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     * in a @ExportedProperty to provide more meaningful values to the end user.
284809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     *
285809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     * @see android.view.ViewDebug.ExportedProperty
286809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy     */
287809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    @Target({ ElementType.TYPE })
288809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    @Retention(RetentionPolicy.RUNTIME)
289809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    public @interface FlagToString {
290809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
291809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The mask to apply to the original value.
292809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
293809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary int value.
294809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
295809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        int mask();
296809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
297809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
298809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The value to compare to the result of:
299809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * <code>original value &amp; {@link #mask()}</code>.
300809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
301809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary value.
302809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
303809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        int equals();
304809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
305809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
306809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * The String to use in place of the original int value.
307809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         *
308809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * @return An arbitrary non-null String.
309809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
310809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        String name();
311809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
312809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        /**
313809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * Indicates whether to output the flag when the test is true,
314809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         * or false. Defaults to true.
315809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy         */
316809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        boolean outputIf() default true;
317809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    }
318809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This annotation can be used to mark fields and methods to be dumped when
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the view is captured. Methods with this annotation must have no arguments
322f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler     * and must return a valid type of data.
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Target({ ElementType.FIELD, ElementType.METHOD })
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Retention(RetentionPolicy.RUNTIME)
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public @interface CapturedViewProperty {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
328a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * When retrieveReturn is true, we need to retrieve second level methods
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod()
330a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * we will set retrieveReturn = true on the annotation of
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * myView.getFirstLevelMethod()
332a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy         * @return true if we need the second level methods
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
334a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        boolean retrieveReturn() default false;
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
336a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null;
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null;
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Maximum delay in ms after which we stop trying to capture a View's drawing
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int CAPTURE_TIMEOUT = 4000;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE";
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_DUMP = "DUMP";
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE";
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
347c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static final String REMOTE_PROFILE = "PROFILE";
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Field[]> sFieldsForClasses;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static HashMap<Class<?>, Method[]> sMethodsForClasses;
351c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static HashMap<AccessibleObject, ExportedProperty> sAnnotations;
352c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defines the type of hierarhcy trace to output to the hierarchy traces file.
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public enum HierarchyTraceType {
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE,
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE_CHILD,
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INVALIDATE_CHILD_IN_PARENT,
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        REQUEST_LAYOUT,
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ON_LAYOUT,
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ON_MEASURE,
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        DRAW,
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BUILD_CACHE
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static BufferedWriter sHierarchyTraces;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static ViewRoot sHierarhcyRoot;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String sHierarchyTracePrefix;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defines the type of recycler trace to output to the recycler traces file.
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public enum RecyclerTraceType {
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        NEW_VIEW,
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BIND_VIEW,
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        RECYCLE_FROM_ACTIVE_HEAP,
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        RECYCLE_FROM_SCRAP_HEAP,
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MOVE_TO_SCRAP_HEAP,
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MOVE_FROM_ACTIVE_TO_SCRAP_HEAP
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class RecyclerTrace {
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int view;
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public RecyclerTraceType type;
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int position;
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int indexOnScreen;
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static View sRecyclerOwnerView;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static List<View> sRecyclerViews;
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static List<RecyclerTrace> sRecyclerTraces;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String sRecyclerTracePrefix;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
396cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Defines the type of motion events trace to output to the motion events traces file.
397cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
398cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @hide
399cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     */
400cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    public enum MotionEventTraceType {
401cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        DISPATCH,
402cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        ON_INTERCEPT,
403cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        ON_TOUCH
404cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    }
405cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
406cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    private static BufferedWriter sMotionEventTraces;
407cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    private static ViewRoot sMotionEventRoot;
408cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    private static String sMotionEventTracePrefix;
409cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
410cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    /**
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of instanciated Views.
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of Views instanciated in the current process.
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static long getViewInstanceCount() {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return View.sInstanceCount;
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of instanciated ViewRoots.
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of ViewRoots instanciated in the current process.
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static long getViewRootInstanceCount() {
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ViewRoot.getInstanceCount();
430a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    }
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Outputs a trace to the currently opened recycler traces. The trace records the type of
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * recycler action performed on the supplied view as well as a number of parameters.
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view the view to trace
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param type the type of the trace
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameters parameters depending on the type of the trace
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void trace(View view, RecyclerTraceType type, int... parameters) {
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sRecyclerOwnerView == null || sRecyclerViews == null) {
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!sRecyclerViews.contains(view)) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sRecyclerViews.add(view);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int index = sRecyclerViews.indexOf(view);
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        RecyclerTrace trace = new RecyclerTrace();
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trace.view = index;
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trace.type = type;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trace.position = parameters[0];
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trace.indexOnScreen = parameters[1];
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerTraces.add(trace);
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Starts tracing the view recycler of the specified view. The trace is identified by a prefix,
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * used to build the traces files names: <code>/EXTERNAL/view-recycler/PREFIX.traces</code> and
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>.
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Only one view recycler can be traced at the same time. After calling this method, any
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * other invocation will result in a <code>IllegalStateException</code> unless
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #stopRecyclerTracing()} is invoked before.
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Traces files are created only after {@link #stopRecyclerTracing()} is invoked.
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This method will return immediately if TRACE_RECYCLER is false.
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param prefix the traces files name prefix
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view the view whose recycler must be traced
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #stopRecyclerTracing()
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void startRecyclerTracing(String prefix, View view) {
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //noinspection PointlessBooleanExpression,ConstantConditions
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!TRACE_RECYCLER) {
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sRecyclerOwnerView != null) {
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("You must call stopRecyclerTracing() before running" +
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                " a new trace!");
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerTracePrefix = prefix;
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerOwnerView = view;
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerViews = new ArrayList<View>();
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerTraces = new LinkedList<RecyclerTrace>();
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Stops the current view recycer tracing.
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.traces</code>
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * containing all the traces (or method calls) relative to the specified view's recycler.
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * containing all of the views used by the recycler of the view supplied to
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #startRecyclerTracing(String, View)}.
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This method will return immediately if TRACE_RECYCLER is false.
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #startRecyclerTracing(String, View)
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stopRecyclerTracing() {
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //noinspection PointlessBooleanExpression,ConstantConditions
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!TRACE_RECYCLER) {
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sRecyclerOwnerView == null || sRecyclerViews == null) {
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("You must call startRecyclerTracing() before" +
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                " stopRecyclerTracing()!");
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
523c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        //noinspection ResultOfMethodCallIgnored
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        recyclerDump.mkdirs();
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler");
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final BufferedWriter out = new BufferedWriter(new FileWriter(recyclerDump), 8 * 1024);
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (View view : sRecyclerViews) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String name = view.getClass().getName();
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.write(name);
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.newLine();
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.close();
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e("View", "Could not dump recycler content");
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces");
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final FileOutputStream file = new FileOutputStream(recyclerDump);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final DataOutputStream out = new DataOutputStream(file);
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (RecyclerTrace trace : sRecyclerTraces) {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.writeInt(trace.view);
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.writeInt(trace.type.ordinal());
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.writeInt(trace.position);
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.writeInt(trace.indexOnScreen);
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.flush();
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.close();
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e("View", "Could not dump recycler traces");
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerViews.clear();
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerViews = null;
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerTraces.clear();
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerTraces = null;
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sRecyclerOwnerView = null;
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Outputs a trace to the currently opened traces file. The trace contains the class name
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and instance's hashcode of the specified view as well as the supplied trace type.
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view the view to trace
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param type the type of the trace
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void trace(View view, HierarchyTraceType type) {
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sHierarchyTraces == null) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces.write(type.name());
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces.write(' ');
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces.write(view.getClass().getName());
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces.write('@');
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces.write(Integer.toHexString(view.hashCode()));
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces.newLine();
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w("View", "Error while dumping trace of type " + type + " for view " + view);
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix,
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * used to build the traces files names: <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> and
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>.
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Only one view hierarchy can be traced at the same time. After calling this method, any
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * other invocation will result in a <code>IllegalStateException</code> unless
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #stopHierarchyTracing()} is invoked before.
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * containing all the traces (or method calls) relative to the specified view's hierarchy.
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This method will return immediately if TRACE_HIERARCHY is false.
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param prefix the traces files name prefix
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view the view whose hierarchy must be traced
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #stopHierarchyTracing()
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #trace(View, android.view.ViewDebug.HierarchyTraceType)
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void startHierarchyTracing(String prefix, View view) {
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //noinspection PointlessBooleanExpression,ConstantConditions
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!TRACE_HIERARCHY) {
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sHierarhcyRoot != null) {
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("You must call stopHierarchyTracing() before running" +
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                " a new trace!");
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
627c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        //noinspection ResultOfMethodCallIgnored
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        hierarchyDump.mkdirs();
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        hierarchyDump = new File(hierarchyDump, prefix + ".traces");
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sHierarchyTracePrefix = prefix;
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024);
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e("View", "Could not dump view hierarchy");
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sHierarhcyRoot = (ViewRoot) view.getRootView().getParent();
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Stops the current view hierarchy tracing. This method closes the file
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>.
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * containing the view hierarchy of the view supplied to
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #startHierarchyTracing(String, View)}.
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This method will return immediately if TRACE_HIERARCHY is false.
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
653a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     * @see #startHierarchyTracing(String, View)
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #trace(View, android.view.ViewDebug.HierarchyTraceType)
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stopHierarchyTracing() {
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //noinspection PointlessBooleanExpression,ConstantConditions
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!TRACE_HIERARCHY) {
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sHierarhcyRoot == null || sHierarchyTraces == null) {
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("You must call startHierarchyTracing() before" +
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                " stopHierarchyTracing()!");
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sHierarchyTraces.close();
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e("View", "Could not write view traces");
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sHierarchyTraces = null;
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
675c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        //noinspection ResultOfMethodCallIgnored
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        hierarchyDump.mkdirs();
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree");
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BufferedWriter out;
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e("View", "Could not dump view hierarchy");
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View view = sHierarhcyRoot.getView();
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view instanceof ViewGroup) {
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ViewGroup group = (ViewGroup) view;
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dumpViewHierarchy(group, out, 0);
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.close();
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e("View", "Could not dump view hierarchy");
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sHierarhcyRoot = null;
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
700a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
701cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    /**
702cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Outputs a trace to the currently opened traces file. The trace contains the class name
703cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * and instance's hashcode of the specified view as well as the supplied trace type.
704cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
705cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @param view the view to trace
706cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @param event the event of the trace
707cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @param type the type of the trace
708cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
709cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @hide
710cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     */
711cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    public static void trace(View view, MotionEvent event, MotionEventTraceType type) {
712cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        if (sMotionEventTraces == null) {
713cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            return;
714cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
715cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
716cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        try {
717cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.write(type.name());
718cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.write(' ');
719cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.write(event.getAction());
720cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.write(' ');
721cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.write(view.getClass().getName());
722cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.write('@');
723cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.write(Integer.toHexString(view.hashCode()));
724cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sHierarchyTraces.newLine();
725cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        } catch (IOException e) {
726cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            Log.w("View", "Error while dumping trace of event " + event + " for view " + view);
727cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
728cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    }
729cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
730cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    /**
731cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Starts tracing the motion events for the hierarchy of the specificy view.
732cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * The trace is identified by a prefix, used to build the traces files names:
733cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * <code>/EXTERNAL/motion-events/PREFIX.traces</code> and
734cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * <code>/EXTERNAL/motion-events/PREFIX.tree</code>.
735cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
736cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Only one view hierarchy can be traced at the same time. After calling this method, any
737cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * other invocation will result in a <code>IllegalStateException</code> unless
738cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * {@link #stopMotionEventTracing()} is invoked before.
739cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
740cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.traces</code>
741cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * containing all the traces (or method calls) relative to the specified view's hierarchy.
742cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
743cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * This method will return immediately if TRACE_HIERARCHY is false.
744cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
745cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @param prefix the traces files name prefix
746cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @param view the view whose hierarchy must be traced
747cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
748cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @see #stopMotionEventTracing()
749cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType)
750cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
751cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @hide
752cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     */
753cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    public static void startMotionEventTracing(String prefix, View view) {
754cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        //noinspection PointlessBooleanExpression,ConstantConditions
755cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        if (!TRACE_MOTION_EVENTS) {
756cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            return;
757cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
758cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
759cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        if (sMotionEventRoot != null) {
760cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            throw new IllegalStateException("You must call stopMotionEventTracing() before running" +
761cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy                " a new trace!");
762cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
763cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
764cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/");
765cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        //noinspection ResultOfMethodCallIgnored
766cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        hierarchyDump.mkdirs();
767cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
768cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        hierarchyDump = new File(hierarchyDump, prefix + ".traces");
769cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        sMotionEventTracePrefix = prefix;
770cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
771cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        try {
772cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces = new BufferedWriter(new FileWriter(hierarchyDump), 32 * 1024);
773cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        } catch (IOException e) {
774cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            Log.e("View", "Could not dump view hierarchy");
775cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            return;
776cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
777cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
778cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        sMotionEventRoot = (ViewRoot) view.getRootView().getParent();
779cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    }
780cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
781cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    /**
782cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Stops the current motion events tracing. This method closes the file
783cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * <code>/EXTERNAL/motion-events/PREFIX.traces</code>.
784cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
785cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.tree</code>
786cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * containing the view hierarchy of the view supplied to
787cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * {@link #startMotionEventTracing(String, View)}.
788cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
789cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * This method will return immediately if TRACE_HIERARCHY is false.
790cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
791cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @see #startMotionEventTracing(String, View)
792cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType)
793cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     *
794cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     * @hide
795cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy     */
796cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    public static void stopMotionEventTracing() {
797cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        //noinspection PointlessBooleanExpression,ConstantConditions
798cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        if (!TRACE_MOTION_EVENTS) {
799cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            return;
800cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
801cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
802cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        if (sMotionEventRoot == null || sMotionEventTraces == null) {
803cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            throw new IllegalStateException("You must call startMotionEventTracing() before" +
804cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy                " stopMotionEventTracing()!");
805cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
806cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
807cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        try {
808cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            sMotionEventTraces.close();
809cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        } catch (IOException e) {
810cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            Log.e("View", "Could not write view traces");
811cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
812cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        sMotionEventTraces = null;
813cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
814cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/");
815cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        //noinspection ResultOfMethodCallIgnored
816cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        hierarchyDump.mkdirs();
817cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        hierarchyDump = new File(hierarchyDump, sMotionEventTracePrefix + ".tree");
818cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
819cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        BufferedWriter out;
820cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        try {
821cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024);
822cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        } catch (IOException e) {
823cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            Log.e("View", "Could not dump view hierarchy");
824cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            return;
825cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
826cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
827cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        View view = sMotionEventRoot.getView();
828cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        if (view instanceof ViewGroup) {
829cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            ViewGroup group = (ViewGroup) view;
830cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            dumpViewHierarchy(group, out, 0);
831cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            try {
832cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy                out.close();
833cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            } catch (IOException e) {
834cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy                Log.e("View", "Could not dump view hierarchy");
835cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy            }
836cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        }
837cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
838cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy        sHierarhcyRoot = null;
839cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy    }
840cf635ae7c65de34f62a41cd330f25f4ee9ddc95bRomain Guy
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static void dispatchCommand(View view, String command, String parameters,
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OutputStream clientStream) throws IOException {
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Paranoid but safe...
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        view = view.getRootView();
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) {
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dump(view, clientStream);
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final String[] params = parameters.split(" ");
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                capture(view, clientStream, params[0]);
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate(view, params[0]);
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requestLayout(view, params[0]);
857c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) {
858c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                profile(view, clientStream, params[0]);
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
863c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static View findView(View root, String parameter) {
864c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        // Look by type/hashcode
865c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (parameter.indexOf('@') != -1) {
866c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final String[] ids = parameter.split("@");
867c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final String className = ids[0];
868236092a36216c79507ec19eb207831810caced19Romain Guy            final int hashCode = (int) Long.parseLong(ids[1], 16);
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
870c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            View view = root.getRootView();
871c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (view instanceof ViewGroup) {
872c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                return findView((ViewGroup) view, className, hashCode);
873c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
874c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
875c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            // Look by id
876c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final int id = root.getResources().getIdentifier(parameter, null, null);
877c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            return root.getRootView().findViewById(id);
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void invalidate(View root, String parameter) {
884c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            view.postInvalidate();
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void requestLayout(View root, String parameter) {
891c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (view != null) {
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            root.post(new Runnable() {
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public void run() {
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    view.requestLayout();
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            });
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
901c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void profile(View root, OutputStream clientStream, String parameter)
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
904c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View view = findView(root, parameter);
905c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        BufferedWriter out = null;
906c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        try {
907c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024);
908c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
909c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (view != null) {
910c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                final long durationMeasure = profileViewOperation(view, new ViewOperation<Void>() {
911c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public Void[] pre() {
912c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        forceLayout(view);
913c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        return null;
914c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
915c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
916c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    private void forceLayout(View view) {
917c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        view.forceLayout();
918c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        if (view instanceof ViewGroup) {
919c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                            ViewGroup group = (ViewGroup) view;
920c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                            final int count = group.getChildCount();
921c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                            for (int i = 0; i < count; i++) {
922c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                                forceLayout(group.getChildAt(i));
923c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                            }
924c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        }
925c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
926c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
927c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public void run(Void... data) {
928c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
929c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
930c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
931c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public void post(Void... data) {
932c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
933c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                });
934c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
935c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                final long durationLayout = profileViewOperation(view, new ViewOperation<Void>() {
936c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public Void[] pre() {
937c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        return null;
938c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
939c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
940c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public void run(Void... data) {
941c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
942c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
943c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
944c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public void post(Void... data) {
945c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
946c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                });
947c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
948c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                final long durationDraw = profileViewOperation(view, new ViewOperation<Object>() {
949c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public Object[] pre() {
950c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        final DisplayMetrics metrics = view.getResources().getDisplayMetrics();
951c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        final Bitmap bitmap = Bitmap.createBitmap(metrics.widthPixels,
952ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project                                metrics.heightPixels, Bitmap.Config.RGB_565);
953c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        final Canvas canvas = new Canvas(bitmap);
954c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        return new Object[] { bitmap, canvas };
955c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
956c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
957c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public void run(Object... data) {
958c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        view.draw((Canvas) data[1]);
959c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
960c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
961c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    public void post(Object... data) {
962c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        ((Bitmap) data[0]).recycle();
963c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
964c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                });
965c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
966c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.write(String.valueOf(durationMeasure));
967c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.write(' ');
968c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.write(String.valueOf(durationLayout));
969c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.write(' ');
970c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.write(String.valueOf(durationDraw));
971c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.newLine();
972c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            } else {
973c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.write("-1 -1 -1");
974c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.newLine();
975c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
976c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } catch (Exception e) {
977c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            android.util.Log.w("View", "Problem profiling the view:", e);
978c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } finally {
979c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (out != null) {
980c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                out.close();
981c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
982c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
983c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
984c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
985c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    interface ViewOperation<T> {
986c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        T[] pre();
987c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        void run(T... data);
988c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        void post(T... data);
989c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
990c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
991c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) {
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final CountDownLatch latch = new CountDownLatch(1);
993c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final long[] duration = new long[1];
994c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
995c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        view.post(new Runnable() {
996c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            public void run() {
997c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                try {
998c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    T[] data = operation.pre();
999c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    long start = Debug.threadCpuTimeNanos();
1000c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    operation.run(data);
1001c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    duration[0] = Debug.threadCpuTimeNanos() - start;
1002c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    operation.post(data);
1003c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } finally {
1004c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    latch.countDown();
1005c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
1006c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1007c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        });
1008c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1009c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        try {
1010c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS);
1011c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } catch (InterruptedException e) {
1012c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            Log.w("View", "Could not complete the profiling of the view " + view);
1013c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            Thread.currentThread().interrupt();
1014c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            return -1;
1015c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1016c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1017c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        return duration[0];
1018c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1019c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1020c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void capture(View root, final OutputStream clientStream, String parameter)
1021c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            throws IOException {
1022c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1023c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final View captureView = findView(root, parameter);
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (captureView != null) {
1026c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final CountDownLatch latch = new CountDownLatch(1);
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Bitmap[] cache = new Bitmap[1];
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            root.post(new Runnable() {
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public void run() {
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
1032958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                        cache[0] = captureView.createSnapshot(
1033958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                                Bitmap.Config.ARGB_8888, 0);
1034958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                    } catch (OutOfMemoryError e) {
1035958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                        try {
1036958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                            cache[0] = captureView.createSnapshot(
1037958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                                    Bitmap.Config.ARGB_4444, 0);
1038958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                        } catch (OutOfMemoryError e2) {
1039958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                            Log.w("View", "Out of memory for bitmap");
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } finally {
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        latch.countDown();
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            });
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS);
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cache[0] != null) {
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    BufferedOutputStream out = null;
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        out = new BufferedOutputStream(clientStream, 32 * 1024);
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        cache[0].compress(Bitmap.CompressFormat.PNG, 100, out);
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        out.flush();
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } finally {
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (out != null) {
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            out.close();
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1060958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                        cache[0].recycle();
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1062958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                } else {
1063958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                    Log.w("View", "Failed to create capture bitmap!");
1064958b9adc086f126dcd757d29f0d7f443ae9064b2Dianne Hackborn                    clientStream.close();
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (InterruptedException e) {
1067c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                Log.w("View", "Could not complete the capture of the view " + captureView);
1068c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                Thread.currentThread().interrupt();
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void dump(View root, OutputStream clientStream) throws IOException {
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BufferedWriter out = null;
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
107638e951b62ed956501b11f0715e23e3bf70942f6dRomain Guy            out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024);
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View view = root.getRootView();
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ViewGroup group = (ViewGroup) view;
1080105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewHierarchyWithProperties(group.getContext(), group, out, 0);
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write("DONE.");
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.newLine();
1084c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } catch (Exception e) {
1085c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            android.util.Log.w("View", "Problem dumping the view:", e);
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (out != null) {
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.close();
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static View findView(ViewGroup group, String className, int hashCode) {
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isRequestedView(group, className, hashCode)) {
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return group;
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = group.getChildCount();
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = group.getChildAt(i);
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final View found = findView((ViewGroup) view, className, hashCode);
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (found != null) {
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return found;
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (isRequestedView(view, className, hashCode)) {
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return view;
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean isRequestedView(View view, String className, int hashCode) {
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1118105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group,
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            BufferedWriter out, int level) {
1120105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (!dumpViewWithProperties(context, group, out, level)) {
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = group.getChildCount();
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = group.getChildAt(i);
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
1128105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1);
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1130105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                dumpViewWithProperties(context, view, out, level + 1);
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1135105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static boolean dumpViewWithProperties(Context context, View view,
1136105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out, int level) {
1137105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < level; i++) {
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.write(' ');
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(view.getClass().getName());
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write('@');
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(Integer.toHexString(view.hashCode()));
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(' ');
1146105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            dumpViewProperties(context, view, out);
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.newLine();
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w("View", "Error while dumping hierarchy tree");
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Field[] getExportedPropertyFields(Class<?> klass) {
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sFieldsForClasses == null) {
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sFieldsForClasses = new HashMap<Class<?>, Field[]>();
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1159c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (sAnnotations == null) {
1160c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
1161c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1162c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Field[]> map = sFieldsForClasses;
1164c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations;
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Field[] fields = map.get(klass);
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fields != null) {
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fields;
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Field> foundFields = new ArrayList<Field>();
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = klass.getDeclaredFields();
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (field.isAnnotationPresent(ExportedProperty.class)) {
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                field.setAccessible(true);
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundFields.add(field);
1180c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                annotations.put(field, field.getAnnotation(ExportedProperty.class));
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = foundFields.toArray(new Field[foundFields.size()]);
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, fields);
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fields;
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Method[] getExportedPropertyMethods(Class<?> klass) {
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sMethodsForClasses == null) {
1192c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sMethodsForClasses = new HashMap<Class<?>, Method[]>(100);
1193c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1194c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (sAnnotations == null) {
1195c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1197c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Method[]> map = sMethodsForClasses;
1199c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations;
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Method[] methods = map.get(klass);
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (methods != null) {
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return methods;
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Method> foundMethods = new ArrayList<Method>();
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = klass.getDeclaredMethods();
1208a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
1211a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            final Method method = methods[i];
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (method.getParameterTypes().length == 0 &&
1213c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    method.isAnnotationPresent(ExportedProperty.class) &&
1214c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    method.getReturnType() != Void.class) {
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.setAccessible(true);
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundMethods.add(method);
1217c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                annotations.put(method, method.getAnnotation(ExportedProperty.class));
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = foundMethods.toArray(new Method[foundMethods.size()]);
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, methods);
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return methods;
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1227105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewProperties(Context context, Object view,
1228105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out) throws IOException {
1229105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1230105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        dumpViewProperties(context, view, out, "");
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1233105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void dumpViewProperties(Context context, Object view,
1234105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            BufferedWriter out, String prefix) throws IOException {
1235105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Class<?> klass = view.getClass();
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        do {
1239105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            exportFields(context, view, out, klass, prefix);
1240105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            exportMethods(context, view, out, klass, prefix);
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            klass = klass.getSuperclass();
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } while (klass != Object.class);
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1244a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
1245105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportMethods(Context context, Object view, BufferedWriter out,
1246105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Class<?> klass, String prefix) throws IOException {
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Method[] methods = getExportedPropertyMethods(klass);
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Method method = methods[i];
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection EmptyCatchBlock
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // TODO: This should happen on the UI thread
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object methodValue = method.invoke(view, (Object[]) null);
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> returnType = method.getReturnType();
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (returnType == int.class) {
1260c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final ExportedProperty property = sAnnotations.get(method);
1261105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (property.resolveId() && context != null) {
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int id = (Integer) methodValue;
1263105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        methodValue = resolveId(context, id);
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
1265809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        final FlagToString[] flagsMapping = property.flagMapping();
1266809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        if (flagsMapping.length > 0) {
1267809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final int intValue = (Integer) methodValue;
1268809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final String valuePrefix = prefix + method.getName() + '_';
1269809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
1270809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        }
1271809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final IntToString[] mapping = property.mapping();
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mapping.length > 0) {
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            final int intValue = (Integer) methodValue;
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            boolean mapped = false;
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            int mappingCount = mapping.length;
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int j = 0; j < mappingCount; j++) {
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                final IntToString mapper = mapping[j];
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (mapper.from() == intValue) {
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    methodValue = mapper.to();
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    mapped = true;
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    break;
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (!mapped) {
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                methodValue = intValue;
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1291c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else if (returnType == int[].class) {
1292c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final ExportedProperty property = sAnnotations.get(method);
1293c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final int[] array = (int[]) methodValue;
1294c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String valuePrefix = prefix + method.getName() + '_';
1295c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String suffix = "()";
1296c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1297105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (!returnType.isPrimitive()) {
1299c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final ExportedProperty property = sAnnotations.get(method);
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (property.deepExport()) {
1301105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        dumpViewProperties(context, methodValue, out, prefix + property.prefix());
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1306c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                writeEntry(out, prefix, method.getName(), "()", methodValue);
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (InvocationTargetException e) {
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1313105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportFields(Context context, Object view, BufferedWriter out,
1314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Class<?> klass, String prefix) throws IOException {
1315105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = getExportedPropertyFields(klass);
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection EmptyCatchBlock
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object fieldValue = null;
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> type = field.getType();
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type == int.class) {
1328c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final ExportedProperty property = sAnnotations.get(field);
1329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (property.resolveId() && context != null) {
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int id = field.getInt(view);
1331105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        fieldValue = resolveId(context, id);
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
1333809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        final FlagToString[] flagsMapping = property.flagMapping();
1334809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        if (flagsMapping.length > 0) {
1335809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final int intValue = field.getInt(view);
1336809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            final String valuePrefix = prefix + field.getName() + '_';
1337809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
1338809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                        }
1339809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final IntToString[] mapping = property.mapping();
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mapping.length > 0) {
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            final int intValue = field.getInt(view);
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            int mappingCount = mapping.length;
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int j = 0; j < mappingCount; j++) {
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                final IntToString mapped = mapping[j];
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (mapped.from() == intValue) {
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    fieldValue = mapped.to();
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    break;
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (fieldValue == null) {
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                fieldValue = intValue;
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1357c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                } else if (type == int[].class) {
1358c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final ExportedProperty property = sAnnotations.get(field);
1359c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final int[] array = (int[]) field.get(view);
1360c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String valuePrefix = prefix + field.getName() + '_';
1361c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final String suffix = "";
1362c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1363105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
1364c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1365c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    // We exit here!
1366c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    return;
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (!type.isPrimitive()) {
1368c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final ExportedProperty property = sAnnotations.get(field);
13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (property.deepExport()) {
1370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        dumpViewProperties(context, field.get(view), out,
1371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                prefix + property.prefix());
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fieldValue == null) {
13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fieldValue = field.get(view);
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1380c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                writeEntry(out, prefix, field.getName(), "", fieldValue);
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1386c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void writeEntry(BufferedWriter out, String prefix, String name,
1387c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String suffix, Object value) throws IOException {
1388c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1389c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(prefix);
1390c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(name);
1391c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(suffix);
1392c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write("=");
1393c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        writeValue(out, value);
1394c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        out.write(' ');
1395c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1396c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1397809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping,
1398809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            int intValue, String prefix) throws IOException {
1399809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
1400809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        final int count = mapping.length;
1401809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        for (int j = 0; j < count; j++) {
1402809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final FlagToString flagMapping = mapping[j];
1403809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final boolean ifTrue = flagMapping.outputIf();
14045bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy            final int maskResult = intValue & flagMapping.mask();
14055bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy            final boolean test = maskResult == flagMapping.equals();
1406809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            if ((test && ifTrue) || (!test && !ifTrue)) {
1407809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                final String name = flagMapping.name();
14085bcdff45bf4ada77ae7c95f520b795876adef75cRomain Guy                final String value = "0x" + Integer.toHexString(maskResult);
1409809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                writeEntry(out, prefix, name, "", value);
1410809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            }
1411809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        }
1412809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    }
1413809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
1414105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static void exportUnrolledArray(Context context, BufferedWriter out,
1415c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            ExportedProperty property, int[] array, String prefix, String suffix)
1416c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            throws IOException {
1417c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1418c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final IntToString[] indexMapping = property.indexMapping();
1419c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final boolean hasIndexMapping = indexMapping.length > 0;
1420c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1421c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final IntToString[] mapping = property.mapping();
1422c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final boolean hasMapping = mapping.length > 0;
1423c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        final boolean resolveId = property.resolveId() && context != null;
1425c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        final int valuesCount = array.length;
1426c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1427c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        for (int j = 0; j < valuesCount; j++) {
1428c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String name;
1429a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            String value = null;
1430c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1431c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            final int intValue = array[j];
1432c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1433c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            name = String.valueOf(j);
1434c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (hasIndexMapping) {
1435c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                int mappingCount = indexMapping.length;
1436c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                for (int k = 0; k < mappingCount; k++) {
1437c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final IntToString mapped = indexMapping[k];
1438c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    if (mapped.from() == j) {
1439c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        name = mapped.to();
1440c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        break;
1441c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
1442c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
1443c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1444c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1445c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (hasMapping) {
1446c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                int mappingCount = mapping.length;
1447c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                for (int k = 0; k < mappingCount; k++) {
1448c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    final IntToString mapped = mapping[k];
1449c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    if (mapped.from() == intValue) {
1450c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        value = mapped.to();
1451c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        break;
1452c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                    }
1453c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                }
1454c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1455c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1456c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (resolveId) {
1457a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                if (value == null) value = (String) resolveId(context, intValue);
1458a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            } else {
1459a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                value = String.valueOf(intValue);
1460c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1461c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1462c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            writeEntry(out, prefix, name, suffix, value);
1463c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1464c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1465c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1466237c1ceea36024cf4194212e713806e3ce8a1c49Romain Guy    static Object resolveId(Context context, int id) {
1467c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        Object fieldValue;
1468105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        final Resources resources = context.getResources();
1469c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (id >= 0) {
1470c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            try {
1471c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                fieldValue = resources.getResourceTypeName(id) + '/' +
1472c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                        resources.getResourceEntryName(id);
1473c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            } catch (Resources.NotFoundException e) {
1474c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                fieldValue = "id/0x" + Integer.toHexString(id);
1475c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
1476c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
1477c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            fieldValue = "NO_ID";
1478c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1479c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        return fieldValue;
1480c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1481c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
1482c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    private static void writeValue(BufferedWriter out, Object value) throws IOException {
1483c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        if (value != null) {
1484c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            String output = value.toString().replace("\n", "\\n");
1485c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write(String.valueOf(output.length()));
1486c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write(",");
1487c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write(output);
1488c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        } else {
1489c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            out.write("4,null");
1490c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        }
1491c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
1492c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void dumpViewHierarchy(ViewGroup group, BufferedWriter out, int level) {
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!dumpView(group, out, level)) {
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int count = group.getChildCount();
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View view = group.getChildAt(i);
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (view instanceof ViewGroup) {
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dumpViewHierarchy((ViewGroup) view, out, level + 1);
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dumpView(view, out, level + 1);
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean dumpView(Object view, BufferedWriter out, int level) {
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < level; i++) {
15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.write(' ');
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(view.getClass().getName());
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write('@');
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.write(Integer.toHexString(view.hashCode()));
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.newLine();
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w("View", "Error while dumping hierarchy tree");
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Field[] capturedViewGetPropertyFields(Class<?> klass) {
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCapturedViewFieldsForClasses == null) {
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>();
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses;
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Field[] fields = map.get(klass);
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fields != null) {
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fields;
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Field> foundFields = new ArrayList<Field>();
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = klass.getFields();
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (field.isAnnotationPresent(CapturedViewProperty.class)) {
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                field.setAccessible(true);
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundFields.add(field);
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fields = foundFields.toArray(new Field[foundFields.size()]);
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, fields);
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fields;
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Method[] capturedViewGetPropertyMethods(Class<?> klass) {
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCapturedViewMethodsForClasses == null) {
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>();
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses;
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Method[] methods = map.get(klass);
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (methods != null) {
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return methods;
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<Method> foundMethods = new ArrayList<Method>();
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = klass.getMethods();
1567a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
1570a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy            final Method method = methods[i];
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (method.getParameterTypes().length == 0 &&
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    method.isAnnotationPresent(CapturedViewProperty.class) &&
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    method.getReturnType() != Void.class) {
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.setAccessible(true);
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                foundMethods.add(method);
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        methods = foundMethods.toArray(new Method[foundMethods.size()]);
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.put(klass, methods);
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return methods;
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1584a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
1585a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    private static String capturedViewExportMethods(Object obj, Class<?> klass,
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String prefix) {
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (obj == null) {
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "null";
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1591a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder();
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Method[] methods = capturedViewGetPropertyMethods(klass);
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = methods.length;
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Method method = methods[i];
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object methodValue = method.invoke(obj, (Object[]) null);
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Class<?> returnType = method.getReturnType();
1601a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class);
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (property.retrieveReturn()) {
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    //we are interested in the second level data only
16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#"));
1606a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                } else {
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(prefix);
16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(method.getName());
16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("()=");
1610a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (methodValue != null) {
1612a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                        final String value = methodValue.toString().replace("\n", "\\n");
1613a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                        sb.append(value);
16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sb.append("null");
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("; ");
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              } catch (IllegalAccessException e) {
1620a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                  //Exception IllegalAccess, it is OK here
16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  //we simply ignore this method
16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              } catch (InvocationTargetException e) {
1623a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                  //Exception InvocationTarget, it is OK here
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  //we simply ignore this method
1625a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy              }
1626a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        }
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) {
1631a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (obj == null) {
16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "null";
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1635a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder();
16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = capturedViewGetPropertyFields(klass);
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fields.length;
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Field field = fields[i];
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Object fieldValue = field.get(obj);
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(prefix);
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(field.getName());
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append("=");
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fieldValue != null) {
16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final String value = fieldValue.toString().replace("\n", "\\n");
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append(value);
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sb.append("null");
16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(' ');
16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalAccessException e) {
1657a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy                //Exception IllegalAccess, it is OK here
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //we simply ignore this field
16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1663a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1665a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     * Dump view info for id based instrument test generation
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (and possibly further data analysis). The results are dumped
1667a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy     * to the log.
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param tag for log
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view for dump
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1671a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy    public static void dumpCapturedView(String tag, Object view) {
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Class<?> klass = view.getClass();
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder(klass.getName() + ": ");
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(capturedViewExportFields(view, klass, ""));
1675a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        sb.append(capturedViewExportMethods(view, klass, ""));
1676a1f3e4aef19882b4b81075d9205bd363efe1e66dRomain Guy        Log.d(tag, sb.toString());
16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1679