AI 146360: Provide an API by which the server (or store) can tag some

of the role-specific folders such as Drafts, Sent, or Trash.
  This allows us to properly target these folders even on
  systems where they have different names.  I capture the
  tagged names into the existing columns in the account data,
  where they are used elsewhere in the code (no changes
  necessary).
  Use default implementations on POP3 and IMAP for now -
  no change from original behavior.  The new code is
  primarily to support EAS (for now).
  BUG=1790798

Automated import of CL 146360
This commit is contained in:
Andy Stadler 2009-04-15 12:58:19 -07:00 committed by The Android Open Source Project
parent 4836f3c289
commit 1f48259d22
7 changed files with 394 additions and 20 deletions

View File

@ -16,21 +16,6 @@
package com.android.email;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import android.app.Application;
import android.content.Context;
import android.os.Process;
import android.util.Config;
import android.util.Log;
import com.android.email.mail.FetchProfile;
import com.android.email.mail.Flag;
import com.android.email.mail.Folder;
@ -48,6 +33,20 @@ import com.android.email.mail.store.LocalStore.LocalFolder;
import com.android.email.mail.store.LocalStore.LocalMessage;
import com.android.email.mail.store.LocalStore.PendingCommand;
import android.app.Application;
import android.content.Context;
import android.os.Process;
import android.util.Config;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Starts a long running (application) Thread that will run through commands
* that require remote mailbox access. This class is used to serialize and
@ -214,6 +213,7 @@ public class MessagingController implements Runnable {
account.getStoreCallbacks());
Folder[] remoteFolders = store.getPersonalNamespaces();
updateAccountFolderNames(account, remoteFolders);
Store localStore = Store.getInstance(
account.getLocalStoreUri(), mApplication, null);
@ -267,6 +267,35 @@ public class MessagingController implements Runnable {
}
}
}
/**
* Asks the store for a list of server-specific folder names and, if provided, updates
* the account record for future getFolder() operations.
*
* NOTE: Inbox is not queried, because we require it to be INBOX, and outbox is not
* queried, because outbox is local-only.
*/
/* package */ static void updateAccountFolderNames(Account account, Folder[] remoteFolders) {
String trash = null;
String sent = null;
String drafts = null;
for (Folder folder : remoteFolders) {
Folder.FolderRole role = folder.getRole();
if (role == Folder.FolderRole.TRASH) {
trash = folder.getName();
} else if (role == Folder.FolderRole.SENT) {
sent = folder.getName();
} else if (role == Folder.FolderRole.DRAFTS) {
drafts = folder.getName();
}
}
// Do not update when null (defaults are already in place)
if (trash != null) account.setTrashFolderName(trash);
if (sent != null) account.setSentFolderName(sent);
if (drafts != null) account.setDraftsFolderName(drafts);
}
/**
* List the local message store for the given folder. This work is done

View File

@ -25,6 +25,20 @@ public abstract class Folder {
public enum FolderType {
HOLDS_FOLDERS, HOLDS_MESSAGES,
}
/**
* Identifiers of "special" folders.
*/
public enum FolderRole {
INBOX, // NOTE: The folder's name must be INBOX
TRASH,
SENT,
DRAFTS,
OUTBOX, // Local folders only - not used in remote Stores
OTHER, // this folder has no specific role
UNKNOWN // the role of this folder is unknown
}
/**
* Forces an open of the MailProvider. If the provider is already open this
@ -109,6 +123,20 @@ public abstract class Folder {
public abstract Flag[] getPermanentFlags() throws MessagingException;
/**
* This method returns a string identifying the name of a "role" folder
* (such as inbox, draft, sent, or trash). Stores that do not implement this
* feature can be used - the account UI will provide default strings. To
* let the server identify specific folder roles, simply override this method.
*
* @return The server- or protocol- specific role for this folder. If some roles are known
* but this is not one of them, return FolderRole.OTHER. If roles are unsupported here,
* return FolderRole.UNKNOWN.
*/
public FolderRole getRole() {
return FolderRole.UNKNOWN;
}
/**
* Callback interface by which a Folder can read and write persistent data.
* TODO This needs to be made more generic & flexible

View File

@ -0,0 +1,145 @@
/*
* Copyright (C) 2009 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;
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.MessageRetrievalListener;
import com.android.email.mail.MessagingException;
import com.android.email.mail.MockFolder;
import com.android.email.mail.Store;
import com.android.email.mail.Folder.FolderRole;
import android.content.SharedPreferences;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
/**
* This is a series of unit tests for the MessagingController class.
*
* Technically these are functional because they use the underlying preferences framework.
*/
@SmallTest
public class MessagingControllerUnitTests extends AndroidTestCase {
private Preferences mPreferences;
private String mUuid;
private Account mAccount;
@Override
protected void setUp() throws Exception {
super.setUp();
mPreferences = Preferences.getPreferences(getContext());
}
/**
* Delete any dummy accounts we set up for this test
*/
@Override
protected void tearDown() throws Exception {
super.tearDown();
if (mAccount != null && mPreferences != null) {
mAccount.delete(mPreferences);
}
}
/**
* Test the code that copies server-supplied folder names into the account data
*/
public void testUpdateAccountFolderNames() {
// Create a dummy account
createTestAccount();
// Refresh it to fill in all fields (many will have default values)
mAccount.refresh(mPreferences);
// Replace one entry, others are not included
Folder[] folders1 = new Folder[] {
new MyMockFolder(Folder.FolderRole.DRAFTS, "DRAFTS_1"),
};
MessagingController.updateAccountFolderNames(mAccount, folders1);
checkServerFolderNames("folders1", "DRAFTS_1", "Sent", "Trash", "Outbox");
// Replace one entry, others are included but called out as unknown
Folder[] folders2 = new Folder[] {
new MyMockFolder(Folder.FolderRole.UNKNOWN, "DRAFTS_2"),
new MyMockFolder(Folder.FolderRole.SENT, "SENT_2"),
new MyMockFolder(Folder.FolderRole.UNKNOWN, "TRASH_2"),
new MyMockFolder(Folder.FolderRole.UNKNOWN, "OUTBOX_2"),
};
MessagingController.updateAccountFolderNames(mAccount, folders2);
checkServerFolderNames("folders2", "DRAFTS_1", "SENT_2", "Trash", "Outbox");
// Replace one entry, check that "other" is ignored, check that Outbox is ignored
Folder[] folders3 = new Folder[] {
new MyMockFolder(Folder.FolderRole.OTHER, "OTHER_3a"),
new MyMockFolder(Folder.FolderRole.TRASH, "TRASH_3"),
new MyMockFolder(Folder.FolderRole.OTHER, "OTHER_3b"),
new MyMockFolder(Folder.FolderRole.OUTBOX, "OUTBOX_3"),
};
MessagingController.updateAccountFolderNames(mAccount, folders3);
checkServerFolderNames("folders2", "DRAFTS_1", "SENT_2", "TRASH_3", "Outbox");
}
/**
* Quickly check all four folder name slots in mAccount
*/
private void checkServerFolderNames(String diagnostic,
String drafts, String sent, String trash, String outbox) {
assertEquals(diagnostic, drafts, mAccount.getDraftsFolderName());
assertEquals(diagnostic, sent, mAccount.getSentFolderName());
assertEquals(diagnostic, trash, mAccount.getTrashFolderName());
assertEquals(diagnostic, outbox, mAccount.getOutboxFolderName());
}
/**
* MockFolder allows setting and retrieving role & name
*/
private static class MyMockFolder extends MockFolder {
private FolderRole mRole;
private String mName;
public MyMockFolder(FolderRole role, String name) {
mRole = role;
mName = name;
}
public String getName() {
return mName;
}
@Override
public FolderRole getRole() {
return mRole;
}
}
/**
* Create a dummy account with minimal fields
*/
private void createTestAccount() {
mAccount = new Account(getContext());
mAccount.save(mPreferences);
mUuid = mAccount.getUuid();
}
}

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2009 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;
public class MockFolder extends Folder {
@Override
public void appendMessages(Message[] messages) throws MessagingException {
// TODO Auto-generated method stub
}
@Override
public void close(boolean expunge) throws MessagingException {
// TODO Auto-generated method stub
}
@Override
public void copyMessages(Message[] msgs, Folder folder) throws MessagingException {
// TODO Auto-generated method stub
}
@Override
public boolean create(FolderType type) throws MessagingException {
// TODO Auto-generated method stub
return false;
}
@Override
public void delete(boolean recurse) throws MessagingException {
// TODO Auto-generated method stub
}
@Override
public boolean exists() throws MessagingException {
// TODO Auto-generated method stub
return false;
}
@Override
public Message[] expunge() throws MessagingException {
// TODO Auto-generated method stub
return null;
}
@Override
public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener)
throws MessagingException {
// TODO Auto-generated method stub
}
@Override
public Message getMessage(String uid) throws MessagingException {
// TODO Auto-generated method stub
return null;
}
@Override
public int getMessageCount() throws MessagingException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
throws MessagingException {
// TODO Auto-generated method stub
return null;
}
@Override
public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException {
// TODO Auto-generated method stub
return null;
}
@Override
public Message[] getMessages(String[] uids, MessageRetrievalListener listener)
throws MessagingException {
// TODO Auto-generated method stub
return null;
}
@Override
public OpenMode getMode() throws MessagingException {
// TODO Auto-generated method stub
return null;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
@Override
public Flag[] getPermanentFlags() throws MessagingException {
// TODO Auto-generated method stub
return null;
}
@Override
public int getUnreadMessageCount() throws MessagingException {
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean isOpen() {
// TODO Auto-generated method stub
return false;
}
@Override
public void open(OpenMode mode, PersistentDataCallbacks callbacks) throws MessagingException {
// TODO Auto-generated method stub
}
@Override
public void setFlags(Message[] messages, Flag[] flags, boolean value) throws MessagingException {
// TODO Auto-generated method stub
}
}

View File

@ -16,19 +16,18 @@
package com.android.email.mail.store;
import com.android.email.mail.Folder;
import com.android.email.mail.MessagingException;
import com.android.email.mail.Transport;
import com.android.email.mail.Folder.OpenMode;
import com.android.email.mail.internet.BinaryTempFileBody;
import com.android.email.mail.store.ImapResponseParser;
import com.android.email.mail.transport.MockTransport;
import java.util.Date;
import java.util.Locale;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import java.util.Date;
import java.util.Locale;
/**
* This is a series of unit tests for the ImapStore class. These tests must be locally
@ -117,6 +116,15 @@ public class ImapStoreUnitTests extends AndroidTestCase {
* TODO: Test small Folder functions that don't really do anything in Imap (if any)
*/
/**
* Lightweight test to confirm that IMAP hasn't implemented any folder roles yet.
*
* TODO: Test this with multiple folders provided by mock server
*/
public void testNoFolderRolesYet() {
assertEquals(Folder.FolderRole.UNKNOWN, mFolder.getRole());
}
/**
* TODO: Test the process of opening and indexing a mailbox with one unread message in it.
*/

View File

@ -312,6 +312,16 @@ public class LocalStoreUnitTests extends AndroidTestCase {
assertEquals(Email.VISIBLE_LIMIT_DEFAULT, folder2.getVisibleLimit());
}
/**
* 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());
}
}
/**
* Tests for database version.
*/

View File

@ -248,6 +248,16 @@ public class Pop3StoreUnitTests extends AndroidTestCase {
}
}
/**
* Lightweight test to confirm that POP3 hasn't implemented any folder roles yet.
*/
public void testNoFolderRolesYet() throws MessagingException {
Folder[] remoteFolders = mStore.getPersonalNamespaces();
for (Folder folder : remoteFolders) {
assertEquals(Folder.FolderRole.UNKNOWN, folder.getRole());
}
}
/**
* Test the process of opening and indexing a mailbox with one unread message in it.
*