1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.util;
18 
19 import java.lang.reflect.Method;
20 import java.lang.reflect.InvocationTargetException;
21 import java.util.Locale;
22 
23 /**
24  * <p>Various utilities for debugging and logging.</p>
25  */
26 public class DebugUtils {
DebugUtils()27     /** @hide */ public DebugUtils() {}
28 
29     /**
30      * <p>Filters objects against the <code>ANDROID_OBJECT_FILTER</code>
31      * environment variable. This environment variable can filter objects
32      * based on their class name and attribute values.</p>
33      *
34      * <p>Here is the syntax for <code>ANDROID_OBJECT_FILTER</code>:</p>
35      *
36      * <p><code>ClassName@attribute1=value1@attribute2=value2...</code></p>
37      *
38      * <p>Examples:</p>
39      * <ul>
40      * <li>Select TextView instances: <code>TextView</code></li>
41      * <li>Select TextView instances of text "Loading" and bottom offset of 22:
42      * <code>TextView@text=Loading.*@bottom=22</code></li>
43      * </ul>
44      *
45      * <p>The class name and the values are regular expressions.</p>
46      *
47      * <p>This class is useful for debugging and logging purpose:</p>
48      * <pre>
49      * if (DEBUG) {
50      *   if (DebugUtils.isObjectSelected(childView) && LOGV_ENABLED) {
51      *     Log.v(TAG, "Object " + childView + " logged!");
52      *   }
53      * }
54      * </pre>
55      *
56      * <p><strong>NOTE</strong>: This method is very expensive as it relies
57      * heavily on regular expressions and reflection. Calls to this method
58      * should always be stripped out of the release binaries and avoided
59      * as much as possible in debug mode.</p>
60      *
61      * @param object any object to match against the ANDROID_OBJECT_FILTER
62      *        environement variable
63      * @return true if object is selected by the ANDROID_OBJECT_FILTER
64      *         environment variable, false otherwise
65      */
isObjectSelected(Object object)66     public static boolean isObjectSelected(Object object) {
67         boolean match = false;
68         String s = System.getenv("ANDROID_OBJECT_FILTER");
69         if (s != null && s.length() > 0) {
70             String[] selectors = s.split("@");
71             // first selector == class name
72             if (object.getClass().getSimpleName().matches(selectors[0])) {
73                 // check potential attributes
74                 for (int i = 1; i < selectors.length; i++) {
75                     String[] pair = selectors[i].split("=");
76                     Class<?> klass = object.getClass();
77                     try {
78                         Method declaredMethod = null;
79                         Class<?> parent = klass;
80                         do {
81                             declaredMethod = parent.getDeclaredMethod("get" +
82                                     pair[0].substring(0, 1).toUpperCase(Locale.ROOT) +
83                                     pair[0].substring(1),
84                                     (Class[]) null);
85                         } while ((parent = klass.getSuperclass()) != null &&
86                                 declaredMethod == null);
87 
88                         if (declaredMethod != null) {
89                             Object value = declaredMethod
90                                     .invoke(object, (Object[])null);
91                             match |= (value != null ?
92                                     value.toString() : "null").matches(pair[1]);
93                         }
94                     } catch (NoSuchMethodException e) {
95                         e.printStackTrace();
96                     } catch (IllegalAccessException e) {
97                         e.printStackTrace();
98                     } catch (InvocationTargetException e) {
99                         e.printStackTrace();
100                     }
101                 }
102             }
103         }
104         return match;
105     }
106 
107     /** @hide */
buildShortClassTag(Object cls, StringBuilder out)108     public static void buildShortClassTag(Object cls, StringBuilder out) {
109         if (cls == null) {
110             out.append("null");
111         } else {
112             String simpleName = cls.getClass().getSimpleName();
113             if (simpleName == null || simpleName.isEmpty()) {
114                 simpleName = cls.getClass().getName();
115                 int end = simpleName.lastIndexOf('.');
116                 if (end > 0) {
117                     simpleName = simpleName.substring(end+1);
118                 }
119             }
120             out.append(simpleName);
121             out.append('{');
122             out.append(Integer.toHexString(System.identityHashCode(cls)));
123         }
124     }
125 
126 }
127