1 /*
2  * Copyright (C) 2014 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 com.android.systemui.recents.misc;
18 
19 
20 import android.content.ComponentCallbacks2;
21 import android.content.Context;
22 import android.util.Log;
23 import android.view.MotionEvent;
24 import android.widget.Toast;
25 
26 import java.util.HashMap;
27 import java.util.Map;
28 
29 
30 public class Console {
31     // Timer
32     public static final Map<Object, Long> mTimeLogs = new HashMap<Object, Long>();
33 
34     // Colors
35     public static final String AnsiReset = "\u001B[0m";
36     public static final String AnsiBlack = "\u001B[30m";
37     public static final String AnsiRed = "\u001B[31m";      // SystemUIHandshake
38     public static final String AnsiGreen = "\u001B[32m";    // MeasureAndLayout
39     public static final String AnsiYellow = "\u001B[33m";   // SynchronizeViewsWithModel
40     public static final String AnsiBlue = "\u001B[34m";     // TouchEvents, Search
41     public static final String AnsiPurple = "\u001B[35m";   // Draw
42     public static final String AnsiCyan = "\u001B[36m";     // ClickEvents
43     public static final String AnsiWhite = "\u001B[37m";
44 
45     // Console enabled state
46     public static boolean Enabled = false;
47 
48     /** Logs a key */
log(String key)49     public static void log(String key) {
50         log(true, key, "", AnsiReset);
51     }
52 
53     /** Logs a conditioned key */
log(boolean condition, String key)54     public static void log(boolean condition, String key) {
55         if (condition) {
56             log(condition, key, "", AnsiReset);
57         }
58     }
59 
60     /** Logs a key in a specific color */
log(boolean condition, String key, Object data)61     public static void log(boolean condition, String key, Object data) {
62         if (condition) {
63             log(condition, key, data, AnsiReset);
64         }
65     }
66 
67     /** Logs a key with data in a specific color */
log(boolean condition, String key, Object data, String color)68     public static void log(boolean condition, String key, Object data, String color) {
69         if (condition) {
70             System.out.println(color + key + AnsiReset + " " + data.toString());
71         }
72     }
73 
74     /** Logs an error */
logError(Context context, String msg)75     public static void logError(Context context, String msg) {
76         Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
77         Log.e("Recents", msg);
78     }
79 
80     /** Logs a raw error */
logRawError(String msg, Exception e)81     public static void logRawError(String msg, Exception e) {
82         Log.e("Recents", msg, e);
83     }
84 
85     /** Logs a divider bar */
logDivider(boolean condition)86     public static void logDivider(boolean condition) {
87         if (condition) {
88             System.out.println("==== [" + System.currentTimeMillis() +
89                     "] ============================================================");
90         }
91     }
92 
93     /** Starts a time trace */
logStartTracingTime(boolean condition, String key)94     public static void logStartTracingTime(boolean condition, String key) {
95         if (condition) {
96             long curTime = System.currentTimeMillis();
97             mTimeLogs.put(key, curTime);
98             Console.log(condition, "[Recents|" + key + "]",
99                     "started @ " + curTime);
100         }
101     }
102 
103     /** Continues a time trace */
logTraceTime(boolean condition, String key, String desc)104     public static void logTraceTime(boolean condition, String key, String desc) {
105         if (condition) {
106             long timeDiff = System.currentTimeMillis() - mTimeLogs.get(key);
107             Console.log(condition, "[Recents|" + key + "|" + desc + "]",
108                     "+" + timeDiff + "ms");
109         }
110     }
111 
112     /** Logs a stack trace */
logStackTrace()113     public static void logStackTrace() {
114         logStackTrace("", 99);
115     }
116 
117     /** Logs a stack trace to a certain depth */
logStackTrace(int depth)118     public static void logStackTrace(int depth) {
119         logStackTrace("", depth);
120     }
121 
122     /** Logs a stack trace to a certain depth with a key */
logStackTrace(String key, int depth)123     public static void logStackTrace(String key, int depth) {
124         int offset = 0;
125         StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
126         String tinyStackTrace = "";
127         // Skip over the known stack trace classes
128         for (int i = 0; i < callStack.length; i++) {
129             StackTraceElement el = callStack[i];
130             String className = el.getClassName();
131             if (className.indexOf("dalvik.system.VMStack") == -1 &&
132                 className.indexOf("java.lang.Thread") == -1 &&
133                 className.indexOf("recents.Console") == -1) {
134                 break;
135             } else {
136                 offset++;
137             }
138         }
139         // Build the pretty stack trace
140         int start = Math.min(offset + depth, callStack.length);
141         int end = offset;
142         String indent = "";
143         for (int i = start - 1; i >= end; i--) {
144             StackTraceElement el = callStack[i];
145             tinyStackTrace += indent + " -> " + el.getClassName() +
146                     "[" + el.getLineNumber() + "]." + el.getMethodName();
147             if (i > end) {
148                 tinyStackTrace += "\n";
149                 indent += "  ";
150             }
151         }
152         log(true, key, tinyStackTrace, AnsiRed);
153     }
154 
155 
156     /** Returns the stringified MotionEvent action */
motionEventActionToString(int action)157     public static String motionEventActionToString(int action) {
158         switch (action) {
159             case MotionEvent.ACTION_DOWN:
160                 return "Down";
161             case MotionEvent.ACTION_UP:
162                 return "Up";
163             case MotionEvent.ACTION_MOVE:
164                 return "Move";
165             case MotionEvent.ACTION_CANCEL:
166                 return "Cancel";
167             case MotionEvent.ACTION_POINTER_DOWN:
168                 return "Pointer Down";
169             case MotionEvent.ACTION_POINTER_UP:
170                 return "Pointer Up";
171             default:
172                 return "" + action;
173         }
174     }
175 
trimMemoryLevelToString(int level)176     public static String trimMemoryLevelToString(int level) {
177         switch (level) {
178             case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
179                 return "UI Hidden";
180             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
181                 return "Running Moderate";
182             case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
183                 return "Background";
184             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
185                 return "Running Low";
186             case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
187                 return "Moderate";
188             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
189                 return "Critical";
190             case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
191                 return "Complete";
192             default:
193                 return "" + level;
194         }
195     }
196 }
197