1 /*
2  * Copyright (C) 2018 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 androidx.constraintlayout.motion.widget;
18 
19 import android.annotation.SuppressLint;
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.util.Log;
23 import android.view.MotionEvent;
24 import android.view.View;
25 import android.view.ViewGroup;
26 
27 import java.lang.reflect.Field;
28 import java.nio.CharBuffer;
29 
30 // @TODO: add description
31 
32 /**
33  * Utilities useful for debugging
34  *
35  */
36 @SuppressLint("LogConditional")
37 public class Debug {
38 
39     /**
40      * This logs n elements in the stack
41      *
42      * @param tag
43      * @param msg
44      * @param n
45      *
46      */
logStack(String tag, String msg, int n)47     public static void logStack(String tag, String msg, int n) {
48         StackTraceElement[] st = new Throwable().getStackTrace();
49         String s = " ";
50         n = Math.min(n, st.length - 1);
51         for (int i = 1; i <= n; i++) {
52             @SuppressWarnings("unused") StackTraceElement ste = st[i];
53             String stack = ".(" + st[i].getFileName() + ":" + st[i].getLineNumber()
54                     + ") " + st[i].getMethodName();
55             s += " ";
56             Log.v(tag, msg + s + stack + s);
57         }
58     }
59 
60     /**
61      * This logs n elements in the stack
62      *
63      * @param msg
64      * @param n
65      *
66      */
printStack(String msg, int n)67     public static void printStack(String msg, int n) {
68         StackTraceElement[] st = new Throwable().getStackTrace();
69         String s = " ";
70         n = Math.min(n, st.length - 1);
71         for (int i = 1; i <= n; i++) {
72             @SuppressWarnings("unused") StackTraceElement ste = st[i];
73             String stack = ".(" + st[i].getFileName() + ":" + st[i].getLineNumber() + ") ";
74             s += " ";
75             System.out.println(msg + s + stack + s);
76         }
77     }
78 
79     /**
80      * This provides return the name of a view
81      *
82      * @param view
83      * @return name of view
84      *
85      */
getName(View view)86     public static String getName(View view) {
87         try {
88             Context context = view.getContext();
89             return context.getResources().getResourceEntryName(view.getId());
90         } catch (Exception ex) {
91             return "UNKNOWN";
92         }
93     }
94 
95     // @TODO: add description
96 
97     /**
98      * @param obj
99      */
dumpPoc(Object obj)100     public static void dumpPoc(Object obj) {
101         StackTraceElement s = new Throwable().getStackTrace()[1];
102         String loc = ".(" + s.getFileName() + ":" + s.getLineNumber() + ")";
103         Class c = obj.getClass();
104         System.out.println(loc + "------------- " + c.getName() + " --------------------");
105         Field[] declaredFields = c.getFields();
106         for (int i = 0; i < declaredFields.length; i++) {
107             Field declaredField = declaredFields[i];
108 
109             try {
110                 Object value = declaredField.get(obj);
111                 if (!declaredField.getName().startsWith("layout_constraint")) {
112                     continue;
113                 }
114                 if (value instanceof Integer && value.toString().equals("-1")) {
115                     continue;
116                 }
117                 if (value instanceof Integer && value.toString().equals("0")) {
118                     continue;
119                 }
120                 if (value instanceof Float && value.toString().equals("1.0")) {
121                     continue;
122                 }
123                 if (value instanceof Float && value.toString().equals("0.5")) {
124                     continue;
125                 }
126                 System.out.println(loc + "    " + declaredField.getName() + " " + value);
127             } catch (IllegalAccessException e) {
128 
129             }
130 
131         }
132         System.out.println(loc + "------------- " + c.getSimpleName() + " --------------------");
133 
134     }
135 
136     /**
137      * This returns the name of a view given its id
138      *
139      * @param context
140      * @param id
141      * @return name of view
142      *
143      */
getName(Context context, int id)144     public static String getName(Context context, int id) {
145         try {
146             if (id != -1) {
147                 return context.getResources().getResourceEntryName(id);
148             } else {
149                 return "UNKNOWN";
150             }
151         } catch (Exception ex) {
152             return "?" + id;
153         }
154     }
155 
156     /**
157      * This returns the name of a view given its id
158      *
159      * @param context
160      * @param id
161      * @return name of view
162      *
163      */
getName(Context context, int[] id)164     public static String getName(Context context, int[] id) {
165         try {
166             String str = id.length + "[";
167             for (int i = 0; i < id.length; i++) {
168                 str += (i == 0) ? "" : " ";
169                 String tmp = null;
170                 try {
171                     tmp = context.getResources().getResourceEntryName(id[i]);
172                 } catch (Resources.NotFoundException e) {
173                     tmp = "? " + id[i] + " ";
174                 }
175 
176                 str += tmp;
177 
178             }
179             return str + "]";
180         } catch (Exception ex) {
181             Log.v("DEBUG", ex.toString());
182             return "UNKNOWN";
183         }
184     }
185 
186     /**
187      * convert an id number to an id String useful in debugging
188      *
189      * @param layout
190      * @param stateId
191      * @return
192      */
getState(MotionLayout layout, int stateId)193     public static String getState(MotionLayout layout, int stateId) {
194         return getState(layout, stateId, -1);
195     }
196 
197     /**
198      * convert an id number to an id String useful in debugging
199      *
200      * @param layout
201      * @param stateId
202      * @param len     trim if string > len
203      * @return
204      */
getState(MotionLayout layout, int stateId, int len)205     public static String getState(MotionLayout layout, int stateId, int len) {
206         if (stateId == -1) {
207             return "UNDEFINED";
208         }
209         Context context = layout.getContext();
210         String str = context.getResources().getResourceEntryName(stateId);
211         if (len != -1) {
212             if (str.length() > len) {
213                 str = str.replaceAll("([^_])[aeiou]+", "$1"); // del vowels ! at start
214             }
215             if (str.length() > len) {
216                 int n = str.replaceAll("[^_]", "").length(); // count number of "_"
217                 if (n > 0) {
218                     int extra = (str.length() - len) / n;
219                     String reg = CharBuffer.allocate(extra).toString().replace('\0', '.') + "_";
220                     str = str.replaceAll(reg, "_");
221                 }
222             }
223         }
224         return str;
225     }
226 
227     /**
228      * Convert a motion event action to a string
229      *
230      * @param event
231      * @return
232      */
getActionType(MotionEvent event)233     public static String getActionType(MotionEvent event) {
234         int type = event.getAction();
235         Field[] fields = MotionEvent.class.getFields();
236         for (int i = 0; i < fields.length; i++) {
237             Field field = fields[i];
238             try {
239                 if (java.lang.reflect.Modifier.isStatic(field.getModifiers())
240                         && field.getType().equals(Integer.TYPE)
241                         && field.getInt(null) == type) {
242                     return field.getName();
243                 }
244             } catch (IllegalAccessException e) {
245             }
246         }
247         return "---";
248     }
249 
250     /**
251      * Get file name and location where this method is called.
252      * Formatting it such that it is clickable by Intellij
253      *
254      * @return (filename : line_no)
255      */
getLocation()256     public static String getLocation() {
257         StackTraceElement s = new Throwable().getStackTrace()[1];
258         return ".(" + s.getFileName() + ":" + s.getLineNumber() + ")";
259     }
260 
261     /**
262      * Get file name and location where this method is called.
263      * Formatting it such that it is clickable by Intellij
264      *
265      * @return (filename : line_no)
266      */
getLoc()267     public static String getLoc() {
268         StackTraceElement s = new Throwable().getStackTrace()[1];
269         return ".(" + s.getFileName() + ":" + s.getLineNumber() + ") " + s.getMethodName() + "()";
270     }
271 
272     /**
273      * Get file name and location where this method is called.
274      * Formatting it such that it is clickable by Intellij
275      *
276      * @return (filename : line_no)
277      */
getLocation2()278     public static String getLocation2() {
279         StackTraceElement s = new Throwable().getStackTrace()[2];
280         return ".(" + s.getFileName() + ":" + s.getLineNumber() + ")";
281     }
282 
283     /**
284      * Get file name and location where this method is called.
285      * Formatting it such that it is clickable by Intellij
286      *
287      * @return (filename : line_no)
288      */
getCallFrom(int n)289     public static String getCallFrom(int n) {
290         StackTraceElement s = new Throwable().getStackTrace()[2 + n];
291         return ".(" + s.getFileName() + ":" + s.getLineNumber() + ")";
292     }
293 
294     // @TODO: add description
295 
296     /**
297      *
298      * @param layout
299      * @param str
300      */
dumpLayoutParams(ViewGroup layout, String str)301     public static void dumpLayoutParams(ViewGroup layout, String str) {
302         StackTraceElement s = new Throwable().getStackTrace()[1];
303         String loc = ".(" + s.getFileName() + ":" + s.getLineNumber() + ") " + str + "  ";
304         int n = layout.getChildCount();
305         System.out.println(str + " children " + n);
306         for (int i = 0; i < n; i++) {
307             View v = layout.getChildAt(i);
308             System.out.println(loc + "     " + getName(v));
309             ViewGroup.LayoutParams param = v.getLayoutParams();
310             Field[] declaredFields = param.getClass().getFields();
311             for (int k = 0; k < declaredFields.length; k++) {
312                 Field declaredField = declaredFields[k];
313 
314                 try {
315                     Object value = declaredField.get(param);
316                     String name = declaredField.getName();
317                     if (!name.contains("To")) {
318                         continue;
319                     }
320                     if (value.toString().equals("-1")) {
321                         continue;
322                     }
323 
324                     System.out.println(loc + "       " + declaredField.getName() + " " + value);
325                 } catch (IllegalAccessException e) {
326 
327                 }
328 
329             }
330 
331         }
332     }
333 
334     // @TODO: add description
335 
336     /**
337      *
338      * @param param
339      * @param str
340      */
dumpLayoutParams(ViewGroup.LayoutParams param, String str)341     public static void dumpLayoutParams(ViewGroup.LayoutParams param, String str) {
342         StackTraceElement s = new Throwable().getStackTrace()[1];
343         String loc = ".(" + s.getFileName() + ":" + s.getLineNumber() + ") " + str + "  ";
344         System.out.println(" >>>>>>>>>>>>>>>>>>. dump " + loc + "  " + param.getClass().getName());
345 
346         Field[] declaredFields = param.getClass().getFields();
347         for (int k = 0; k < declaredFields.length; k++) {
348             Field declaredField = declaredFields[k];
349 
350             try {
351                 Object value = declaredField.get(param);
352                 String name = declaredField.getName();
353                 if (!name.contains("To")) {
354                     continue;
355                 }
356                 if (value.toString().equals("-1")) {
357                     continue;
358                 }
359 //                    if (value instanceof  Integer && value.toString().equals("-1")) {
360 //                        continue;
361 //                    }
362 
363                 System.out.println(loc + "       " + name + " " + value);
364             } catch (IllegalAccessException e) {
365 
366             }
367 
368         }
369         System.out.println(" <<<<<<<<<<<<<<<<< dump " + loc);
370 
371     }
372 }
373