1 /**
2  * Copyright (c) 2011, Google Inc.
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 package com.android.mail.utils;
17 
18 import android.net.Uri;
19 import android.text.TextUtils;
20 import android.util.Log;
21 
22 import com.google.common.annotations.VisibleForTesting;
23 
24 import java.util.List;
25 import java.util.regex.Pattern;
26 
27 public class LogUtils {
28 
29     public static final String TAG = LogTag.getLogTag();
30 
31     // "GMT" + "+" or "-" + 4 digits
32     private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE =
33             Pattern.compile("GMT([-+]\\d{4})$");
34 
35     private static final String ACCOUNT_PREFIX = "account:";
36 
37     /**
38      * Priority constant for the println method; use LogUtils.v.
39      */
40     public static final int VERBOSE = Log.VERBOSE;
41 
42     /**
43      * Priority constant for the println method; use LogUtils.d.
44      */
45     public static final int DEBUG = Log.DEBUG;
46 
47     /**
48      * Priority constant for the println method; use LogUtils.i.
49      */
50     public static final int INFO = Log.INFO;
51 
52     /**
53      * Priority constant for the println method; use LogUtils.w.
54      */
55     public static final int WARN = Log.WARN;
56 
57     /**
58      * Priority constant for the println method; use LogUtils.e.
59      */
60     public static final int ERROR = Log.ERROR;
61 
62     /**
63      * Used to enable/disable logging that we don't want included in
64      * production releases.  This should be set to DEBUG for production releases, and VERBOSE for
65      * internal builds.
66      */
67     private static final int MAX_ENABLED_LOG_LEVEL = DEBUG;
68 
69     private static Boolean sDebugLoggingEnabledForTests = null;
70 
71     /**
72      * Enable debug logging for unit tests.
73      */
74     @VisibleForTesting
setDebugLoggingEnabledForTests(boolean enabled)75     public static void setDebugLoggingEnabledForTests(boolean enabled) {
76         setDebugLoggingEnabledForTestsInternal(enabled);
77     }
78 
setDebugLoggingEnabledForTestsInternal(boolean enabled)79     protected static void setDebugLoggingEnabledForTestsInternal(boolean enabled) {
80         sDebugLoggingEnabledForTests = Boolean.valueOf(enabled);
81     }
82 
83     /**
84      * Returns true if the build configuration prevents debug logging.
85      */
86     @VisibleForTesting
buildPreventsDebugLogging()87     public static boolean buildPreventsDebugLogging() {
88         return MAX_ENABLED_LOG_LEVEL > VERBOSE;
89     }
90 
91     /**
92      * Returns a boolean indicating whether debug logging is enabled.
93      */
isDebugLoggingEnabled(String tag)94     protected static boolean isDebugLoggingEnabled(String tag) {
95         if (buildPreventsDebugLogging()) {
96             return false;
97         }
98         if (sDebugLoggingEnabledForTests != null) {
99             return sDebugLoggingEnabledForTests.booleanValue();
100         }
101         return Log.isLoggable(tag, Log.DEBUG) || Log.isLoggable(TAG, Log.DEBUG);
102     }
103 
104     /**
105      * Returns a String for the specified content provider uri.  This will do
106      * sanitation of the uri to remove PII if debug logging is not enabled.
107      */
contentUriToString(final Uri uri)108     public static String contentUriToString(final Uri uri) {
109         return contentUriToString(TAG, uri);
110     }
111 
112     /**
113      * Returns a String for the specified content provider uri.  This will do
114      * sanitation of the uri to remove PII if debug logging is not enabled.
115      */
contentUriToString(String tag, Uri uri)116     public static String contentUriToString(String tag, Uri uri) {
117         if (isDebugLoggingEnabled(tag)) {
118             // Debug logging has been enabled, so log the uri as is
119             return uri.toString();
120         } else {
121             // Debug logging is not enabled, we want to remove the email address from the uri.
122             List<String> pathSegments = uri.getPathSegments();
123 
124             Uri.Builder builder = new Uri.Builder()
125                     .scheme(uri.getScheme())
126                     .authority(uri.getAuthority())
127                     .query(uri.getQuery())
128                     .fragment(uri.getFragment());
129 
130             // This assumes that the first path segment is the account
131             final String account = pathSegments.get(0);
132 
133             builder = builder.appendPath(sanitizeAccountName(account));
134             for (int i = 1; i < pathSegments.size(); i++) {
135                 builder.appendPath(pathSegments.get(i));
136             }
137             return builder.toString();
138         }
139     }
140 
141     /**
142      * Sanitizes an account name.  If debug logging is not enabled, a sanitized name
143      * is returned.
144      */
sanitizeAccountName(String accountName)145     public static String sanitizeAccountName(String accountName) {
146         if (TextUtils.isEmpty(accountName)) {
147             return "";
148         }
149 
150         return ACCOUNT_PREFIX + sanitizeName(TAG, accountName);
151     }
152 
sanitizeName(final String tag, final String name)153     public static String sanitizeName(final String tag, final String name) {
154         if (TextUtils.isEmpty(name)) {
155             return "";
156         }
157 
158         if (isDebugLoggingEnabled(tag)) {
159             return name;
160         }
161 
162         return String.valueOf(name.hashCode());
163     }
164 
165     /**
166      * Checks to see whether or not a log for the specified tag is loggable at the specified level.
167      */
isLoggable(String tag, int level)168     public static boolean isLoggable(String tag, int level) {
169         if (MAX_ENABLED_LOG_LEVEL > level) {
170             return false;
171         }
172         return Log.isLoggable(tag, level) || Log.isLoggable(TAG, level);
173     }
174 
175     /**
176      * Send a {@link #VERBOSE} log message.
177      * @param tag Used to identify the source of a log message.  It usually identifies
178      *        the class or activity where the log call occurs.
179      * @param format the format string (see {@link java.util.Formatter#format})
180      * @param args
181      *            the list of arguments passed to the formatter. If there are
182      *            more arguments than required by {@code format},
183      *            additional arguments are ignored.
184      */
v(String tag, String format, Object... args)185     public static int v(String tag, String format, Object... args) {
186         if (isLoggable(tag, VERBOSE)) {
187             return Log.v(tag, String.format(format, args));
188         }
189         return 0;
190     }
191 
192     /**
193      * Send a {@link #VERBOSE} log message.
194      * @param tag Used to identify the source of a log message.  It usually identifies
195      *        the class or activity where the log call occurs.
196      * @param tr An exception to log
197      * @param format the format string (see {@link java.util.Formatter#format})
198      * @param args
199      *            the list of arguments passed to the formatter. If there are
200      *            more arguments than required by {@code format},
201      *            additional arguments are ignored.
202      */
v(String tag, Throwable tr, String format, Object... args)203     public static int v(String tag, Throwable tr, String format, Object... args) {
204         if (isLoggable(tag, VERBOSE)) {
205             return Log.v(tag, String.format(format, args), tr);
206         }
207         return 0;
208     }
209 
210     /**
211      * Send a {@link #DEBUG} log message.
212      * @param tag Used to identify the source of a log message.  It usually identifies
213      *        the class or activity where the log call occurs.
214      * @param format the format string (see {@link java.util.Formatter#format})
215      * @param args
216      *            the list of arguments passed to the formatter. If there are
217      *            more arguments than required by {@code format},
218      *            additional arguments are ignored.
219      */
d(String tag, String format, Object... args)220     public static int d(String tag, String format, Object... args) {
221         if (isLoggable(tag, DEBUG)) {
222             return Log.d(tag, String.format(format, args));
223         }
224         return 0;
225     }
226 
227     /**
228      * Send a {@link #DEBUG} log message.
229      * @param tag Used to identify the source of a log message.  It usually identifies
230      *        the class or activity where the log call occurs.
231      * @param tr An exception to log
232      * @param format the format string (see {@link java.util.Formatter#format})
233      * @param args
234      *            the list of arguments passed to the formatter. If there are
235      *            more arguments than required by {@code format},
236      *            additional arguments are ignored.
237      */
d(String tag, Throwable tr, String format, Object... args)238     public static int d(String tag, Throwable tr, String format, Object... args) {
239         if (isLoggable(tag, DEBUG)) {
240             return Log.d(tag, String.format(format, args), tr);
241         }
242         return 0;
243     }
244 
245     /**
246      * Send a {@link #INFO} log message.
247      * @param tag Used to identify the source of a log message.  It usually identifies
248      *        the class or activity where the log call occurs.
249      * @param format the format string (see {@link java.util.Formatter#format})
250      * @param args
251      *            the list of arguments passed to the formatter. If there are
252      *            more arguments than required by {@code format},
253      *            additional arguments are ignored.
254      */
i(String tag, String format, Object... args)255     public static int i(String tag, String format, Object... args) {
256         if (isLoggable(tag, INFO)) {
257             return Log.i(tag, String.format(format, args));
258         }
259         return 0;
260     }
261 
262     /**
263      * Send a {@link #INFO} log message.
264      * @param tag Used to identify the source of a log message.  It usually identifies
265      *        the class or activity where the log call occurs.
266      * @param tr An exception to log
267      * @param format the format string (see {@link java.util.Formatter#format})
268      * @param args
269      *            the list of arguments passed to the formatter. If there are
270      *            more arguments than required by {@code format},
271      *            additional arguments are ignored.
272      */
i(String tag, Throwable tr, String format, Object... args)273     public static int i(String tag, Throwable tr, String format, Object... args) {
274         if (isLoggable(tag, INFO)) {
275             return Log.i(tag, String.format(format, args), tr);
276         }
277         return 0;
278     }
279 
280     /**
281      * Send a {@link #WARN} log message.
282      * @param tag Used to identify the source of a log message.  It usually identifies
283      *        the class or activity where the log call occurs.
284      * @param format the format string (see {@link java.util.Formatter#format})
285      * @param args
286      *            the list of arguments passed to the formatter. If there are
287      *            more arguments than required by {@code format},
288      *            additional arguments are ignored.
289      */
w(String tag, String format, Object... args)290     public static int w(String tag, String format, Object... args) {
291         if (isLoggable(tag, WARN)) {
292             return Log.w(tag, String.format(format, args));
293         }
294         return 0;
295     }
296 
297     /**
298      * Send a {@link #WARN} log message.
299      * @param tag Used to identify the source of a log message.  It usually identifies
300      *        the class or activity where the log call occurs.
301      * @param tr An exception to log
302      * @param format the format string (see {@link java.util.Formatter#format})
303      * @param args
304      *            the list of arguments passed to the formatter. If there are
305      *            more arguments than required by {@code format},
306      *            additional arguments are ignored.
307      */
w(String tag, Throwable tr, String format, Object... args)308     public static int w(String tag, Throwable tr, String format, Object... args) {
309         if (isLoggable(tag, WARN)) {
310             return Log.w(tag, String.format(format, args), tr);
311         }
312         return 0;
313     }
314 
315     /**
316      * Send a {@link #ERROR} log message.
317      * @param tag Used to identify the source of a log message.  It usually identifies
318      *        the class or activity where the log call occurs.
319      * @param format the format string (see {@link java.util.Formatter#format})
320      * @param args
321      *            the list of arguments passed to the formatter. If there are
322      *            more arguments than required by {@code format},
323      *            additional arguments are ignored.
324      */
e(String tag, String format, Object... args)325     public static int e(String tag, String format, Object... args) {
326         if (isLoggable(tag, ERROR)) {
327             return Log.e(tag, String.format(format, args));
328         }
329         return 0;
330     }
331 
332     /**
333      * Send a {@link #ERROR} log message.
334      * @param tag Used to identify the source of a log message.  It usually identifies
335      *        the class or activity where the log call occurs.
336      * @param tr An exception to log
337      * @param format the format string (see {@link java.util.Formatter#format})
338      * @param args
339      *            the list of arguments passed to the formatter. If there are
340      *            more arguments than required by {@code format},
341      *            additional arguments are ignored.
342      */
e(String tag, Throwable tr, String format, Object... args)343     public static int e(String tag, Throwable tr, String format, Object... args) {
344         if (isLoggable(tag, ERROR)) {
345             return Log.e(tag, String.format(format, args), tr);
346         }
347         return 0;
348     }
349 
350     /**
351      * What a Terrible Failure: Report a condition that should never happen.
352      * The error will always be logged at level ASSERT with the call stack.
353      * Depending on system configuration, a report may be added to the
354      * {@link android.os.DropBoxManager} and/or the process may be terminated
355      * immediately with an error dialog.
356      * @param tag Used to identify the source of a log message.  It usually identifies
357      *        the class or activity where the log call occurs.
358      * @param format the format string (see {@link java.util.Formatter#format})
359      * @param args
360      *            the list of arguments passed to the formatter. If there are
361      *            more arguments than required by {@code format},
362      *            additional arguments are ignored.
363      */
wtf(String tag, String format, Object... args)364     public static int wtf(String tag, String format, Object... args) {
365         return Log.wtf(tag, String.format(format, args), new Error());
366     }
367 
368     /**
369      * What a Terrible Failure: Report a condition that should never happen.
370      * The error will always be logged at level ASSERT with the call stack.
371      * Depending on system configuration, a report may be added to the
372      * {@link android.os.DropBoxManager} and/or the process may be terminated
373      * immediately with an error dialog.
374      * @param tag Used to identify the source of a log message.  It usually identifies
375      *        the class or activity where the log call occurs.
376      * @param tr An exception to log
377      * @param format the format string (see {@link java.util.Formatter#format})
378      * @param args
379      *            the list of arguments passed to the formatter. If there are
380      *            more arguments than required by {@code format},
381      *            additional arguments are ignored.
382      */
wtf(String tag, Throwable tr, String format, Object... args)383     public static int wtf(String tag, Throwable tr, String format, Object... args) {
384         return Log.wtf(tag, String.format(format, args), tr);
385     }
386 
387 
388     /**
389      * Try to make a date MIME(RFC 2822/5322)-compliant.
390      *
391      * It fixes:
392      * - "Thu, 10 Dec 09 15:08:08 GMT-0700" to "Thu, 10 Dec 09 15:08:08 -0700"
393      *   (4 digit zone value can't be preceded by "GMT")
394      *   We got a report saying eBay sends a date in this format
395      */
cleanUpMimeDate(String date)396     public static String cleanUpMimeDate(String date) {
397         if (TextUtils.isEmpty(date)) {
398             return date;
399         }
400         date = DATE_CLEANUP_PATTERN_WRONG_TIMEZONE.matcher(date).replaceFirst("$1");
401         return date;
402     }
403 
404 
byteToHex(int b)405     public static String byteToHex(int b) {
406         return byteToHex(new StringBuilder(), b).toString();
407     }
408 
byteToHex(StringBuilder sb, int b)409     public static StringBuilder byteToHex(StringBuilder sb, int b) {
410         b &= 0xFF;
411         sb.append("0123456789ABCDEF".charAt(b >> 4));
412         sb.append("0123456789ABCDEF".charAt(b & 0xF));
413         return sb;
414     }
415 
416 }
417