();
- MimeUtility.collectParts(oldMessage, viewables, attachments);
- LegacyConversions.updateBodyFields(newBody, newMessage, viewables);
- // commit changes so far so we have real id's
- newMessage.save(context);
- newBody.save(context);
- // convert attachments
- if (localAttachments) {
- // These are references to local data, and should create records only
- // (e.g. the content URI). No files should be created.
- LegacyConversions.updateAttachments(context, newMessage, attachments,
- true);
- }
- }
- // done
- if (handler != null) {
- handler.incProgress(accountNum);
- }
- } catch (MessagingException me) {
- e = me;
- } catch (IOException ioe) {
- e = ioe;
- }
- if (e != null) {
- Log.d(Email.LOG_TAG, "Exception copying message " + oldMessage.getSubject()
- + ": "+ e);
- if (handler != null) {
- handler.error(accountNum,
- context.getString(R.string.upgrade_accounts_error));
- }
- }
- }
- } catch (MessagingException e) {
- // Couldn't copy folder at all
- Log.d(Email.LOG_TAG, "Exception while copying messages in " +
- conversion.folder.toString() + ": " + e);
- if (handler != null) {
- handler.error(accountNum, context.getString(R.string.upgrade_accounts_error));
- }
- }
- }
-
- /**
- * Delete an account
- */
- /* package */ static void deleteAccountStore(Context context, Account account, int accountNum,
- UIHandler handler) {
- try {
- Store store = LocalStore.newInstance(account.getLocalStoreUri(), context, null);
- store.delete();
- // delete() closes the store
- } catch (MessagingException e) {
- Log.d(Email.LOG_TAG, "Exception while deleting account " + e);
- if (handler != null) {
- handler.error(accountNum, context.getString(R.string.upgrade_accounts_error));
- }
- }
- }
-
- /**
- * Cleanup SSL, TLS, etc for each converted account.
- */
- /* package */ static void cleanupConnections(Context context, EmailContent.Account newAccount,
- Account account) {
- // 1. Look up provider for this email address
- String email = newAccount.mEmailAddress;
- int atSignPos = email.lastIndexOf('@');
- String domain = email.substring(atSignPos + 1);
- Provider p = AccountSettingsUtils.findProviderForDomain(context, domain);
-
- // 2. If provider found, just use its settings (overriding what user had)
- // This is drastic but most reliable. Note: This also benefits from newer provider
- // data that might be found in a vendor policy module.
- if (p != null) {
- // Incoming
- try {
- URI incomingUriTemplate = p.incomingUriTemplate;
- String incomingUsername = newAccount.mHostAuthRecv.mLogin;
- String incomingPassword = newAccount.mHostAuthRecv.mPassword;
- URI incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUsername + ":"
- + incomingPassword, incomingUriTemplate.getHost(),
- incomingUriTemplate.getPort(), incomingUriTemplate.getPath(), null, null);
- newAccount.mHostAuthRecv.setStoreUri(incomingUri.toString());
- } catch (URISyntaxException e) {
- // Ignore - just use the data we copied across (for better or worse)
- }
- // Outgoing
- try {
- URI outgoingUriTemplate = p.outgoingUriTemplate;
- String outgoingUsername = newAccount.mHostAuthSend.mLogin;
- String outgoingPassword = newAccount.mHostAuthSend.mPassword;
- URI outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":"
- + outgoingPassword, outgoingUriTemplate.getHost(),
- outgoingUriTemplate.getPort(), outgoingUriTemplate.getPath(), null, null);
- newAccount.mHostAuthSend.setStoreUri(outgoingUri.toString());
- } catch (URISyntaxException e) {
- // Ignore - just use the data we copied across (for better or worse)
- }
- Log.d(Email.LOG_TAG, "Rewriting connection details for " + account.getDescription());
- return;
- }
-
- // 3. Otherwise, use simple heuristics to adjust connection and attempt to keep it
- // reliable. NOTE: These are the "legacy" ssl/tls encodings, not the ones in
- // the current provider.
- newAccount.mHostAuthRecv.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
- String receiveUri = account.getStoreUri();
- if (receiveUri.contains("+ssl+")) {
- // non-optional SSL - keep as is, with trust all
- } else if (receiveUri.contains("+ssl")) {
- // optional SSL - TBD
- } else if (receiveUri.contains("+tls+")) {
- // non-optional TLS - keep as is, with trust all
- } else if (receiveUri.contains("+tls")) {
- // optional TLS - TBD
- }
- newAccount.mHostAuthSend.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
- String sendUri = account.getSenderUri();
- if (sendUri.contains("+ssl+")) {
- // non-optional SSL - keep as is, with trust all
- } else if (sendUri.contains("+ssl")) {
- // optional SSL - TBD
- } else if (sendUri.contains("+tls+")) {
- // non-optional TLS - keep as is, with trust all
- } else if (sendUri.contains("+tls")) {
- // optional TLS - TBD
- }
- }
-
- /**
- * Bulk upgrade old accounts if exist.
- *
- * @return true if bulk upgrade has started. false otherwise.
- */
- /* package */ static boolean doBulkUpgradeIfNecessary(Context context) {
-// if (bulkUpgradesRequired(context, Preferences.getPreferences(context))) {
-// UpgradeAccounts.actionStart(context);
-// return true;
-// }
- return false;
- }
-
- /**
- * Test for bulk upgrades and return true if necessary
- *
- * @return true if upgrades required (old accounts exist). false otherwise.
- */
- private static boolean bulkUpgradesRequired(Context context, Preferences preferences) {
- if (DEBUG_FORCE_UPGRADES) {
- // build at least one fake account
- Account fake = new Account(context);
- fake.setDescription("Fake Account");
- fake.setEmail("user@gmail.com");
- fake.setName("First Last");
- fake.setSenderUri("smtp://user:password@smtp.gmail.com");
- fake.setStoreUri("imap://user:password@imap.gmail.com");
- fake.save(preferences);
- return true;
- }
-
- // 1. Get list of legacy accounts and look for any non-backup entries
- Account[] legacyAccounts = preferences.getAccounts();
- if (legacyAccounts.length == 0) {
- return false;
- }
-
- // 2. Look at the first legacy account and decide what to do
- // We only need to look at the first: If it's not a backup account, then it's a true
- // legacy account, and there are one or more accounts needing upgrade. If it is a backup
- // account, then we know for sure that there are no legacy accounts (backup deletes all
- // old accounts, and indicates that "modern" code has already run on this device.)
- if (0 != (legacyAccounts[0].getBackupFlags() & Account.BACKUP_FLAGS_IS_BACKUP)) {
- return false;
- } else {
- return true;
- }
- }
-}
diff --git a/src/com/android/email/activity/Welcome.java b/src/com/android/email/activity/Welcome.java
index 0f18b447c..68888523d 100644
--- a/src/com/android/email/activity/Welcome.java
+++ b/src/com/android/email/activity/Welcome.java
@@ -156,13 +156,6 @@ public class Welcome extends Activity {
// Reset the "accounts changed" notification, now that we're here
Email.setNotifyUiAccountsChanged(false);
- // Quickly check for bulk upgrades (from older app versions) and switch to the
- // upgrade activity if necessary
- if (UpgradeAccounts.doBulkUpgradeIfNecessary(this)) {
- finish();
- return;
- }
-
// Restore accounts, if it has not happened already
// NOTE: This is blocking, which it should not be (in the UI thread)
// We're going to live with this for the short term and replace with something
diff --git a/src/com/android/email/mail/internet/EmailHtmlUtil.java b/src/com/android/email/mail/internet/EmailHtmlUtil.java
index d457879e2..acccdc0bd 100755
--- a/src/com/android/email/mail/internet/EmailHtmlUtil.java
+++ b/src/com/android/email/mail/internet/EmailHtmlUtil.java
@@ -16,15 +16,6 @@
package com.android.email.mail.internet;
-import com.android.email.mail.MessagingException;
-import com.android.email.mail.Multipart;
-import com.android.email.mail.Part;
-import com.android.email.mail.store.LocalStore.LocalAttachmentBodyPart;
-import com.android.email.provider.AttachmentProvider;
-
-import android.content.ContentResolver;
-import android.net.Uri;
-
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -34,51 +25,6 @@ public class EmailHtmlUtil {
// multiple continuous spaces.
private static final Pattern PLAIN_TEXT_TO_ESCAPE = Pattern.compile("[<>&]| {2,}|\r?\n");
- //TODO: make resolveInlineImage() work in the new content provider model.
- /**
- * Resolve content-id reference in src attribute of img tag to AttachmentProvider's
- * content uri. This method calls itself recursively at most the number of
- * LocalAttachmentPart that mime type is image and has content id.
- * The attribute src="cid:content_id" is resolved as src="content://...".
- * This method is package scope for testing purpose.
- *
- * @param text html email text
- * @param part mime part which may contain inline image
- * @return html text in which src attribute of img tag may be replaced with content uri
- */
- public static String resolveInlineImage(
- ContentResolver resolver, long accountId, String text, Part part, int depth)
- throws MessagingException {
- // avoid too deep recursive call.
- if (depth >= 10 || text == null) {
- return text;
- }
- String contentType = MimeUtility.unfoldAndDecode(part.getContentType());
- String contentId = part.getContentId();
- if (contentType.startsWith("image/") &&
- contentId != null &&
- part instanceof LocalAttachmentBodyPart) {
- LocalAttachmentBodyPart attachment = (LocalAttachmentBodyPart)part;
- Uri attachmentUri =
- AttachmentProvider.getAttachmentUri(accountId, attachment.getAttachmentId());
- Uri contentUri =
- AttachmentProvider.resolveAttachmentIdToContentUri(resolver, attachmentUri);
- // Regexp which matches ' src="cid:contentId"'.
- String contentIdRe = "\\s+(?i)src=\"cid(?-i):\\Q" + contentId + "\\E\"";
- // Replace all occurrences of src attribute with ' src="content://contentUri"'.
- text = text.replaceAll(contentIdRe, " src=\"" + contentUri + "\"");
- }
-
- if (part.getBody() instanceof Multipart) {
- Multipart mp = (Multipart)part.getBody();
- for (int i = 0; i < mp.getCount(); i++) {
- text = resolveInlineImage(resolver, accountId, text, mp.getBodyPart(i), depth + 1);
- }
- }
-
- return text;
- }
-
/**
* Escape some special character as HTML escape sequence.
*
diff --git a/src/com/android/email/mail/store/LocalStore.java b/src/com/android/email/mail/store/LocalStore.java
deleted file mode 100644
index 67a3daaff..000000000
--- a/src/com/android/email/mail/store/LocalStore.java
+++ /dev/null
@@ -1,1849 +0,0 @@
-/*
- * Copyright (C) 2008 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 com.android.email.mail.store;
-
-import com.android.email.Email;
-import com.android.email.Utility;
-import com.android.email.mail.Address;
-import com.android.email.mail.Body;
-import com.android.email.mail.FetchProfile;
-import com.android.email.mail.Flag;
-import com.android.email.mail.Folder;
-import com.android.email.mail.Message;
-import com.android.email.mail.MessagingException;
-import com.android.email.mail.Part;
-import com.android.email.mail.Store;
-import com.android.email.mail.Message.RecipientType;
-import com.android.email.mail.Store.PersistentDataCallbacks;
-import com.android.email.mail.internet.MimeBodyPart;
-import com.android.email.mail.internet.MimeHeader;
-import com.android.email.mail.internet.MimeMessage;
-import com.android.email.mail.internet.MimeMultipart;
-import com.android.email.mail.internet.MimeUtility;
-import com.android.email.mail.internet.TextBody;
-
-import org.apache.commons.io.IOUtils;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Base64;
-import android.util.Base64OutputStream;
-import android.util.Log;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.UUID;
-
-/**
- *
- * Implements a SQLite database backed local store for Messages.
- *
- */
-public class LocalStore extends Store implements PersistentDataCallbacks {
- /**
- * History of database revisions.
- *
- * db version Shipped in Notes
- * ---------- ---------- -----
- * 18 pre-1.0 Development versions. No upgrade path.
- * 18 1.0, 1.1 1.0 Release version.
- * 19 - Added message_id column to messages table.
- * 20 1.5 Added content_id column to attachments table.
- * 21 - Added remote_store_data table
- * 22 - Added store_flag_1 and store_flag_2 columns to messages table.
- * 23 - Added flag_downloaded_full, flag_downloaded_partial, flag_deleted
- * columns to message table.
- * 24 - Added x_headers to messages table.
- */
-
- private static final int DB_VERSION = 24;
-
- private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
-
- private final String mPath;
- private SQLiteDatabase mDb;
- private final File mAttachmentsDir;
- private final Context mContext;
- private int mVisibleLimitDefault = -1;
-
- /**
- * Static named constructor.
- */
- public static LocalStore newInstance(String uri, Context context,
- PersistentDataCallbacks callbacks) throws MessagingException {
- return new LocalStore(uri, context);
- }
-
- /**
- * @param uri local://localhost/path/to/database/uuid.db
- */
- private LocalStore(String _uri, Context context) throws MessagingException {
- mContext = context;
- URI uri = null;
- try {
- uri = new URI(_uri);
- } catch (Exception e) {
- throw new MessagingException("Invalid uri for LocalStore");
- }
- if (!uri.getScheme().equals("local")) {
- throw new MessagingException("Invalid scheme");
- }
- mPath = uri.getPath();
-
- File parentDir = new File(mPath).getParentFile();
- if (!parentDir.exists()) {
- parentDir.mkdirs();
- }
- mDb = SQLiteDatabase.openOrCreateDatabase(mPath, null);
- int oldVersion = mDb.getVersion();
-
- /*
- * TODO we should have more sophisticated way to upgrade database.
- */
- if (oldVersion != DB_VERSION) {
- if (Email.LOGD) {
- Log.v(Email.LOG_TAG, String.format("Upgrading database from %d to %d",
- oldVersion, DB_VERSION));
- }
- if (oldVersion < 18) {
- /**
- * Missing or old: Create up-to-date tables
- */
- mDb.execSQL("DROP TABLE IF EXISTS folders");
- mDb.execSQL("CREATE TABLE folders (id INTEGER PRIMARY KEY, name TEXT, "
- + "last_updated INTEGER, unread_count INTEGER, visible_limit INTEGER)");
-
- mDb.execSQL("DROP TABLE IF EXISTS messages");
- mDb.execSQL("CREATE TABLE messages (id INTEGER PRIMARY KEY, folder_id INTEGER, " +
- "uid TEXT, subject TEXT, date INTEGER, flags TEXT, sender_list TEXT, " +
- "to_list TEXT, cc_list TEXT, bcc_list TEXT, reply_to_list TEXT, " +
- "html_content TEXT, text_content TEXT, attachment_count INTEGER, " +
- "internal_date INTEGER, message_id TEXT, store_flag_1 INTEGER, " +
- "store_flag_2 INTEGER, flag_downloaded_full INTEGER," +
- "flag_downloaded_partial INTEGER, flag_deleted INTEGER, x_headers TEXT)");
-
- mDb.execSQL("DROP TABLE IF EXISTS attachments");
- mDb.execSQL("CREATE TABLE attachments (id INTEGER PRIMARY KEY, message_id INTEGER,"
- + "store_data TEXT, content_uri TEXT, size INTEGER, name TEXT,"
- + "mime_type TEXT, content_id TEXT)");
-
- mDb.execSQL("DROP TABLE IF EXISTS pending_commands");
- mDb.execSQL("CREATE TABLE pending_commands " +
- "(id INTEGER PRIMARY KEY, command TEXT, arguments TEXT)");
-
- addRemoteStoreDataTable();
-
- addFolderDeleteTrigger();
-
- mDb.execSQL("DROP TRIGGER IF EXISTS delete_message");
- mDb.execSQL("CREATE TRIGGER delete_message BEFORE DELETE ON messages BEGIN DELETE FROM attachments WHERE old.id = message_id; END;");
- mDb.setVersion(DB_VERSION);
- }
- else {
- if (oldVersion < 19) {
- /**
- * Upgrade 18 to 19: add message_id to messages table
- */
- mDb.execSQL("ALTER TABLE messages ADD COLUMN message_id TEXT;");
- mDb.setVersion(19);
- }
- if (oldVersion < 20) {
- /**
- * Upgrade 19 to 20: add content_id to attachments table
- */
- mDb.execSQL("ALTER TABLE attachments ADD COLUMN content_id TEXT;");
- mDb.setVersion(20);
- }
- if (oldVersion < 21) {
- /**
- * Upgrade 20 to 21: add remote_store_data and update triggers to match
- */
- addRemoteStoreDataTable();
- addFolderDeleteTrigger();
- mDb.setVersion(21);
- }
- if (oldVersion < 22) {
- /**
- * Upgrade 21 to 22: add store_flag_1 and store_flag_2 to messages table
- */
- mDb.execSQL("ALTER TABLE messages ADD COLUMN store_flag_1 INTEGER;");
- mDb.execSQL("ALTER TABLE messages ADD COLUMN store_flag_2 INTEGER;");
- mDb.setVersion(22);
- }
- if (oldVersion < 23) {
- /**
- * Upgrade 22 to 23: add flag_downloaded_full & flag_downloaded_partial
- * and flag_deleted columns to message table *and upgrade existing messages*.
- */
- mDb.beginTransaction();
- try {
- mDb.execSQL(
- "ALTER TABLE messages ADD COLUMN flag_downloaded_full INTEGER;");
- mDb.execSQL(
- "ALTER TABLE messages ADD COLUMN flag_downloaded_partial INTEGER;");
- mDb.execSQL(
- "ALTER TABLE messages ADD COLUMN flag_deleted INTEGER;");
- migrateMessageFlags();
- mDb.setVersion(23);
- mDb.setTransactionSuccessful();
- } finally {
- mDb.endTransaction();
- }
- }
- if (oldVersion < 24) {
- /**
- * Upgrade 23 to 24: add x_headers to messages table
- */
- mDb.execSQL("ALTER TABLE messages ADD COLUMN x_headers TEXT;");
- mDb.setVersion(24);
- }
- }
-
- if (mDb.getVersion() != DB_VERSION) {
- throw new Error("Database upgrade failed!");
- }
- }
- mAttachmentsDir = new File(mPath + "_att");
- if (!mAttachmentsDir.exists()) {
- mAttachmentsDir.mkdirs();
- }
- }
-
- /**
- * Common code to add the remote_store_data table
- */
- private void addRemoteStoreDataTable() {
- mDb.execSQL("DROP TABLE IF EXISTS remote_store_data");
- mDb.execSQL("CREATE TABLE remote_store_data (" +
- "id INTEGER PRIMARY KEY, folder_id INTEGER, data_key TEXT, data TEXT, " +
- "UNIQUE (folder_id, data_key) ON CONFLICT REPLACE" +
- ")");
- }
-
- /**
- * Common code to add folder delete trigger
- */
- private void addFolderDeleteTrigger() {
- mDb.execSQL("DROP TRIGGER IF EXISTS delete_folder");
- mDb.execSQL("CREATE TRIGGER delete_folder "
- + "BEFORE DELETE ON folders "
- + "BEGIN "
- + "DELETE FROM messages WHERE old.id = folder_id; "
- + "DELETE FROM remote_store_data WHERE old.id = folder_id; "
- + "END;");
- }
-
- /**
- * When upgrading from 22 to 23, we have to move any flags "X_DOWNLOADED_FULL" or
- * "X_DOWNLOADED_PARTIAL" or "DELETED" from the old string-based storage to their own columns.
- *
- * Note: Caller should open a db transaction around this
- */
- private void migrateMessageFlags() {
- Cursor cursor = mDb.query("messages",
- new String[] { "id", "flags" },
- null, null, null, null, null);
- try {
- int columnId = cursor.getColumnIndexOrThrow("id");
- int columnFlags = cursor.getColumnIndexOrThrow("flags");
-
- while (cursor.moveToNext()) {
- String oldFlags = cursor.getString(columnFlags);
- ContentValues values = new ContentValues();
- int newFlagDlFull = 0;
- int newFlagDlPartial = 0;
- int newFlagDeleted = 0;
- if (oldFlags != null) {
- if (oldFlags.contains(Flag.X_DOWNLOADED_FULL.toString())) {
- newFlagDlFull = 1;
- }
- if (oldFlags.contains(Flag.X_DOWNLOADED_PARTIAL.toString())) {
- newFlagDlPartial = 1;
- }
- if (oldFlags.contains(Flag.DELETED.toString())) {
- newFlagDeleted = 1;
- }
- }
- // Always commit the new flags.
- // Note: We don't have to pay the cost of rewriting the old string,
- // because the old flag will be ignored, and will eventually be overwritten
- // anyway.
- values.put("flag_downloaded_full", newFlagDlFull);
- values.put("flag_downloaded_partial", newFlagDlPartial);
- values.put("flag_deleted", newFlagDeleted);
- int rowId = cursor.getInt(columnId);
- mDb.update("messages", values, "id=" + rowId, null);
- }
- } finally {
- cursor.close();
- }
- }
-
- @Override
- public Folder getFolder(String name) throws MessagingException {
- return new LocalFolder(name);
- }
-
- // TODO this takes about 260-300ms, seems slow.
- @Override
- public Folder[] getPersonalNamespaces() throws MessagingException {
- ArrayList folders = new ArrayList();
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery("SELECT name FROM folders", null);
- while (cursor.moveToNext()) {
- folders.add(new LocalFolder(cursor.getString(0)));
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return folders.toArray(new Folder[] {});
- }
-
- @Override
- public Bundle checkSettings() throws MessagingException {
- return null;
- }
-
- /**
- * Local store only: Allow it to be closed. This is necessary for the account upgrade process
- * because we open and close each database a few times as we proceed.
- */
- public void close() {
- try {
- mDb.close();
- mDb = null;
- } catch (Exception e) {
- // Log and discard. This is best-effort, and database finalizers will try again.
- Log.d(Email.LOG_TAG, "Caught exception while closing localstore db: " + e);
- }
- }
-
- /**
- * Delete the entire Store and it's backing database.
- */
- @Override
- public void delete() {
- try {
- mDb.close();
- } catch (Exception e) {
-
- }
- try{
- File[] attachments = mAttachmentsDir.listFiles();
- for (File attachment : attachments) {
- if (attachment.exists()) {
- attachment.delete();
- }
- }
- if (mAttachmentsDir.exists()) {
- mAttachmentsDir.delete();
- }
- }
- catch (Exception e) {
- }
- try {
- new File(mPath).delete();
- }
- catch (Exception e) {
-
- }
- }
-
- /**
- * Report # of attachments (for migration estimates only - catches all exceptions and
- * just returns zero)
- */
- public int getStoredAttachmentCount() {
- try{
- File[] attachments = mAttachmentsDir.listFiles();
- return attachments.length;
- }
- catch (Exception e) {
- return 0;
- }
- }
-
- /**
- * Deletes all cached attachments for the entire store.
- */
- public int pruneCachedAttachments() throws MessagingException {
- int prunedCount = 0;
- File[] files = mAttachmentsDir.listFiles();
- for (File file : files) {
- if (file.exists()) {
- try {
- Cursor cursor = null;
- try {
- cursor = mDb.query(
- "attachments",
- new String[] { "store_data" },
- "id = ?",
- new String[] { file.getName() },
- null,
- null,
- null);
- if (cursor.moveToNext()) {
- if (cursor.getString(0) == null) {
- /*
- * If the attachment has no store data it is not recoverable, so
- * we won't delete it.
- */
- continue;
- }
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- ContentValues cv = new ContentValues();
- cv.putNull("content_uri");
- mDb.update("attachments", cv, "id = ?", new String[] { file.getName() });
- }
- catch (Exception e) {
- /*
- * If the row has gone away before we got to mark it not-downloaded that's
- * okay.
- */
- }
- if (!file.delete()) {
- file.deleteOnExit();
- }
- prunedCount++;
- }
- }
- return prunedCount;
- }
-
- /**
- * Set the visible limit for all folders in a given store.
- *
- * @param visibleLimit the value to write to all folders. -1 may also be used as a marker.
- */
- public void resetVisibleLimits(int visibleLimit) {
- mVisibleLimitDefault = visibleLimit; // used for future Folder.create ops
- ContentValues cv = new ContentValues();
- cv.put("visible_limit", Integer.toString(visibleLimit));
- mDb.update("folders", cv, null, null);
- }
-
- public ArrayList getPendingCommands() {
- Cursor cursor = null;
- try {
- cursor = mDb.query("pending_commands",
- new String[] { "id", "command", "arguments" },
- null,
- null,
- null,
- null,
- "id ASC");
- ArrayList commands = new ArrayList();
- while (cursor.moveToNext()) {
- PendingCommand command = new PendingCommand();
- command.mId = cursor.getLong(0);
- command.command = cursor.getString(1);
- String arguments = cursor.getString(2);
- command.arguments = arguments.split(",");
- for (int i = 0; i < command.arguments.length; i++) {
- command.arguments[i] = Utility.fastUrlDecode(command.arguments[i]);
- }
- commands.add(command);
- }
- return commands;
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- public void addPendingCommand(PendingCommand command) {
- try {
- for (int i = 0; i < command.arguments.length; i++) {
- command.arguments[i] = URLEncoder.encode(command.arguments[i], "UTF-8");
- }
- ContentValues cv = new ContentValues();
- cv.put("command", command.command);
- cv.put("arguments", Utility.combine(command.arguments, ','));
- mDb.insert("pending_commands", "command", cv);
- }
- catch (UnsupportedEncodingException usee) {
- throw new Error("Aparently UTF-8 has been lost to the annals of history.");
- }
- }
-
- public void removePendingCommand(PendingCommand command) {
- mDb.delete("pending_commands", "id = ?", new String[] { Long.toString(command.mId) });
- }
-
- public static class PendingCommand {
- private long mId;
- public String command;
- public String[] arguments;
-
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append(command);
- sb.append("\n");
- for (String argument : arguments) {
- sb.append(" ");
- sb.append(argument);
- sb.append("\n");
- }
- return sb.toString();
- }
- }
-
- /**
- * LocalStore-only function to get the callbacks API
- */
- public PersistentDataCallbacks getPersistentCallbacks() throws MessagingException {
- return this;
- }
-
- public String getPersistentString(String key, String defaultValue) {
- return getPersistentString(-1, key, defaultValue);
- }
-
- public void setPersistentString(String key, String value) {
- setPersistentString(-1, key, value);
- }
-
- /**
- * Common implementation of getPersistentString
- * @param folderId The id of the associated folder, or -1 for "store" values
- * @param key The key
- * @param defaultValue The value to return if the row is not found
- * @return The row data or the default
- */
- private String getPersistentString(long folderId, String key, String defaultValue) {
- String result = defaultValue;
- Cursor cursor = null;
- try {
- cursor = mDb.query("remote_store_data",
- new String[] { "data" },
- "folder_id = ? AND data_key = ?",
- new String[] { Long.toString(folderId), key },
- null,
- null,
- null);
- if (cursor != null && cursor.moveToNext()) {
- result = cursor.getString(0);
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return result;
- }
-
- /**
- * Common implementation of setPersistentString
- * @param folderId The id of the associated folder, or -1 for "store" values
- * @param key The key
- * @param value The value to store
- */
- private void setPersistentString(long folderId, String key, String value) {
- ContentValues cv = new ContentValues();
- cv.put("folder_id", Long.toString(folderId));
- cv.put("data_key", key);
- cv.put("data", value);
- // Note: Table has on-conflict-replace rule
- mDb.insert("remote_store_data", null, cv);
- }
-
- public class LocalFolder extends Folder implements Folder.PersistentDataCallbacks {
- private final String mName;
- private long mFolderId = -1;
- private int mUnreadMessageCount = -1;
- private int mVisibleLimit = -1;
-
- public LocalFolder(String name) {
- this.mName = name;
- }
-
- public long getId() {
- return mFolderId;
- }
-
- /**
- * This is just used by the internal callers
- */
- private void open(OpenMode mode) throws MessagingException {
- open(mode, null);
- }
-
- @Override
- public void open(OpenMode mode, PersistentDataCallbacks callbacks)
- throws MessagingException {
- if (isOpen()) {
- return;
- }
- if (!exists()) {
- create(FolderType.HOLDS_MESSAGES);
- }
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery("SELECT id, unread_count, visible_limit FROM folders "
- + "where folders.name = ?",
- new String[] {
- mName
- });
- if (!cursor.moveToFirst()) {
- throw new MessagingException("Nonexistent folder");
- }
- mFolderId = cursor.getInt(0);
- mUnreadMessageCount = cursor.getInt(1);
- mVisibleLimit = cursor.getInt(2);
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- @Override
- public boolean isOpen() {
- return mFolderId != -1;
- }
-
- @Override
- public OpenMode getMode() throws MessagingException {
- return OpenMode.READ_WRITE;
- }
-
- @Override
- public String getName() {
- return mName;
- }
-
- @Override
- public boolean exists() throws MessagingException {
- return Utility.arrayContains(getPersonalNamespaces(), this);
- }
-
- // LocalStore supports folder creation
- @Override
- public boolean canCreate(FolderType type) {
- return true;
- }
-
- @Override
- public boolean create(FolderType type) throws MessagingException {
- if (exists()) {
- throw new MessagingException("Folder " + mName + " already exists.");
- }
- mDb.execSQL("INSERT INTO folders (name, visible_limit) VALUES (?, ?)", new Object[] {
- mName,
- mVisibleLimitDefault
- });
- return true;
- }
-
- @Override
- public void close(boolean expunge) throws MessagingException {
- if (expunge) {
- expunge();
- }
- mFolderId = -1;
- }
-
- @Override
- public int getMessageCount() throws MessagingException {
- return getMessageCount(null, null);
- }
-
- /**
- * Return number of messages based on the state of the flags.
- *
- * @param setFlags The flags that should be set for a message to be selected (null ok)
- * @param clearFlags The flags that should be clear for a message to be selected (null ok)
- * @return The number of messages matching the desired flag states.
- * @throws MessagingException
- */
- public int getMessageCount(Flag[] setFlags, Flag[] clearFlags) throws MessagingException {
- // Generate WHERE clause based on flags observed
- StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM messages WHERE ");
- buildFlagPredicates(sql, setFlags, clearFlags);
- sql.append("messages.folder_id = ?");
-
- open(OpenMode.READ_WRITE);
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery(
- sql.toString(),
- new String[] {
- Long.toString(mFolderId)
- });
- cursor.moveToFirst();
- int messageCount = cursor.getInt(0);
- return messageCount;
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- @Override
- public int getUnreadMessageCount() throws MessagingException {
- if (!isOpen()) {
- // opening it will read all columns including mUnreadMessageCount
- open(OpenMode.READ_WRITE);
- } else {
- // already open. refresh from db in case another instance wrote to it
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery("SELECT unread_count FROM folders WHERE folders.name = ?",
- new String[] { mName });
- if (!cursor.moveToFirst()) {
- throw new MessagingException("Nonexistent folder");
- }
- mUnreadMessageCount = cursor.getInt(0);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- return mUnreadMessageCount;
- }
-
- public void setUnreadMessageCount(int unreadMessageCount) throws MessagingException {
- open(OpenMode.READ_WRITE);
- mUnreadMessageCount = Math.max(0, unreadMessageCount);
- mDb.execSQL("UPDATE folders SET unread_count = ? WHERE id = ?",
- new Object[] { mUnreadMessageCount, mFolderId });
- }
-
- public int getVisibleLimit() throws MessagingException {
- if (!isOpen()) {
- // opening it will read all columns including mVisibleLimit
- open(OpenMode.READ_WRITE);
- } else {
- // already open. refresh from db in case another instance wrote to it
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery(
- "SELECT visible_limit FROM folders WHERE folders.name = ?",
- new String[] { mName });
- if (!cursor.moveToFirst()) {
- throw new MessagingException("Nonexistent folder");
- }
- mVisibleLimit = cursor.getInt(0);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- return mVisibleLimit;
- }
-
- public void setVisibleLimit(int visibleLimit) throws MessagingException {
- open(OpenMode.READ_WRITE);
- mVisibleLimit = visibleLimit;
- mDb.execSQL("UPDATE folders SET visible_limit = ? WHERE id = ?",
- new Object[] { mVisibleLimit, mFolderId });
- }
-
- /**
- * Supports FetchProfile.Item.BODY and FetchProfile.Item.STRUCTURE
- */
- @Override
- public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener)
- throws MessagingException {
- open(OpenMode.READ_WRITE);
- if (fp.contains(FetchProfile.Item.BODY) || fp.contains(FetchProfile.Item.STRUCTURE)) {
- for (Message message : messages) {
- LocalMessage localMessage = (LocalMessage)message;
- Cursor cursor = null;
- localMessage.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "multipart/mixed");
- MimeMultipart mp = new MimeMultipart();
- mp.setSubType("mixed");
- localMessage.setBody(mp);
-
- // If fetching the body, retrieve html & plaintext from DB.
- // If fetching structure, simply build placeholders for them.
- if (fp.contains(FetchProfile.Item.BODY)) {
- try {
- cursor = mDb.rawQuery("SELECT html_content, text_content FROM messages "
- + "WHERE id = ?",
- new String[] { Long.toString(localMessage.mId) });
- cursor.moveToNext();
- String htmlContent = cursor.getString(0);
- String textContent = cursor.getString(1);
-
- if (htmlContent != null) {
- TextBody body = new TextBody(htmlContent);
- MimeBodyPart bp = new MimeBodyPart(body, "text/html");
- mp.addBodyPart(bp);
- }
-
- if (textContent != null) {
- TextBody body = new TextBody(textContent);
- MimeBodyPart bp = new MimeBodyPart(body, "text/plain");
- mp.addBodyPart(bp);
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- } else {
- MimeBodyPart bp = new MimeBodyPart();
- bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
- "text/html;\n charset=\"UTF-8\"");
- mp.addBodyPart(bp);
-
- bp = new MimeBodyPart();
- bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
- "text/plain;\n charset=\"UTF-8\"");
- mp.addBodyPart(bp);
- }
-
- try {
- cursor = mDb.query(
- "attachments",
- new String[] {
- "id",
- "size",
- "name",
- "mime_type",
- "store_data",
- "content_uri",
- "content_id" },
- "message_id = ?",
- new String[] { Long.toString(localMessage.mId) },
- null,
- null,
- null);
-
- while (cursor.moveToNext()) {
- long id = cursor.getLong(0);
- int size = cursor.getInt(1);
- String name = cursor.getString(2);
- String type = cursor.getString(3);
- String storeData = cursor.getString(4);
- String contentUri = cursor.getString(5);
- String contentId = cursor.getString(6);
- Body body = null;
- if (contentUri != null) {
- body = new LocalAttachmentBody(Uri.parse(contentUri), mContext);
- }
- MimeBodyPart bp = new LocalAttachmentBodyPart(body, id);
- bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
- String.format("%s;\n name=\"%s\"",
- type,
- name));
- bp.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
- bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
- String.format("attachment;\n filename=\"%s\";\n size=%d",
- name,
- size));
- bp.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId);
-
- /*
- * HEADER_ANDROID_ATTACHMENT_STORE_DATA is a custom header we add to that
- * we can later pull the attachment from the remote store if neccesary.
- */
- bp.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, storeData);
-
- mp.addBodyPart(bp);
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- }
- }
-
- /**
- * The columns to select when calling populateMessageFromGetMessageCursor()
- */
- private final String POPULATE_MESSAGE_SELECT_COLUMNS =
- "subject, sender_list, date, uid, flags, id, to_list, cc_list, " +
- "bcc_list, reply_to_list, attachment_count, internal_date, message_id, " +
- "store_flag_1, store_flag_2, flag_downloaded_full, flag_downloaded_partial, " +
- "flag_deleted, x_headers";
-
- /**
- * Populate a message from a cursor with the following columns:
- *
- * 0 subject
- * 1 from address
- * 2 date (long)
- * 3 uid
- * 4 flag list (older flags - comma-separated string)
- * 5 local id (long)
- * 6 to addresses
- * 7 cc addresses
- * 8 bcc addresses
- * 9 reply-to address
- * 10 attachment count (int)
- * 11 internal date (long)
- * 12 message id (from Mime headers)
- * 13 store flag 1
- * 14 store flag 2
- * 15 flag "downloaded full"
- * 16 flag "downloaded partial"
- * 17 flag "deleted"
- * 18 extended headers ("\r\n"-separated string)
- */
- private void populateMessageFromGetMessageCursor(LocalMessage message, Cursor cursor)
- throws MessagingException{
- message.setSubject(cursor.getString(0) == null ? "" : cursor.getString(0));
- Address[] from = Address.legacyUnpack(cursor.getString(1));
- if (from.length > 0) {
- message.setFrom(from[0]);
- }
- message.setSentDate(new Date(cursor.getLong(2)));
- message.setUid(cursor.getString(3));
- String flagList = cursor.getString(4);
- if (flagList != null && flagList.length() > 0) {
- String[] flags = flagList.split(",");
- try {
- for (String flag : flags) {
- message.setFlagInternal(Flag.valueOf(flag.toUpperCase()), true);
- }
- } catch (Exception e) {
- }
- }
- message.mId = cursor.getLong(5);
- message.setRecipients(RecipientType.TO, Address.legacyUnpack(cursor.getString(6)));
- message.setRecipients(RecipientType.CC, Address.legacyUnpack(cursor.getString(7)));
- message.setRecipients(RecipientType.BCC, Address.legacyUnpack(cursor.getString(8)));
- message.setReplyTo(Address.legacyUnpack(cursor.getString(9)));
- message.mAttachmentCount = cursor.getInt(10);
- message.setInternalDate(new Date(cursor.getLong(11)));
- message.setMessageId(cursor.getString(12));
- message.setFlagInternal(Flag.X_STORE_1, (0 != cursor.getInt(13)));
- message.setFlagInternal(Flag.X_STORE_2, (0 != cursor.getInt(14)));
- message.setFlagInternal(Flag.X_DOWNLOADED_FULL, (0 != cursor.getInt(15)));
- message.setFlagInternal(Flag.X_DOWNLOADED_PARTIAL, (0 != cursor.getInt(16)));
- message.setFlagInternal(Flag.DELETED, (0 != cursor.getInt(17)));
- message.setExtendedHeaders(cursor.getString(18));
- }
-
- @Override
- public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
- throws MessagingException {
- open(OpenMode.READ_WRITE);
- throw new MessagingException(
- "LocalStore.getMessages(int, int, MessageRetrievalListener) not yet implemented");
- }
-
- @Override
- public Message getMessage(String uid) throws MessagingException {
- open(OpenMode.READ_WRITE);
- LocalMessage message = new LocalMessage(uid, this);
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery(
- "SELECT " + POPULATE_MESSAGE_SELECT_COLUMNS +
- " FROM messages" +
- " WHERE uid = ? AND folder_id = ?",
- new String[] {
- message.getUid(), Long.toString(mFolderId)
- });
- if (!cursor.moveToNext()) {
- return null;
- }
- populateMessageFromGetMessageCursor(message, cursor);
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return message;
- }
-
- @Override
- public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException {
- open(OpenMode.READ_WRITE);
- ArrayList messages = new ArrayList();
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery(
- "SELECT " + POPULATE_MESSAGE_SELECT_COLUMNS +
- " FROM messages" +
- " WHERE folder_id = ?",
- new String[] {
- Long.toString(mFolderId)
- });
-
- while (cursor.moveToNext()) {
- LocalMessage message = new LocalMessage(null, this);
- populateMessageFromGetMessageCursor(message, cursor);
- messages.add(message);
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- return messages.toArray(new Message[] {});
- }
-
- @Override
- public Message[] getMessages(String[] uids, MessageRetrievalListener listener)
- throws MessagingException {
- open(OpenMode.READ_WRITE);
- if (uids == null) {
- return getMessages(listener);
- }
- ArrayList messages = new ArrayList();
- for (String uid : uids) {
- messages.add(getMessage(uid));
- }
- return messages.toArray(new Message[] {});
- }
-
- /**
- * Return a set of messages based on the state of the flags.
- *
- * @param setFlags The flags that should be set for a message to be selected (null ok)
- * @param clearFlags The flags that should be clear for a message to be selected (null ok)
- * @param listener
- * @return A list of messages matching the desired flag states.
- * @throws MessagingException
- */
- @Override
- public Message[] getMessages(Flag[] setFlags, Flag[] clearFlags,
- MessageRetrievalListener listener) throws MessagingException {
- // Generate WHERE clause based on flags observed
- StringBuilder sql = new StringBuilder(
- "SELECT " + POPULATE_MESSAGE_SELECT_COLUMNS +
- " FROM messages" +
- " WHERE ");
- buildFlagPredicates(sql, setFlags, clearFlags);
- sql.append("folder_id = ?");
-
- open(OpenMode.READ_WRITE);
- ArrayList messages = new ArrayList();
-
- Cursor cursor = null;
- try {
- cursor = mDb.rawQuery(
- sql.toString(),
- new String[] {
- Long.toString(mFolderId)
- });
-
- while (cursor.moveToNext()) {
- LocalMessage message = new LocalMessage(null, this);
- populateMessageFromGetMessageCursor(message, cursor);
- messages.add(message);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- return messages.toArray(new Message[] {});
- }
-
- /*
- * Build SQL where predicates expression from set and clear flag arrays.
- */
- private void buildFlagPredicates(StringBuilder sql, Flag[] setFlags, Flag[] clearFlags)
- throws MessagingException {
- if (setFlags != null) {
- for (Flag flag : setFlags) {
- if (flag == Flag.X_STORE_1) {
- sql.append("store_flag_1 = 1 AND ");
- } else if (flag == Flag.X_STORE_2) {
- sql.append("store_flag_2 = 1 AND ");
- } else if (flag == Flag.X_DOWNLOADED_FULL) {
- sql.append("flag_downloaded_full = 1 AND ");
- } else if (flag == Flag.X_DOWNLOADED_PARTIAL) {
- sql.append("flag_downloaded_partial = 1 AND ");
- } else if (flag == Flag.DELETED) {
- sql.append("flag_deleted = 1 AND ");
- } else {
- throw new MessagingException("Unsupported flag " + flag);
- }
- }
- }
- if (clearFlags != null) {
- for (Flag flag : clearFlags) {
- if (flag == Flag.X_STORE_1) {
- sql.append("store_flag_1 = 0 AND ");
- } else if (flag == Flag.X_STORE_2) {
- sql.append("store_flag_2 = 0 AND ");
- } else if (flag == Flag.X_DOWNLOADED_FULL) {
- sql.append("flag_downloaded_full = 0 AND ");
- } else if (flag == Flag.X_DOWNLOADED_PARTIAL) {
- sql.append("flag_downloaded_partial = 0 AND ");
- } else if (flag == Flag.DELETED) {
- sql.append("flag_deleted = 0 AND ");
- } else {
- throw new MessagingException("Unsupported flag " + flag);
- }
- }
- }
- }
-
- @Override
- public void copyMessages(Message[] msgs, Folder folder, MessageUpdateCallbacks callbacks)
- throws MessagingException {
- if (!(folder instanceof LocalFolder)) {
- throw new MessagingException("copyMessages called with incorrect Folder");
- }
- ((LocalFolder) folder).appendMessages(msgs, true);
- }
-
- /**
- * The method differs slightly from the contract; If an incoming message already has a uid
- * assigned and it matches the uid of an existing message then this message will replace the
- * old message. It is implemented as a delete/insert. This functionality is used in saving
- * of drafts and re-synchronization of updated server messages.
- */
- @Override
- public void appendMessages(Message[] messages) throws MessagingException {
- appendMessages(messages, false);
- }
-
- /**
- * The method differs slightly from the contract; If an incoming message already has a uid
- * assigned and it matches the uid of an existing message then this message will replace the
- * old message. It is implemented as a delete/insert. This functionality is used in saving
- * of drafts and re-synchronization of updated server messages.
- */
- public void appendMessages(Message[] messages, boolean copy) throws MessagingException {
- open(OpenMode.READ_WRITE);
- for (Message message : messages) {
- if (!(message instanceof MimeMessage)) {
- throw new Error("LocalStore can only store Messages that extend MimeMessage");
- }
-
- String uid = message.getUid();
- if (uid == null) {
- message.setUid("Local" + UUID.randomUUID().toString());
- }
- else {
- /*
- * The message may already exist in this Folder, so delete it first.
- */
- deleteAttachments(message.getUid());
- mDb.execSQL("DELETE FROM messages WHERE folder_id = ? AND uid = ?",
- new Object[] { mFolderId, message.getUid() });
- }
-
- ArrayList viewables = new ArrayList();
- ArrayList attachments = new ArrayList();
- MimeUtility.collectParts(message, viewables, attachments);
-
- StringBuffer sbHtml = new StringBuffer();
- StringBuffer sbText = new StringBuffer();
- for (Part viewable : viewables) {
- try {
- String text = MimeUtility.getTextFromPart(viewable);
- /*
- * Anything with MIME type text/html will be stored as such. Anything
- * else will be stored as text/plain.
- */
- if (viewable.getMimeType().equalsIgnoreCase("text/html")) {
- sbHtml.append(text);
- }
- else {
- sbText.append(text);
- }
- } catch (Exception e) {
- throw new MessagingException("Unable to get text for message part", e);
- }
- }
-
- try {
- ContentValues cv = new ContentValues();
- cv.put("uid", message.getUid());
- cv.put("subject", message.getSubject());
- cv.put("sender_list", Address.legacyPack(message.getFrom()));
- cv.put("date", message.getSentDate() == null
- ? System.currentTimeMillis() : message.getSentDate().getTime());
- cv.put("flags", makeFlagsString(message));
- cv.put("folder_id", mFolderId);
- cv.put("to_list", Address.legacyPack(message.getRecipients(RecipientType.TO)));
- cv.put("cc_list", Address.legacyPack(message.getRecipients(RecipientType.CC)));
- cv.put("bcc_list", Address.legacyPack(
- message.getRecipients(RecipientType.BCC)));
- cv.put("html_content", sbHtml.length() > 0 ? sbHtml.toString() : null);
- cv.put("text_content", sbText.length() > 0 ? sbText.toString() : null);
- cv.put("reply_to_list", Address.legacyPack(message.getReplyTo()));
- cv.put("attachment_count", attachments.size());
- cv.put("internal_date", message.getInternalDate() == null
- ? System.currentTimeMillis() : message.getInternalDate().getTime());
- cv.put("message_id", ((MimeMessage)message).getMessageId());
- cv.put("store_flag_1", makeFlagNumeric(message, Flag.X_STORE_1));
- cv.put("store_flag_2", makeFlagNumeric(message, Flag.X_STORE_2));
- cv.put("flag_downloaded_full",
- makeFlagNumeric(message, Flag.X_DOWNLOADED_FULL));
- cv.put("flag_downloaded_partial",
- makeFlagNumeric(message, Flag.X_DOWNLOADED_PARTIAL));
- cv.put("flag_deleted", makeFlagNumeric(message, Flag.DELETED));
- cv.put("x_headers", ((MimeMessage) message).getExtendedHeaders());
- long messageId = mDb.insert("messages", "uid", cv);
- for (Part attachment : attachments) {
- saveAttachment(messageId, attachment, copy);
- }
- } catch (Exception e) {
- throw new MessagingException("Error appending message", e);
- }
- }
- }
-
- /**
- * Update the given message in the LocalStore without first deleting the existing
- * message (contrast with appendMessages). This method is used to store changes
- * to the given message while updating attachments and not removing existing
- * attachment data.
- * TODO In the future this method should be combined with appendMessages since the Message
- * contains enough data to decide what to do.
- * @param message
- * @throws MessagingException
- */
- public void updateMessage(LocalMessage message) throws MessagingException {
- open(OpenMode.READ_WRITE);
- ArrayList viewables = new ArrayList();
- ArrayList attachments = new ArrayList();
- MimeUtility.collectParts(message, viewables, attachments);
-
- StringBuffer sbHtml = new StringBuffer();
- StringBuffer sbText = new StringBuffer();
- for (int i = 0, count = viewables.size(); i < count; i++) {
- Part viewable = viewables.get(i);
- try {
- String text = MimeUtility.getTextFromPart(viewable);
- /*
- * Anything with MIME type text/html will be stored as such. Anything
- * else will be stored as text/plain.
- */
- if (viewable.getMimeType().equalsIgnoreCase("text/html")) {
- sbHtml.append(text);
- }
- else {
- sbText.append(text);
- }
- } catch (Exception e) {
- throw new MessagingException("Unable to get text for message part", e);
- }
- }
-
- try {
- mDb.execSQL("UPDATE messages SET "
- + "uid = ?, subject = ?, sender_list = ?, date = ?, flags = ?, "
- + "folder_id = ?, to_list = ?, cc_list = ?, bcc_list = ?, "
- + "html_content = ?, text_content = ?, reply_to_list = ?, "
- + "attachment_count = ?, message_id = ?, store_flag_1 = ?, "
- + "store_flag_2 = ?, flag_downloaded_full = ?, "
- + "flag_downloaded_partial = ?, flag_deleted = ?, x_headers = ? "
- + "WHERE id = ?",
- new Object[] {
- message.getUid(),
- message.getSubject(),
- Address.legacyPack(message.getFrom()),
- message.getSentDate() == null ? System
- .currentTimeMillis() : message.getSentDate()
- .getTime(),
- makeFlagsString(message),
- mFolderId,
- Address.legacyPack(message
- .getRecipients(RecipientType.TO)),
- Address.legacyPack(message
- .getRecipients(RecipientType.CC)),
- Address.legacyPack(message
- .getRecipients(RecipientType.BCC)),
- sbHtml.length() > 0 ? sbHtml.toString() : null,
- sbText.length() > 0 ? sbText.toString() : null,
- Address.legacyPack(message.getReplyTo()),
- attachments.size(),
- message.getMessageId(),
- makeFlagNumeric(message, Flag.X_STORE_1),
- makeFlagNumeric(message, Flag.X_STORE_2),
- makeFlagNumeric(message, Flag.X_DOWNLOADED_FULL),
- makeFlagNumeric(message, Flag.X_DOWNLOADED_PARTIAL),
- makeFlagNumeric(message, Flag.DELETED),
- message.getExtendedHeaders(),
-
- message.mId
- });
-
- for (int i = 0, count = attachments.size(); i < count; i++) {
- Part attachment = attachments.get(i);
- saveAttachment(message.mId, attachment, false);
- }
- } catch (Exception e) {
- throw new MessagingException("Error appending message", e);
- }
- }
-
- /**
- * @param messageId
- * @param attachment
- * @param attachmentId -1 to create a new attachment or >= 0 to update an existing
- * @throws IOException
- * @throws MessagingException
- */
- private void saveAttachment(long messageId, Part attachment, boolean saveAsNew)
- throws IOException, MessagingException {
- long attachmentId = -1;
- Uri contentUri = null;
- int size = -1;
- File tempAttachmentFile = null;
-
- if ((!saveAsNew) && (attachment instanceof LocalAttachmentBodyPart)) {
- attachmentId = ((LocalAttachmentBodyPart) attachment).getAttachmentId();
- }
-
- if (attachment.getBody() != null) {
- Body body = attachment.getBody();
- if (body instanceof LocalAttachmentBody) {
- contentUri = ((LocalAttachmentBody) body).getContentUri();
- }
- else {
- /*
- * If the attachment has a body we're expected to save it into the local store
- * so we copy the data into a cached attachment file.
- */
- InputStream in = attachment.getBody().getInputStream();
- tempAttachmentFile = File.createTempFile("att", null, mAttachmentsDir);
- FileOutputStream out = new FileOutputStream(tempAttachmentFile);
- size = IOUtils.copy(in, out);
- in.close();
- out.close();
- }
- }
-
- if (size == -1) {
- /*
- * If the attachment is not yet downloaded see if we can pull a size
- * off the Content-Disposition.
- */
- String disposition = attachment.getDisposition();
- if (disposition != null) {
- String s = MimeUtility.getHeaderParameter(disposition, "size");
- if (s != null) {
- size = Integer.parseInt(s);
- }
- }
- }
- if (size == -1) {
- size = 0;
- }
-
- String storeData =
- Utility.combine(attachment.getHeader(
- MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA), ',');
-
- String name = MimeUtility.getHeaderParameter(attachment.getContentType(), "name");
- String contentId = attachment.getContentId();
-
- if (attachmentId == -1) {
- ContentValues cv = new ContentValues();
- cv.put("message_id", messageId);
- cv.put("content_uri", contentUri != null ? contentUri.toString() : null);
- cv.put("store_data", storeData);
- cv.put("size", size);
- cv.put("name", name);
- cv.put("mime_type", attachment.getMimeType());
- cv.put("content_id", contentId);
-
- attachmentId = mDb.insert("attachments", "message_id", cv);
- }
- else {
- ContentValues cv = new ContentValues();
- cv.put("content_uri", contentUri != null ? contentUri.toString() : null);
- cv.put("size", size);
- cv.put("content_id", contentId);
- cv.put("message_id", messageId);
- mDb.update(
- "attachments",
- cv,
- "id = ?",
- new String[] { Long.toString(attachmentId) });
- }
-
- if (tempAttachmentFile != null) {
- File attachmentFile = new File(mAttachmentsDir, Long.toString(attachmentId));
- tempAttachmentFile.renameTo(attachmentFile);
- // Doing this requires knowing the account id
-// contentUri = AttachmentProvider.getAttachmentUri(
-// new File(mPath).getName(),
-// attachmentId);
- attachment.setBody(new LocalAttachmentBody(contentUri, mContext));
- ContentValues cv = new ContentValues();
- cv.put("content_uri", contentUri != null ? contentUri.toString() : null);
- mDb.update(
- "attachments",
- cv,
- "id = ?",
- new String[] { Long.toString(attachmentId) });
- }
-
- if (attachment instanceof LocalAttachmentBodyPart) {
- ((LocalAttachmentBodyPart) attachment).setAttachmentId(attachmentId);
- }
- }
-
- /**
- * Changes the stored uid of the given message (using it's internal id as a key) to
- * the uid in the message.
- * @param message
- */
- public void changeUid(LocalMessage message) throws MessagingException {
- open(OpenMode.READ_WRITE);
- ContentValues cv = new ContentValues();
- cv.put("uid", message.getUid());
- mDb.update("messages", cv, "id = ?", new String[] { Long.toString(message.mId) });
- }
-
- @Override
- public void setFlags(Message[] messages, Flag[] flags, boolean value)
- throws MessagingException {
- open(OpenMode.READ_WRITE);
- for (Message message : messages) {
- message.setFlags(flags, value);
- }
- }
-
- @Override
- public Message[] expunge() throws MessagingException {
- open(OpenMode.READ_WRITE);
- ArrayList expungedMessages = new ArrayList();
- /*
- * epunge() doesn't do anything because deleted messages are saved for their uids
- * and really, really deleted messages are "Destroyed" and removed immediately.
- */
- return expungedMessages.toArray(new Message[] {});
- }
-
- @Override
- public void delete(boolean recurse) throws MessagingException {
- // We need to open the folder first to make sure we've got it's id
- open(OpenMode.READ_ONLY);
- Message[] messages = getMessages(null);
- for (Message message : messages) {
- deleteAttachments(message.getUid());
- }
- mDb.execSQL("DELETE FROM folders WHERE id = ?", new Object[] {
- Long.toString(mFolderId),
- });
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof LocalFolder) {
- return ((LocalFolder)o).mName.equals(mName);
- }
- return super.equals(o);
- }
-
- @Override
- public Flag[] getPermanentFlags() throws MessagingException {
- return PERMANENT_FLAGS;
- }
-
- private void deleteAttachments(String uid) throws MessagingException {
- open(OpenMode.READ_WRITE);
- Cursor messagesCursor = null;
- try {
- messagesCursor = mDb.query(
- "messages",
- new String[] { "id" },
- "folder_id = ? AND uid = ?",
- new String[] { Long.toString(mFolderId), uid },
- null,
- null,
- null);
- while (messagesCursor.moveToNext()) {
- long messageId = messagesCursor.getLong(0);
- Cursor attachmentsCursor = null;
- try {
- attachmentsCursor = mDb.query(
- "attachments",
- new String[] { "id" },
- "message_id = ?",
- new String[] { Long.toString(messageId) },
- null,
- null,
- null);
- while (attachmentsCursor.moveToNext()) {
- long attachmentId = attachmentsCursor.getLong(0);
- try{
- File file = new File(mAttachmentsDir, Long.toString(attachmentId));
- if (file.exists()) {
- file.delete();
- }
- }
- catch (Exception e) {
-
- }
- }
- }
- finally {
- if (attachmentsCursor != null) {
- attachmentsCursor.close();
- }
- }
- }
- }
- finally {
- if (messagesCursor != null) {
- messagesCursor.close();
- }
- }
- }
-
- /**
- * Support for local persistence for our remote stores.
- * Will open the folder if necessary.
- */
- public Folder.PersistentDataCallbacks getPersistentCallbacks() throws MessagingException {
- open(OpenMode.READ_WRITE);
- return this;
- }
-
- public String getPersistentString(String key, String defaultValue) {
- return LocalStore.this.getPersistentString(mFolderId, key, defaultValue);
- }
-
- public void setPersistentString(String key, String value) {
- LocalStore.this.setPersistentString(mFolderId, key, value);
- }
-
- /**
- * Transactionally combine a key/value and a complete message flags flip. Used
- * for setting sync bits in messages.
- *
- * Note: Not all flags are supported here and can only be changed with Message.setFlag().
- * For example, Flag.DELETED has side effects (removes attachments).
- *
- * @param key
- * @param value
- * @param setFlags
- * @param clearFlags
- */
- public void setPersistentStringAndMessageFlags(String key, String value,
- Flag[] setFlags, Flag[] clearFlags) throws MessagingException {
- mDb.beginTransaction();
- try {
- // take care of folder persistence
- if (key != null) {
- setPersistentString(key, value);
- }
-
- // take care of flags
- ContentValues cv = new ContentValues();
- if (setFlags != null) {
- for (Flag flag : setFlags) {
- if (flag == Flag.X_STORE_1) {
- cv.put("store_flag_1", 1);
- } else if (flag == Flag.X_STORE_2) {
- cv.put("store_flag_2", 1);
- } else if (flag == Flag.X_DOWNLOADED_FULL) {
- cv.put("flag_downloaded_full", 1);
- } else if (flag == Flag.X_DOWNLOADED_PARTIAL) {
- cv.put("flag_downloaded_partial", 1);
- } else {
- throw new MessagingException("Unsupported flag " + flag);
- }
- }
- }
- if (clearFlags != null) {
- for (Flag flag : clearFlags) {
- if (flag == Flag.X_STORE_1) {
- cv.put("store_flag_1", 0);
- } else if (flag == Flag.X_STORE_2) {
- cv.put("store_flag_2", 0);
- } else if (flag == Flag.X_DOWNLOADED_FULL) {
- cv.put("flag_downloaded_full", 0);
- } else if (flag == Flag.X_DOWNLOADED_PARTIAL) {
- cv.put("flag_downloaded_partial", 0);
- } else {
- throw new MessagingException("Unsupported flag " + flag);
- }
- }
- }
- mDb.update("messages", cv,
- "folder_id = ?", new String[] { Long.toString(mFolderId) });
-
- mDb.setTransactionSuccessful();
- } finally {
- mDb.endTransaction();
- }
-
- }
-
- @Override
- public Message createMessage(String uid) throws MessagingException {
- return new LocalMessage(uid, this);
- }
- }
-
- public class LocalMessage extends MimeMessage {
- private long mId;
- private int mAttachmentCount;
-
- LocalMessage(String uid, Folder folder) throws MessagingException {
- this.mUid = uid;
- this.mFolder = folder;
- }
-
- public int getAttachmentCount() {
- return mAttachmentCount;
- }
-
- @Override
- public void parse(InputStream in) throws IOException, MessagingException {
- super.parse(in);
- }
-
- public void setFlagInternal(Flag flag, boolean set) throws MessagingException {
- super.setFlag(flag, set);
- }
-
- public long getId() {
- return mId;
- }
-
- @Override
- public void setFlag(Flag flag, boolean set) throws MessagingException {
- if (flag == Flag.DELETED && set) {
- /*
- * If a message is being marked as deleted we want to clear out it's content
- * and attachments as well. Delete will not actually remove the row since we need
- * to retain the uid for synchronization purposes.
- */
-
- /*
- * Delete all of the messages' content to save space.
- */
- mDb.execSQL(
- "UPDATE messages SET " +
- "subject = NULL, " +
- "sender_list = NULL, " +
- "date = NULL, " +
- "to_list = NULL, " +
- "cc_list = NULL, " +
- "bcc_list = NULL, " +
- "html_content = NULL, " +
- "text_content = NULL, " +
- "reply_to_list = NULL " +
- "WHERE id = ?",
- new Object[] {
- mId
- });
-
- ((LocalFolder) mFolder).deleteAttachments(getUid());
-
- /*
- * Delete all of the messages' attachments to save space.
- */
- mDb.execSQL("DELETE FROM attachments WHERE id = ?",
- new Object[] {
- mId
- });
- }
- else if (flag == Flag.X_DESTROYED && set) {
- ((LocalFolder) mFolder).deleteAttachments(getUid());
- mDb.execSQL("DELETE FROM messages WHERE id = ?",
- new Object[] { mId });
- }
-
- /*
- * Update the unread count on the folder.
- */
- try {
- if (flag == Flag.DELETED || flag == Flag.X_DESTROYED || flag == Flag.SEEN) {
- LocalFolder folder = (LocalFolder)mFolder;
- if (set && !isSet(Flag.SEEN)) {
- folder.setUnreadMessageCount(folder.getUnreadMessageCount() - 1);
- }
- else if (!set && isSet(Flag.SEEN)) {
- folder.setUnreadMessageCount(folder.getUnreadMessageCount() + 1);
- }
- }
- }
- catch (MessagingException me) {
- Log.e(Email.LOG_TAG, "Unable to update LocalStore unread message count",
- me);
- throw new RuntimeException(me);
- }
-
- super.setFlag(flag, set);
- /*
- * Set the flags on the message.
- */
- mDb.execSQL("UPDATE messages "
- + "SET flags = ?, store_flag_1 = ?, store_flag_2 = ?, "
- + "flag_downloaded_full = ?, flag_downloaded_partial = ?, flag_deleted = ? "
- + "WHERE id = ?",
- new Object[] {
- makeFlagsString(this),
- makeFlagNumeric(this, Flag.X_STORE_1),
- makeFlagNumeric(this, Flag.X_STORE_2),
- makeFlagNumeric(this, Flag.X_DOWNLOADED_FULL),
- makeFlagNumeric(this, Flag.X_DOWNLOADED_PARTIAL),
- makeFlagNumeric(this, Flag.DELETED),
- mId
- });
- }
- }
-
- /**
- * Convert *old* flags to flags string. Some flags are kept in their own columns
- * (for selecting) and are not included here.
- * @param message The message containing the flag(s)
- * @return a comma-separated list of flags, to write into the "flags" column
- */
- /* package */ String makeFlagsString(Message message) {
- StringBuilder sb = null;
- boolean nonEmpty = false;
- for (Flag flag : Flag.values()) {
- if (flag != Flag.X_STORE_1 && flag != Flag.X_STORE_2 &&
- flag != Flag.X_DOWNLOADED_FULL && flag != Flag.X_DOWNLOADED_PARTIAL &&
- flag != Flag.DELETED &&
- message.isSet(flag)) {
- if (sb == null) {
- sb = new StringBuilder();
- }
- if (nonEmpty) {
- sb.append(',');
- }
- sb.append(flag.toString());
- nonEmpty = true;
- }
- }
- return (sb == null) ? null : sb.toString();
- }
-
- /**
- * Convert flags to numeric form (0 or 1) for database storage.
- * @param message The message containing the flag of interest
- * @param flag The flag of interest
- *
- */
- /* package */ int makeFlagNumeric(Message message, Flag flag) {
- return message.isSet(flag) ? 1 : 0;
- }
-
-
- public class LocalAttachmentBodyPart extends MimeBodyPart {
- private long mAttachmentId = -1;
-
- public LocalAttachmentBodyPart(Body body, long attachmentId) throws MessagingException {
- super(body);
- mAttachmentId = attachmentId;
- }
-
- /**
- * Returns the local attachment id of this body, or -1 if it is not stored.
- * @return
- */
- public long getAttachmentId() {
- return mAttachmentId;
- }
-
- public void setAttachmentId(long attachmentId) {
- mAttachmentId = attachmentId;
- }
-
- @Override
- public String toString() {
- return "" + mAttachmentId;
- }
- }
-
- public static class LocalAttachmentBody implements Body {
- private Context mContext;
- private Uri mUri;
-
- public LocalAttachmentBody(Uri uri, Context context) {
- mContext = context;
- mUri = uri;
- }
-
- public InputStream getInputStream() throws MessagingException {
- try {
- return mContext.getContentResolver().openInputStream(mUri);
- }
- catch (FileNotFoundException fnfe) {
- /*
- * Since it's completely normal for us to try to serve up attachments that
- * have been blown away, we just return an empty stream.
- */
- return new ByteArrayInputStream(new byte[0]);
- }
- catch (IOException ioe) {
- throw new MessagingException("Invalid attachment.", ioe);
- }
- }
-
- public void writeTo(OutputStream out) throws IOException, MessagingException {
- InputStream in = getInputStream();
- Base64OutputStream base64Out = new Base64OutputStream(
- out, Base64.CRLF | Base64.NO_CLOSE);
- IOUtils.copy(in, base64Out);
- base64Out.close();
- }
-
- public Uri getContentUri() {
- return mUri;
- }
- }
-
- /**
- * LocalStore does not have SettingActivity.
- */
- @Override
- public Class extends android.app.Activity> getSettingActivityClass() {
- return null;
- }
-}
diff --git a/tests/src/com/android/email/LegacyConversionsTests.java b/tests/src/com/android/email/LegacyConversionsTests.java
index 3ec8a41ab..d946d6a27 100644
--- a/tests/src/com/android/email/LegacyConversionsTests.java
+++ b/tests/src/com/android/email/LegacyConversionsTests.java
@@ -17,11 +17,8 @@
package com.android.email;
import com.android.email.mail.Address;
-import com.android.email.mail.Body;
import com.android.email.mail.BodyPart;
import com.android.email.mail.Flag;
-import com.android.email.mail.Folder;
-import com.android.email.mail.Folder.OpenMode;
import com.android.email.mail.Message;
import com.android.email.mail.Message.RecipientType;
import com.android.email.mail.MessageTestUtils;
@@ -34,11 +31,8 @@ import com.android.email.mail.internet.MimeHeader;
import com.android.email.mail.internet.MimeMessage;
import com.android.email.mail.internet.MimeUtility;
import com.android.email.mail.internet.TextBody;
-import com.android.email.mail.store.LocalStore;
-import com.android.email.mail.store.LocalStoreUnitTests;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Attachment;
-import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
@@ -213,13 +207,13 @@ public class LegacyConversionsTests extends ProviderTestCase2 {
// test 1: legacy message using content-type:name style for name
final EmailContent.Message localMessage = ProviderTestUtils.setupMessage(
"local-message", accountId, mailboxId, false, true, mProviderContext);
- final Message legacyMessage = prepareLegacyMessageWithAttachments(2, false, false);
+ final Message legacyMessage = prepareLegacyMessageWithAttachments(2, false);
convertAndCheckcheckAddedAttachments(localMessage, legacyMessage);
// test 2: legacy message using content-disposition:filename style for name
final EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage(
"local-message", accountId, mailboxId, false, true, mProviderContext);
- final Message legacyMessage2 = prepareLegacyMessageWithAttachments(2, false, true);
+ final Message legacyMessage2 = prepareLegacyMessageWithAttachments(2, true);
convertAndCheckcheckAddedAttachments(localMessage2, legacyMessage2);
}
@@ -232,7 +226,7 @@ public class LegacyConversionsTests extends ProviderTestCase2 {
ArrayList viewables = new ArrayList();
ArrayList attachments = new ArrayList();
MimeUtility.collectParts(legacyMessage, viewables, attachments);
- LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false);
+ LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
// Read back all attachments for message and check field values
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
@@ -320,86 +314,38 @@ public class LegacyConversionsTests extends ProviderTestCase2 {
"local-message", accountId, mailboxId, false, true, mProviderContext);
// Prepare a legacy message with attachments
- Message legacyMessage = prepareLegacyMessageWithAttachments(2, false, false);
+ Message legacyMessage = prepareLegacyMessageWithAttachments(2, false);
// Now, convert from legacy to provider and see what happens
ArrayList viewables = new ArrayList();
ArrayList attachments = new ArrayList();
MimeUtility.collectParts(legacyMessage, viewables, attachments);
- LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false);
+ LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
// Confirm two attachment objects created
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
assertEquals(2, EmailContent.count(mProviderContext, uri, null, null));
// Now add the attachments again and confirm there are still only two
- LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false);
+ LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
assertEquals(2, EmailContent.count(mProviderContext, uri, null, null));
// Now add a 3rd & 4th attachment and make sure the total is 4, not 2 or 6
- legacyMessage = prepareLegacyMessageWithAttachments(4, false, false);
+ legacyMessage = prepareLegacyMessageWithAttachments(4, false);
viewables = new ArrayList();
attachments = new ArrayList();
MimeUtility.collectParts(legacyMessage, viewables, attachments);
- LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false);
+ LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
assertEquals(4, EmailContent.count(mProviderContext, uri, null, null));
}
- /**
- * Sunny day test of adding attachments in "local account upgrade" mode
- */
- public void testLocalUpgradeAttachments() throws MessagingException, IOException {
- // Prepare a local message to add the attachments to
- final long accountId = 1;
- final long mailboxId = 1;
- final EmailContent.Message localMessage = ProviderTestUtils.setupMessage(
- "local-upgrade", accountId, mailboxId, false, true, mProviderContext);
-
- // Prepare a legacy message with attachments
- final Message legacyMessage = prepareLegacyMessageWithAttachments(2, true, false);
-
- // Now, convert from legacy to provider and see what happens
- ArrayList viewables = new ArrayList();
- ArrayList attachments = new ArrayList();
- MimeUtility.collectParts(legacyMessage, viewables, attachments);
- LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, true);
-
- // Read back all attachments for message and check field values
- Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
- Cursor c = mProviderContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
- null, null, null);
- try {
- assertEquals(2, c.getCount());
- while (c.moveToNext()) {
- Attachment attachment = Attachment.getContent(c, Attachment.class);
- // This attachment should look as if created by modern (provider) MessageCompose.
- // 1. find the original that it was created from
- Part fromPart = null;
- for (Part from : attachments) {
- String contentType = MimeUtility.unfoldAndDecode(from.getContentType());
- String name = MimeUtility.getHeaderParameter(contentType, "name");
- if (name.equals(attachment.mFileName)) {
- fromPart = from;
- break;
- }
- }
- assertTrue(fromPart != null);
- // 2. Check values
- checkAttachment(attachment.mFileName, fromPart, attachment, accountId);
- }
- } finally {
- c.close();
- }
- }
-
/**
* Prepare a legacy message with 1+ attachments
* @param numAttachments how many attachments to add
- * @param localData if true, attachments are "local" data. false = "remote" (from server)
* @param filenameInDisposition False: attachment names are sent as content-type:name. True:
* attachment names are sent as content-disposition:filename.
*/
- private Message prepareLegacyMessageWithAttachments(int numAttachments, boolean localData,
+ private Message prepareLegacyMessageWithAttachments(int numAttachments,
boolean filenameInDisposition) throws MessagingException {
BodyPart[] attachmentParts = new BodyPart[numAttachments];
for (int i = 0; i < numAttachments; ++i) {
@@ -412,30 +358,18 @@ public class LegacyConversionsTests extends ProviderTestCase2 {
} else {
name = ";\n name=" + quotedName;
}
- if (localData) {
- // generate an attachment that was generated by legacy code (e.g. donut)
- // for test of upgrading accounts in place
- // This creator models the code in legacy MessageCompose
- Uri uri = Uri.parse("content://test/attachment/" + i);
- MimeBodyPart bp = new MimeBodyPart(
- new LocalStore.LocalAttachmentBody(uri, mProviderContext));
- bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name);
- bp.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
- bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "attachment" + filename);
- attachmentParts[i] = bp;
- } else {
- // generate an attachment that came from a server
- BodyPart attachmentPart = MessageTestUtils.bodyPart("image/jpg", null);
- // name=attachmentN size=N00 location=10N
- attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name);
- attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
- attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
- "attachment" + filename + ";\n size=" + (i+1) + "00");
- attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "10" + i);
+ // generate an attachment that came from a server
+ BodyPart attachmentPart = MessageTestUtils.bodyPart("image/jpg", null);
- attachmentParts[i] = attachmentPart;
- }
+ // name=attachmentN size=N00 location=10N
+ attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name);
+ attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
+ attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
+ "attachment" + filename + ";\n size=" + (i+1) + "00");
+ attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "10" + i);
+
+ attachmentParts[i] = attachmentPart;
}
return prepareLegacyMessageWithAttachments(attachmentParts);
@@ -504,17 +438,8 @@ public class LegacyConversionsTests extends ProviderTestCase2 {
String expectedName = (contentTypeName != null) ? contentTypeName : dispositionFilename;
assertEquals(tag, expectedName, actual.mFileName);
- // content URI either both null or both matching
- String expectedUriString = null;
- Body body = expected.getBody();
- if (body instanceof LocalStore.LocalAttachmentBody) {
- LocalStore.LocalAttachmentBody localBody = (LocalStore.LocalAttachmentBody) body;
- Uri contentUri = localBody.getContentUri();
- if (contentUri != null) {
- expectedUriString = contentUri.toString();
- }
- }
- assertEquals(tag, expectedUriString, actual.mContentUri);
+ // content URI should be null
+ assertNull(tag, actual.mContentUri);
assertTrue(tag, 0 != actual.mMessageKey);
@@ -805,48 +730,4 @@ public class LegacyConversionsTests extends ProviderTestCase2 {
assertEquals(tag + " security", expect.mSecurityFlags, actual.mSecurityFlags);
assertEquals(tag + " signature", expect.mSignature, actual.mSignature);
}
-
- /**
- * Test conversion of a legacy mailbox to a provider mailbox
- */
- public void testMakeProviderMailbox() throws MessagingException {
- EmailContent.Account toAccount = ProviderTestUtils.setupAccount("convert-mailbox",
- true, mProviderContext);
- Folder fromFolder = buildTestFolder("INBOX");
- Mailbox toMailbox = LegacyConversions.makeMailbox(mProviderContext, toAccount, fromFolder);
-
- // Now test fields in created mailbox
- assertEquals("INBOX", toMailbox.mDisplayName);
- assertNull(toMailbox.mServerId);
- assertNull(toMailbox.mParentServerId);
- assertEquals(toAccount.mId, toMailbox.mAccountKey);
- assertEquals(Mailbox.TYPE_INBOX, toMailbox.mType);
- assertEquals(0, toMailbox.mDelimiter);
- assertNull(toMailbox.mSyncKey);
- assertEquals(0, toMailbox.mSyncLookback);
- assertEquals(0, toMailbox.mSyncInterval);
- assertEquals(0, toMailbox.mSyncTime);
- assertTrue(toMailbox.mFlagVisible);
- assertEquals(0, toMailbox.mFlags);
- assertEquals(Email.VISIBLE_LIMIT_DEFAULT, toMailbox.mVisibleLimit);
- assertNull(toMailbox.mSyncStatus);
- }
-
- /**
- * Build a lightweight Store Folder with simple field population. The folder is "open"
- * and should be closed by the caller.
- */
- private Folder buildTestFolder(String folderName) throws MessagingException {
- String localStoreUri =
- "local://localhost/" + mProviderContext.getDatabasePath(LocalStoreUnitTests.DB_NAME);
- LocalStore store = (LocalStore) LocalStore.newInstance(localStoreUri, getContext(), null);
- LocalStore.LocalFolder folder = (LocalStore.LocalFolder) store.getFolder(folderName);
- folder.open(OpenMode.READ_WRITE, null); // this will create it
-
- // set a few fields to test values
- // folder.getName - set by getFolder()
- folder.setUnreadMessageCount(100);
-
- return folder;
- }
}
diff --git a/tests/src/com/android/email/mail/MessageTestUtils.java b/tests/src/com/android/email/mail/MessageTestUtils.java
index 6594c46b1..487fbfa33 100644
--- a/tests/src/com/android/email/mail/MessageTestUtils.java
+++ b/tests/src/com/android/email/mail/MessageTestUtils.java
@@ -16,19 +16,16 @@
package com.android.email.mail;
-import com.android.email.mail.internet.BinaryTempFileBody;
import com.android.email.mail.internet.MimeBodyPart;
import com.android.email.mail.internet.MimeHeader;
import com.android.email.mail.internet.MimeMessage;
import com.android.email.mail.internet.MimeMultipart;
import com.android.email.mail.internet.TextBody;
-import com.android.email.mail.store.LocalStore;
import com.android.email.provider.AttachmentProvider;
import com.android.email.provider.EmailContent;
import android.net.Uri;
-import java.io.IOException;
import java.util.ArrayList;
/**
@@ -100,29 +97,6 @@ public class MessageTestUtils {
return textPart;
}
- /**
- * Create attachment BodyPart with content-id.
- *
- * @param mimeType MIME type of image body
- * @param contentId content-id header value (optional - null for no header)
- * @param attachmentId attachment id of store
- * @param store LocalStore which stores attachment
- * @return LocalAttachmentBodyPart with content-id
- * @throws MessagingException
- * @throws IOException
- */
- public static BodyPart imagePart(String mimeType, String contentId,
- long attachmentId, LocalStore store) throws MessagingException, IOException {
- final BinaryTempFileBody imageBody = new BinaryTempFileBody();
- final LocalStore.LocalAttachmentBodyPart imagePart =
- store.new LocalAttachmentBodyPart(imageBody, attachmentId);
- imagePart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
- if (contentId != null) {
- imagePart.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId);
- }
- return imagePart;
- }
-
/**
* Builder class for Multipart.
*
diff --git a/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java b/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java
index b25d6bb62..581a5b2a7 100755
--- a/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java
+++ b/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java
@@ -16,24 +16,8 @@
package com.android.email.mail.internet;
-import com.android.email.Email;
-import com.android.email.mail.Message;
-import com.android.email.mail.MessageTestUtils;
-import com.android.email.mail.MessagingException;
-import com.android.email.mail.MessageTestUtils.MessageBuilder;
-import com.android.email.mail.MessageTestUtils.MultipartBuilder;
-import com.android.email.mail.MessageTestUtils.TextBuilder;
-import com.android.email.mail.store.LocalStore;
-import com.android.email.provider.EmailContent;
-import com.android.email.provider.EmailContent.Account;
-
-import android.content.ContentUris;
-import android.content.Context;
-import android.net.Uri;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import java.io.IOException;
+import android.test.suitebuilder.annotation.SmallTest;
/**
* Tests of the Email HTML utils.
@@ -41,139 +25,13 @@ import java.io.IOException;
* You can run this entire test case with:
* runtest -c com.android.email.mail.internet.EmailHtmlUtilTest email
*/
-@MediumTest
+@SmallTest
public class EmailHtmlUtilTest extends AndroidTestCase {
- private EmailContent.Account mAccount;
- private long mCreatedAccountId = -1;
private static final String textTags = "Plain &";
private static final String textSpaces = "3 spaces end.";
private static final String textNewlines = "ab \r\n \n \n\r\n";
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- // Force assignment of a default account, and retrieve it
- Context context = getContext();
- Email.setTempDirectory(context);
-
- // Force assignment of a default account
- long accountId = Account.getDefaultAccountId(context);
- if (accountId == -1) {
- Account account = new Account();
- account.mSenderName = "Bob Sender";
- account.mEmailAddress = "bob@sender.com";
- account.save(context);
- accountId = account.mId;
- mCreatedAccountId = accountId;
- }
- Account.restoreAccountWithId(context, accountId);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- Context context = getContext();
- // If we created an account, delete it here
- if (mCreatedAccountId > -1) {
- context.getContentResolver().delete(
- ContentUris.withAppendedId(Account.CONTENT_URI, mCreatedAccountId), null, null);
- }
- }
-
- /**
- * Tests for resolving inline image src cid: reference to content uri.
- *
- * TODO: These need to be completely rewritten to not use LocalStore messages.
- */
- public void disable_testResolveInlineImage() throws MessagingException, IOException {
- final LocalStore store = (LocalStore) LocalStore.newInstance(
- mAccount.getLocalStoreUri(getContext()), mContext, null);
- // Single cid case.
- final String cid1 = "cid.1@android.com";
- final long aid1 = 10;
- final Uri uri1 = MessageTestUtils.contentUri(aid1, mAccount);
- final String text1 = new TextBuilder("text1 > ").addCidImg(cid1).build(" <.");
- final String expected1 = new TextBuilder("text1 > ").addUidImg(uri1).build(" <.");
-
- // message with cid1
- final Message msg1 = new MessageBuilder()
- .setBody(new MultipartBuilder("multipart/related")
- .addBodyPart(MessageTestUtils.textPart("text/html", text1))
- .addBodyPart(MessageTestUtils.imagePart("image/jpeg", "<"+cid1+">", aid1, store))
- .build())
- .build();
- // Simple case.
- final String actual1 = EmailHtmlUtil.resolveInlineImage(
- getContext().getContentResolver(), mAccount.mId, text1, msg1, 0);
- assertEquals("one content id reference is not resolved",
- expected1, actual1);
-
- // Exceed recursive limit.
- final String actual0 = EmailHtmlUtil.resolveInlineImage(
- getContext().getContentResolver(), mAccount.mId, text1, msg1, 10);
- assertEquals("recursive call limit may exceeded",
- text1, actual0);
-
- // Multiple cids case.
- final String cid2 = "cid.2@android.com";
- final long aid2 = 20;
- final Uri uri2 = MessageTestUtils.contentUri(aid2, mAccount);
- final String text2 = new TextBuilder("text2 ").addCidImg(cid2).build(".");
- final String expected2 = new TextBuilder("text2 ").addUidImg(uri2).build(".");
-
- // message with only cid2
- final Message msg2 = new MessageBuilder()
- .setBody(new MultipartBuilder("multipart/related")
- .addBodyPart(MessageTestUtils.textPart("text/html", text1 + text2))
- .addBodyPart(MessageTestUtils.imagePart("image/gif", cid2, aid2, store))
- .build())
- .build();
- // cid1 is not replaced
- final String actual2 = EmailHtmlUtil.resolveInlineImage(
- getContext().getContentResolver(), mAccount.mId, text1 + text2, msg2, 0);
- assertEquals("only one of two content id is resolved",
- text1 + expected2, actual2);
-
- // message with cid1 and cid2
- final Message msg3 = new MessageBuilder()
- .setBody(new MultipartBuilder("multipart/related")
- .addBodyPart(MessageTestUtils.textPart("text/html", text2 + text1))
- .addBodyPart(MessageTestUtils.imagePart("image/jpeg", cid1, aid1, store))
- .addBodyPart(MessageTestUtils.imagePart("image/gif", cid2, aid2, store))
- .build())
- .build();
- // cid1 and cid2 are replaced
- final String actual3 = EmailHtmlUtil.resolveInlineImage(
- getContext().getContentResolver(), mAccount.mId, text2 + text1, msg3, 0);
- assertEquals("two content ids are resolved correctly",
- expected2 + expected1, actual3);
-
- // message with many cids and normal attachments
- final Message msg4 = new MessageBuilder()
- .setBody(new MultipartBuilder("multipart/mixed")
- .addBodyPart(MessageTestUtils.imagePart("image/jpeg", null, 30, store))
- .addBodyPart(MessageTestUtils.imagePart("application/pdf", cid1, aid1, store))
- .addBodyPart(new MultipartBuilder("multipart/related")
- .addBodyPart(MessageTestUtils.textPart("text/html", text2 + text1))
- .addBodyPart(MessageTestUtils.imagePart("image/jpg", cid1, aid1, store))
- .addBodyPart(MessageTestUtils.imagePart("image/gif", cid2, aid2, store))
- .buildBodyPart())
- .addBodyPart(MessageTestUtils.imagePart("application/pdf", cid2, aid2, store))
- .build())
- .build();
- // cid1 and cid2 are replaced
- final String actual4 = EmailHtmlUtil.resolveInlineImage(
- getContext().getContentResolver(), mAccount.mId, text2 + text1, msg4, 0);
- assertEquals("two content ids in deep multipart level are resolved",
- expected2 + expected1, actual4);
-
- // No crash on null text
- final String actual5 = EmailHtmlUtil.resolveInlineImage(getContext().getContentResolver(),
- mAccount.mId, null, msg4, 0);
- assertNull(actual5);
- }
-
/**
* Test for escapeCharacterToDisplay in plain text mode.
*/
diff --git a/tests/src/com/android/email/mail/store/LocalStoreUnitTests.java b/tests/src/com/android/email/mail/store/LocalStoreUnitTests.java
deleted file mode 100644
index afd0ea731..000000000
--- a/tests/src/com/android/email/mail/store/LocalStoreUnitTests.java
+++ /dev/null
@@ -1,1398 +0,0 @@
-/*
- * Copyright (C) 2008 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 com.android.email.mail.store;
-
-import com.android.email.Email;
-import com.android.email.mail.Address;
-import com.android.email.mail.Body;
-import com.android.email.mail.FetchProfile;
-import com.android.email.mail.Flag;
-import com.android.email.mail.Folder;
-import com.android.email.mail.Folder.FolderType;
-import com.android.email.mail.Folder.OpenMode;
-import com.android.email.mail.Message;
-import com.android.email.mail.Message.RecipientType;
-import com.android.email.mail.MessageTestUtils;
-import com.android.email.mail.MessageTestUtils.MultipartBuilder;
-import com.android.email.mail.MessagingException;
-import com.android.email.mail.Part;
-import com.android.email.mail.Store;
-import com.android.email.mail.internet.MimeMessage;
-import com.android.email.mail.internet.MimeUtility;
-import com.android.email.mail.internet.TextBody;
-import com.android.email.mail.store.LocalStore.LocalMessage;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.test.AndroidTestCase;
-import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import java.io.File;
-import java.net.URI;
-import java.util.HashSet;
-
-/**
- * This is a series of unit tests for the LocalStore class.
- */
-@MediumTest
-public class LocalStoreUnitTests extends AndroidTestCase {
-
- public static final String DB_NAME = "com.android.email.mail.store.LocalStoreUnitTests.db";
-
- private static final String SENDER = "sender@android.com";
- private static final String RECIPIENT_TO = "recipient-to@android.com";
- private static final String SUBJECT = "This is the subject";
- private static final String BODY = "This is the body. This is also the body.";
- private static final String MESSAGE_ID = "Test-Message-ID";
- private static final String MESSAGE_ID_2 = "Test-Message-ID-Second";
-
- private static final int DATABASE_VERSION = 24;
-
- private static final String FOLDER_NAME = "TEST";
- private static final String MISSING_FOLDER_NAME = "TEST-NO-FOLDER";
-
- /* These values are provided by setUp() */
- private String mLocalStoreUri = null;
- private LocalStore mStore = null;
- private LocalStore.LocalFolder mFolder = null;
- private SQLiteDatabase mDatabase;
-
- /**
- * Setup code. We generate a lightweight LocalStore and LocalStore.LocalFolder.
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- Email.setTempDirectory(getContext());
-
- // These are needed so we can get at the inner classes
- // Create a dummy database (be sure to delete it in tearDown())
- mLocalStoreUri = "local://localhost/" + getContext().getDatabasePath(DB_NAME);
-
- mStore = LocalStore.newInstance(mLocalStoreUri, getContext(), null);
- mFolder = (LocalStore.LocalFolder) mStore.getFolder(FOLDER_NAME);
- }
-
- /**
- * Teardown code. Delete the local database and any other files
- */
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- closeDatabase();
- if (mFolder != null) {
- mFolder.close(false);
- mFolder = null;
- }
-
- // First, try the official way
- if (mStore != null) {
- mStore.delete();
- mStore = null;
- }
-
- // Next, just try hacking and slashing files
- // (Mostly, this is actually copied from LocalStore.delete
- URI uri = new URI(mLocalStoreUri);
- String path = uri.getPath();
- File attachmentsDir = new File(path + "_att");
-
- // Delete any attachments we dribbled out
- try {
- File[] attachments = attachmentsDir.listFiles();
- for (File attachment : attachments) {
- if (attachment.exists()) {
- attachment.delete();
- }
- }
- } catch (RuntimeException e) { }
- // Delete attachments dir
- try {
- if (attachmentsDir.exists()) {
- attachmentsDir.delete();
- }
- } catch (RuntimeException e) { }
- // Delete db file
- try {
- new File(path).delete();
- }
- catch (RuntimeException e) { }
- }
-
- private void openDatabase() throws Exception {
- closeDatabase(); // Calling this method twice is okay.
- mDatabase = SQLiteDatabase.openOrCreateDatabase(new URI(mLocalStoreUri).getPath(), null);
- }
-
- private boolean closeDatabase() {
- if (mDatabase != null) {
- mDatabase.close();
- mDatabase = null;
- return true;
- }
- return false;
- }
-
- /**
- * Upgrades the database.
- */
- private void upgradeDatabase() throws Exception {
- // Need to close the db if it's already open.
- boolean opened = closeDatabase();
- LocalStore.newInstance(mLocalStoreUri, getContext(), null).close();
- if (opened) openDatabase();
- }
-
- /**
- * Test that messages are being stored with Message-ID intact.
- *
- * This variant tests appendMessages() and getMessage() and getMessages()
- */
- public void testMessageId_1() throws MessagingException {
- final MimeMessage message = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message.setMessageId(MESSAGE_ID);
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(new Message[]{ message });
- String localUid = message.getUid();
-
- // Now try to read it back from the database using getMessage()
-
- MimeMessage retrieved = (MimeMessage) mFolder.getMessage(localUid);
- assertEquals(MESSAGE_ID, retrieved.getMessageId());
-
- // Now try to read it back from the database using getMessages()
-
- Message[] retrievedArray = mFolder.getMessages(null);
- assertEquals(1, retrievedArray.length);
- MimeMessage retrievedEntry = (MimeMessage) retrievedArray[0];
- assertEquals(MESSAGE_ID, retrievedEntry.getMessageId());
- }
-
- /**
- * Test that messages are being stored with Message-ID intact.
- *
- * This variant tests updateMessage() and getMessages()
- */
- public void testMessageId_2() throws MessagingException {
- final MimeMessage message = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message.setMessageId(MESSAGE_ID);
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(new Message[]{ message });
- String localUid = message.getUid();
-
- // Now try to read it back from the database using getMessage()
- MimeMessage retrieved = (MimeMessage) mFolder.getMessage(localUid);
- assertEquals(MESSAGE_ID, retrieved.getMessageId());
-
- // Now change the Message-ID and try to update() the message
- // Note, due to a weakness in the API, you have to use a message object you got from
- // LocalStore when making the update call
- retrieved.setMessageId(MESSAGE_ID_2);
- mFolder.updateMessage((LocalStore.LocalMessage)retrieved);
-
- // And read back once more to confirm the change (using getMessages() to confirm "just one")
- Message[] retrievedArray = mFolder.getMessages(null);
- assertEquals(1, retrievedArray.length);
- MimeMessage retrievedEntry = (MimeMessage) retrievedArray[0];
- assertEquals(MESSAGE_ID_2, retrievedEntry.getMessageId());
- }
-
- /**
- * Build a test message that can be used as input to processSourceMessage
- *
- * @param to Recipient(s) of the message
- * @param sender Sender(s) of the message
- * @param subject Subject of the message
- * @param content Content of the message
- * @return a complete Message object
- */
- private MimeMessage buildTestMessage(String to, String sender, String subject, String content)
- throws MessagingException {
- MimeMessage message = new MimeMessage();
-
- if (to != null) {
- Address[] addresses = Address.parse(to);
- message.setRecipients(RecipientType.TO, addresses);
- }
-
- if (sender != null) {
- Address[] addresses = Address.parse(sender);
- message.setFrom(Address.parse(sender)[0]);
- }
-
- if (subject != null) {
- message.setSubject(subject);
- }
-
- if (content != null) {
- TextBody body = new TextBody(content);
- message.setBody(body);
- }
-
- return message;
- }
-
- /**
- * Test two modes (STRUCTURE vs. BODY) of fetch()
- */
- public void testFetchModes() throws MessagingException {
- final String BODY_TEXT_PLAIN = "This is the body text.";
- final String BODY_TEXT_HTML = "But this is the HTML version of the body text.";
-
- MimeMessage message = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message.setMessageId(MESSAGE_ID);
- Body body = new MultipartBuilder("multipart/mixed")
- .addBodyPart(MessageTestUtils.bodyPart("image/tiff", "cid.4@android.com"))
- .addBodyPart(new MultipartBuilder("multipart/related")
- .addBodyPart(new MultipartBuilder("multipart/alternative")
- .addBodyPart(MessageTestUtils.textPart("text/plain", BODY_TEXT_PLAIN))
- .addBodyPart(MessageTestUtils.textPart("text/html", BODY_TEXT_HTML))
- .buildBodyPart())
- .buildBodyPart())
- .addBodyPart(MessageTestUtils.bodyPart("image/gif", "cid.3@android.com"))
- .build();
- message.setBody(body);
-
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(new Message[]{ message });
-
- // Now read it back, and fetch it two ways - first, structure only
- Message[] messages = mFolder.getMessages(null);
- FetchProfile fp = new FetchProfile();
- fp.add(FetchProfile.Item.STRUCTURE);
- mFolder.fetch(messages, fp, null);
- // check for empty body parts
- Part textPart = MimeUtility.findFirstPartByMimeType(messages[0], "text/plain");
- Part htmlPart = MimeUtility.findFirstPartByMimeType(messages[0], "text/html");
- assertNull(MimeUtility.getTextFromPart(textPart));
- assertNull(MimeUtility.getTextFromPart(htmlPart));
-
- // Next, complete body
- messages = mFolder.getMessages(null);
- fp.clear();
- fp.add(FetchProfile.Item.BODY);
- mFolder.fetch(messages, fp, null);
- // check for real body parts
- textPart = MimeUtility.findFirstPartByMimeType(messages[0], "text/plain");
- htmlPart = MimeUtility.findFirstPartByMimeType(messages[0], "text/html");
- assertEquals(BODY_TEXT_PLAIN, MimeUtility.getTextFromPart(textPart));
- assertEquals(BODY_TEXT_HTML, MimeUtility.getTextFromPart(htmlPart));
- }
-
- /**
- * Test the new store persistent data code.
- *
- * This test, and the underlying code, reflect the essential error in the Account class. The
- * account objects should have been singletons-per-account. As it stands there are lots of
- * them floating around, which is very expensive (we waste a lot of effort creating them)
- * and forces slow sync hacks for dynamic data like the store's persistent data.
- */
- public void testStorePersistentData() {
-
- final String TEST_KEY = "the.test.key";
- final String TEST_KEY_2 = "a.different.test.key";
- final String TEST_STRING = "This is the store's persistent data.";
- final String TEST_STRING_2 = "Rewrite the store data.";
-
- // confirm default reads on new store
- assertEquals("the-default", mStore.getPersistentString(TEST_KEY, "the-default"));
-
- // test write/readback
- mStore.setPersistentString(TEST_KEY, TEST_STRING);
- mStore.setPersistentString(TEST_KEY_2, TEST_STRING_2);
- assertEquals(TEST_STRING, mStore.getPersistentString(TEST_KEY, null));
- assertEquals(TEST_STRING_2, mStore.getPersistentString(TEST_KEY_2, null));
- }
-
- /**
- * Test the callbacks for setting & getting persistent data
- */
- public void testStorePersistentCallbacks() throws MessagingException {
-
- final String TEST_KEY = "the.test.key";
- final String TEST_KEY_2 = "a.different.test.key";
- final String TEST_STRING = "This is the store's persistent data.";
- final String TEST_STRING_2 = "Rewrite the store data.";
-
- Store.PersistentDataCallbacks callbacks = mStore.getPersistentCallbacks();
-
- // confirm default reads on new store
- assertEquals("the-default", callbacks.getPersistentString(TEST_KEY, "the-default"));
-
- // test write/readback
- callbacks.setPersistentString(TEST_KEY, TEST_STRING);
- callbacks.setPersistentString(TEST_KEY_2, TEST_STRING_2);
- assertEquals(TEST_STRING, mStore.getPersistentString(TEST_KEY, null));
- assertEquals(TEST_STRING_2, mStore.getPersistentString(TEST_KEY_2, null));
- }
-
- /**
- * Test functionality of setting & saving store persistence values
- */
- public void testFolderPersistentStorage() throws MessagingException {
- mFolder.open(OpenMode.READ_WRITE, null);
-
- // set up a 2nd folder to confirm independent storage
- LocalStore.LocalFolder folder2 = (LocalStore.LocalFolder) mStore.getFolder("FOLDER-2");
- assertFalse(folder2.exists());
- folder2.create(FolderType.HOLDS_MESSAGES);
- folder2.open(OpenMode.READ_WRITE, null);
-
- // use the callbacks, as these are the "official" API
- Folder.PersistentDataCallbacks callbacks = mFolder.getPersistentCallbacks();
- Folder.PersistentDataCallbacks callbacks2 = folder2.getPersistentCallbacks();
-
- // set some values - tests independence & inserts
- callbacks.setPersistentString("key1", "value-1-1");
- callbacks.setPersistentString("key2", "value-1-2");
- callbacks2.setPersistentString("key1", "value-2-1");
- callbacks2.setPersistentString("key2", "value-2-2");
-
- // readback initial values
- assertEquals("value-1-1", callbacks.getPersistentString("key1", null));
- assertEquals("value-1-2", callbacks.getPersistentString("key2", null));
- assertEquals("value-2-1", callbacks2.getPersistentString("key1", null));
- assertEquals("value-2-2", callbacks2.getPersistentString("key2", null));
-
- // readback with default values
- assertEquals("value-1-3", callbacks.getPersistentString("key3", "value-1-3"));
- assertEquals("value-2-3", callbacks2.getPersistentString("key3", "value-2-3"));
-
- // partial updates
- callbacks.setPersistentString("key1", "value-1-1b");
- callbacks2.setPersistentString("key2", "value-2-2b");
- assertEquals("value-1-1b", callbacks.getPersistentString("key1", null)); // changed
- assertEquals("value-1-2", callbacks.getPersistentString("key2", null)); // same
- assertEquals("value-2-1", callbacks2.getPersistentString("key1", null)); // same
- assertEquals("value-2-2b", callbacks2.getPersistentString("key2", null)); // changed
- }
-
- /**
- * Test functionality of persistence update with bulk update
- */
- public void testFolderPersistentBulkUpdate() throws MessagingException {
- mFolder.open(OpenMode.READ_WRITE, null);
-
- // set up a 2nd folder to confirm independent storage
- LocalStore.LocalFolder folder2 = (LocalStore.LocalFolder) mStore.getFolder("FOLDER-2");
- assertFalse(folder2.exists());
- folder2.create(FolderType.HOLDS_MESSAGES);
- folder2.open(OpenMode.READ_WRITE, null);
-
- // use the callbacks, as these are the "official" API
- Folder.PersistentDataCallbacks callbacks = mFolder.getPersistentCallbacks();
- Folder.PersistentDataCallbacks callbacks2 = folder2.getPersistentCallbacks();
-
- // set some values - tests independence & inserts
- callbacks.setPersistentString("key1", "value-1-1");
- callbacks.setPersistentString("key2", "value-1-2");
- callbacks2.setPersistentString("key1", "value-2-1");
- callbacks2.setPersistentString("key2", "value-2-2");
-
- final MimeMessage message1 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message1.setFlag(Flag.X_STORE_1, false);
- message1.setFlag(Flag.X_STORE_2, false);
-
- final MimeMessage message2 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message2.setFlag(Flag.X_STORE_1, true);
- message2.setFlag(Flag.X_STORE_2, false);
-
- final MimeMessage message3 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message3.setFlag(Flag.X_STORE_1, false);
- message3.setFlag(Flag.X_STORE_2, true);
-
- final MimeMessage message4 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message4.setFlag(Flag.X_STORE_1, true);
- message4.setFlag(Flag.X_STORE_2, true);
-
- Message[] allOriginals = new Message[]{ message1, message2, message3, message4 };
-
- mFolder.appendMessages(allOriginals);
-
- // Now make a bulk update (set)
- callbacks.setPersistentStringAndMessageFlags("key1", "value-1-1a",
- new Flag[]{ Flag.X_STORE_1 }, null);
- // And check all messages for that flag now set, but other flag was not set
- Message[] messages = mFolder.getMessages(null);
- for (Message msg : messages) {
- assertTrue(msg.isSet(Flag.X_STORE_1));
- if (msg.getUid().equals(message1.getUid())) assertFalse(msg.isSet(Flag.X_STORE_2));
- if (msg.getUid().equals(message2.getUid())) assertFalse(msg.isSet(Flag.X_STORE_2));
- }
- assertEquals("value-1-1a", callbacks.getPersistentString("key1", null));
-
- // Same test, but clearing
- callbacks.setPersistentStringAndMessageFlags("key2", "value-1-2a",
- null, new Flag[]{ Flag.X_STORE_2 });
- // And check all messages for that flag now set, but other flag was not set
- messages = mFolder.getMessages(null);
- for (Message msg : messages) {
- assertTrue(msg.isSet(Flag.X_STORE_1));
- assertFalse(msg.isSet(Flag.X_STORE_2));
- }
- assertEquals("value-1-2a", callbacks.getPersistentString("key2", null));
- }
-
- /**
- * Test that messages are being stored with store flags properly persisted.
- *
- * This variant tests appendMessages() and updateMessages() and getMessage()
- */
- public void testStoreFlags() throws MessagingException {
- final MimeMessage message = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message.setMessageId(MESSAGE_ID);
- message.setFlag(Flag.X_STORE_1, true);
- message.setFlag(Flag.X_STORE_2, false);
-
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(new Message[]{ message });
- String localUid = message.getUid();
-
- // Now try to read it back from the database using getMessage()
-
- MimeMessage retrieved = (MimeMessage) mFolder.getMessage(localUid);
- assertEquals(MESSAGE_ID, retrieved.getMessageId());
- assertTrue(message.isSet(Flag.X_STORE_1));
- assertFalse(message.isSet(Flag.X_STORE_2));
-
- // Now try to update it using updateMessages()
-
- retrieved.setFlag(Flag.X_STORE_1, false);
- retrieved.setFlag(Flag.X_STORE_2, true);
- mFolder.updateMessage((LocalStore.LocalMessage)retrieved);
-
- // And read back once more to confirm the change (using getMessages() to confirm "just one")
- Message[] retrievedArray = mFolder.getMessages(null);
- assertEquals(1, retrievedArray.length);
- MimeMessage retrievedEntry = (MimeMessage) retrievedArray[0];
- assertEquals(MESSAGE_ID, retrieved.getMessageId());
-
- assertFalse(retrievedEntry.isSet(Flag.X_STORE_1));
- assertTrue(retrievedEntry.isSet(Flag.X_STORE_2));
- }
-
- /**
- * Test that messages are being stored with download & delete state flags properly persisted.
- *
- * This variant tests appendMessages() and updateMessages() and getMessage()
- */
- public void testDownloadAndDeletedFlags() throws MessagingException {
- final MimeMessage message = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message.setMessageId(MESSAGE_ID);
- message.setFlag(Flag.X_STORE_1, true);
- message.setFlag(Flag.X_STORE_2, false);
- message.setFlag(Flag.X_DOWNLOADED_FULL, true);
- message.setFlag(Flag.X_DOWNLOADED_PARTIAL, false);
- message.setFlag(Flag.DELETED, false);
-
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(new Message[]{ message });
- String localUid = message.getUid();
-
- // Now try to read it back from the database using getMessage()
-
- MimeMessage retrieved = (MimeMessage) mFolder.getMessage(localUid);
- assertEquals(MESSAGE_ID, retrieved.getMessageId());
- assertTrue(retrieved.isSet(Flag.X_STORE_1));
- assertFalse(retrieved.isSet(Flag.X_STORE_2));
- assertTrue(retrieved.isSet(Flag.X_DOWNLOADED_FULL));
- assertFalse(retrieved.isSet(Flag.X_DOWNLOADED_PARTIAL));
- assertFalse(retrieved.isSet(Flag.DELETED));
-
- // Now try to update it using updateMessages()
-
- retrieved.setFlag(Flag.X_STORE_1, false);
- retrieved.setFlag(Flag.X_STORE_2, true);
- retrieved.setFlag(Flag.X_DOWNLOADED_FULL, false);
- retrieved.setFlag(Flag.X_DOWNLOADED_PARTIAL, true);
- mFolder.updateMessage((LocalStore.LocalMessage)retrieved);
-
- // And read back once more to confirm the change (using getMessages() to confirm "just one")
- Message[] retrievedArray = mFolder.getMessages(null);
- assertEquals(1, retrievedArray.length);
- MimeMessage retrievedEntry = (MimeMessage) retrievedArray[0];
- assertEquals(MESSAGE_ID, retrievedEntry.getMessageId());
-
- assertFalse(retrievedEntry.isSet(Flag.X_STORE_1));
- assertTrue(retrievedEntry.isSet(Flag.X_STORE_2));
- assertFalse(retrievedEntry.isSet(Flag.X_DOWNLOADED_FULL));
- assertTrue(retrievedEntry.isSet(Flag.X_DOWNLOADED_PARTIAL));
- assertFalse(retrievedEntry.isSet(Flag.DELETED));
-
- // Finally test setFlag(Flag.DELETED)
- retrievedEntry.setFlag(Flag.DELETED, true);
- mFolder.updateMessage((LocalStore.LocalMessage)retrievedEntry);
- Message[] retrievedArray2 = mFolder.getMessages(null);
- assertEquals(1, retrievedArray2.length);
- MimeMessage retrievedEntry2 = (MimeMessage) retrievedArray2[0];
- assertEquals(MESSAGE_ID, retrievedEntry2.getMessageId());
-
- assertFalse(retrievedEntry2.isSet(Flag.X_STORE_1));
- assertTrue(retrievedEntry2.isSet(Flag.X_STORE_2));
- assertFalse(retrievedEntry2.isSet(Flag.X_DOWNLOADED_FULL));
- assertTrue(retrievedEntry2.isSet(Flag.X_DOWNLOADED_PARTIAL));
- assertTrue(retrievedEntry2.isSet(Flag.DELETED));
- }
-
- /**
- * Test that store flags are separated into separate columns and not replicated in the
- * (should be deprecated) string flags column.
- */
- public void testStoreFlagStorage() throws Exception {
- final MimeMessage message = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message.setMessageId(MESSAGE_ID);
- message.setFlag(Flag.SEEN, true);
- message.setFlag(Flag.FLAGGED, true);
- message.setFlag(Flag.X_STORE_1, true);
- message.setFlag(Flag.X_STORE_2, true);
- message.setFlag(Flag.X_DOWNLOADED_FULL, true);
- message.setFlag(Flag.X_DOWNLOADED_PARTIAL, true);
- message.setFlag(Flag.DELETED, true);
-
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(new Message[]{ message });
- String localUid = message.getUid();
- long folderId = mFolder.getId();
- mFolder.close(false);
-
- // read back using direct db calls, to view columns
- openDatabase();
-
- Cursor cursor = null;
- try {
- cursor = mDatabase.rawQuery(
- "SELECT flags, store_flag_1, store_flag_2," +
- " flag_downloaded_full, flag_downloaded_partial, flag_deleted" +
- " FROM messages" +
- " WHERE uid = ? AND folder_id = ?",
- new String[] {
- localUid, Long.toString(folderId)
- });
- assertTrue("appended message not found", cursor.moveToNext());
- String flagString = cursor.getString(0);
- String[] flags = flagString.split(",");
- assertEquals(2, flags.length); // 2 = SEEN & FLAGGED
- for (String flag : flags) {
- assertFalse("storeFlag1 in string", flag.equals(Flag.X_STORE_1.toString()));
- assertFalse("storeFlag2 in string", flag.equals(Flag.X_STORE_2.toString()));
- assertFalse("flag_downloaded_full in string",
- flag.equals(Flag.X_DOWNLOADED_FULL.toString()));
- assertFalse("flag_downloaded_partial in string",
- flag.equals(Flag.X_DOWNLOADED_PARTIAL.toString()));
- assertFalse("flag_deleted in string", flag.equals(Flag.DELETED.toString()));
- }
- assertEquals(1, cursor.getInt(1)); // store flag 1 is set
- assertEquals(1, cursor.getInt(2)); // store flag 2 is set
- assertEquals(1, cursor.getInt(3)); // flag_downloaded_full is set
- assertEquals(1, cursor.getInt(4)); // flag_downloaded_partial is set
- assertEquals(1, cursor.getInt(5)); // flag_deleted is set
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- /**
- * Test the new functionality of getting messages from LocalStore based on their flags.
- */
- public void testGetMessagesFlags() throws MessagingException {
-
- final MimeMessage message1 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message1.setFlag(Flag.X_STORE_1, false);
- message1.setFlag(Flag.X_STORE_2, false);
-
- final MimeMessage message2 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message2.setFlag(Flag.X_STORE_1, true);
- message2.setFlag(Flag.X_STORE_2, false);
-
- final MimeMessage message3 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message3.setFlag(Flag.X_STORE_1, false);
- message3.setFlag(Flag.X_STORE_2, true);
-
- final MimeMessage message4 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message4.setFlag(Flag.X_STORE_1, true);
- message4.setFlag(Flag.X_STORE_2, true);
-
- final MimeMessage message5 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message5.setFlag(Flag.X_DOWNLOADED_FULL, true);
-
- final MimeMessage message6 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message6.setFlag(Flag.X_DOWNLOADED_PARTIAL, true);
-
- final MimeMessage message7 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message7.setFlag(Flag.DELETED, true);
-
- Message[] allOriginals = new Message[] {
- message1, message2, message3, message4, message5, message6, message7 };
-
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(allOriginals);
- mFolder.close(false);
-
- // Now try getting various permutation and see if it works
-
- // Null lists are the same as empty lists - return all messages
- mFolder.open(OpenMode.READ_WRITE, null);
- Message[] getAll1 = mFolder.getMessages(null, null, null);
- checkGottenMessages("null filters", allOriginals, getAll1);
-
- Message[] getAll2 = mFolder.getMessages(new Flag[0], new Flag[0], null);
- checkGottenMessages("empty filters", allOriginals, getAll2);
-
- // Now try some selections, trying set and clear cases
- Message[] getSome1 = mFolder.getMessages(new Flag[]{ Flag.X_STORE_1 }, null, null);
- checkGottenMessages("store_1 set", new Message[]{ message2, message4 }, getSome1);
-
- Message[] getSome2 = mFolder.getMessages(null, new Flag[]{ Flag.X_STORE_1 }, null);
- checkGottenMessages("store_1 clear",
- new Message[]{ message1, message3, message5, message6, message7 }, getSome2);
-
- Message[] getSome3 = mFolder.getMessages(new Flag[]{ Flag.X_STORE_2 }, null, null);
- checkGottenMessages("store_2 set", new Message[]{ message3, message4 }, getSome3);
-
- Message[] getSome4 = mFolder.getMessages(null, new Flag[]{ Flag.X_STORE_2 }, null);
- checkGottenMessages("store_2 clear",
- new Message[]{ message1, message2, message5, message6, message7 }, getSome4);
-
- Message[] getOne1 = mFolder.getMessages(new Flag[]{ Flag.X_DOWNLOADED_FULL }, null, null);
- checkGottenMessages("downloaded full", new Message[]{ message5 }, getOne1);
-
- Message[] getOne2 = mFolder.getMessages(new Flag[]{ Flag.X_DOWNLOADED_PARTIAL }, null,
- null);
- checkGottenMessages("downloaded partial", new Message[]{ message6 }, getOne2);
-
- Message[] getOne3 = mFolder.getMessages(new Flag[]{ Flag.DELETED }, null, null);
- checkGottenMessages("deleted", new Message[]{ message7 }, getOne3);
-
- // Multi-flag selections
- Message[] getSingle1 = mFolder.getMessages(new Flag[]{ Flag.X_STORE_1, Flag.X_STORE_2 },
- null, null);
- checkGottenMessages("both set", new Message[]{ message4 }, getSingle1);
-
- Message[] getSingle2 = mFolder.getMessages(null,
- new Flag[]{ Flag.X_STORE_1, Flag.X_STORE_2 }, null);
- checkGottenMessages("both clear", new Message[]{ message1, message5, message6, message7 },
- getSingle2);
- }
-
- /**
- * Check for matching uid's between two lists of messages
- */
- private void checkGottenMessages(String failMessage, Message[] expected, Message[] actual) {
- HashSet expectedUids = new HashSet();
- for (Message message : expected) {
- expectedUids.add(message.getUid());
- }
- HashSet actualUids = new HashSet();
- for (Message message : actual) {
- actualUids.add(message.getUid());
- }
- assertEquals(failMessage, expectedUids, actualUids);
- }
-
- /**
- * Test for getMessageCount
- */
- public void testMessageCount() throws MessagingException {
-
- final MimeMessage message1 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message1.setFlag(Flag.X_STORE_1, false);
- message1.setFlag(Flag.X_STORE_2, false);
- message1.setFlag(Flag.X_DOWNLOADED_FULL, true);
-
- final MimeMessage message2 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message2.setFlag(Flag.X_STORE_1, true);
- message2.setFlag(Flag.X_STORE_2, false);
-
- final MimeMessage message3 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message3.setFlag(Flag.X_STORE_1, false);
- message3.setFlag(Flag.X_STORE_2, true);
- message3.setFlag(Flag.X_DOWNLOADED_FULL, true);
-
- final MimeMessage message4 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message4.setFlag(Flag.X_STORE_1, true);
- message4.setFlag(Flag.X_STORE_2, true);
- message4.setFlag(Flag.X_DOWNLOADED_FULL, true);
-
- final MimeMessage message5 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message5.setFlag(Flag.X_DOWNLOADED_FULL, true);
-
- final MimeMessage message6 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message6.setFlag(Flag.X_DOWNLOADED_PARTIAL, true);
-
- final MimeMessage message7 = buildTestMessage(RECIPIENT_TO, SENDER, SUBJECT, BODY);
- message7.setFlag(Flag.DELETED, true);
-
- Message[] allOriginals = new Message[] {
- message1, message2, message3, message4, message5, message6, message7 };
-
- mFolder.open(OpenMode.READ_WRITE, null);
- mFolder.appendMessages(allOriginals);
- mFolder.close(false);
-
- // Null lists are the same as empty lists - return all messages
- mFolder.open(OpenMode.READ_WRITE, null);
-
- int allMessages = mFolder.getMessageCount();
- assertEquals("all messages", 7, allMessages);
-
- int storeFlag1 = mFolder.getMessageCount(new Flag[] { Flag.X_STORE_1 }, null);
- assertEquals("store flag 1", 2, storeFlag1);
-
- int storeFlag1NotFlag2 = mFolder.getMessageCount(
- new Flag[] { Flag.X_STORE_1 }, new Flag[] { Flag.X_STORE_2 });
- assertEquals("store flag 1, not 2", 1, storeFlag1NotFlag2);
-
- int downloadedFull = mFolder.getMessageCount(new Flag[] { Flag.X_DOWNLOADED_FULL }, null);
- assertEquals("downloaded full", 4, downloadedFull);
-
- int storeFlag2Full = mFolder.getMessageCount(
- new Flag[] { Flag.X_STORE_2, Flag.X_DOWNLOADED_FULL }, null);
- assertEquals("store flag 2, full", 2, storeFlag2Full);
-
- int notDeleted = mFolder.getMessageCount(null, new Flag[] { Flag.DELETED });
- assertEquals("not deleted", 6, notDeleted);
- }
-
- /**
- * Test unread messages count
- */
- public void testUnreadMessages() throws MessagingException {
- mFolder.open(OpenMode.READ_WRITE, null);
-
- // set up a 2nd folder to confirm independent storage
- LocalStore.LocalFolder folder2 = (LocalStore.LocalFolder) mStore.getFolder("FOLDER-2");
- assertFalse(folder2.exists());
- folder2.create(FolderType.HOLDS_MESSAGES);
- folder2.open(OpenMode.READ_WRITE, null);
-
- // read and write, look for independent storage
- mFolder.setUnreadMessageCount(400);
- folder2.setUnreadMessageCount(425);
-
- mFolder.close(false);
- folder2.close(false);
- mFolder.open(OpenMode.READ_WRITE, null);
- folder2.open(OpenMode.READ_WRITE, null);
-
- assertEquals(400, mFolder.getUnreadMessageCount());
- assertEquals(425, folder2.getUnreadMessageCount());
- }
-
- /**
- * Test unread messages count - concurrent access via two folder objects
- */
- public void testUnreadMessagesConcurrent() throws MessagingException {
- mFolder.open(OpenMode.READ_WRITE, null);
-
- // set up a 2nd folder to confirm concurrent access
- LocalStore.LocalFolder folder2 = (LocalStore.LocalFolder) mStore.getFolder(FOLDER_NAME);
- assertTrue(folder2.exists());
- folder2.open(OpenMode.READ_WRITE, null);
-
- // read and write, look for concurrent storage
- mFolder.setUnreadMessageCount(450);
- assertEquals(450, folder2.getUnreadMessageCount());
- }
-
- /**
- * Test visible limits support
- */
- public void testReadWriteVisibleLimits() throws MessagingException {
- mFolder.open(OpenMode.READ_WRITE, null);
-
- // set up a 2nd folder to confirm independent storage
- LocalStore.LocalFolder folder2 = (LocalStore.LocalFolder) mStore.getFolder("FOLDER-2");
- assertFalse(folder2.exists());
- folder2.create(FolderType.HOLDS_MESSAGES);
- folder2.open(OpenMode.READ_WRITE, null);
-
- // read and write, look for independent storage
- mFolder.setVisibleLimit(100);
- folder2.setVisibleLimit(200);
-
- mFolder.close(false);
- folder2.close(false);
- mFolder.open(OpenMode.READ_WRITE, null);
- folder2.open(OpenMode.READ_WRITE, null);
-
- assertEquals(100, mFolder.getVisibleLimit());
- assertEquals(200, folder2.getVisibleLimit());
- }
-
- /**
- * Test visible limits support - concurrent access via two folder objects
- */
- public void testVisibleLimitsConcurrent() throws MessagingException {
- mFolder.open(OpenMode.READ_WRITE, null);
-
- // set up a 2nd folder to confirm concurrent access
- LocalStore.LocalFolder folder2 = (LocalStore.LocalFolder) mStore.getFolder(FOLDER_NAME);
- assertTrue(folder2.exists());
- folder2.open(OpenMode.READ_WRITE, null);
-
- // read and write, look for concurrent storage
- mFolder.setVisibleLimit(300);
- assertEquals(300, folder2.getVisibleLimit());
- }
-
- /**
- * Test reset limits support
- */
- public void testResetVisibleLimits() throws MessagingException {
- mFolder.open(OpenMode.READ_WRITE, null);
-
- // set up a 2nd folder to confirm independent storage
- LocalStore.LocalFolder folder2 = (LocalStore.LocalFolder) mStore.getFolder("FOLDER-2");
- assertFalse(folder2.exists());
- folder2.create(FolderType.HOLDS_MESSAGES);
- folder2.open(OpenMode.READ_WRITE, null);
-
- // read and write, look for independent storage
- mFolder.setVisibleLimit(100);
- folder2.setVisibleLimit(200);
-
- mFolder.close(false);
- folder2.close(false);
- mFolder.open(OpenMode.READ_WRITE, null);
- folder2.open(OpenMode.READ_WRITE, null);
-
- mStore.resetVisibleLimits(Email.VISIBLE_LIMIT_DEFAULT);
- assertEquals(Email.VISIBLE_LIMIT_DEFAULT, mFolder.getVisibleLimit());
- assertEquals(Email.VISIBLE_LIMIT_DEFAULT, folder2.getVisibleLimit());
-
- mFolder.close(false);
- folder2.close(false);
- }
-
- /**
- * Lightweight test to confirm that LocalStore hasn't implemented any folder roles yet.
- */
- public void testNoFolderRolesYet() throws MessagingException {
- Folder[] localFolders = mStore.getPersonalNamespaces();
- for (Folder folder : localFolders) {
- assertEquals(Folder.FolderRole.UNKNOWN, folder.getRole());
- }
- }
-
- /**
- * Test missing folder (on open). This should succeed because open will create it.
- */
- public void testMissingFolderOpen() throws MessagingException {
- Folder noFolder = mStore.getFolder(MISSING_FOLDER_NAME);
- noFolder.open(OpenMode.READ_WRITE, null);
- noFolder.close(false);
- }
-
- /**
- * Test missing folder (on getMessageCount). This should not fail - it should return zero,
- * which is the actual count of messages in that folder.
- */
- public void testMissingFolderGetMessageCount() throws MessagingException {
- Folder noFolder = mStore.getFolder(MISSING_FOLDER_NAME);
- noFolder.open(OpenMode.READ_WRITE, null);
-
- // Now delete it behind its back
- Folder noFolder2 = mStore.getFolder(MISSING_FOLDER_NAME);
- noFolder2.delete(true);
-
- // Now try the call on the first instance
- int count = noFolder.getMessageCount();
- assertEquals(0, count);
- }
-
- /**
- * Test missing folder (on getUnreadMessageCount). This should fail because we delete the
- * open folder, simulating multi-threading behavior.
- */
- public void testMissingFolderGetUnreadMessageCount() throws MessagingException {
- Folder noFolder = mStore.getFolder(MISSING_FOLDER_NAME);
- noFolder.open(OpenMode.READ_WRITE, null);
-
- // Now delete it behind its back
- Folder noFolder2 = mStore.getFolder(MISSING_FOLDER_NAME);
- noFolder2.delete(true);
-
- // Now try the call on the first instance
- try {
- noFolder.getUnreadMessageCount();
- fail("MessagingException expected");
- } catch (MessagingException me) {
- // OK - success.
- }
- }
-
- /**
- * Test missing folder (on getVisibleLimit). This should fail because we delete the
- * open folder, simulating multi-threading behavior.
- */
- public void testMissingFolderGetVisibleLimit() throws MessagingException {
- LocalStore.LocalFolder noFolder =
- (LocalStore.LocalFolder) mStore.getFolder(MISSING_FOLDER_NAME);
- noFolder.open(OpenMode.READ_WRITE, null);
-
- // Now delete it behind its back
- Folder noFolder2 = mStore.getFolder(MISSING_FOLDER_NAME);
- noFolder2.delete(true);
-
- // Now try the call on the first instance
- try {
- noFolder.getVisibleLimit();
- fail("MessagingException expected");
- } catch (MessagingException me) {
- // OK - success.
- }
- }
-
- /**
- * Test for setExtendedHeader() and getExtendedHeader()
- */
- public void testExtendedHeader() throws MessagingException {
- MimeMessage message = new MimeMessage();
- message.setUid("message1");
- mFolder.appendMessages(new Message[] { message });
-
- message.setUid("message2");
- message.setExtendedHeader("X-Header1", "value1");
- message.setExtendedHeader("X-Header2", "value2\r\n value3\n value4\r\n");
- mFolder.appendMessages(new Message[] { message });
-
- LocalMessage message1 = (LocalMessage) mFolder.getMessage("message1");
- assertNull("none existent header", message1.getExtendedHeader("X-None-Existent"));
-
- LocalMessage message2 = (LocalMessage) mFolder.getMessage("message2");
- assertEquals("header 1", "value1", message2.getExtendedHeader("X-Header1"));
- assertEquals("header 2", "value2 value3 value4", message2.getExtendedHeader("X-Header2"));
- assertNull("header 3", message2.getExtendedHeader("X-Header3"));
- }
-
- /**
- * Tests for database version.
- */
- public void testDbVersion() throws Exception {
- // build current version database.
- upgradeDatabase();
-
- openDatabase();
-
- // database version should be latest.
- assertEquals("database version should be latest", DATABASE_VERSION, mDatabase.getVersion());
- }
-
- /**
- * Helper function convert Cursor data to ContentValues
- */
- private ContentValues cursorToContentValues(Cursor c, String[] schema) {
- if (c.getColumnCount() != schema.length) {
- throw new IndexOutOfBoundsException("schema length is not mach with cursor columns");
- }
-
- final ContentValues cv = new ContentValues();
- for (int i = 0, count = c.getColumnCount(); i < count; ++i) {
- final String key = c.getColumnName(i);
- final String type = schema[i];
- if (type == "text") {
- cv.put(key, c.getString(i));
- } else if (type == "integer" || type == "primary") {
- cv.put(key, c.getLong(i));
- } else if (type == "numeric" || type == "real") {
- cv.put(key, c.getDouble(i));
- } else if (type == "blob") {
- cv.put(key, c.getBlob(i));
- } else {
- throw new IllegalArgumentException("unsupported type at index " + i);
- }
- }
- return cv;
- }
-
- /**
- * Helper function to read out Cursor columns
- */
- private HashSet cursorToColumnNames(Cursor c) {
- HashSet result = new HashSet();
- for (int i = 0, count = c.getColumnCount(); i < count; ++i) {
- result.add(c.getColumnName(i));
- }
- return result;
- }
-
- /**
- * Tests for database upgrade from version 18 to current version.
- */
- public void testDbUpgrade18ToLatest() throws Exception {
- openDatabase();
-
- // create sample version 18 db tables
- createSampleDb(mDatabase, 18);
-
- // sample message data and expected data
- final ContentValues initialMessage = new ContentValues();
- initialMessage.put("folder_id", (long) 2); // folder_id type integer == Long
- initialMessage.put("internal_date", (long) 3); // internal_date type integer == Long
- final ContentValues expectedMessage = new ContentValues(initialMessage);
- expectedMessage.put("id", mDatabase.insert("messages", null, initialMessage));
-
- // sample attachment data and expected data
- final ContentValues initialAttachment = new ContentValues();
- initialAttachment.put("message_id", (long) 4); // message_id type integer == Long
- initialAttachment.put("mime_type", "a"); // mime_type type text == String
- final ContentValues expectedAttachment = new ContentValues(initialAttachment);
- expectedAttachment.put("id", mDatabase.insert("attachments", null, initialAttachment));
-
- // upgrade database 18 to latest
- upgradeDatabase();
-
- // added message_id column should be initialized as null
- expectedMessage.put("message_id", (String) null); // message_id type text == String
- // added content_id column should be initialized as null
- expectedAttachment.put("content_id", (String) null); // content_id type text == String
-
- // database should be upgraded
- assertEquals("database should be upgraded", DATABASE_VERSION, mDatabase.getVersion());
- Cursor c;
-
- // check for all "latest version" tables
- checkAllTablesFound(mDatabase);
-
- // check message table
- c = mDatabase.query("messages",
- new String[] { "id", "folder_id", "internal_date", "message_id" },
- null, null, null, null, null);
- // check if data is available
- assertTrue("messages table should have one data", c.moveToNext());
-
- // check if data are expected
- final ContentValues actualMessage = cursorToContentValues(c,
- new String[] { "primary", "integer", "integer", "text" });
- assertEquals("messages table cursor does not have expected values",
- expectedMessage, actualMessage);
- c.close();
-
- // check attachment table
- c = mDatabase.query("attachments",
- new String[] { "id", "message_id", "mime_type", "content_id" },
- null, null, null, null, null);
- // check if data is available
- assertTrue("attachments table should have one data", c.moveToNext());
-
- // check if data are expected
- final ContentValues actualAttachment = cursorToContentValues(c,
- new String[] { "primary", "integer", "text", "text" });
- assertEquals("attachment table cursor does not have expected values",
- expectedAttachment, actualAttachment);
- c.close();
- }
-
- /**
- * Tests for database upgrade from version 19 to current version.
- */
- public void testDbUpgrade19ToLatest() throws Exception {
- openDatabase();
-
- // create sample version 19 db tables
- createSampleDb(mDatabase, 19);
-
- // sample message data and expected data
- final ContentValues initialMessage = new ContentValues();
- initialMessage.put("folder_id", (long) 2); // folder_id type integer == Long
- initialMessage.put("internal_date", (long) 3); // internal_date integer == Long
- initialMessage.put("message_id", "x"); // message_id text == String
- final ContentValues expectedMessage = new ContentValues(initialMessage);
- expectedMessage.put("id", mDatabase.insert("messages", null, initialMessage));
-
- // sample attachment data and expected data
- final ContentValues initialAttachment = new ContentValues();
- initialAttachment.put("message_id", (long) 4); // message_id type integer == Long
- initialAttachment.put("mime_type", "a"); // mime_type type text == String
- final ContentValues expectedAttachment = new ContentValues(initialAttachment);
- expectedAttachment.put("id", mDatabase.insert("attachments", null, initialAttachment));
-
- // upgrade database 19 to latest
- upgradeDatabase();
-
- // added content_id column should be initialized as null
- expectedAttachment.put("content_id", (String) null); // content_id type text == String
-
- // database should be upgraded
- assertEquals("database should be upgraded", DATABASE_VERSION, mDatabase.getVersion());
- Cursor c;
-
- // check for all "latest version" tables
- checkAllTablesFound(mDatabase);
-
- // check message table
- c = mDatabase.query("messages",
- new String[] { "id", "folder_id", "internal_date", "message_id" },
- null, null, null, null, null);
- try {
- // check if data is available
- assertTrue("attachments table should have one data", c.moveToNext());
-
- // check if data are expected
- final ContentValues actualMessage = cursorToContentValues(c,
- new String[] { "primary", "integer", "integer", "text" });
- assertEquals("messages table cursor does not have expected values",
- expectedMessage, actualMessage);
- } finally {
- c.close();
- }
-
- // check attachment table
- c = mDatabase.query("attachments",
- new String[] { "id", "message_id", "mime_type", "content_id" },
- null, null, null, null, null);
- try {
- // check if data is available
- assertTrue("attachments table should have one data", c.moveToNext());
-
- // check if data are expected
- final ContentValues actualAttachment = cursorToContentValues(c,
- new String[] { "primary", "integer", "text", "text" });
- assertEquals("attachment table cursor does not have expected values",
- expectedAttachment, actualAttachment);
-
- } finally {
- c.close();
- }
- }
-
- /**
- * Check upgrade from db version 20 to latest
- */
- public void testDbUpgrade20ToLatest() throws Exception {
- openDatabase();
-
- // create sample version 20 db tables
- createSampleDb(mDatabase, 20);
-
- // upgrade database 20 to latest
- upgradeDatabase();
-
- // database should be upgraded
- assertEquals("database should be upgraded", DATABASE_VERSION, mDatabase.getVersion());
-
- // check for all "latest version" tables
- checkAllTablesFound(mDatabase);
- }
-
- /**
- * Check upgrade from db version 21 to latest
- */
- public void testDbUpgrade21ToLatest() throws Exception {
- openDatabase();
-
- // create sample version 21 db tables
- createSampleDb(mDatabase, 21);
-
- // upgrade database 21 to latest
- upgradeDatabase();
-
- // database should be upgraded
- assertEquals("database should be upgraded", DATABASE_VERSION, mDatabase.getVersion());
-
- // check for all "latest version" tables
- checkAllTablesFound(mDatabase);
- }
-
- /**
- * Check upgrade from db version 22 to latest.
- * Flags must be migrated to new columns.
- */
- public void testDbUpgrade22ToLatest() throws Exception {
- openDatabase();
-
- // create sample version 22 db tables
- createSampleDb(mDatabase, 22);
-
- // insert three messages, one for each migration flag
- final ContentValues inMessage1 = new ContentValues();
- inMessage1.put("message_id", "x"); // message_id text == String
- inMessage1.put("flags", Flag.X_DOWNLOADED_FULL.toString());
- final ContentValues outMessage1 = new ContentValues(inMessage1);
- outMessage1.put("id", mDatabase.insert("messages", null, inMessage1));
-
- final ContentValues inMessage2 = new ContentValues();
- inMessage2.put("message_id", "y"); // message_id text == String
- inMessage2.put("flags", Flag.X_DOWNLOADED_PARTIAL.toString());
- final ContentValues outMessage2 = new ContentValues(inMessage2);
- outMessage2.put("id", mDatabase.insert("messages", null, inMessage2));
-
- final ContentValues inMessage3 = new ContentValues();
- inMessage3.put("message_id", "z"); // message_id text == String
- inMessage3.put("flags", Flag.DELETED.toString());
- final ContentValues outMessage3 = new ContentValues(inMessage3);
- outMessage3.put("id", mDatabase.insert("messages", null, inMessage3));
-
- // upgrade database 22 to latest
- upgradeDatabase();
-
- // database should be upgraded
- assertEquals("database should be upgraded", DATABASE_VERSION, mDatabase.getVersion());
-
- // check for all "latest version" tables
- checkAllTablesFound(mDatabase);
-
- // check message table for migrated flags
- String[] columns = new String[] { "id", "message_id", "flags",
- "flag_downloaded_full", "flag_downloaded_partial", "flag_deleted" };
- Cursor c = mDatabase.query("messages", columns, null, null, null, null, null);
- try {
- for (int msgNum = 0; msgNum <= 2; ++msgNum) {
- assertTrue(c.moveToNext());
- ContentValues actualMessage = cursorToContentValues(c, new String[] {
- "primary", "text", "text", "integer", "integer", "integer" });
- String messageId = actualMessage.getAsString("message_id");
- int outDlFull = actualMessage.getAsInteger("flag_downloaded_full");
- int outDlPartial = actualMessage.getAsInteger("flag_downloaded_partial");
- int outDeleted = actualMessage.getAsInteger("flag_deleted");
- if ("x".equals(messageId)) {
- assertTrue("converted flag_downloaded_full",
- outDlFull == 1 && outDlPartial == 0 && outDeleted == 0);
- } else if ("y".equals(messageId)) {
- assertTrue("converted flag_downloaded_partial",
- outDlFull == 0 && outDlPartial == 1 && outDeleted == 0);
- } else if ("z".equals(messageId)) {
- assertTrue("converted flag_deleted",
- outDlFull == 0 && outDlPartial == 0 && outDeleted == 1);
- }
- }
- } finally {
- c.close();
- }
- }
-
- /**
- * Tests for database upgrade from version 23 to current version.
- */
- public void testDbUpgrade23ToLatest() throws Exception {
- openDatabase();
-
- // create sample version 23 db tables
- createSampleDb(mDatabase, 23);
-
- // sample message data and expected data
- final ContentValues initialMessage = new ContentValues();
- initialMessage.put("folder_id", (long) 2); // folder_id type integer == Long
- initialMessage.put("internal_date", (long) 3); // internal_date type integer == Long
- final ContentValues expectedMessage = new ContentValues(initialMessage);
- expectedMessage.put("id", mDatabase.insert("messages", null, initialMessage));
-
- // upgrade database 23 to latest
- upgradeDatabase();
-
- // added message_id column should be initialized as null
- expectedMessage.put("message_id", (String) null); // message_id type text == String
-
- // database should be upgraded
- assertEquals("database should be upgraded", DATABASE_VERSION, mDatabase.getVersion());
- Cursor c;
-
- // check for all "latest version" tables
- checkAllTablesFound(mDatabase);
-
- // check message table
- c = mDatabase.query("messages",
- new String[] { "id", "folder_id", "internal_date", "message_id" },
- null, null, null, null, null);
- try {
- // check if data is available
- assertTrue("messages table should have one data", c.moveToNext());
-
- // check if data are expected
- final ContentValues actualMessage = cursorToContentValues(c,
- new String[] { "primary", "integer", "integer", "text" });
- assertEquals("messages table cursor does not have expected values",
- expectedMessage, actualMessage);
- } finally {
- c.close();
- }
- }
-
- /**
- * Checks the database to confirm that all tables, with all expected columns are found.
- */
- private void checkAllTablesFound(SQLiteDatabase db) {
- checkColumnNames(db, "messages",
- "id", "folder_id", "uid", "subject", "date", "flags", "sender_list",
- "to_list", "cc_list", "bcc_list", "reply_to_list",
- "html_content", "text_content", "attachment_count",
- "internal_date", "store_flag_1", "store_flag_2", "flag_downloaded_full",
- "flag_downloaded_partial", "flag_deleted", "x_headers"
- );
- checkColumnNames(db, "attachments",
- "id", "message_id",
- "store_data", "content_uri", "size", "name",
- "mime_type", "content_id"
- );
- checkColumnNames(db, "remote_store_data",
- "id", "folder_id", "data_key", "data"
- );
- }
-
- private void checkColumnNames(SQLiteDatabase db, String tableName, String... expectedColumns) {
- Cursor c = db.query(tableName, null, null, null, null, null, null);
- try {
- final HashSet expectedSet = new HashSet();
- for (String expectedColumn : expectedColumns) {
- expectedSet.add(expectedColumn);
- }
- final HashSet actualSet = cursorToColumnNames(c);
-
- expectedSet.removeAll(actualSet);
-
- MoreAsserts.assertEmpty(expectedSet);
- } finally {
- c.close();
- }
- }
-
- private static void createSampleDb(SQLiteDatabase db, int version) {
- db.execSQL("DROP TABLE IF EXISTS messages");
- db.execSQL("CREATE TABLE messages (id INTEGER PRIMARY KEY, folder_id INTEGER, " +
- "uid TEXT, subject TEXT, date INTEGER, flags TEXT, sender_list TEXT, " +
- "to_list TEXT, cc_list TEXT, bcc_list TEXT, reply_to_list TEXT, " +
- "html_content TEXT, text_content TEXT, attachment_count INTEGER, " +
- "internal_date INTEGER" +
- ((version >= 19) ? ", message_id TEXT" : "") +
- ((version >= 22) ? ", store_flag_1 INTEGER, store_flag_2 INTEGER" : "") +
- ((version >= 23) ?
- ", flag_downloaded_full INTEGER, flag_downloaded_partial INTEGER" : "") +
- ((version >= 23) ? ", flag_deleted INTEGER" : "") +
- ((version >= 24) ? ", x_headers TEXT" : "") +
- ")");
- db.execSQL("DROP TABLE IF EXISTS attachments");
- db.execSQL("CREATE TABLE attachments (id INTEGER PRIMARY KEY, message_id INTEGER," +
- "store_data TEXT, content_uri TEXT, size INTEGER, name TEXT," +
- "mime_type TEXT" +
- ((version >= 20) ? ", content_id" : "") +
- ")");
-
- if (version >= 21) {
- db.execSQL("DROP TABLE IF EXISTS remote_store_data");
- db.execSQL("CREATE TABLE remote_store_data "
- + "(id INTEGER PRIMARY KEY, folder_id INTEGER, "
- + "data_key TEXT, data TEXT)");
- }
-
- db.setVersion(version);
- }
-}
diff --git a/tests/src/com/android/email/provider/AttachmentProviderTests.java b/tests/src/com/android/email/provider/AttachmentProviderTests.java
index 9a830dbe8..86b03db4d 100644
--- a/tests/src/com/android/email/provider/AttachmentProviderTests.java
+++ b/tests/src/com/android/email/provider/AttachmentProviderTests.java
@@ -19,7 +19,6 @@ package com.android.email.provider;
import com.android.email.AttachmentInfo;
import com.android.email.R;
import com.android.email.mail.MessagingException;
-import com.android.email.mail.store.LocalStore;
import com.android.email.provider.AttachmentProvider.AttachmentProviderColumns;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.Attachment;
@@ -27,11 +26,9 @@ import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
@@ -51,14 +48,6 @@ import java.io.IOException;
*/
public class AttachmentProviderTests extends ProviderTestCase2 {
- /*
- * This switch will enable us to transition these tests, and the AttachmentProvider, from the
- * "old" LocalStore model to the "new" provider model. After the transition is complete,
- * this flag (and its associated code) can be removed.
- */
- private final boolean USE_LOCALSTORE = false;
- LocalStore mLocalStore = null;
-
EmailProvider mEmailProvider;
Context mMockContext;
ContentResolver mMockResolver;
@@ -81,15 +70,6 @@ public class AttachmentProviderTests extends ProviderTestCase2