Utility.java revision f52afae9424fe41071cc34a8d6cbcb82b992a411
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 297e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onukiimport android.app.Activity; 30e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport android.content.ContentResolver; 31f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.content.Context; 32533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onukiimport android.content.pm.ActivityInfo; 3344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onukiimport android.content.res.Resources; 34f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.content.res.TypedArray; 35e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport android.database.Cursor; 36f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.graphics.drawable.Drawable; 37bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onukiimport android.net.Uri; 3859cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onukiimport android.os.AsyncTask; 39833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onukiimport android.os.Parcelable; 40d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.security.MessageDigest; 41d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.telephony.TelephonyManager; 42128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukiimport android.text.TextUtils; 436cec1104fe8863fce2ee86ff5145076e6c436a00Doug Zongkerimport android.util.Base64; 44d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.util.Log; 45833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onukiimport android.widget.AbsListView; 46f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.widget.TextView; 477e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onukiimport android.widget.Toast; 48e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 497e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport java.io.ByteArrayInputStream; 5044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onukiimport java.io.File; 5196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException; 5296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream; 5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStreamReader; 5496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.UnsupportedEncodingException; 5520225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.ByteBuffer; 5620225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.CharBuffer; 5720225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.charset.Charset; 58d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport java.security.NoSuchAlgorithmException; 59f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onukiimport java.util.ArrayList; 6096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Date; 61989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Predaimport java.util.GregorianCalendar; 62989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Predaimport java.util.TimeZone; 63128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukiimport java.util.regex.Pattern; 6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class Utility { 6620225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki public static final Charset UTF_8 = Charset.forName("UTF-8"); 677e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static final Charset ASCII = Charset.forName("US-ASCII"); 687e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 697e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static final String[] EMPTY_STRINGS = new String[0]; 70f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public static final Long[] EMPTY_LONGS = new Long[0]; 7120225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki 72128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki // "GMT" + "+" or "-" + 4 digits 73128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE = 74128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki Pattern.compile("GMT([-+]\\d{4})$"); 75128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki 7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public final static String readInputStream(InputStream in, String encoding) throws IOException { 7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project InputStreamReader reader = new InputStreamReader(in, encoding); 7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int count; 8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project char[] buf = new char[512]; 8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((count = reader.read(buf)) != -1) { 8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(buf, 0, count); 8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return sb.toString(); 8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public final static boolean arrayContains(Object[] a, Object o) { 8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = a.length; i < count; i++) { 8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (a[i].equals(o)) { 9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Combines the given array of Objects into a single string using the 9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * seperator character and each Object's toString() method. between each 9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * part. 10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param parts 10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param seperator 10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String combine(Object[] parts, char seperator) { 10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (parts == null) { 10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0; i < parts.length; i++) { 11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(parts[i].toString()); 11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (i < parts.length - 1) { 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(seperator); 11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return sb.toString(); 11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String base64Decode(String encoded) { 11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (encoded == null) { 12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 122f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker byte[] decoded = Base64.decode(encoded, Base64.DEFAULT); 12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new String(decoded); 12496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 12596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 12696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String base64Encode(String s) { 12796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (s == null) { 12896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return s; 12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 130f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker return Base64.encodeToString(s.getBytes(), Base64.NO_WRAP); 13196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 13296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 133e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank public static boolean isTextViewNotEmpty(TextView view) { 134e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank return !TextUtils.isEmpty(view.getText()); 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 137e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank public static boolean isPortFieldValid(TextView view) { 138e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank CharSequence chars = view.getText(); 139e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank if (TextUtils.isEmpty(chars)) return false; 140e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank Integer port; 141e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank // In theory, we can't get an illegal value here, since the field is monitored for valid 142e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank // numeric input. But this might be used elsewhere without such a check. 143e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank try { 144e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank port = Integer.parseInt(chars.toString()); 145e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank } catch (NumberFormatException e) { 146e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank return false; 147e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank } 148e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank return port > 0 && port < 65536; 149e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank } 15096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 15196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 152e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank * Ensures that the given string starts and ends with the double quote character. The string is 153e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank * not modified in any way except to add the double quote character to start and end if it's not 154e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank * already there. 155f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 15696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * TODO: Rename this, because "quoteString()" can mean so many different things. 157f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 15896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * sample -> "sample" 15996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sample" -> "sample" 16096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * ""sample"" -> "sample" 16196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sample"" -> "sample" 16296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * sa"mp"le -> "sa"mp"le" 16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sa"mp"le" -> "sa"mp"le" 16496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * (empty string) -> "" 16596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * " -> "" 16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param s 16796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 16996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String quoteString(String s) { 17096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (s == null) { 17196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 17296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 17396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!s.matches("^\".*\"$")) { 17496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "\"" + s + "\""; 17596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 17696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else { 17796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return s; 17896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 17996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 180f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 18196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 182f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * Apply quoting rules per IMAP RFC, 18396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * quoted = DQUOTE *QUOTED-CHAR DQUOTE 18496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials 18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * quoted-specials = DQUOTE / "\" 186f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is used primarily for IMAP login, but might be useful elsewhere. 188f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * NOTE: Not very efficient - you may wish to preflight this, or perhaps it should check 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * for trouble chars before calling the replace functions. 191f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param s The string to be quoted. 19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return A copy of the string, having undergone quoting as described above 19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 19596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String imapQuoted(String s) { 196f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 19796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // First, quote any backslashes by replacing \ with \\ 19896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // regex Pattern: \\ (Java string const = \\\\) 19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Substitute: \\\\ (Java string const = \\\\\\\\) 20096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String result = s.replaceAll("\\\\", "\\\\\\\\"); 201f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 20296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Then, quote any double-quotes by replacing " with \" 20396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // regex Pattern: " (Java string const = \") 20496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Substitute: \\" (Java string const = \\\\\") 20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project result = result.replaceAll("\"", "\\\\\""); 206f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // return string with quotes around it 20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "\"" + result + "\""; 20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 210f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 21196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 21296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * A fast version of URLDecoder.decode() that works only with UTF-8 and does only two 21396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * allocations. This version is around 3x as fast as the standard one and I'm using it 21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * hundreds of times in places that slow down the UI, so it helps. 21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 21696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String fastUrlDecode(String s) { 21796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 21896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project byte[] bytes = s.getBytes("UTF-8"); 21996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project byte ch; 22096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int length = 0; 22196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = bytes.length; i < count; i++) { 22296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ch = bytes[i]; 22396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (ch == '%') { 22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int h = (bytes[i + 1] - '0'); 22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int l = (bytes[i + 2] - '0'); 22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (h > 9) { 22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project h -= 7; 22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (l > 9) { 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project l -= 7; 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = (byte) ((h << 4) | l); 23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project i += 2; 23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (ch == '+') { 23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = ' '; 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else { 23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = bytes[i]; 24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project length++; 24296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new String(bytes, 0, length, "UTF-8"); 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (UnsupportedEncodingException uee) { 24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Returns true if the specified date is within today. Returns false otherwise. 25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param date 25396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static boolean isDateToday(Date date) { 25696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // TODO But Calendar is so slowwwwwww.... 25796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Date today = new Date(); 25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (date.getYear() == today.getYear() && 25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project date.getMonth() == today.getMonth() && 26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project date.getDate() == today.getDate()) { 26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * TODO disabled this method globally. It is used in all the settings screens but I just 26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * noticed that an unrelated icon was dimmed. Android must share drawables internally. 26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static void setCompoundDrawablesAlpha(TextView view, int alpha) { 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// Drawable[] drawables = view.getCompoundDrawables(); 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// for (Drawable drawable : drawables) { 27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// if (drawable != null) { 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// drawable.setAlpha(alpha); 27596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// } 27696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// } 27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 278e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 279e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // TODO: unit test this 280e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler public static String buildMailboxIdSelection(ContentResolver resolver, long mailboxId) { 281e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // Setup default selection & args, then add to it as necessary 282e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler StringBuilder selection = new StringBuilder( 2836c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler MessageColumns.FLAG_LOADED + " IN (" 2846c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler + Message.FLAG_LOADED_PARTIAL + "," + Message.FLAG_LOADED_COMPLETE 2856c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler + ") AND "); 286e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (mailboxId == Mailbox.QUERY_ALL_INBOXES 287e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler || mailboxId == Mailbox.QUERY_ALL_DRAFTS 288e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler || mailboxId == Mailbox.QUERY_ALL_OUTBOX) { 289e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // query for all mailboxes of type INBOX, DRAFTS, or OUTBOX 290e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler int type; 291e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { 292e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_INBOX; 293e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) { 294e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_DRAFTS; 295e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else { 296e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_OUTBOX; 297e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 298e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler StringBuilder inboxes = new StringBuilder(); 299e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler Cursor c = resolver.query(Mailbox.CONTENT_URI, 300e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler EmailContent.ID_PROJECTION, 301e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler MailboxColumns.TYPE + "=? AND " + MailboxColumns.FLAG_VISIBLE + "=1", 302e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler new String[] { Integer.toString(type) }, null); 303e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // build an IN (mailboxId, ...) list 304e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // TODO do this directly in the provider 305e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler while (c.moveToNext()) { 306e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (inboxes.length() != 0) { 307e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler inboxes.append(","); 308e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 309e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler inboxes.append(c.getLong(EmailContent.ID_PROJECTION_COLUMN)); 310e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 311e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler c.close(); 312e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(MessageColumns.MAILBOX_KEY + " IN "); 313e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append("(").append(inboxes).append(")"); 314e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_UNREAD) { 315e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(Message.FLAG_READ + "=0"); 316e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) { 317e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(Message.FLAG_FAVORITE + "=1"); 318e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else { 319e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(MessageColumns.MAILBOX_KEY + "=" + mailboxId); 320e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 321e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler return selection.toString(); 322e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 323dadba9949895696108b31124fc0c6aa1a297ab1csatok 324833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // TODO When the UI is settled, cache all strings/drawables 325833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // TODO When the UI is settled, write up tests 326833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // TODO When the UI is settled, remove backward-compatibility methods 327dadba9949895696108b31124fc0c6aa1a297ab1csatok public static class FolderProperties { 328dadba9949895696108b31124fc0c6aa1a297ab1csatok 329dadba9949895696108b31124fc0c6aa1a297ab1csatok private static FolderProperties sInstance; 330dadba9949895696108b31124fc0c6aa1a297ab1csatok 331833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Context mContext; 332833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 333dadba9949895696108b31124fc0c6aa1a297ab1csatok // Caches for frequently accessed resources. 334833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final String[] mSpecialMailbox; 335833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final TypedArray mSpecialMailboxDrawable; 336833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Drawable mDefaultMailboxDrawable; 337833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Drawable mSummaryStarredMailboxDrawable; 338833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Drawable mSummaryCombinedInboxDrawable; 339dadba9949895696108b31124fc0c6aa1a297ab1csatok 340dadba9949895696108b31124fc0c6aa1a297ab1csatok private FolderProperties(Context context) { 341833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki mContext = context.getApplicationContext(); 342fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler mSpecialMailbox = context.getResources().getStringArray(R.array.mailbox_display_names); 343dadba9949895696108b31124fc0c6aa1a297ab1csatok for (int i = 0; i < mSpecialMailbox.length; ++i) { 344dadba9949895696108b31124fc0c6aa1a297ab1csatok if ("".equals(mSpecialMailbox[i])) { 345dadba9949895696108b31124fc0c6aa1a297ab1csatok // there is no localized name, so use the display name from the server 346dadba9949895696108b31124fc0c6aa1a297ab1csatok mSpecialMailbox[i] = null; 347dadba9949895696108b31124fc0c6aa1a297ab1csatok } 348dadba9949895696108b31124fc0c6aa1a297ab1csatok } 349dadba9949895696108b31124fc0c6aa1a297ab1csatok mSpecialMailboxDrawable = 350fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler context.getResources().obtainTypedArray(R.array.mailbox_display_icons); 351dadba9949895696108b31124fc0c6aa1a297ab1csatok mDefaultMailboxDrawable = 352dadba9949895696108b31124fc0c6aa1a297ab1csatok context.getResources().getDrawable(R.drawable.ic_list_folder); 3533786cab2aa1776e92fc67af3931a76cd8b848b48satok mSummaryStarredMailboxDrawable = 3543786cab2aa1776e92fc67af3931a76cd8b848b48satok context.getResources().getDrawable(R.drawable.ic_list_starred); 3553786cab2aa1776e92fc67af3931a76cd8b848b48satok mSummaryCombinedInboxDrawable = 3563786cab2aa1776e92fc67af3931a76cd8b848b48satok context.getResources().getDrawable(R.drawable.ic_list_combined_inbox); 357dadba9949895696108b31124fc0c6aa1a297ab1csatok } 358dadba9949895696108b31124fc0c6aa1a297ab1csatok 3591f2caa80957e92519258e212b5fd45fb6c168a73Makoto Onuki public static synchronized FolderProperties getInstance(Context context) { 360dadba9949895696108b31124fc0c6aa1a297ab1csatok if (sInstance == null) { 3611f2caa80957e92519258e212b5fd45fb6c168a73Makoto Onuki sInstance = new FolderProperties(context); 362dadba9949895696108b31124fc0c6aa1a297ab1csatok } 363dadba9949895696108b31124fc0c6aa1a297ab1csatok return sInstance; 364dadba9949895696108b31124fc0c6aa1a297ab1csatok } 365dadba9949895696108b31124fc0c6aa1a297ab1csatok 366833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // For backward compatibility. 367833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public String getDisplayName(int type) { 368833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return getDisplayName(type, -1); 369833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 370833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 371833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // For backward compatibility. 372833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public Drawable getSummaryMailboxIconIds(long id) { 373833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return getIcon(-1, id); 374833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 375833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 376833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public Drawable getIconIds(int type) { 377833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return getIcon(type, -1); 378833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 379833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 380dadba9949895696108b31124fc0c6aa1a297ab1csatok /** 381dadba9949895696108b31124fc0c6aa1a297ab1csatok * Lookup names of localized special mailboxes 382dadba9949895696108b31124fc0c6aa1a297ab1csatok */ 383833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public String getDisplayName(int type, long mailboxId) { 384833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // Special combined mailboxes 385833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki int resId = 0; 386833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 387833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // Can't use long for switch!? 388833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { 389833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_inbox; 390833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) { 391833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_starred; 392833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) { 393833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_drafts; 394833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_OUTBOX) { 395833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_outbox; 396833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 397833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (resId != 0) { 398833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return mContext.getString(resId); 399833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 400833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 401dadba9949895696108b31124fc0c6aa1a297ab1csatok if (type < mSpecialMailbox.length) { 402dadba9949895696108b31124fc0c6aa1a297ab1csatok return mSpecialMailbox[type]; 403dadba9949895696108b31124fc0c6aa1a297ab1csatok } 404dadba9949895696108b31124fc0c6aa1a297ab1csatok return null; 405dadba9949895696108b31124fc0c6aa1a297ab1csatok } 406dadba9949895696108b31124fc0c6aa1a297ab1csatok 407dadba9949895696108b31124fc0c6aa1a297ab1csatok /** 408dadba9949895696108b31124fc0c6aa1a297ab1csatok * Lookup icons of special mailboxes 409dadba9949895696108b31124fc0c6aa1a297ab1csatok */ 410833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public Drawable getIcon(int type, long mailboxId) { 411833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { 4123786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSummaryCombinedInboxDrawable; 413833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) { 4143786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSummaryStarredMailboxDrawable; 415833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) { 4163786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSpecialMailboxDrawable.getDrawable(Mailbox.TYPE_DRAFTS); 417833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_OUTBOX) { 4183786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSpecialMailboxDrawable.getDrawable(Mailbox.TYPE_OUTBOX); 4193786cab2aa1776e92fc67af3931a76cd8b848b48satok } 420833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (0 <= type && type < mSpecialMailboxDrawable.length()) { 421833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return mSpecialMailboxDrawable.getDrawable(type); 422833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 4233786cab2aa1776e92fc67af3931a76cd8b848b48satok return mDefaultMailboxDrawable; 4243786cab2aa1776e92fc67af3931a76cd8b848b48satok } 425dadba9949895696108b31124fc0c6aa1a297ab1csatok } 426da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 427da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler private final static String HOSTAUTH_WHERE_CREDENTIALS = HostAuthColumns.ADDRESS + " like ?" 428da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler + " and " + HostAuthColumns.LOGIN + " like ?" 429da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler + " and " + HostAuthColumns.PROTOCOL + " not like \"smtp\""; 430da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler private final static String ACCOUNT_WHERE_HOSTAUTH = AccountColumns.HOST_AUTH_KEY_RECV + "=?"; 431da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 432da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler /** 433da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * Look for an existing account with the same username & server 434da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * 435da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param context a system context 436da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param allowAccountId this account Id will not trigger (when editing an existing account) 4379d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank * @param hostName the server's address 4389d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank * @param userLogin the user's login string 4399d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank * @result null = no matching account found. Account = matching account 440da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler */ 4419d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank public static Account findExistingAccount(Context context, long allowAccountId, 4429d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank String hostName, String userLogin) { 443da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler ContentResolver resolver = context.getContentResolver(); 444da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Cursor c = resolver.query(HostAuth.CONTENT_URI, HostAuth.ID_PROJECTION, 445da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler HOSTAUTH_WHERE_CREDENTIALS, new String[] { hostName, userLogin }, null); 446da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler try { 447da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler while (c.moveToNext()) { 448da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler long hostAuthId = c.getLong(HostAuth.ID_PROJECTION_COLUMN); 4499d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank // Find account with matching hostauthrecv key, and return it 450da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Cursor c2 = resolver.query(Account.CONTENT_URI, Account.ID_PROJECTION, 451da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler ACCOUNT_WHERE_HOSTAUTH, new String[] { Long.toString(hostAuthId) }, null); 452da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler try { 453da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler while (c2.moveToNext()) { 454da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler long accountId = c2.getLong(Account.ID_PROJECTION_COLUMN); 455da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler if (accountId != allowAccountId) { 456da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Account account = Account.restoreAccountWithId(context, accountId); 457da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler if (account != null) { 4589d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank return account; 459da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 460da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 461da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 462da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } finally { 463da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler c2.close(); 464da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 465da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 466da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } finally { 467da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler c.close(); 468da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 469da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 470da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler return null; 471da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 472eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 473eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler /** 474eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Generate a random message-id header for locally-generated messages. 475eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler */ 476eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler public static String generateMessageId() { 477eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler StringBuffer sb = new StringBuffer(); 478eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("<"); 479eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler for (int i = 0; i < 24; i++) { 480eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append(Integer.toString((int)(Math.random() * 35), 36)); 481eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 482eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("."); 483eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append(Long.toString(System.currentTimeMillis())); 484eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("@email.android.com>"); 485eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler return sb.toString(); 486eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 487eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 488989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 489989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a time in milliseconds from a date string that represents a date/time in GMT 490989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param DateTime date string in format 20090211T180303Z (rfc2445, iCalendar). 491989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the time in milliseconds (since Jan 1, 1970) 492989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 493989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static long parseDateTimeToMillis(String date) { 494989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = parseDateTimeToCalendar(date); 495989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal.getTimeInMillis(); 496989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 497989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda 498989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 499989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a GregorianCalendar from a date string that represents a date/time in GMT 500989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param DateTime date string in format 20090211T180303Z (rfc2445, iCalendar). 501989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the GregorianCalendar 502989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 503989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static GregorianCalendar parseDateTimeToCalendar(String date) { 504989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = new GregorianCalendar(Integer.parseInt(date.substring(0, 4)), 505989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(4, 6)) - 1, Integer.parseInt(date.substring(6, 8)), 506989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(9, 11)), Integer.parseInt(date.substring(11, 13)), 507989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(13, 15))); 508989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda cal.setTimeZone(TimeZone.getTimeZone("GMT")); 509989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal; 510989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 511989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda 512989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 513989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a time in milliseconds from an email date string that represents a date/time in GMT 514989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param Email style DateTime string in format 2010-02-23T16:00:00.000Z (ISO 8601, rfc3339) 515989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the time in milliseconds (since Jan 1, 1970) 516989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 517989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static long parseEmailDateTimeToMillis(String date) { 518989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = new GregorianCalendar(Integer.parseInt(date.substring(0, 4)), 519989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(5, 7)) - 1, Integer.parseInt(date.substring(8, 10)), 520989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(11, 13)), Integer.parseInt(date.substring(14, 16)), 521989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(17, 19))); 522989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda cal.setTimeZone(TimeZone.getTimeZone("GMT")); 523989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal.getTimeInMillis(); 524989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 52520225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki 5267e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki private static byte[] encode(Charset charset, String s) { 52720225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki if (s == null) { 52820225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki return null; 52920225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki } 5307e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki final ByteBuffer buffer = charset.encode(CharBuffer.wrap(s)); 53120225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki final byte[] bytes = new byte[buffer.limit()]; 53220225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki buffer.get(bytes); 53320225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki return bytes; 53420225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki } 53588a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki 5367e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki private static String decode(Charset charset, byte[] b) { 537fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki if (b == null) { 538fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki return null; 539fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki } 5407e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki final CharBuffer cb = charset.decode(ByteBuffer.wrap(b)); 541fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki return new String(cb.array(), 0, cb.length()); 542fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki } 543fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki 5447e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Converts a String to UTF-8 */ 5457e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static byte[] toUtf8(String s) { 5467e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return encode(UTF_8, s); 5477e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5487e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 5497e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Builds a String from UTF-8 bytes */ 5507e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static String fromUtf8(byte[] b) { 5517e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return decode(UTF_8, b); 5527e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5537e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 5547e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Converts a String to ASCII bytes */ 5557e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static byte[] toAscii(String s) { 5567e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return encode(ASCII, s); 5577e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5587e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 5597e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Builds a String from ASCII bytes */ 5607e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static String fromAscii(byte[] b) { 5617e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return decode(ASCII, b); 5627e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5637e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 56488a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki /** 56588a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki * @return true if the input is the first (or only) byte in a UTF-8 character 56688a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki */ 56788a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki public static boolean isFirstUtf8Byte(byte b) { 56888a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki // If the top 2 bits is '10', it's not a first byte. 56988a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki return (b & 0xc0) != 0x80; 57088a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki } 571dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki 572dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki public static String byteToHex(int b) { 573dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki return byteToHex(new StringBuilder(), b).toString(); 574dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki } 575dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki 576dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki public static StringBuilder byteToHex(StringBuilder sb, int b) { 577dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki b &= 0xFF; 578dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki sb.append("0123456789ABCDEF".charAt(b >> 4)); 579dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki sb.append("0123456789ABCDEF".charAt(b & 0xF)); 580dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki return sb; 581dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki } 582eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank 583eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank public static String replaceBareLfWithCrlf(String str) { 584eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank return str.replace("\r", "").replace("\n", "\r\n"); 585eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank } 58659cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki 58759cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki /** 58859cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * Cancel an {@link AsyncTask}. If it's already running, it'll be interrupted. 58959cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki */ 59059cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki public static void cancelTaskInterrupt(AsyncTask<?, ?, ?> task) { 59159cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki cancelTask(task, true); 59259cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 59359cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki 59459cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki /** 59559cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * Cancel an {@link AsyncTask}. 59659cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * 59759cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this 59859cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * task should be interrupted; otherwise, in-progress tasks are allowed 59959cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * to complete. 60059cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki */ 60159cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki public static void cancelTask(AsyncTask<?, ?, ?> task, boolean mayInterruptIfRunning) { 60259cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) { 60359cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki task.cancel(mayInterruptIfRunning); 60459cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 60559cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 606d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki 607d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /** 608d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki * @return Device's unique ID if available. null if the device has no unique ID. 609d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki */ 610d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki public static String getConsistentDeviceId(Context context) { 611d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final String deviceId; 612d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki try { 613d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki TelephonyManager tm = 614d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 615d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki if (tm == null) { 616d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 617d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 618d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki deviceId = tm.getDeviceId(); 619d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki if (deviceId == null) { 620d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 621d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 622d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } catch (Exception e) { 623d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki Log.d(Email.LOG_TAG, "Error in TelephonyManager.getDeviceId(): " + e.getMessage()); 624d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 625d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 626d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final MessageDigest sha; 627d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki try { 628d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki sha = MessageDigest.getInstance("SHA-1"); 629d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } catch (NoSuchAlgorithmException impossible) { 630d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 631d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 632d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki sha.update(Utility.toUtf8(deviceId)); 633d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final int hash = getSmallHashFromSha1(sha.digest()); 634d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return Integer.toString(hash); 635d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 636d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki 637d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /** 638d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki * @return a non-negative integer generated from 20 byte SHA-1 hash. 639d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki */ 640d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /* package for testing */ static int getSmallHashFromSha1(byte[] sha1) { 641d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final int offset = sha1[19] & 0xf; // SHA1 is 20 bytes. 642d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return ((sha1[offset] & 0x7f) << 24) 643d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 1] & 0xff) << 16) 644d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 2] & 0xff) << 8) 645d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 3] & 0xff)); 646d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 647128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki 648128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki /** 649128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * Try to make a date MIME(RFC 2822/5322)-compliant. 650128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * 651128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * It fixes: 652128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * - "Thu, 10 Dec 09 15:08:08 GMT-0700" to "Thu, 10 Dec 09 15:08:08 -0700" 653128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * (4 digit zone value can't be preceded by "GMT") 654128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * We got a report saying eBay sends a date in this format 655128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki */ 656128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki public static String cleanUpMimeDate(String date) { 657128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki if (TextUtils.isEmpty(date)) { 658128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki return date; 659128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki } 660128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki date = DATE_CLEANUP_PATTERN_WRONG_TIMEZONE.matcher(date).replaceFirst("$1"); 661128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki return date; 662128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki } 6637e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 6647e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static ByteArrayInputStream streamFromAsciiString(String ascii) { 6657e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return new ByteArrayInputStream(toAscii(ascii)); 6667e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 6677e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki 6687e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki /** 6697e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * A thread safe way to show a Toast. This method uses {@link Activity#runOnUiThread}, so it 6707e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * can be called on any thread. 6717e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * 6727e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * @param activity Parent activity. 6737e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * @param resId Resource ID of the message string. 6747e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki */ 67591d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki public static void showToast(Activity activity, int resId) { 67691d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki showToast(activity, activity.getResources().getString(resId)); 67791d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki } 67891d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki 67991d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki /** 68091d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * A thread safe way to show a Toast. This method uses {@link Activity#runOnUiThread}, so it 68191d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * can be called on any thread. 68291d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * 68391d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * @param activity Parent activity. 68491d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * @param message Message to show. 68591d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki */ 68691d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki public static void showToast(final Activity activity, final String message) { 6877e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki activity.runOnUiThread(new Runnable() { 6887e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki public void run() { 68991d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki Toast.makeText(activity, message, Toast.LENGTH_LONG).show(); 6907e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki } 6917e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki }); 6927e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki } 6933f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki 6943f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki /** 6953f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki * Run {@code r} on a worker thread. 6963f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki */ 6973f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public static void runAsync(final Runnable r) { 6983f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki new AsyncTask<Void, Void, Void>() { 6993f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki @Override protected Void doInBackground(Void... params) { 7003f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki r.run(); 7013f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki return null; 7023f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 7033f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki }.execute(); 7043f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 70544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 70644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /** 70744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * Formats the given size as a String in bytes, kB, MB or GB. Ex: 12,315,000 = 11 MB 70844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki */ 70944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public static String formatSize(Context context, long size) { 71044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final Resources res = context.getResources(); 71144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final long KB = 1024; 71244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final long MB = (KB * 1024); 71344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final long GB = (MB * 1024); 71444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 71544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki int resId; 71644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki int value; 71744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 71844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (size < KB) { 71944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_bytes; 72044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) size; 72144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else if (size < MB) { 72244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_kilobytes; 72344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) (size / KB); 72444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else if (size < GB) { 72544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_megabytes; 72644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) (size / MB); 72744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else { 72844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_gigabytes; 72944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) (size / GB); 73044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 73144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return res.getQuantityString(resId, value, value); 73244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 73344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 73444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /** 73544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * Interface used in {@link #createUniqueFile} instead of {@link File#createNewFile()} to make 73644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * it testable. 73744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki */ 73844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /* package */ interface NewFileCreator { 73944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public static final NewFileCreator DEFAULT = new NewFileCreator() { 74044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki @Override public boolean createNewFile(File f) throws IOException { 74144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return f.createNewFile(); 74244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 74344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki }; 74444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public boolean createNewFile(File f) throws IOException ; 74544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 74644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 74744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /** 74844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * Creates a new empty file with a unique name in the given directory by appending a hyphen and 74944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * a number to the given filename. 75044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * 75144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * @return a new File object, or null if one could not be created 75244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki */ 75344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public static File createUniqueFile(File directory, String filename) throws IOException { 75444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return createUniqueFileInternal(NewFileCreator.DEFAULT, directory, filename); 75544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 75644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 75744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /* package */ static File createUniqueFileInternal(NewFileCreator nfc, 75844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki File directory, String filename) throws IOException { 75944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki File file = new File(directory, filename); 76044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (nfc.createNewFile(file)) { 76144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return file; 76244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 76344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki // Get the extension of the file, if any. 76444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki int index = filename.lastIndexOf('.'); 76544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki String format; 76644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (index != -1) { 76744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki String name = filename.substring(0, index); 76844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki String extension = filename.substring(index); 76944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki format = name + "-%d" + extension; 77044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else { 77144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki format = filename + "-%d"; 77244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 77344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 77444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki for (int i = 2; i < Integer.MAX_VALUE; i++) { 77544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki file = new File(directory, String.format(format, i)); 77644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (nfc.createNewFile(file)) { 77744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return file; 77844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 77944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 78044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return null; 78144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 782bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki 783bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki /** 784bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki * @return a long in column {@code column} of the first result row, if the query returns at 785bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki * least 1 row. Otherwise returns {@code defaultValue}. 786bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki */ 787bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki public static Long getFirstRowLong(Context context, Uri uri, String[] projection, 788bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column, 789bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki Long defaultValue) { 790bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki Cursor c = context.getContentResolver().query(uri, projection, selection, selectionArgs, 791bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki sortOrder); 792bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki try { 793bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki if (c.moveToFirst()) { 794bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki return c.getLong(column); 795bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 796bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } finally { 797bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki c.close(); 798bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 799bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki return defaultValue; 800bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 801bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki 802bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki /** 803bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki * {@link #getFirstRowLong} with null as a default value. 804bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki */ 805bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki public static Long getFirstRowLong(Context context, Uri uri, String[] projection, 806bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column) { 807bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki return getFirstRowLong(context, uri, projection, selection, selectionArgs, 808bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki sortOrder, column, null); 809bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 810833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 811833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki /** 81236bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki * @return an integer in column {@code column} of the first result row, if the query returns at 81336bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki * least 1 row. Otherwise returns {@code defaultValue}. 81436bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki */ 81536bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki public static Integer getFirstRowInt(Context context, Uri uri, String[] projection, 81636bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column, 81736bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki Integer defaultValue) { 81836bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki Long longDefault = (defaultValue == null) ? null : defaultValue.longValue(); 81936bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki Long result = getFirstRowLong(context, uri, projection, selection, selectionArgs, sortOrder, 82036bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki column, longDefault); 82136bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki return (result == null) ? null : result.intValue(); 82236bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki } 82336bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki 82436bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki /** 82536bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki * {@link #getFirstRowInt} with null as a default value. 82636bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki */ 82736bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki public static Integer getFirstRowInt(Context context, Uri uri, String[] projection, 82836bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column) { 82936bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki return getFirstRowInt(context, uri, projection, selection, selectionArgs, 83036bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki sortOrder, column, null); 83136bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki } 83236bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki 83336bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki /** 834833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki * A class used to restore ListView state (e.g. scroll position) when changing adapter. 835833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki * 836833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki * TODO For some reason it doesn't always work. Investigate and fix it. 837833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki */ 838833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public static class ListStateSaver { 839833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Parcelable mState; 840833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 841833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public ListStateSaver(AbsListView lv) { 842833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki mState = lv.onSaveInstanceState(); 843833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 844833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 845833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public void restore(AbsListView lv) { 846833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki lv.onRestoreInstanceState(mState); 847833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 848833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 849533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki 850533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki /** 851533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki * STOPSHIP Remove this method 852533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki * Toggle between portrait and landscape. Developement use only. 853533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki */ 854533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki public static void changeOrientation(Activity activity) { 855533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki activity.setRequestedOrientation( 856533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 857533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE 858533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 859533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki } 860f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 861f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki /** 862f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki * Class that supports running any operation for each account. 863f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki */ 864f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public abstract static class ForEachAccount extends AsyncTask<Void, Void, Long[]> { 865f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki private final Context mContext; 866f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 867f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public ForEachAccount(Context context) { 868f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki mContext = context; 869f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 870f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 871f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki @Override 872f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected final Long[] doInBackground(Void... params) { 873f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki ArrayList<Long> ids = new ArrayList<Long>(); 874f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki Cursor c = mContext.getContentResolver().query(EmailContent.Account.CONTENT_URI, 875f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki EmailContent.Account.ID_PROJECTION, null, null, null); 876f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki try { 877f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki while (c.moveToNext()) { 878f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki ids.add(c.getLong(EmailContent.Account.ID_PROJECTION_COLUMN)); 879f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 880f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } finally { 881f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki c.close(); 882f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 883f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki return ids.toArray(EMPTY_LONGS); 884f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 885f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 886f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki @Override 887f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected final void onPostExecute(Long[] ids) { 888f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki if (ids != null && !isCancelled()) { 889f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki for (long id : ids) { 890f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki performAction(id); 891f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 892f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 893f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki onFinished(); 894f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 895f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 896f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki /** 897f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki * This method will be called for each account. 898f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki */ 899f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected abstract void performAction(long accountId); 900f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 901f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki /** 902f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki * Called when the iteration is finished. 903f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki */ 904f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected void onFinished() { 905f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 906f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 90796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project} 908