Utility.java revision 128fb393e8ed613c2ce283c0bd51684af2ba444d
196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* 296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License. 696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at 796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and 1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License. 1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email; 1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1933c972e0c62e474d2b2f5a293b92893cac0ea47aDoug Zongkerimport com.android.email.provider.EmailContent; 20da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadlerimport com.android.email.provider.EmailContent.Account; 21da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadlerimport com.android.email.provider.EmailContent.AccountColumns; 22da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadlerimport com.android.email.provider.EmailContent.HostAuth; 23da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadlerimport com.android.email.provider.EmailContent.HostAuthColumns; 24e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.Mailbox; 25e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.MailboxColumns; 26e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.Message; 27e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.MessageColumns; 28e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 29e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport android.content.ContentResolver; 30f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.content.Context; 31f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.content.res.TypedArray; 32e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport android.database.Cursor; 33f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.graphics.drawable.Drawable; 3459cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onukiimport android.os.AsyncTask; 35d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.security.MessageDigest; 36d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.telephony.TelephonyManager; 37f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.text.Editable; 38128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukiimport android.text.TextUtils; 396cec1104fe8863fce2ee86ff5145076e6c436a00Doug Zongkerimport android.util.Base64; 40d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.util.Log; 41f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.widget.TextView; 42e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException; 4496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream; 4596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStreamReader; 4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.UnsupportedEncodingException; 4720225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.ByteBuffer; 4820225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.CharBuffer; 4920225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.charset.Charset; 50d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport java.security.NoSuchAlgorithmException; 5196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Date; 52989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Predaimport java.util.GregorianCalendar; 53989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Predaimport java.util.TimeZone; 54128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukiimport java.util.regex.Pattern; 5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 5696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class Utility { 5720225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki public static final Charset UTF_8 = Charset.forName("UTF-8"); 5820225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki 59128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki // "GMT" + "+" or "-" + 4 digits 60128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE = 61128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki Pattern.compile("GMT([-+]\\d{4})$"); 62128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki 6396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public final static String readInputStream(InputStream in, String encoding) throws IOException { 6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project InputStreamReader reader = new InputStreamReader(in, encoding); 6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 6696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int count; 6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project char[] buf = new char[512]; 6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((count = reader.read(buf)) != -1) { 6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(buf, 0, count); 7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return sb.toString(); 7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public final static boolean arrayContains(Object[] a, Object o) { 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = a.length; i < count; i++) { 7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (a[i].equals(o)) { 7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Combines the given array of Objects into a single string using the 8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * seperator character and each Object's toString() method. between each 8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * part. 8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param parts 8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param seperator 9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String combine(Object[] parts, char seperator) { 9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (parts == null) { 9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0; i < parts.length; i++) { 9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(parts[i].toString()); 9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (i < parts.length - 1) { 10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(seperator); 10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return sb.toString(); 10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String base64Decode(String encoded) { 10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (encoded == null) { 10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 109f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker byte[] decoded = Base64.decode(encoded, Base64.DEFAULT); 11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new String(decoded); 11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String base64Encode(String s) { 11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (s == null) { 11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return s; 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 117f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker return Base64.encodeToString(s.getBytes(), Base64.NO_WRAP); 11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static boolean requiredFieldValid(TextView view) { 12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return view.getText() != null && view.getText().length() > 0; 12296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 12496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static boolean requiredFieldValid(Editable s) { 12596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return s != null && s.length() > 0; 12696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 12796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 12896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Ensures that the given string starts and ends with the double quote character. The string is not modified in any way except to add the 13096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * double quote character to start and end if it's not already there. 131f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 13296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * TODO: Rename this, because "quoteString()" can mean so many different things. 133f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 13496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * sample -> "sample" 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sample" -> "sample" 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * ""sample"" -> "sample" 13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sample"" -> "sample" 13896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * sa"mp"le -> "sa"mp"le" 13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sa"mp"le" -> "sa"mp"le" 14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * (empty string) -> "" 14196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * " -> "" 14296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param s 14396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 14496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 14596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String quoteString(String s) { 14696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (s == null) { 14796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 14896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 14996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!s.matches("^\".*\"$")) { 15096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "\"" + s + "\""; 15196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 15296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else { 15396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return s; 15496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 15596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 156f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 15796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 158f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * Apply quoting rules per IMAP RFC, 15996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * quoted = DQUOTE *QUOTED-CHAR DQUOTE 16096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials 16196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * quoted-specials = DQUOTE / "\" 162f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is used primarily for IMAP login, but might be useful elsewhere. 164f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 16596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * NOTE: Not very efficient - you may wish to preflight this, or perhaps it should check 16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * for trouble chars before calling the replace functions. 167f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param s The string to be quoted. 16996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return A copy of the string, having undergone quoting as described above 17096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 17196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String imapQuoted(String s) { 172f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 17396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // First, quote any backslashes by replacing \ with \\ 17496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // regex Pattern: \\ (Java string const = \\\\) 17596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Substitute: \\\\ (Java string const = \\\\\\\\) 17696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String result = s.replaceAll("\\\\", "\\\\\\\\"); 177f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 17896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Then, quote any double-quotes by replacing " with \" 17996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // regex Pattern: " (Java string const = \") 18096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Substitute: \\" (Java string const = \\\\\") 18196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project result = result.replaceAll("\"", "\\\\\""); 182f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 18396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // return string with quotes around it 18496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "\"" + result + "\""; 18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 186f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 18896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * A fast version of URLDecoder.decode() that works only with UTF-8 and does only two 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * allocations. This version is around 3x as fast as the standard one and I'm using it 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * hundreds of times in places that slow down the UI, so it helps. 19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String fastUrlDecode(String s) { 19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project byte[] bytes = s.getBytes("UTF-8"); 19596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project byte ch; 19696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int length = 0; 19796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = bytes.length; i < count; i++) { 19896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ch = bytes[i]; 19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (ch == '%') { 20096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int h = (bytes[i + 1] - '0'); 20196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int l = (bytes[i + 2] - '0'); 20296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (h > 9) { 20396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project h -= 7; 20496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (l > 9) { 20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project l -= 7; 20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = (byte) ((h << 4) | l); 20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project i += 2; 21096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (ch == '+') { 21296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = ' '; 21396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else { 21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = bytes[i]; 21696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project length++; 21896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new String(bytes, 0, length, "UTF-8"); 22096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (UnsupportedEncodingException uee) { 22296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 22396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Returns true if the specified date is within today. Returns false otherwise. 22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param date 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static boolean isDateToday(Date date) { 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // TODO But Calendar is so slowwwwwww.... 23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Date today = new Date(); 23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (date.getYear() == today.getYear() && 23596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project date.getMonth() == today.getMonth() && 23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project date.getDate() == today.getDate()) { 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 24296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * TODO disabled this method globally. It is used in all the settings screens but I just 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * noticed that an unrelated icon was dimmed. Android must share drawables internally. 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static void setCompoundDrawablesAlpha(TextView view, int alpha) { 24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// Drawable[] drawables = view.getCompoundDrawables(); 24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// for (Drawable drawable : drawables) { 24996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// if (drawable != null) { 25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// drawable.setAlpha(alpha); 25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// } 25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// } 25396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 254e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 255e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // TODO: unit test this 256e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler public static String buildMailboxIdSelection(ContentResolver resolver, long mailboxId) { 257e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // Setup default selection & args, then add to it as necessary 258e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler StringBuilder selection = new StringBuilder( 2596c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler MessageColumns.FLAG_LOADED + " IN (" 2606c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler + Message.FLAG_LOADED_PARTIAL + "," + Message.FLAG_LOADED_COMPLETE 2616c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler + ") AND "); 262e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (mailboxId == Mailbox.QUERY_ALL_INBOXES 263e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler || mailboxId == Mailbox.QUERY_ALL_DRAFTS 264e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler || mailboxId == Mailbox.QUERY_ALL_OUTBOX) { 265e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // query for all mailboxes of type INBOX, DRAFTS, or OUTBOX 266e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler int type; 267e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { 268e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_INBOX; 269e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) { 270e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_DRAFTS; 271e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else { 272e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_OUTBOX; 273e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 274e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler StringBuilder inboxes = new StringBuilder(); 275e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler Cursor c = resolver.query(Mailbox.CONTENT_URI, 276e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler EmailContent.ID_PROJECTION, 277e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler MailboxColumns.TYPE + "=? AND " + MailboxColumns.FLAG_VISIBLE + "=1", 278e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler new String[] { Integer.toString(type) }, null); 279e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // build an IN (mailboxId, ...) list 280e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // TODO do this directly in the provider 281e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler while (c.moveToNext()) { 282e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (inboxes.length() != 0) { 283e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler inboxes.append(","); 284e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 285e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler inboxes.append(c.getLong(EmailContent.ID_PROJECTION_COLUMN)); 286e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 287e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler c.close(); 288e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(MessageColumns.MAILBOX_KEY + " IN "); 289e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append("(").append(inboxes).append(")"); 290e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_UNREAD) { 291e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(Message.FLAG_READ + "=0"); 292e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) { 293e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(Message.FLAG_FAVORITE + "=1"); 294e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else { 295e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(MessageColumns.MAILBOX_KEY + "=" + mailboxId); 296e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 297e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler return selection.toString(); 298e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 299dadba9949895696108b31124fc0c6aa1a297ab1csatok 300dadba9949895696108b31124fc0c6aa1a297ab1csatok public static class FolderProperties { 301dadba9949895696108b31124fc0c6aa1a297ab1csatok 302dadba9949895696108b31124fc0c6aa1a297ab1csatok private static FolderProperties sInstance; 303dadba9949895696108b31124fc0c6aa1a297ab1csatok 304dadba9949895696108b31124fc0c6aa1a297ab1csatok // Caches for frequently accessed resources. 305dadba9949895696108b31124fc0c6aa1a297ab1csatok private String[] mSpecialMailbox = new String[] {}; 306dadba9949895696108b31124fc0c6aa1a297ab1csatok private TypedArray mSpecialMailboxDrawable; 307dadba9949895696108b31124fc0c6aa1a297ab1csatok private Drawable mDefaultMailboxDrawable; 3083786cab2aa1776e92fc67af3931a76cd8b848b48satok private Drawable mSummaryStarredMailboxDrawable; 3093786cab2aa1776e92fc67af3931a76cd8b848b48satok private Drawable mSummaryCombinedInboxDrawable; 310dadba9949895696108b31124fc0c6aa1a297ab1csatok 311dadba9949895696108b31124fc0c6aa1a297ab1csatok private FolderProperties(Context context) { 312fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler mSpecialMailbox = context.getResources().getStringArray(R.array.mailbox_display_names); 313dadba9949895696108b31124fc0c6aa1a297ab1csatok for (int i = 0; i < mSpecialMailbox.length; ++i) { 314dadba9949895696108b31124fc0c6aa1a297ab1csatok if ("".equals(mSpecialMailbox[i])) { 315dadba9949895696108b31124fc0c6aa1a297ab1csatok // there is no localized name, so use the display name from the server 316dadba9949895696108b31124fc0c6aa1a297ab1csatok mSpecialMailbox[i] = null; 317dadba9949895696108b31124fc0c6aa1a297ab1csatok } 318dadba9949895696108b31124fc0c6aa1a297ab1csatok } 319dadba9949895696108b31124fc0c6aa1a297ab1csatok mSpecialMailboxDrawable = 320fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler context.getResources().obtainTypedArray(R.array.mailbox_display_icons); 321dadba9949895696108b31124fc0c6aa1a297ab1csatok mDefaultMailboxDrawable = 322dadba9949895696108b31124fc0c6aa1a297ab1csatok context.getResources().getDrawable(R.drawable.ic_list_folder); 3233786cab2aa1776e92fc67af3931a76cd8b848b48satok mSummaryStarredMailboxDrawable = 3243786cab2aa1776e92fc67af3931a76cd8b848b48satok context.getResources().getDrawable(R.drawable.ic_list_starred); 3253786cab2aa1776e92fc67af3931a76cd8b848b48satok mSummaryCombinedInboxDrawable = 3263786cab2aa1776e92fc67af3931a76cd8b848b48satok context.getResources().getDrawable(R.drawable.ic_list_combined_inbox); 327dadba9949895696108b31124fc0c6aa1a297ab1csatok } 328dadba9949895696108b31124fc0c6aa1a297ab1csatok 3291f2caa80957e92519258e212b5fd45fb6c168a73Makoto Onuki public static synchronized FolderProperties getInstance(Context context) { 330dadba9949895696108b31124fc0c6aa1a297ab1csatok if (sInstance == null) { 3311f2caa80957e92519258e212b5fd45fb6c168a73Makoto Onuki sInstance = new FolderProperties(context); 332dadba9949895696108b31124fc0c6aa1a297ab1csatok } 333dadba9949895696108b31124fc0c6aa1a297ab1csatok return sInstance; 334dadba9949895696108b31124fc0c6aa1a297ab1csatok } 335dadba9949895696108b31124fc0c6aa1a297ab1csatok 336dadba9949895696108b31124fc0c6aa1a297ab1csatok /** 337dadba9949895696108b31124fc0c6aa1a297ab1csatok * Lookup names of localized special mailboxes 338dadba9949895696108b31124fc0c6aa1a297ab1csatok * @param type 339dadba9949895696108b31124fc0c6aa1a297ab1csatok * @return Localized strings 340dadba9949895696108b31124fc0c6aa1a297ab1csatok */ 341dadba9949895696108b31124fc0c6aa1a297ab1csatok public String getDisplayName(int type) { 342dadba9949895696108b31124fc0c6aa1a297ab1csatok if (type < mSpecialMailbox.length) { 343dadba9949895696108b31124fc0c6aa1a297ab1csatok return mSpecialMailbox[type]; 344dadba9949895696108b31124fc0c6aa1a297ab1csatok } 345dadba9949895696108b31124fc0c6aa1a297ab1csatok return null; 346dadba9949895696108b31124fc0c6aa1a297ab1csatok } 347dadba9949895696108b31124fc0c6aa1a297ab1csatok 348dadba9949895696108b31124fc0c6aa1a297ab1csatok /** 349dadba9949895696108b31124fc0c6aa1a297ab1csatok * Lookup icons of special mailboxes 350dadba9949895696108b31124fc0c6aa1a297ab1csatok * @param type 351dadba9949895696108b31124fc0c6aa1a297ab1csatok * @return icon's drawable 352dadba9949895696108b31124fc0c6aa1a297ab1csatok */ 3534bb52e36b18ab5e2fb9242069611bc0ef6116c09satok public Drawable getIconIds(int type) { 354dadba9949895696108b31124fc0c6aa1a297ab1csatok if (type < mSpecialMailboxDrawable.length()) { 355dadba9949895696108b31124fc0c6aa1a297ab1csatok return mSpecialMailboxDrawable.getDrawable(type); 356dadba9949895696108b31124fc0c6aa1a297ab1csatok } 357dadba9949895696108b31124fc0c6aa1a297ab1csatok return mDefaultMailboxDrawable; 358dadba9949895696108b31124fc0c6aa1a297ab1csatok } 3593786cab2aa1776e92fc67af3931a76cd8b848b48satok 3603786cab2aa1776e92fc67af3931a76cd8b848b48satok public Drawable getSummaryMailboxIconIds(long mailboxKey) { 3613786cab2aa1776e92fc67af3931a76cd8b848b48satok if (mailboxKey == Mailbox.QUERY_ALL_INBOXES) { 3623786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSummaryCombinedInboxDrawable; 3633786cab2aa1776e92fc67af3931a76cd8b848b48satok } else if (mailboxKey == Mailbox.QUERY_ALL_FAVORITES) { 3643786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSummaryStarredMailboxDrawable; 3653786cab2aa1776e92fc67af3931a76cd8b848b48satok } else if (mailboxKey == Mailbox.QUERY_ALL_DRAFTS) { 3663786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSpecialMailboxDrawable.getDrawable(Mailbox.TYPE_DRAFTS); 3673786cab2aa1776e92fc67af3931a76cd8b848b48satok } else if (mailboxKey == Mailbox.QUERY_ALL_OUTBOX) { 3683786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSpecialMailboxDrawable.getDrawable(Mailbox.TYPE_OUTBOX); 3693786cab2aa1776e92fc67af3931a76cd8b848b48satok } 3703786cab2aa1776e92fc67af3931a76cd8b848b48satok return mDefaultMailboxDrawable; 3713786cab2aa1776e92fc67af3931a76cd8b848b48satok } 372dadba9949895696108b31124fc0c6aa1a297ab1csatok } 373da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 374da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler private final static String HOSTAUTH_WHERE_CREDENTIALS = HostAuthColumns.ADDRESS + " like ?" 375da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler + " and " + HostAuthColumns.LOGIN + " like ?" 376da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler + " and " + HostAuthColumns.PROTOCOL + " not like \"smtp\""; 377da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler private final static String ACCOUNT_WHERE_HOSTAUTH = AccountColumns.HOST_AUTH_KEY_RECV + "=?"; 378da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 379da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler /** 380da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * Look for an existing account with the same username & server 381da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * 382da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param context a system context 383da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param allowAccountId this account Id will not trigger (when editing an existing account) 384da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param hostName the server 385da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param userLogin the user login string 386da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @result null = no dupes found. non-null = dupe account's display name 387da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler */ 388da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler public static String findDuplicateAccount(Context context, long allowAccountId, String hostName, 389da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler String userLogin) { 390da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler ContentResolver resolver = context.getContentResolver(); 391da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Cursor c = resolver.query(HostAuth.CONTENT_URI, HostAuth.ID_PROJECTION, 392da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler HOSTAUTH_WHERE_CREDENTIALS, new String[] { hostName, userLogin }, null); 393da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler try { 394da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler while (c.moveToNext()) { 395da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler long hostAuthId = c.getLong(HostAuth.ID_PROJECTION_COLUMN); 396da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler // Find account with matching hostauthrecv key, and return its display name 397da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Cursor c2 = resolver.query(Account.CONTENT_URI, Account.ID_PROJECTION, 398da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler ACCOUNT_WHERE_HOSTAUTH, new String[] { Long.toString(hostAuthId) }, null); 399da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler try { 400da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler while (c2.moveToNext()) { 401da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler long accountId = c2.getLong(Account.ID_PROJECTION_COLUMN); 402da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler if (accountId != allowAccountId) { 403da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Account account = Account.restoreAccountWithId(context, accountId); 404da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler if (account != null) { 405da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler return account.mDisplayName; 406da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 407da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 408da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 409da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } finally { 410da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler c2.close(); 411da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 412da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 413da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } finally { 414da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler c.close(); 415da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 416da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 417da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler return null; 418da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 419eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 420eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler /** 421eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Generate a random message-id header for locally-generated messages. 422eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler */ 423eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler public static String generateMessageId() { 424eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler StringBuffer sb = new StringBuffer(); 425eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("<"); 426eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler for (int i = 0; i < 24; i++) { 427eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append(Integer.toString((int)(Math.random() * 35), 36)); 428eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 429eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("."); 430eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append(Long.toString(System.currentTimeMillis())); 431eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("@email.android.com>"); 432eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler return sb.toString(); 433eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 434eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 435989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 436989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a time in milliseconds from a date string that represents a date/time in GMT 437989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param DateTime date string in format 20090211T180303Z (rfc2445, iCalendar). 438989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the time in milliseconds (since Jan 1, 1970) 439989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 440989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static long parseDateTimeToMillis(String date) { 441989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = parseDateTimeToCalendar(date); 442989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal.getTimeInMillis(); 443989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 444989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda 445989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 446989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a GregorianCalendar from a date string that represents a date/time in GMT 447989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param DateTime date string in format 20090211T180303Z (rfc2445, iCalendar). 448989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the GregorianCalendar 449989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 450989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static GregorianCalendar parseDateTimeToCalendar(String date) { 451989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = new GregorianCalendar(Integer.parseInt(date.substring(0, 4)), 452989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(4, 6)) - 1, Integer.parseInt(date.substring(6, 8)), 453989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(9, 11)), Integer.parseInt(date.substring(11, 13)), 454989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(13, 15))); 455989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda cal.setTimeZone(TimeZone.getTimeZone("GMT")); 456989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal; 457989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 458989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda 459989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 460989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a time in milliseconds from an email date string that represents a date/time in GMT 461989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param Email style DateTime string in format 2010-02-23T16:00:00.000Z (ISO 8601, rfc3339) 462989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the time in milliseconds (since Jan 1, 1970) 463989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 464989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static long parseEmailDateTimeToMillis(String date) { 465989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = new GregorianCalendar(Integer.parseInt(date.substring(0, 4)), 466989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(5, 7)) - 1, Integer.parseInt(date.substring(8, 10)), 467989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(11, 13)), Integer.parseInt(date.substring(14, 16)), 468989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(17, 19))); 469989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda cal.setTimeZone(TimeZone.getTimeZone("GMT")); 470989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal.getTimeInMillis(); 471989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 47220225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki 47320225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki /** Converts a String to UTF-8 */ 47420225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki public static byte[] toUtf8(String s) { 47520225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki if (s == null) { 47620225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki return null; 47720225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki } 47820225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki final ByteBuffer buffer = UTF_8.encode(CharBuffer.wrap(s)); 47920225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki final byte[] bytes = new byte[buffer.limit()]; 48020225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki buffer.get(bytes); 48120225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki return bytes; 48220225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki } 48388a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki 484fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki /** Build a String from UTF-8 bytes */ 485fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki public static String fromUtf8(byte[] b) { 486fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki if (b == null) { 487fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki return null; 488fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki } 489fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki final CharBuffer cb = Utility.UTF_8.decode(ByteBuffer.wrap(b)); 490fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki return new String(cb.array(), 0, cb.length()); 491fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki } 492fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki 49388a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki /** 49488a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki * @return true if the input is the first (or only) byte in a UTF-8 character 49588a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki */ 49688a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki public static boolean isFirstUtf8Byte(byte b) { 49788a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki // If the top 2 bits is '10', it's not a first byte. 49888a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki return (b & 0xc0) != 0x80; 49988a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki } 500dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki 501dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki public static String byteToHex(int b) { 502dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki return byteToHex(new StringBuilder(), b).toString(); 503dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki } 504dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki 505dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki public static StringBuilder byteToHex(StringBuilder sb, int b) { 506dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki b &= 0xFF; 507dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki sb.append("0123456789ABCDEF".charAt(b >> 4)); 508dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki sb.append("0123456789ABCDEF".charAt(b & 0xF)); 509dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki return sb; 510dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki } 511eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank 512eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank public static String replaceBareLfWithCrlf(String str) { 513eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank return str.replace("\r", "").replace("\n", "\r\n"); 514eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank } 51559cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki 51659cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki /** 51759cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * Cancel an {@link AsyncTask}. If it's already running, it'll be interrupted. 51859cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki */ 51959cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki public static void cancelTaskInterrupt(AsyncTask<?, ?, ?> task) { 52059cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki cancelTask(task, true); 52159cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 52259cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki 52359cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki /** 52459cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * Cancel an {@link AsyncTask}. 52559cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * 52659cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this 52759cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * task should be interrupted; otherwise, in-progress tasks are allowed 52859cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * to complete. 52959cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki */ 53059cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki public static void cancelTask(AsyncTask<?, ?, ?> task, boolean mayInterruptIfRunning) { 53159cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) { 53259cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki task.cancel(mayInterruptIfRunning); 53359cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 53459cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 535d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki 536d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /** 537d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki * @return Device's unique ID if available. null if the device has no unique ID. 538d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki */ 539d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki public static String getConsistentDeviceId(Context context) { 540d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final String deviceId; 541d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki try { 542d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki TelephonyManager tm = 543d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 544d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki if (tm == null) { 545d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 546d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 547d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki deviceId = tm.getDeviceId(); 548d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki if (deviceId == null) { 549d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 550d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 551d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } catch (Exception e) { 552d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki Log.d(Email.LOG_TAG, "Error in TelephonyManager.getDeviceId(): " + e.getMessage()); 553d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 554d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 555d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final MessageDigest sha; 556d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki try { 557d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki sha = MessageDigest.getInstance("SHA-1"); 558d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } catch (NoSuchAlgorithmException impossible) { 559d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 560d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 561d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki sha.update(Utility.toUtf8(deviceId)); 562d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final int hash = getSmallHashFromSha1(sha.digest()); 563d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return Integer.toString(hash); 564d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 565d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki 566d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /** 567d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki * @return a non-negative integer generated from 20 byte SHA-1 hash. 568d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki */ 569d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /* package for testing */ static int getSmallHashFromSha1(byte[] sha1) { 570d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final int offset = sha1[19] & 0xf; // SHA1 is 20 bytes. 571d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return ((sha1[offset] & 0x7f) << 24) 572d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 1] & 0xff) << 16) 573d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 2] & 0xff) << 8) 574d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 3] & 0xff)); 575d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 576128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki 577128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki /** 578128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * Try to make a date MIME(RFC 2822/5322)-compliant. 579128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * 580128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * It fixes: 581128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * - "Thu, 10 Dec 09 15:08:08 GMT-0700" to "Thu, 10 Dec 09 15:08:08 -0700" 582128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * (4 digit zone value can't be preceded by "GMT") 583128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * We got a report saying eBay sends a date in this format 584128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki */ 585128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki public static String cleanUpMimeDate(String date) { 586128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki if (TextUtils.isEmpty(date)) { 587128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki return date; 588128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki } 589128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki date = DATE_CLEANUP_PATTERN_WRONG_TIMEZONE.matcher(date).replaceFirst("$1"); 590128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki return date; 591128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki } 59296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project} 593