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