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
17package com.android.systemui.recents.misc;
18
19
20import android.content.ComponentCallbacks2;
21import android.content.Context;
22import android.util.Log;
23import android.view.MotionEvent;
24import android.widget.Toast;
25
26import java.util.HashMap;
27import java.util.Map;
28
29
30public 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 */
49    public static void log(String key) {
50        log(true, key, "", AnsiReset);
51    }
52
53    /** Logs a conditioned 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 */
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 */
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 */
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 */
81    public static void logRawError(String msg, Exception e) {
82        Log.e("Recents", msg, e);
83    }
84
85    /** Logs a divider bar */
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 */
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 */
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 */
113    public static void logStackTrace() {
114        logStackTrace("", 99);
115    }
116
117    /** Logs a stack trace to a certain 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 */
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 */
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
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