Utility.java revision 07597e547bc02cd2247caa866d25b94745dcd448
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; 2209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blankimport com.android.email.provider.EmailContent.Attachment; 2309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blankimport com.android.email.provider.EmailContent.AttachmentColumns; 24da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadlerimport com.android.email.provider.EmailContent.HostAuth; 25da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadlerimport com.android.email.provider.EmailContent.HostAuthColumns; 26e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.Mailbox; 27e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.MailboxColumns; 28e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.Message; 29e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport com.android.email.provider.EmailContent.MessageColumns; 30e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 317e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onukiimport android.app.Activity; 32e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport android.content.ContentResolver; 3309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blankimport android.content.ContentUris; 3409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blankimport android.content.ContentValues; 35f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.content.Context; 36533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onukiimport android.content.pm.ActivityInfo; 3744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onukiimport android.content.res.Resources; 38f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.content.res.TypedArray; 39e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadlerimport android.database.Cursor; 40f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.graphics.drawable.Drawable; 41bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onukiimport android.net.Uri; 4259cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onukiimport android.os.AsyncTask; 4309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blankimport android.os.Environment; 44082443978595bee3b7907563dc7665f908872e20Makoto Onukiimport android.os.Handler; 457fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onukiimport android.os.Parcel; 46833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onukiimport android.os.Parcelable; 47d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.telephony.TelephonyManager; 48128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukiimport android.text.TextUtils; 496cec1104fe8863fce2ee86ff5145076e6c436a00Doug Zongkerimport android.util.Base64; 50d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport android.util.Log; 51833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onukiimport android.widget.AbsListView; 52082443978595bee3b7907563dc7665f908872e20Makoto Onukiimport android.widget.ListView; 53f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongkerimport android.widget.TextView; 547e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onukiimport android.widget.Toast; 55e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 567e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport java.io.ByteArrayInputStream; 5744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onukiimport java.io.File; 58d755cdce13217d25ac33169b5e410709636255c4Makoto Onukiimport java.io.FileNotFoundException; 5996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException; 6096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream; 6196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStreamReader; 6296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.UnsupportedEncodingException; 6320225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.ByteBuffer; 6420225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.CharBuffer; 6520225d57609d6a5e482c088fdad60c29212d31a0Makoto Onukiimport java.nio.charset.Charset; 66697f98aea5a8344a17ca5e9b0410d484fdce6555Makoto Onukiimport java.security.MessageDigest; 67d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onukiimport java.security.NoSuchAlgorithmException; 68f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onukiimport java.util.ArrayList; 69767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onukiimport java.util.Collection; 7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Date; 71989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Predaimport java.util.GregorianCalendar; 72989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Predaimport java.util.TimeZone; 73128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukiimport java.util.regex.Pattern; 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class Utility { 7620225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki public static final Charset UTF_8 = Charset.forName("UTF-8"); 777e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static final Charset ASCII = Charset.forName("US-ASCII"); 787e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 797e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static final String[] EMPTY_STRINGS = new String[0]; 80f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public static final Long[] EMPTY_LONGS = new Long[0]; 8120225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki 82128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki // "GMT" + "+" or "-" + 4 digits 83128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE = 84128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki Pattern.compile("GMT([-+]\\d{4})$"); 85128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki 867183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki private static final String SELECTION_FLAG_LOADED_FOR_VISIBLE_MESSAGE = 877183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki " AND (" 887183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki + MessageColumns.FLAG_LOADED + " IN (" 897183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki + Message.FLAG_LOADED_PARTIAL + "," + Message.FLAG_LOADED_COMPLETE 907183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki + "))"; 917183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki 9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public final static String readInputStream(InputStream in, String encoding) throws IOException { 9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project InputStreamReader reader = new InputStreamReader(in, encoding); 9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int count; 9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project char[] buf = new char[512]; 9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((count = reader.read(buf)) != -1) { 9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(buf, 0, count); 9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return sb.toString(); 10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public final static boolean arrayContains(Object[] a, Object o) { 10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = a.length; i < count; i++) { 10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (a[i].equals(o)) { 10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Combines the given array of Objects into a single string using the 11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * seperator character and each Object's toString() method. between each 11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * part. 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param parts 11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param seperator 11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String combine(Object[] parts, char seperator) { 12296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (parts == null) { 12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 12496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 12596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 12696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0; i < parts.length; i++) { 12796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(parts[i].toString()); 12896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (i < parts.length - 1) { 12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(seperator); 13096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 13196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 13296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return sb.toString(); 13396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 13496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String base64Decode(String encoded) { 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (encoded == null) { 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 138f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker byte[] decoded = Base64.decode(encoded, Base64.DEFAULT); 13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new String(decoded); 14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 14196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 14296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String base64Encode(String s) { 14396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (s == null) { 14496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return s; 14596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 146f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker return Base64.encodeToString(s.getBytes(), Base64.NO_WRAP); 14796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 14896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 149e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank public static boolean isTextViewNotEmpty(TextView view) { 150e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank return !TextUtils.isEmpty(view.getText()); 15196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 15296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 153e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank public static boolean isPortFieldValid(TextView view) { 154e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank CharSequence chars = view.getText(); 155e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank if (TextUtils.isEmpty(chars)) return false; 156e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank Integer port; 157e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank // In theory, we can't get an illegal value here, since the field is monitored for valid 158e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank // numeric input. But this might be used elsewhere without such a check. 159e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank try { 160e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank port = Integer.parseInt(chars.toString()); 161e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank } catch (NumberFormatException e) { 162e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank return false; 163e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank } 164e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank return port > 0 && port < 65536; 165e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank } 16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 16796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 168e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank * Ensures that the given string starts and ends with the double quote character. The string is 169e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank * not modified in any way except to add the double quote character to start and end if it's not 170e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank * already there. 171f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 17296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * TODO: Rename this, because "quoteString()" can mean so many different things. 173f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 17496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * sample -> "sample" 17596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sample" -> "sample" 17696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * ""sample"" -> "sample" 17796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sample"" -> "sample" 17896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * sa"mp"le -> "sa"mp"le" 17996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "sa"mp"le" -> "sa"mp"le" 18096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * (empty string) -> "" 18196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * " -> "" 18296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param s 18396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 18496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String quoteString(String s) { 18696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (s == null) { 18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 18896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!s.matches("^\".*\"$")) { 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "\"" + s + "\""; 19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else { 19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return s; 19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 196f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 19796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 198f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * Apply quoting rules per IMAP RFC, 19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * quoted = DQUOTE *QUOTED-CHAR DQUOTE 20096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials 20196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * quoted-specials = DQUOTE / "\" 202f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 20396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is used primarily for IMAP login, but might be useful elsewhere. 204f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * NOTE: Not very efficient - you may wish to preflight this, or perhaps it should check 20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * for trouble chars before calling the replace functions. 207f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker * 20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param s The string to be quoted. 20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return A copy of the string, having undergone quoting as described above 21096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 21196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String imapQuoted(String s) { 212f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 21396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // First, quote any backslashes by replacing \ with \\ 21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // regex Pattern: \\ (Java string const = \\\\) 21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Substitute: \\\\ (Java string const = \\\\\\\\) 21696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String result = s.replaceAll("\\\\", "\\\\\\\\"); 217f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 21896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Then, quote any double-quotes by replacing " with \" 21996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // regex Pattern: " (Java string const = \") 22096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // Substitute: \\" (Java string const = \\\\\") 22196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project result = result.replaceAll("\"", "\\\\\""); 222f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 22396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // return string with quotes around it 22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "\"" + result + "\""; 22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 226f44a40cda14a49d5b02636a3a8a8b2eb8c23fc00Doug Zongker 22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * A fast version of URLDecoder.decode() that works only with UTF-8 and does only two 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * allocations. This version is around 3x as fast as the standard one and I'm using it 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * hundreds of times in places that slow down the UI, so it helps. 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static String fastUrlDecode(String s) { 23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project byte[] bytes = s.getBytes("UTF-8"); 23596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project byte ch; 23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int length = 0; 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = bytes.length; i < count; i++) { 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ch = bytes[i]; 23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (ch == '%') { 24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int h = (bytes[i + 1] - '0'); 24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int l = (bytes[i + 2] - '0'); 24296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (h > 9) { 24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project h -= 7; 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (l > 9) { 24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project l -= 7; 24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = (byte) ((h << 4) | l); 24996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project i += 2; 25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (ch == '+') { 25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = ' '; 25396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else { 25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project bytes[length] = bytes[i]; 25696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project length++; 25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return new String(bytes, 0, length, "UTF-8"); 26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (UnsupportedEncodingException uee) { 26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Returns true if the specified date is within today. Returns false otherwise. 26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param date 26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @return 27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static boolean isDateToday(Date date) { 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // TODO But Calendar is so slowwwwwww.... 27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Date today = new Date(); 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (date.getYear() == today.getYear() && 27596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project date.getMonth() == today.getMonth() && 27696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project date.getDate() == today.getDate()) { 27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return false; 28096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 28296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 28396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * TODO disabled this method globally. It is used in all the settings screens but I just 28496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * noticed that an unrelated icon was dimmed. Android must share drawables internally. 28596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 28696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static void setCompoundDrawablesAlpha(TextView view, int alpha) { 28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// Drawable[] drawables = view.getCompoundDrawables(); 28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// for (Drawable drawable : drawables) { 28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// if (drawable != null) { 29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// drawable.setAlpha(alpha); 29196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// } 29296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project// } 29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 294e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler 2957183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki /** 2967183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki * Returns the where clause for a message list selection. 2977183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki * 2987183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki * MUST NOT be called on the UI thread. 2997183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki */ 3007183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki public static String buildMailboxIdSelection(Context context, long mailboxId) { 3017183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki final ContentResolver resolver = context.getContentResolver(); 3027183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki final StringBuilder selection = new StringBuilder(); 3037183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki 3047183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki // We don't check "flagLoaded" for messages in Outbox. 3057183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki boolean testFlagLoaded = true; 3067183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki 307e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (mailboxId == Mailbox.QUERY_ALL_INBOXES 308e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler || mailboxId == Mailbox.QUERY_ALL_DRAFTS 309e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler || mailboxId == Mailbox.QUERY_ALL_OUTBOX) { 310e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // query for all mailboxes of type INBOX, DRAFTS, or OUTBOX 311e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler int type; 312e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { 313e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_INBOX; 314e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) { 315e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_DRAFTS; 316e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else { 317e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler type = Mailbox.TYPE_OUTBOX; 3187183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki testFlagLoaded = false; 319e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 320e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler StringBuilder inboxes = new StringBuilder(); 321e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler Cursor c = resolver.query(Mailbox.CONTENT_URI, 322e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler EmailContent.ID_PROJECTION, 323e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler MailboxColumns.TYPE + "=? AND " + MailboxColumns.FLAG_VISIBLE + "=1", 324e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler new String[] { Integer.toString(type) }, null); 325e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler // build an IN (mailboxId, ...) list 326e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler while (c.moveToNext()) { 327e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler if (inboxes.length() != 0) { 328e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler inboxes.append(","); 329e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 330e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler inboxes.append(c.getLong(EmailContent.ID_PROJECTION_COLUMN)); 331e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 332e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler c.close(); 333e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(MessageColumns.MAILBOX_KEY + " IN "); 334e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append("(").append(inboxes).append(")"); 335e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_UNREAD) { 336e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(Message.FLAG_READ + "=0"); 337e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) { 338e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(Message.FLAG_FAVORITE + "=1"); 339e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } else { 340e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler selection.append(MessageColumns.MAILBOX_KEY + "=" + mailboxId); 3417183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki if (Mailbox.getMailboxType(context, mailboxId) == Mailbox.TYPE_OUTBOX) { 3427183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki testFlagLoaded = false; 3437183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki } 344e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 3457183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki 3467183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki if (testFlagLoaded) { 3477183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki // POP messages at the initial stage have very little information. (Server UID only) 3487183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki // This makes sure they're not visible in the message list. 3497183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki // This means unread counts on the mailbox list can be different from the 3507183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki // number of messages in the message list, but it should be transient... 3517183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki selection.append(SELECTION_FLAG_LOADED_FOR_VISIBLE_MESSAGE); 3527183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki } 3537183724276e0d829fd01a5bc1f2f6d0f6b6a8818Makoto Onuki 354e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler return selection.toString(); 355e1f0b0a9bcc78ade7f3b2ac540705701f19cd6cdAndrew Stadler } 356dadba9949895696108b31124fc0c6aa1a297ab1csatok 357833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // TODO When the UI is settled, cache all strings/drawables 358833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // TODO When the UI is settled, write up tests 359833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // TODO When the UI is settled, remove backward-compatibility methods 360dadba9949895696108b31124fc0c6aa1a297ab1csatok public static class FolderProperties { 361dadba9949895696108b31124fc0c6aa1a297ab1csatok 362dadba9949895696108b31124fc0c6aa1a297ab1csatok private static FolderProperties sInstance; 363dadba9949895696108b31124fc0c6aa1a297ab1csatok 364833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Context mContext; 365833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 366dadba9949895696108b31124fc0c6aa1a297ab1csatok // Caches for frequently accessed resources. 367833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final String[] mSpecialMailbox; 368833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final TypedArray mSpecialMailboxDrawable; 369833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Drawable mDefaultMailboxDrawable; 370833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Drawable mSummaryStarredMailboxDrawable; 371833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Drawable mSummaryCombinedInboxDrawable; 372dadba9949895696108b31124fc0c6aa1a297ab1csatok 373dadba9949895696108b31124fc0c6aa1a297ab1csatok private FolderProperties(Context context) { 374833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki mContext = context.getApplicationContext(); 375fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler mSpecialMailbox = context.getResources().getStringArray(R.array.mailbox_display_names); 376dadba9949895696108b31124fc0c6aa1a297ab1csatok for (int i = 0; i < mSpecialMailbox.length; ++i) { 377dadba9949895696108b31124fc0c6aa1a297ab1csatok if ("".equals(mSpecialMailbox[i])) { 378dadba9949895696108b31124fc0c6aa1a297ab1csatok // there is no localized name, so use the display name from the server 379dadba9949895696108b31124fc0c6aa1a297ab1csatok mSpecialMailbox[i] = null; 380dadba9949895696108b31124fc0c6aa1a297ab1csatok } 381dadba9949895696108b31124fc0c6aa1a297ab1csatok } 382dadba9949895696108b31124fc0c6aa1a297ab1csatok mSpecialMailboxDrawable = 383fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler context.getResources().obtainTypedArray(R.array.mailbox_display_icons); 384dadba9949895696108b31124fc0c6aa1a297ab1csatok mDefaultMailboxDrawable = 385dadba9949895696108b31124fc0c6aa1a297ab1csatok context.getResources().getDrawable(R.drawable.ic_list_folder); 3863786cab2aa1776e92fc67af3931a76cd8b848b48satok mSummaryStarredMailboxDrawable = 3873786cab2aa1776e92fc67af3931a76cd8b848b48satok context.getResources().getDrawable(R.drawable.ic_list_starred); 3883786cab2aa1776e92fc67af3931a76cd8b848b48satok mSummaryCombinedInboxDrawable = 3893786cab2aa1776e92fc67af3931a76cd8b848b48satok context.getResources().getDrawable(R.drawable.ic_list_combined_inbox); 390dadba9949895696108b31124fc0c6aa1a297ab1csatok } 391dadba9949895696108b31124fc0c6aa1a297ab1csatok 3921f2caa80957e92519258e212b5fd45fb6c168a73Makoto Onuki public static synchronized FolderProperties getInstance(Context context) { 393dadba9949895696108b31124fc0c6aa1a297ab1csatok if (sInstance == null) { 3941f2caa80957e92519258e212b5fd45fb6c168a73Makoto Onuki sInstance = new FolderProperties(context); 395dadba9949895696108b31124fc0c6aa1a297ab1csatok } 396dadba9949895696108b31124fc0c6aa1a297ab1csatok return sInstance; 397dadba9949895696108b31124fc0c6aa1a297ab1csatok } 398dadba9949895696108b31124fc0c6aa1a297ab1csatok 399833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // For backward compatibility. 400833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public String getDisplayName(int type) { 401833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return getDisplayName(type, -1); 402833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 403833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 404833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // For backward compatibility. 405833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public Drawable getSummaryMailboxIconIds(long id) { 406833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return getIcon(-1, id); 407833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 408833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 409833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public Drawable getIconIds(int type) { 410833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return getIcon(type, -1); 411833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 412833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 413dadba9949895696108b31124fc0c6aa1a297ab1csatok /** 414dadba9949895696108b31124fc0c6aa1a297ab1csatok * Lookup names of localized special mailboxes 415dadba9949895696108b31124fc0c6aa1a297ab1csatok */ 416833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public String getDisplayName(int type, long mailboxId) { 417833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // Special combined mailboxes 418833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki int resId = 0; 419833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 420833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki // Can't use long for switch!? 421833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { 422833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_inbox; 423833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) { 424833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_starred; 425833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) { 426833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_drafts; 427833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_OUTBOX) { 428833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki resId = R.string.account_folder_list_summary_outbox; 429833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 430833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (resId != 0) { 431833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return mContext.getString(resId); 432833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 433833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 434dadba9949895696108b31124fc0c6aa1a297ab1csatok if (type < mSpecialMailbox.length) { 435dadba9949895696108b31124fc0c6aa1a297ab1csatok return mSpecialMailbox[type]; 436dadba9949895696108b31124fc0c6aa1a297ab1csatok } 437dadba9949895696108b31124fc0c6aa1a297ab1csatok return null; 438dadba9949895696108b31124fc0c6aa1a297ab1csatok } 439dadba9949895696108b31124fc0c6aa1a297ab1csatok 440dadba9949895696108b31124fc0c6aa1a297ab1csatok /** 441dadba9949895696108b31124fc0c6aa1a297ab1csatok * Lookup icons of special mailboxes 442dadba9949895696108b31124fc0c6aa1a297ab1csatok */ 443833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public Drawable getIcon(int type, long mailboxId) { 444833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (mailboxId == Mailbox.QUERY_ALL_INBOXES) { 4453786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSummaryCombinedInboxDrawable; 446833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) { 4473786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSummaryStarredMailboxDrawable; 448833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) { 4493786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSpecialMailboxDrawable.getDrawable(Mailbox.TYPE_DRAFTS); 450833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } else if (mailboxId == Mailbox.QUERY_ALL_OUTBOX) { 4513786cab2aa1776e92fc67af3931a76cd8b848b48satok return mSpecialMailboxDrawable.getDrawable(Mailbox.TYPE_OUTBOX); 4523786cab2aa1776e92fc67af3931a76cd8b848b48satok } 453833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki if (0 <= type && type < mSpecialMailboxDrawable.length()) { 454833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki return mSpecialMailboxDrawable.getDrawable(type); 455833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 4563786cab2aa1776e92fc67af3931a76cd8b848b48satok return mDefaultMailboxDrawable; 4573786cab2aa1776e92fc67af3931a76cd8b848b48satok } 458dadba9949895696108b31124fc0c6aa1a297ab1csatok } 459da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 460da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler private final static String HOSTAUTH_WHERE_CREDENTIALS = HostAuthColumns.ADDRESS + " like ?" 461da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler + " and " + HostAuthColumns.LOGIN + " like ?" 462da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler + " and " + HostAuthColumns.PROTOCOL + " not like \"smtp\""; 463da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler private final static String ACCOUNT_WHERE_HOSTAUTH = AccountColumns.HOST_AUTH_KEY_RECV + "=?"; 464da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 465da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler /** 466da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * Look for an existing account with the same username & server 467da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * 468da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param context a system context 469da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler * @param allowAccountId this account Id will not trigger (when editing an existing account) 4709d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank * @param hostName the server's address 4719d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank * @param userLogin the user's login string 4729d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank * @result null = no matching account found. Account = matching account 473da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler */ 4749d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank public static Account findExistingAccount(Context context, long allowAccountId, 4759d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank String hostName, String userLogin) { 476da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler ContentResolver resolver = context.getContentResolver(); 477da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Cursor c = resolver.query(HostAuth.CONTENT_URI, HostAuth.ID_PROJECTION, 478da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler HOSTAUTH_WHERE_CREDENTIALS, new String[] { hostName, userLogin }, null); 479da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler try { 480da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler while (c.moveToNext()) { 481da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler long hostAuthId = c.getLong(HostAuth.ID_PROJECTION_COLUMN); 4829d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank // Find account with matching hostauthrecv key, and return it 483da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Cursor c2 = resolver.query(Account.CONTENT_URI, Account.ID_PROJECTION, 484da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler ACCOUNT_WHERE_HOSTAUTH, new String[] { Long.toString(hostAuthId) }, null); 485da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler try { 486da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler while (c2.moveToNext()) { 487da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler long accountId = c2.getLong(Account.ID_PROJECTION_COLUMN); 488da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler if (accountId != allowAccountId) { 489da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler Account account = Account.restoreAccountWithId(context, accountId); 490da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler if (account != null) { 4919d387ff0bb88ad952b53c956b468dcbcec248752Marc Blank return account; 492da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 493da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 494da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 495da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } finally { 496da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler c2.close(); 497da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 498da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 499da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } finally { 500da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler c.close(); 501da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 502da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler 503da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler return null; 504da8836a76cd8a6eaa7e3693eeacc6393870b2066Andrew Stadler } 505eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 506eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler /** 507eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Generate a random message-id header for locally-generated messages. 508eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler */ 509eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler public static String generateMessageId() { 510eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler StringBuffer sb = new StringBuffer(); 511eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("<"); 512eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler for (int i = 0; i < 24; i++) { 513eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append(Integer.toString((int)(Math.random() * 35), 36)); 514eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 515eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("."); 516eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append(Long.toString(System.currentTimeMillis())); 517eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler sb.append("@email.android.com>"); 518eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler return sb.toString(); 519eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 520eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 521989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 522989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a time in milliseconds from a date string that represents a date/time in GMT 523989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param DateTime date string in format 20090211T180303Z (rfc2445, iCalendar). 524989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the time in milliseconds (since Jan 1, 1970) 525989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 526989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static long parseDateTimeToMillis(String date) { 527989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = parseDateTimeToCalendar(date); 528989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal.getTimeInMillis(); 529989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 530989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda 531989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 532989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a GregorianCalendar from a date string that represents a date/time in GMT 533989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param DateTime date string in format 20090211T180303Z (rfc2445, iCalendar). 534989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the GregorianCalendar 535989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 536989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static GregorianCalendar parseDateTimeToCalendar(String date) { 537989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = new GregorianCalendar(Integer.parseInt(date.substring(0, 4)), 538989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(4, 6)) - 1, Integer.parseInt(date.substring(6, 8)), 539989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(9, 11)), Integer.parseInt(date.substring(11, 13)), 540989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(13, 15))); 541989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda cal.setTimeZone(TimeZone.getTimeZone("GMT")); 542989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal; 543989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 544989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda 545989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda /** 546989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * Generate a time in milliseconds from an email date string that represents a date/time in GMT 547989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @param Email style DateTime string in format 2010-02-23T16:00:00.000Z (ISO 8601, rfc3339) 548989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda * @return the time in milliseconds (since Jan 1, 1970) 549989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda */ 550989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda public static long parseEmailDateTimeToMillis(String date) { 551989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda GregorianCalendar cal = new GregorianCalendar(Integer.parseInt(date.substring(0, 4)), 552989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(5, 7)) - 1, Integer.parseInt(date.substring(8, 10)), 553989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(11, 13)), Integer.parseInt(date.substring(14, 16)), 554989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda Integer.parseInt(date.substring(17, 19))); 555989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda cal.setTimeZone(TimeZone.getTimeZone("GMT")); 556989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda return cal.getTimeInMillis(); 557989552c10744e2d7f8fca1bdb2baef5273a8a0b9Mihai Preda } 55820225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki 5597e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki private static byte[] encode(Charset charset, String s) { 56020225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki if (s == null) { 56120225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki return null; 56220225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki } 5637e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki final ByteBuffer buffer = charset.encode(CharBuffer.wrap(s)); 56420225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki final byte[] bytes = new byte[buffer.limit()]; 56520225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki buffer.get(bytes); 56620225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki return bytes; 56720225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki } 56888a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki 5697e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki private static String decode(Charset charset, byte[] b) { 570fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki if (b == null) { 571fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki return null; 572fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki } 5737e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki final CharBuffer cb = charset.decode(ByteBuffer.wrap(b)); 574fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki return new String(cb.array(), 0, cb.length()); 575fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki } 576fe61f358ab67cac2aa454a6dd3ea6bbf876e343cMakoto Onuki 5777e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Converts a String to UTF-8 */ 5787e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static byte[] toUtf8(String s) { 5797e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return encode(UTF_8, s); 5807e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5817e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 5827e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Builds a String from UTF-8 bytes */ 5837e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static String fromUtf8(byte[] b) { 5847e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return decode(UTF_8, b); 5857e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5867e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 5877e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Converts a String to ASCII bytes */ 5887e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static byte[] toAscii(String s) { 5897e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return encode(ASCII, s); 5907e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5917e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 5927e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki /** Builds a String from ASCII bytes */ 5937e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static String fromAscii(byte[] b) { 5947e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return decode(ASCII, b); 5957e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 5967e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 59788a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki /** 59888a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki * @return true if the input is the first (or only) byte in a UTF-8 character 59988a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki */ 60088a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki public static boolean isFirstUtf8Byte(byte b) { 60188a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki // If the top 2 bits is '10', it's not a first byte. 60288a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki return (b & 0xc0) != 0x80; 60388a94bca1922615564e70a27bb6ae72bca487c75Makoto Onuki } 604dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki 605dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki public static String byteToHex(int b) { 606dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki return byteToHex(new StringBuilder(), b).toString(); 607dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki } 608dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki 609dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki public static StringBuilder byteToHex(StringBuilder sb, int b) { 610dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki b &= 0xFF; 611dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki sb.append("0123456789ABCDEF".charAt(b >> 4)); 612dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki sb.append("0123456789ABCDEF".charAt(b & 0xF)); 613dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki return sb; 614dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki } 615eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank 616eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank public static String replaceBareLfWithCrlf(String str) { 617eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank return str.replace("\r", "").replace("\n", "\r\n"); 618eba33f8b5a0cc4a28ae5a9d6632df475c4b0a794Marc Blank } 61959cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki 62059cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki /** 62159cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * Cancel an {@link AsyncTask}. If it's already running, it'll be interrupted. 62259cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki */ 62359cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki public static void cancelTaskInterrupt(AsyncTask<?, ?, ?> task) { 62459cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki cancelTask(task, true); 62559cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 62659cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki 62759cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki /** 62859cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * Cancel an {@link AsyncTask}. 62959cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * 63059cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this 63159cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * task should be interrupted; otherwise, in-progress tasks are allowed 63259cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki * to complete. 63359cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki */ 63459cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki public static void cancelTask(AsyncTask<?, ?, ?> task, boolean mayInterruptIfRunning) { 63559cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) { 63659cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki task.cancel(mayInterruptIfRunning); 63759cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 63859cf1d05c111e3b5fb18417db41ce47b623b5b1eMakoto Onuki } 639d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki 640d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /** 641d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki * @return Device's unique ID if available. null if the device has no unique ID. 642d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki */ 643d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki public static String getConsistentDeviceId(Context context) { 644d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final String deviceId; 645d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki try { 646d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki TelephonyManager tm = 647d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 648d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki if (tm == null) { 649d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 650d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 651d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki deviceId = tm.getDeviceId(); 652d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki if (deviceId == null) { 653d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 654d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 655d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } catch (Exception e) { 656d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki Log.d(Email.LOG_TAG, "Error in TelephonyManager.getDeviceId(): " + e.getMessage()); 657d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 658d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 659697f98aea5a8344a17ca5e9b0410d484fdce6555Makoto Onuki return getSmallHash(deviceId); 660697f98aea5a8344a17ca5e9b0410d484fdce6555Makoto Onuki } 661697f98aea5a8344a17ca5e9b0410d484fdce6555Makoto Onuki 662697f98aea5a8344a17ca5e9b0410d484fdce6555Makoto Onuki /* package */ static String getSmallHash(final String value) { 663d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final MessageDigest sha; 664d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki try { 665d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki sha = MessageDigest.getInstance("SHA-1"); 666d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } catch (NoSuchAlgorithmException impossible) { 667d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return null; 668d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 669697f98aea5a8344a17ca5e9b0410d484fdce6555Makoto Onuki sha.update(Utility.toUtf8(value)); 670d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final int hash = getSmallHashFromSha1(sha.digest()); 671d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return Integer.toString(hash); 672d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 673d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki 674d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /** 675d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki * @return a non-negative integer generated from 20 byte SHA-1 hash. 676d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki */ 677d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki /* package for testing */ static int getSmallHashFromSha1(byte[] sha1) { 678d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki final int offset = sha1[19] & 0xf; // SHA1 is 20 bytes. 679d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki return ((sha1[offset] & 0x7f) << 24) 680d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 1] & 0xff) << 16) 681d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 2] & 0xff) << 8) 682d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki | ((sha1[offset + 3] & 0xff)); 683d2a0d23380a2751d82f9d1f955a812f94a301e2aMakoto Onuki } 684128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki 685128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki /** 686128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * Try to make a date MIME(RFC 2822/5322)-compliant. 687128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * 688128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * It fixes: 689128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * - "Thu, 10 Dec 09 15:08:08 GMT-0700" to "Thu, 10 Dec 09 15:08:08 -0700" 690128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * (4 digit zone value can't be preceded by "GMT") 691128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki * We got a report saying eBay sends a date in this format 692128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki */ 693128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki public static String cleanUpMimeDate(String date) { 694128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki if (TextUtils.isEmpty(date)) { 695128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki return date; 696128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki } 697128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki date = DATE_CLEANUP_PATTERN_WRONG_TIMEZONE.matcher(date).replaceFirst("$1"); 698128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki return date; 699128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki } 7007e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki 7017e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki public static ByteArrayInputStream streamFromAsciiString(String ascii) { 7027e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki return new ByteArrayInputStream(toAscii(ascii)); 7037e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki } 7047e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki 7057e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki /** 7067e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * A thread safe way to show a Toast. This method uses {@link Activity#runOnUiThread}, so it 7077e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * can be called on any thread. 7087e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * 7097e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * @param activity Parent activity. 7107e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki * @param resId Resource ID of the message string. 7117e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki */ 71291d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki public static void showToast(Activity activity, int resId) { 71391d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki showToast(activity, activity.getResources().getString(resId)); 71491d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki } 71591d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki 71691d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki /** 71791d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * A thread safe way to show a Toast. This method uses {@link Activity#runOnUiThread}, so it 71891d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * can be called on any thread. 71991d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * 72091d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * @param activity Parent activity. 72191d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki * @param message Message to show. 72291d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki */ 72391d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki public static void showToast(final Activity activity, final String message) { 7247e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki activity.runOnUiThread(new Runnable() { 7257e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki public void run() { 72691d47ccb47e4d4e340854a091d39886fbbadbf15Makoto Onuki Toast.makeText(activity, message, Toast.LENGTH_LONG).show(); 7277e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki } 7287e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki }); 7297e24c6c6f9efcba98b7e26f9e387b6591acd1355Makoto Onuki } 7303f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki 7313f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki /** 732b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank * Run {@code r} on a worker thread, returning the AsyncTask 733b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank * @return the AsyncTask; this is primarily for use by unit tests, which require the 734b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank * result of the task 7353f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki */ 736b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank public static AsyncTask<Void, Void, Void> runAsync(final Runnable r) { 737b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank return new AsyncTask<Void, Void, Void>() { 7383f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki @Override protected Void doInBackground(Void... params) { 7393f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki r.run(); 7403f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki return null; 7413f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 7423f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki }.execute(); 7433f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 74444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 74544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /** 74644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * Formats the given size as a String in bytes, kB, MB or GB. Ex: 12,315,000 = 11 MB 74744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki */ 74844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public static String formatSize(Context context, long size) { 74944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final Resources res = context.getResources(); 75044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final long KB = 1024; 75144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final long MB = (KB * 1024); 75244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki final long GB = (MB * 1024); 75344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 75444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki int resId; 75544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki int value; 75644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 75744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (size < KB) { 75844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_bytes; 75944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) size; 76044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else if (size < MB) { 76144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_kilobytes; 76244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) (size / KB); 76344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else if (size < GB) { 76444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_megabytes; 76544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) (size / MB); 76644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else { 76744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki resId = R.plurals.message_view_attachment_gigabytes; 76844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki value = (int) (size / GB); 76944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 77044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return res.getQuantityString(resId, value, value); 77144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 77244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 77344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /** 77444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * Interface used in {@link #createUniqueFile} instead of {@link File#createNewFile()} to make 77544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * it testable. 77644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki */ 77744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /* package */ interface NewFileCreator { 77844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public static final NewFileCreator DEFAULT = new NewFileCreator() { 77944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki @Override public boolean createNewFile(File f) throws IOException { 78044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return f.createNewFile(); 78144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 78244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki }; 78344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public boolean createNewFile(File f) throws IOException ; 78444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 78544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 78644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /** 78744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * Creates a new empty file with a unique name in the given directory by appending a hyphen and 78844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * a number to the given filename. 78944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * 79044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki * @return a new File object, or null if one could not be created 79144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki */ 79244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki public static File createUniqueFile(File directory, String filename) throws IOException { 79344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return createUniqueFileInternal(NewFileCreator.DEFAULT, directory, filename); 79444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 79544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 79644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki /* package */ static File createUniqueFileInternal(NewFileCreator nfc, 79744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki File directory, String filename) throws IOException { 79844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki File file = new File(directory, filename); 79944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (nfc.createNewFile(file)) { 80044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return file; 80144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 80244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki // Get the extension of the file, if any. 80344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki int index = filename.lastIndexOf('.'); 80444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki String format; 80544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (index != -1) { 80644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki String name = filename.substring(0, index); 80744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki String extension = filename.substring(index); 80844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki format = name + "-%d" + extension; 80944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } else { 81044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki format = filename + "-%d"; 81144b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 81244b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki 81344b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki for (int i = 2; i < Integer.MAX_VALUE; i++) { 81444b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki file = new File(directory, String.format(format, i)); 81544b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki if (nfc.createNewFile(file)) { 81644b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return file; 81744b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 81844b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 81944b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki return null; 82044b5242edd938450f5e7bc5569852fa5f793da41Makoto Onuki } 821bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki 82207597e547bc02cd2247caa866d25b94745dcd448Marc Blank public interface CursorGetter<T> { 82307597e547bc02cd2247caa866d25b94745dcd448Marc Blank T get(Cursor cursor, int column); 82407597e547bc02cd2247caa866d25b94745dcd448Marc Blank } 82507597e547bc02cd2247caa866d25b94745dcd448Marc Blank 82607597e547bc02cd2247caa866d25b94745dcd448Marc Blank private static final CursorGetter<Long> LONG_GETTER = new CursorGetter<Long>() { 82707597e547bc02cd2247caa866d25b94745dcd448Marc Blank public Long get(Cursor cursor, int column) { 82807597e547bc02cd2247caa866d25b94745dcd448Marc Blank return cursor.getLong(column); 82907597e547bc02cd2247caa866d25b94745dcd448Marc Blank } 83007597e547bc02cd2247caa866d25b94745dcd448Marc Blank }; 83107597e547bc02cd2247caa866d25b94745dcd448Marc Blank 83207597e547bc02cd2247caa866d25b94745dcd448Marc Blank private static final CursorGetter<Integer> INT_GETTER = new CursorGetter<Integer>() { 83307597e547bc02cd2247caa866d25b94745dcd448Marc Blank public Integer get(Cursor cursor, int column) { 83407597e547bc02cd2247caa866d25b94745dcd448Marc Blank return cursor.getInt(column); 83507597e547bc02cd2247caa866d25b94745dcd448Marc Blank } 83607597e547bc02cd2247caa866d25b94745dcd448Marc Blank }; 83707597e547bc02cd2247caa866d25b94745dcd448Marc Blank 83807597e547bc02cd2247caa866d25b94745dcd448Marc Blank private static final CursorGetter<byte[]> BLOB_GETTER = new CursorGetter<byte[]>() { 83907597e547bc02cd2247caa866d25b94745dcd448Marc Blank public byte[] get(Cursor cursor, int column) { 84007597e547bc02cd2247caa866d25b94745dcd448Marc Blank return cursor.getBlob(column); 84107597e547bc02cd2247caa866d25b94745dcd448Marc Blank } 84207597e547bc02cd2247caa866d25b94745dcd448Marc Blank }; 84307597e547bc02cd2247caa866d25b94745dcd448Marc Blank 844bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki /** 84507597e547bc02cd2247caa866d25b94745dcd448Marc Blank * @return a generic in column {@code column} of the first result row, if the query returns at 846bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki * least 1 row. Otherwise returns {@code defaultValue}. 847bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki */ 84807597e547bc02cd2247caa866d25b94745dcd448Marc Blank public static <T extends Object> T getFirstRowColumn(Context context, Uri uri, 84907597e547bc02cd2247caa866d25b94745dcd448Marc Blank String[] projection, String selection, String[] selectionArgs, String sortOrder, 85007597e547bc02cd2247caa866d25b94745dcd448Marc Blank int column, T defaultValue, CursorGetter<T> getter) { 85107597e547bc02cd2247caa866d25b94745dcd448Marc Blank // Use PARAMETER_LIMIT to restrict the query to the single row we need 85207597e547bc02cd2247caa866d25b94745dcd448Marc Blank uri = uri.buildUpon().appendQueryParameter(EmailContent.PARAMETER_LIMIT, "1").build(); 853bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki Cursor c = context.getContentResolver().query(uri, projection, selection, selectionArgs, 854bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki sortOrder); 855b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki if (c != null) { 856b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki try { 857b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki if (c.moveToFirst()) { 85807597e547bc02cd2247caa866d25b94745dcd448Marc Blank return getter.get(c, column); 859b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki } 860b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki } finally { 861b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki c.close(); 862bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 863bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 864bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki return defaultValue; 865bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 866bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki 867bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki /** 86807597e547bc02cd2247caa866d25b94745dcd448Marc Blank * {@link #getFirstRowColumn} for a Long with null as a default value. 869bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki */ 870bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki public static Long getFirstRowLong(Context context, Uri uri, String[] projection, 871bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column) { 87207597e547bc02cd2247caa866d25b94745dcd448Marc Blank return getFirstRowColumn(context, uri, projection, selection, selectionArgs, 87307597e547bc02cd2247caa866d25b94745dcd448Marc Blank sortOrder, column, null, LONG_GETTER); 874bcf32320e2600e96c8a9e997a8903bfc3893b35eMakoto Onuki } 875833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 876833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki /** 87707597e547bc02cd2247caa866d25b94745dcd448Marc Blank * {@link #getFirstRowColumn} for a Long with a provided default value. 87836bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki */ 87907597e547bc02cd2247caa866d25b94745dcd448Marc Blank public static Long getFirstRowLong(Context context, Uri uri, String[] projection, 88036bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column, 88107597e547bc02cd2247caa866d25b94745dcd448Marc Blank Long defaultValue) { 88207597e547bc02cd2247caa866d25b94745dcd448Marc Blank return getFirstRowColumn(context, uri, projection, selection, selectionArgs, 88307597e547bc02cd2247caa866d25b94745dcd448Marc Blank sortOrder, column, defaultValue, LONG_GETTER); 88436bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki } 88536bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki 88636bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki /** 88707597e547bc02cd2247caa866d25b94745dcd448Marc Blank * {@link #getFirstRowColumn} for an Integer with null as a default value. 88836bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki */ 88936bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki public static Integer getFirstRowInt(Context context, Uri uri, String[] projection, 89036bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column) { 89107597e547bc02cd2247caa866d25b94745dcd448Marc Blank return getFirstRowColumn(context, uri, projection, selection, selectionArgs, 89207597e547bc02cd2247caa866d25b94745dcd448Marc Blank sortOrder, column, null, INT_GETTER); 89307597e547bc02cd2247caa866d25b94745dcd448Marc Blank } 89407597e547bc02cd2247caa866d25b94745dcd448Marc Blank 89507597e547bc02cd2247caa866d25b94745dcd448Marc Blank /** 89607597e547bc02cd2247caa866d25b94745dcd448Marc Blank * {@link #getFirstRowColumn} for an Integer with a provided default value. 89707597e547bc02cd2247caa866d25b94745dcd448Marc Blank */ 89807597e547bc02cd2247caa866d25b94745dcd448Marc Blank public static Integer getFirstRowInt(Context context, Uri uri, String[] projection, 89907597e547bc02cd2247caa866d25b94745dcd448Marc Blank String selection, String[] selectionArgs, String sortOrder, int column, 90007597e547bc02cd2247caa866d25b94745dcd448Marc Blank Integer defaultValue) { 90107597e547bc02cd2247caa866d25b94745dcd448Marc Blank return getFirstRowColumn(context, uri, projection, selection, selectionArgs, 90207597e547bc02cd2247caa866d25b94745dcd448Marc Blank sortOrder, column, defaultValue, INT_GETTER); 90336bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki } 90436bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki 90507597e547bc02cd2247caa866d25b94745dcd448Marc Blank /** 90607597e547bc02cd2247caa866d25b94745dcd448Marc Blank * {@link #getFirstRowColumn} for a byte array with null as a default value. 90707597e547bc02cd2247caa866d25b94745dcd448Marc Blank */ 908b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki public static byte[] getFirstRowBlob(Context context, Uri uri, String[] projection, 909b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki String selection, String[] selectionArgs, String sortOrder, int column, 910b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki byte[] defaultValue) { 91107597e547bc02cd2247caa866d25b94745dcd448Marc Blank return getFirstRowColumn(context, uri, projection, selection, selectionArgs, sortOrder, 91207597e547bc02cd2247caa866d25b94745dcd448Marc Blank column, defaultValue, BLOB_GETTER); 913b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki } 914b1ea9c3c12d8d9da5c1e49a8752076ce60861e9fMakoto Onuki 91536bdeeb0e17cb6fbf08023eeb3e4f1db58b48aeaMakoto Onuki /** 916833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki * A class used to restore ListView state (e.g. scroll position) when changing adapter. 917833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki */ 9187fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki public static class ListStateSaver implements Parcelable { 919833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki private final Parcelable mState; 920833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 9217fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki private ListStateSaver(Parcel p) { 9227fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki mState = p.readParcelable(null); 9237fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki } 9247fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki 925833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public ListStateSaver(AbsListView lv) { 926833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki mState = lv.onSaveInstanceState(); 927833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 928833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki 929833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki public void restore(AbsListView lv) { 930833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki lv.onRestoreInstanceState(mState); 931833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 9327fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki 9337fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki @Override 9347fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki public int describeContents() { 9357fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki return 0; 9367fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki } 9377fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki 9387fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki @Override 9397fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki public void writeToParcel(Parcel dest, int flags) { 9407fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki dest.writeParcelable(mState, flags); 9417fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki } 9427fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki 9437fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki public static final Parcelable.Creator<ListStateSaver> CREATOR 9447fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki = new Parcelable.Creator<ListStateSaver>() { 9457fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki public ListStateSaver createFromParcel(Parcel in) { 9467fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki return new ListStateSaver(in); 9477fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki } 9487fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki 9497fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki public ListStateSaver[] newArray(int size) { 9507fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki return new ListStateSaver[size]; 9517fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki } 9527fd307212f076fab56f575988e5e5bfaf1abdcc3Makoto Onuki }; 953833fe73b99e62ad9cf6e80c782717c7de1ff12e4Makoto Onuki } 954533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki 9554dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank public static boolean attachmentExists(Context context, Attachment attachment) { 9564dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank if (attachment == null) { 9574dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank return false; 9584dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank } else if (attachment.mContentBytes != null) { 9594dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank return true; 9604dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank } else if (TextUtils.isEmpty(attachment.mContentUri)) { 961567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki Log.w(Email.LOG_TAG, "attachmentExists ContentUri null."); 962d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki return false; 963d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki } 964d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki if (Email.DEBUG) { 965d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki Log.d(Email.LOG_TAG, "attachmentExists URI=" + attachment.mContentUri); 966d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki } 967d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki try { 968567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki Uri fileUri = Uri.parse(attachment.mContentUri); 969d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki try { 970567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki InputStream inStream = context.getContentResolver().openInputStream(fileUri); 971567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki try { 972567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki inStream.close(); 973567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki } catch (IOException e) { 974567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki // Nothing to be done if can't close the stream 975567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki } 976567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki return true; 977567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki } catch (FileNotFoundException e) { 978567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki return false; 979d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki } 980567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki } catch (RuntimeException re) { 981567ed19f7b2ca4c97f022b299ff2f9b5eba8c937Makoto Onuki Log.w(Email.LOG_TAG, "attachmentExists RuntimeException=" + re); 982d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki return false; 983d755cdce13217d25ac33169b5e410709636255c4Makoto Onuki } 98409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 98509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 98609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank /** 98709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * Check whether the message with a given id has unloaded attachments. If the message is 98809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * a forwarded message, we look instead at the messages's source for the attachments. If the 98909fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * message or forward source can't be found, we return false 99009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * @param context the caller's context 99109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * @param messageId the id of the message 99209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * @return whether or not the message has unloaded attachments 99309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank */ 99409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank public static boolean hasUnloadedAttachments(Context context, long messageId) { 99509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank Message msg = Message.restoreMessageWithId(context, messageId); 99609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank if (msg == null) return false; 99709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank Attachment[] atts = Attachment.restoreAttachmentsWithMessageId(context, messageId); 99809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank for (Attachment att: atts) { 9994dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank if (!attachmentExists(context, att)) { 100009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank // If the attachment doesn't exist and isn't marked for download, we're in trouble 100109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank // since the outbound message will be stuck indefinitely in the Outbox. Instead, 100209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank // we'll just delete the attachment and continue; this is far better than the 100309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank // alternative. In theory, this situation shouldn't be possible. 100409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank if ((att.mFlags & (Attachment.FLAG_DOWNLOAD_FORWARD | 100509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank Attachment.FLAG_DOWNLOAD_USER_REQUEST)) == 0) { 100609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank Log.d(Email.LOG_TAG, "Unloaded attachment isn't marked for download: " + 100709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank att.mFileName + ", #" + att.mId); 100809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank Attachment.delete(context, Attachment.CONTENT_URI, att.mId); 100909fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } else if (att.mContentUri != null) { 101009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank // In this case, the attachment file is gone from the cache; let's clear the 101109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank // contentUri; this should be a very unusual case 101209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank ContentValues cv = new ContentValues(); 101309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank cv.putNull(AttachmentColumns.CONTENT_URI); 101409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank Attachment.update(context, Attachment.CONTENT_URI, att.mId, cv); 101509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 101609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return true; 101709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 101809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 101909fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return false; 102009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 102109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 102209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank /** 102309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * Convenience method wrapping calls to retrieve columns from a single row, via EmailProvider. 102409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * The arguments are exactly the same as to contentResolver.query(). Results are returned in 102509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * an array of Strings corresponding to the columns in the projection. If the cursor has no 102609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * rows, null is returned. 102709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank */ 102809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank public static String[] getRowColumns(Context context, Uri contentUri, String[] projection, 102909fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank String selection, String[] selectionArgs) { 103009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank String[] values = new String[projection.length]; 103109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank ContentResolver cr = context.getContentResolver(); 103209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank Cursor c = cr.query(contentUri, projection, selection, selectionArgs, null); 103309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank try { 103409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank if (c.moveToFirst()) { 103509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank for (int i = 0; i < projection.length; i++) { 103609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank values[i] = c.getString(i); 103709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 103809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } else { 103909fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return null; 104009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 104109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } finally { 104209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank c.close(); 104309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 104409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return values; 104509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 104609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 104709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank /** 104809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * Convenience method for retrieving columns from a particular row in EmailProvider. 104909fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * Passed in here are a base uri (e.g. Message.CONTENT_URI), the unique id of a row, and 105009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank * a projection. This method calls the previous one with the appropriate URI. 105109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank */ 105209fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank public static String[] getRowColumns(Context context, Uri baseUri, long id, 105309fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank String ... projection) { 105409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return getRowColumns(context, ContentUris.withAppendedId(baseUri, id), projection, null, 105509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank null); 105609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 105709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 105809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank public static boolean isExternalStorageMounted() { 105909fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); 106009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 1061533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki /** 1062533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki * STOPSHIP Remove this method 1063533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki * Toggle between portrait and landscape. Developement use only. 1064533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki */ 1065533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki public static void changeOrientation(Activity activity) { 1066533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki activity.setRequestedOrientation( 1067533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1068533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE 1069533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1070533e0f5beb15659832b589c1d68f96e6ef1b7e40Makoto Onuki } 1071f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 1072f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki /** 1073f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki * Class that supports running any operation for each account. 1074f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki */ 1075f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public abstract static class ForEachAccount extends AsyncTask<Void, Void, Long[]> { 1076f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki private final Context mContext; 1077f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 1078f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public ForEachAccount(Context context) { 1079f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki mContext = context; 1080f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1081f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 1082f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki @Override 1083f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected final Long[] doInBackground(Void... params) { 1084f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki ArrayList<Long> ids = new ArrayList<Long>(); 1085f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki Cursor c = mContext.getContentResolver().query(EmailContent.Account.CONTENT_URI, 1086f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki EmailContent.Account.ID_PROJECTION, null, null, null); 1087f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki try { 1088f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki while (c.moveToNext()) { 1089f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki ids.add(c.getLong(EmailContent.Account.ID_PROJECTION_COLUMN)); 1090f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1091f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } finally { 1092f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki c.close(); 1093f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1094f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki return ids.toArray(EMPTY_LONGS); 1095f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1096f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 1097f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki @Override 1098f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected final void onPostExecute(Long[] ids) { 1099f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki if (ids != null && !isCancelled()) { 1100f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki for (long id : ids) { 1101f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki performAction(id); 1102f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1103f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1104f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki onFinished(); 1105f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1106f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 1107f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki /** 1108f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki * This method will be called for each account. 1109f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki */ 1110f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected abstract void performAction(long accountId); 1111f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 1112f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki /** 1113f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki * Called when the iteration is finished. 1114f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki */ 1115f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected void onFinished() { 1116f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1117f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 1118767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki 1119767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki public static long[] toPrimitiveLongArray(Collection<Long> collection) { 1120767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki final int size = collection.size(); 1121767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki final long[] ret = new long[size]; 1122767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki // Collection doesn't have get(i). (Iterable doesn't have size()) 1123767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki int i = 0; 1124767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki for (Long value : collection) { 1125767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki ret[i++] = value; 1126767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki } 1127767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki return ret; 1128767f9fe2ebcca7eee20f2a048f33a96ad4bf53daMakoto Onuki } 1129082443978595bee3b7907563dc7665f908872e20Makoto Onuki 1130082443978595bee3b7907563dc7665f908872e20Makoto Onuki /** 1131082443978595bee3b7907563dc7665f908872e20Makoto Onuki * Workaround for the {@link ListView#smoothScrollToPosition} randomly scroll the view bug 1132082443978595bee3b7907563dc7665f908872e20Makoto Onuki * if it's called right after {@link ListView#setAdapter}. 1133082443978595bee3b7907563dc7665f908872e20Makoto Onuki */ 1134082443978595bee3b7907563dc7665f908872e20Makoto Onuki public static void listViewSmoothScrollToPosition(final Activity activity, 1135082443978595bee3b7907563dc7665f908872e20Makoto Onuki final ListView listView, final int position) { 1136082443978595bee3b7907563dc7665f908872e20Makoto Onuki // Workarond: delay-call smoothScrollToPosition() 1137082443978595bee3b7907563dc7665f908872e20Makoto Onuki new Handler().post(new Runnable() { 1138082443978595bee3b7907563dc7665f908872e20Makoto Onuki @Override 1139082443978595bee3b7907563dc7665f908872e20Makoto Onuki public void run() { 1140082443978595bee3b7907563dc7665f908872e20Makoto Onuki if (activity.isFinishing()) { 1141082443978595bee3b7907563dc7665f908872e20Makoto Onuki return; // Activity being destroyed 1142082443978595bee3b7907563dc7665f908872e20Makoto Onuki } 1143082443978595bee3b7907563dc7665f908872e20Makoto Onuki listView.smoothScrollToPosition(position); 1144082443978595bee3b7907563dc7665f908872e20Makoto Onuki } 1145082443978595bee3b7907563dc7665f908872e20Makoto Onuki }); 1146082443978595bee3b7907563dc7665f908872e20Makoto Onuki } 114796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project} 1148