From 286b191d30dfd8b63efb1fb2c0d403a3b02d4e0f Mon Sep 17 00:00:00 2001 From: Paul Westbrook Date: Tue, 8 Dec 2009 12:11:13 -0800 Subject: Deleted Gmail.java from frameworks. Previously it had been moved to vendor/google/.../Gmail/... --- core/java/android/provider/Gmail.java | 2468 --------------------------------- preloaded-classes | 10 - 2 files changed, 2478 deletions(-) delete mode 100644 core/java/android/provider/Gmail.java diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java deleted file mode 100644 index 8bb7adf..0000000 --- a/core/java/android/provider/Gmail.java +++ /dev/null @@ -1,2468 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.provider; - -import com.google.android.collect.Lists; -import com.google.android.collect.Maps; -import com.google.android.collect.Sets; - -import android.content.AsyncQueryHandler; -import android.content.ContentQueryMap; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.DataSetObserver; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.text.Html; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.TextUtils; -import android.text.TextUtils.SimpleStringSplitter; -import android.text.style.CharacterStyle; -import android.util.Log; - -import com.android.common.Patterns; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Observable; -import java.util.Observer; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A thin wrapper over the content resolver for accessing the gmail provider. - * - * @hide - */ -public final class Gmail { - // Set to true to enable extra debugging. - private static final boolean DEBUG = false; - - public static final String GMAIL_AUTH_SERVICE = "mail"; - // These constants come from google3/java/com/google/caribou/backend/MailLabel.java. - public static final String LABEL_SENT = "^f"; - public static final String LABEL_INBOX = "^i"; - public static final String LABEL_DRAFT = "^r"; - public static final String LABEL_UNREAD = "^u"; - public static final String LABEL_TRASH = "^k"; - public static final String LABEL_SPAM = "^s"; - public static final String LABEL_STARRED = "^t"; - public static final String LABEL_CHAT = "^b"; // 'b' for 'buzz' - public static final String LABEL_VOICEMAIL = "^vm"; - public static final String LABEL_IGNORED = "^g"; - public static final String LABEL_ALL = "^all"; - // These constants (starting with "^^") are only used locally and are not understood by the - // server. - public static final String LABEL_VOICEMAIL_INBOX = "^^vmi"; - public static final String LABEL_CACHED = "^^cached"; - public static final String LABEL_OUTBOX = "^^out"; - - public static final String AUTHORITY = "gmail-ls"; - private static final String TAG = "Gmail"; - private static final String AUTHORITY_PLUS_CONVERSATIONS = - "content://" + AUTHORITY + "/conversations/"; - private static final String AUTHORITY_PLUS_LABELS = - "content://" + AUTHORITY + "/labels/"; - private static final String AUTHORITY_PLUS_MESSAGES = - "content://" + AUTHORITY + "/messages/"; - private static final String AUTHORITY_PLUS_SETTINGS = - "content://" + AUTHORITY + "/settings/"; - - public static final Uri BASE_URI = Uri.parse( - "content://" + AUTHORITY); - private static final Uri LABELS_URI = - Uri.parse(AUTHORITY_PLUS_LABELS); - private static final Uri CONVERSATIONS_URI = - Uri.parse(AUTHORITY_PLUS_CONVERSATIONS); - private static final Uri SETTINGS_URI = - Uri.parse(AUTHORITY_PLUS_SETTINGS); - - /** Separates email addresses in strings in the database. */ - public static final String EMAIL_SEPARATOR = "\n"; - public static final Pattern EMAIL_SEPARATOR_PATTERN = Pattern.compile(EMAIL_SEPARATOR); - - /** - * Space-separated lists have separators only between items. - */ - private static final char SPACE_SEPARATOR = ' '; - public static final Pattern SPACE_SEPARATOR_PATTERN = Pattern.compile(" "); - - /** - * Comma-separated lists have separators between each item, before the first and after the last - * item. The empty list is ,. - * - *

This makes them easier to modify with SQL since it is not a special case to add or - * remove the last item. Having a separator on each side of each value also makes it safe to use - * SQL's REPLACE to remove an item from a string by using REPLACE(',value,', ','). - * - *

We could use the same separator for both lists but this makes it easier to remember which - * kind of list one is dealing with. - */ - private static final char COMMA_SEPARATOR = ','; - public static final Pattern COMMA_SEPARATOR_PATTERN = Pattern.compile(","); - - /** Separates attachment info parts in strings in the database. */ - public static final String ATTACHMENT_INFO_SEPARATOR = "\n"; - public static final Pattern ATTACHMENT_INFO_SEPARATOR_PATTERN = - Pattern.compile(ATTACHMENT_INFO_SEPARATOR); - - public static final Character SENDER_LIST_SEPARATOR = '\n'; - public static final String SENDER_LIST_TOKEN_ELIDED = "e"; - public static final String SENDER_LIST_TOKEN_NUM_MESSAGES = "n"; - public static final String SENDER_LIST_TOKEN_NUM_DRAFTS = "d"; - public static final String SENDER_LIST_TOKEN_LITERAL = "l"; - public static final String SENDER_LIST_TOKEN_SENDING = "s"; - public static final String SENDER_LIST_TOKEN_SEND_FAILED = "f"; - - /** Used for finding status in a cursor's extras. */ - public static final String EXTRA_STATUS = "status"; - - public static final String RESPOND_INPUT_COMMAND = "command"; - public static final String COMMAND_RETRY = "retry"; - public static final String COMMAND_ACTIVATE = "activate"; - public static final String COMMAND_SET_VISIBLE = "setVisible"; - public static final String SET_VISIBLE_PARAM_VISIBLE = "visible"; - public static final String RESPOND_OUTPUT_COMMAND_RESPONSE = "commandResponse"; - public static final String COMMAND_RESPONSE_OK = "ok"; - public static final String COMMAND_RESPONSE_UNKNOWN = "unknownCommand"; - - public static final String INSERT_PARAM_ATTACHMENT_ORIGIN = "origin"; - public static final String INSERT_PARAM_ATTACHMENT_ORIGIN_EXTRAS = "originExtras"; - - private static final Pattern NAME_ADDRESS_PATTERN = Pattern.compile("\"(.*)\""); - private static final Pattern UNNAMED_ADDRESS_PATTERN = Pattern.compile("([^<]+)@"); - - private static final Map sPriorityToLength = Maps.newHashMap(); - public static final SimpleStringSplitter sSenderListSplitter = - new SimpleStringSplitter(SENDER_LIST_SEPARATOR); - public static String[] sSenderFragments = new String[8]; - - /** - * Returns the name in an address string - * @param addressString such as "bobby" <bob@example.com> - * @return returns the quoted name in the addressString, otherwise the username from the email - * address - */ - public static String getNameFromAddressString(String addressString) { - Matcher namedAddressMatch = NAME_ADDRESS_PATTERN.matcher(addressString); - if (namedAddressMatch.find()) { - String name = namedAddressMatch.group(1); - if (name.length() > 0) return name; - addressString = - addressString.substring(namedAddressMatch.end(), addressString.length()); - } - - Matcher unnamedAddressMatch = UNNAMED_ADDRESS_PATTERN.matcher(addressString); - if (unnamedAddressMatch.find()) { - return unnamedAddressMatch.group(1); - } - - return addressString; - } - - /** - * Returns the email address in an address string - * @param addressString such as "bobby" <bob@example.com> - * @return returns the email address, such as bob@example.com from the example above - */ - public static String getEmailFromAddressString(String addressString) { - String result = addressString; - Matcher match = Patterns.EMAIL_ADDRESS.matcher(addressString); - if (match.find()) { - result = addressString.substring(match.start(), match.end()); - } - - return result; - } - - /** - * Returns whether the label is user-defined (versus system-defined labels such as inbox, whose - * names start with "^"). - */ - public static boolean isLabelUserDefined(String label) { - // TODO: label should never be empty so we should be able to say [label.charAt(0) != '^']. - // However, it's a release week and I'm too scared to make that change. - return !label.startsWith("^"); - } - - private static final Set USER_SETTABLE_BUILTIN_LABELS = Sets.newHashSet( - Gmail.LABEL_INBOX, - Gmail.LABEL_UNREAD, - Gmail.LABEL_TRASH, - Gmail.LABEL_SPAM, - Gmail.LABEL_STARRED, - Gmail.LABEL_IGNORED); - - /** - * Returns whether the label is user-settable. For example, labels such as LABEL_DRAFT should - * only be set internally. - */ - public static boolean isLabelUserSettable(String label) { - return USER_SETTABLE_BUILTIN_LABELS.contains(label) || isLabelUserDefined(label); - } - - /** - * Returns the set of labels using the raw labels from a previous getRawLabels() - * as input. - * @return a copy of the set of labels. To add or remove labels call - * MessageCursor.addOrRemoveLabel on each message in the conversation. - */ - public static Set getLabelIdsFromLabelIdsString( - TextUtils.StringSplitter splitter) { - Set labelIds = Sets.newHashSet(); - for (String labelIdString : splitter) { - labelIds.add(Long.valueOf(labelIdString)); - } - return labelIds; - } - - /** - * @deprecated remove when the activities stop using canonical names to identify labels - */ - public static Set getCanonicalNamesFromLabelIdsString( - LabelMap labelMap, TextUtils.StringSplitter splitter) { - Set canonicalNames = Sets.newHashSet(); - for (long labelId : getLabelIdsFromLabelIdsString(splitter)) { - final String canonicalName = labelMap.getCanonicalName(labelId); - // We will sometimes see labels that the label map does not yet know about or that - // do not have names yet. - if (!TextUtils.isEmpty(canonicalName)) { - canonicalNames.add(canonicalName); - } else { - Log.w(TAG, "getCanonicalNamesFromLabelIdsString skipping label id: " + labelId); - } - } - return canonicalNames; - } - - /** - * @return a StringSplitter that is configured to split message label id strings - */ - public static TextUtils.StringSplitter newMessageLabelIdsSplitter() { - return new TextUtils.SimpleStringSplitter(SPACE_SEPARATOR); - } - - /** - * @return a StringSplitter that is configured to split conversation label id strings - */ - public static TextUtils.StringSplitter newConversationLabelIdsSplitter() { - return new CommaStringSplitter(); - } - - /** - * A splitter for strings of the form described in the docs for COMMA_SEPARATOR. - */ - private static class CommaStringSplitter extends TextUtils.SimpleStringSplitter { - - public CommaStringSplitter() { - super(COMMA_SEPARATOR); - } - - @Override - public void setString(String string) { - // The string should always be at least a single comma. - super.setString(string.substring(1)); - } - } - - /** - * Creates a single string of the form that getLabelIdsFromLabelIdsString can split. - */ - public static String getLabelIdsStringFromLabelIds(Set labelIds) { - StringBuilder sb = new StringBuilder(); - sb.append(COMMA_SEPARATOR); - for (Long labelId : labelIds) { - sb.append(labelId); - sb.append(COMMA_SEPARATOR); - } - return sb.toString(); - } - - public static final class ConversationColumns { - public static final String ID = "_id"; - public static final String SUBJECT = "subject"; - public static final String SNIPPET = "snippet"; - public static final String FROM = "fromAddress"; - public static final String DATE = "date"; - public static final String PERSONAL_LEVEL = "personalLevel"; - /** A list of label names with a space after each one (including the last one). This makes - * it easier remove individual labels from this list using SQL. */ - public static final String LABEL_IDS = "labelIds"; - public static final String NUM_MESSAGES = "numMessages"; - public static final String MAX_MESSAGE_ID = "maxMessageId"; - public static final String HAS_ATTACHMENTS = "hasAttachments"; - public static final String HAS_MESSAGES_WITH_ERRORS = "hasMessagesWithErrors"; - public static final String FORCE_ALL_UNREAD = "forceAllUnread"; - - private ConversationColumns() {} - } - - public static final class MessageColumns { - - public static final String ID = "_id"; - public static final String MESSAGE_ID = "messageId"; - public static final String CONVERSATION_ID = "conversation"; - public static final String SUBJECT = "subject"; - public static final String SNIPPET = "snippet"; - public static final String FROM = "fromAddress"; - public static final String TO = "toAddresses"; - public static final String CC = "ccAddresses"; - public static final String BCC = "bccAddresses"; - public static final String REPLY_TO = "replyToAddresses"; - public static final String DATE_SENT_MS = "dateSentMs"; - public static final String DATE_RECEIVED_MS = "dateReceivedMs"; - public static final String LIST_INFO = "listInfo"; - public static final String PERSONAL_LEVEL = "personalLevel"; - public static final String BODY = "body"; - public static final String EMBEDS_EXTERNAL_RESOURCES = "bodyEmbedsExternalResources"; - public static final String LABEL_IDS = "labelIds"; - public static final String JOINED_ATTACHMENT_INFOS = "joinedAttachmentInfos"; - public static final String ERROR = "error"; - // TODO: add a method for accessing this - public static final String REF_MESSAGE_ID = "refMessageId"; - - // Fake columns used only for saving or sending messages. - public static final String FAKE_SAVE = "save"; - public static final String FAKE_REF_MESSAGE_ID = "refMessageId"; - - private MessageColumns() {} - } - - public static final class LabelColumns { - public static final String CANONICAL_NAME = "canonicalName"; - public static final String NAME = "name"; - public static final String NUM_CONVERSATIONS = "numConversations"; - public static final String NUM_UNREAD_CONVERSATIONS = - "numUnreadConversations"; - - private LabelColumns() {} - } - - public static final class SettingsColumns { - public static final String LABELS_INCLUDED = "labelsIncluded"; - public static final String LABELS_PARTIAL = "labelsPartial"; - public static final String CONVERSATION_AGE_DAYS = - "conversationAgeDays"; - public static final String MAX_ATTACHMENET_SIZE_MB = - "maxAttachmentSize"; - } - - /** - * These flags can be included as Selection Arguments when - * querying the provider. - */ - public static class SelectionArguments { - private SelectionArguments() { - // forbid instantiation - } - - /** - * Specifies that you do NOT wish the returned cursor to - * become the Active Network Cursor. If you do not include - * this flag as a selectionArg, the new cursor will become the - * Active Network Cursor by default. - */ - public static final String DO_NOT_BECOME_ACTIVE_NETWORK_CURSOR = - "SELECTION_ARGUMENT_DO_NOT_BECOME_ACTIVE_NETWORK_CURSOR"; - } - - // These are the projections that we need when getting cursors from the - // content provider. - private static String[] CONVERSATION_PROJECTION = { - ConversationColumns.ID, - ConversationColumns.SUBJECT, - ConversationColumns.SNIPPET, - ConversationColumns.FROM, - ConversationColumns.DATE, - ConversationColumns.PERSONAL_LEVEL, - ConversationColumns.LABEL_IDS, - ConversationColumns.NUM_MESSAGES, - ConversationColumns.MAX_MESSAGE_ID, - ConversationColumns.HAS_ATTACHMENTS, - ConversationColumns.HAS_MESSAGES_WITH_ERRORS, - ConversationColumns.FORCE_ALL_UNREAD}; - private static String[] MESSAGE_PROJECTION = { - MessageColumns.ID, - MessageColumns.MESSAGE_ID, - MessageColumns.CONVERSATION_ID, - MessageColumns.SUBJECT, - MessageColumns.SNIPPET, - MessageColumns.FROM, - MessageColumns.TO, - MessageColumns.CC, - MessageColumns.BCC, - MessageColumns.REPLY_TO, - MessageColumns.DATE_SENT_MS, - MessageColumns.DATE_RECEIVED_MS, - MessageColumns.LIST_INFO, - MessageColumns.PERSONAL_LEVEL, - MessageColumns.BODY, - MessageColumns.EMBEDS_EXTERNAL_RESOURCES, - MessageColumns.LABEL_IDS, - MessageColumns.JOINED_ATTACHMENT_INFOS, - MessageColumns.ERROR}; - private static String[] LABEL_PROJECTION = { - BaseColumns._ID, - LabelColumns.CANONICAL_NAME, - LabelColumns.NAME, - LabelColumns.NUM_CONVERSATIONS, - LabelColumns.NUM_UNREAD_CONVERSATIONS}; - private static String[] SETTINGS_PROJECTION = { - SettingsColumns.LABELS_INCLUDED, - SettingsColumns.LABELS_PARTIAL, - SettingsColumns.CONVERSATION_AGE_DAYS, - SettingsColumns.MAX_ATTACHMENET_SIZE_MB, - }; - - private ContentResolver mContentResolver; - - public Gmail(ContentResolver contentResolver) { - mContentResolver = contentResolver; - } - - /** - * Returns source if source is non-null. Returns the empty string otherwise. - */ - private static String toNonnullString(String source) { - if (source == null) { - return ""; - } else { - return source; - } - } - - /** - * Behavior for a new cursor: should it become the Active Network - * Cursor? This could potentially lead to bad behavior if someone - * else is using the Active Network Cursor, since theirs will stop - * being the Active Network Cursor. - */ - public static enum BecomeActiveNetworkCursor { - /** - * The new cursor should become the one and only Active - * Network Cursor. Any other cursor that might already be the - * Active Network Cursor will cease to be so. - */ - YES, - - /** - * The new cursor should not become the Active Network - * Cursor. Any other cursor that might already be the Active - * Network Cursor will continue to be so. - */ - NO - } - - /** - * Wraps a Cursor in a ConversationCursor - * - * @param account the account the cursor is associated with - * @param cursor The Cursor to wrap - * @return a new ConversationCursor - */ - public ConversationCursor getConversationCursorForCursor(String account, Cursor cursor) { - if (TextUtils.isEmpty(account)) { - throw new IllegalArgumentException("account is empty"); - } - return new ConversationCursor(this, account, cursor); - } - - /** - * Creates an array of SelectionArguments suitable for passing to the provider's query. - * Currently this only handles one flag, but it could be expanded in the future. - */ - private static String[] getSelectionArguments( - BecomeActiveNetworkCursor becomeActiveNetworkCursor) { - if (BecomeActiveNetworkCursor.NO == becomeActiveNetworkCursor) { - return new String[] {SelectionArguments.DO_NOT_BECOME_ACTIVE_NETWORK_CURSOR}; - } else { - // Default behavior; no args required. - return null; - } - } - - /** - * Asynchronously gets a cursor over all conversations matching a query. The - * query is in Gmail's query syntax. When the operation is complete the handler's - * onQueryComplete() method is called with the resulting Cursor. - * - * @param account run the query on this account - * @param handler An AsyncQueryHanlder that will be used to run the query - * @param token The token to pass to startQuery, which will be passed back to onQueryComplete - * @param query a query in Gmail's query syntax - * @param becomeActiveNetworkCursor whether or not the returned - * cursor should become the Active Network Cursor - */ - public void runQueryForConversations(String account, AsyncQueryHandler handler, int token, - String query, BecomeActiveNetworkCursor becomeActiveNetworkCursor) { - if (TextUtils.isEmpty(account)) { - throw new IllegalArgumentException("account is empty"); - } - String[] selectionArgs = getSelectionArguments(becomeActiveNetworkCursor); - handler.startQuery(token, null, Uri.withAppendedPath(CONVERSATIONS_URI, account), - CONVERSATION_PROJECTION, query, selectionArgs, null); - } - - /** - * Synchronously gets a cursor over all conversations matching a query. The - * query is in Gmail's query syntax. - * - * @param account run the query on this account - * @param query a query in Gmail's query syntax - * @param becomeActiveNetworkCursor whether or not the returned - * cursor should become the Active Network Cursor - */ - public ConversationCursor getConversationCursorForQuery( - String account, String query, BecomeActiveNetworkCursor becomeActiveNetworkCursor) { - String[] selectionArgs = getSelectionArguments(becomeActiveNetworkCursor); - Cursor cursor = mContentResolver.query( - Uri.withAppendedPath(CONVERSATIONS_URI, account), CONVERSATION_PROJECTION, - query, selectionArgs, null); - return new ConversationCursor(this, account, cursor); - } - - /** - * Gets a message cursor over the single message with the given id. - * - * @param account get the cursor for messages in this account - * @param messageId the id of the message - * @return a cursor over the message - */ - public MessageCursor getMessageCursorForMessageId(String account, long messageId) { - if (TextUtils.isEmpty(account)) { - throw new IllegalArgumentException("account is empty"); - } - Uri uri = Uri.parse(AUTHORITY_PLUS_MESSAGES + account + "/" + messageId); - Cursor cursor = mContentResolver.query(uri, MESSAGE_PROJECTION, null, null, null); - return new MessageCursor(this, mContentResolver, account, cursor); - } - - /** - * Gets a message cursor over the messages that match the query. Note that - * this simply finds all of the messages that match and returns them. It - * does not return all messages in conversations where any message matches. - * - * @param account get the cursor for messages in this account - * @param query a query in GMail's query syntax. Currently only queries of - * the form [label:

The intent will have the action ACTION_PROVIDER_CHANGED and the extras mentioned below. - * The data for the intent will be content://gmail-ls/unread/. - * - *

The goal is to support the following user experience: