Provisional initial commit of MessagingProvider code by

stephane.lajeunesse and koxx33

We're going to try it out in the 3.1 dev series. if it ends up looking
good, it'll be in 3.2
This commit is contained in:
Jesse Vincent 2010-08-18 02:49:13 +00:00
parent ff5024eaec
commit 0b62640eac
8 changed files with 1012 additions and 430 deletions

View File

@ -37,6 +37,18 @@
android:label="@string/remote_control_label"
android:description="@string/remote_control_desc"/>
<uses-permission android:name="com.fsck.k9.permission.REMOTE_CONTROL"/>
<permission android:name="com.fsck.k9.permission.READ_MESSAGES"
android:permissionGroup="android.permission-group.MESSAGES"
android:protectionLevel="normal"
android:label="@string/read_messages_label"
android:description="@string/read_messages_desc"/>
<uses-permission android:name="com.fsck.k9.permission.READ_MESSAGES"/>
<permission android:name="com.fsck.k9.permission.DELETE_MESSAGES"
android:permissionGroup="android.permission-group.MESSAGES"
android:protectionLevel="normal"
android:label="@string/delete_messages_label"
android:description="@string/read_messages_desc"/>
<uses-permission android:name="com.fsck.k9.permission.DELETE_MESSAGES"/>
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
@ -329,5 +341,13 @@
android:grantUriPermissions="true"
android:readPermission="com.fsck.k9.permission.READ_ATTACHMENT"
/>
<provider
android:name="com.fsck.k9.provider.MessageProvider"
android:authorities="com.fsck.k9.messageprovider"
android:multiprocess="true"
android:grantUriPermissions="true"
android:readPermission="com.fsck.k9.permission.READ_MESSAGES"
android:writePermission="com.fsck.k9.permission.DELETE_MESSAGES"
/>
</application>
</manifest>

View File

@ -10,6 +10,10 @@
<string name="read_attachment_label">read Email attachments</string>
<string name="read_attachment_desc">Allows this application to read your Email attachments.</string>
<string name="read_messages_label">read Emails</string>
<string name="read_messages_desc">Allows this application to read your Emails.</string>
<string name="delete_messages_label">Delete Emails</string>
<string name="delete_messages_desc">Allows this application to delete your Emails.</string>
<string name="about_title_fmt">About <xliff:g id="app_name">%s</xliff:g></string>
<string name="accounts_title">Accounts</string>

View File

@ -20,6 +20,7 @@ import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.BinaryTempFileBody;
import com.fsck.k9.provider.MessageProvider;
import com.fsck.k9.service.BootReceiver;
import com.fsck.k9.service.MailService;
@ -252,6 +253,7 @@ public class K9 extends Application
{
public static final String ACTION_EMAIL_RECEIVED = "com.fsck.k9.intent.action.EMAIL_RECEIVED";
public static final String ACTION_EMAIL_DELETED = "com.fsck.k9.intent.action.EMAIL_DELETED";
public static final String ACTION_REFRESH_OBSERVER = "com.fsck.k9.intent.action.REFRESH_OBSERVER";
public static final String EXTRA_ACCOUNT = "com.fsck.k9.intent.extra.ACCOUNT";
public static final String EXTRA_FOLDER = "com.fsck.k9.intent.extra.FOLDER";
public static final String EXTRA_SENT_DATE = "com.fsck.k9.intent.extra.SENT_DATE";
@ -393,6 +395,8 @@ public class K9 extends Application
K9.setK9Language(sprefs.getString("language", ""));
K9.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
MessagingController.getInstance(this).resetVisibleLimits(prefs.getAccounts());
MessageProvider mp = new MessageProvider();
mp.setApplication(this);
/*
* We have to give MimeMessage a temp directory because File.createTempFile(String, String)

View File

@ -0,0 +1,267 @@
package com.fsck.k9.activity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.text.Spannable;
import android.text.style.TextAppearanceSpan;
import android.util.Config;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.text.format.DateFormat;
import com.fsck.k9.Account;
import com.fsck.k9.AccountStats;
import com.fsck.k9.FontSizes;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.R;
import com.fsck.k9.SearchSpecification;
import com.fsck.k9.activity.setup.AccountSettings;
import com.fsck.k9.activity.setup.FolderSettings;
import com.fsck.k9.activity.setup.Prefs;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingController.SORT_TYPE;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
public class FolderInfoHolder implements Comparable<FolderInfoHolder>
{
public String name;
public String displayName;
public long lastChecked;
public int unreadMessageCount;
public int flaggedMessageCount;
public boolean loading;
public String status;
public boolean lastCheckFailed;
public Folder folder;
public boolean pushActive;
/**
* Outbox is handled differently from any other folder.
*/
public boolean outbox;
@Override
public boolean equals(Object o)
{
return this.name.equals(((FolderInfoHolder)o).name);
}
@Override
public int hashCode()
{
return name.hashCode();
}
public int compareTo(FolderInfoHolder o)
{
String s1 = this.name;
String s2 = o.name;
int ret = s1.compareToIgnoreCase(s2);
if (ret != 0)
{
return ret;
}
else
{
return s1.compareTo(s2);
}
}
private String truncateStatus(String mess)
{
if (mess != null && mess.length() > 27)
{
mess = mess.substring(0, 27);
}
return mess;
}
// constructor for an empty object for comparisons
public FolderInfoHolder()
{
}
public FolderInfoHolder(Context context, Folder folder, Account account)
{
populate(context, folder, account);
}
public FolderInfoHolder(Context context, Folder folder, Account mAccount, int unreadCount)
{
populate(context, folder, mAccount, unreadCount);
}
public void populate(Context context, Folder folder, Account mAccount, int unreadCount)
{
try
{
folder.open(Folder.OpenMode.READ_WRITE);
// unreadCount = folder.getUnreadMessageCount();
}
catch (MessagingException me)
{
Log.e(K9.LOG_TAG, "Folder.getUnreadMessageCount() failed", me);
}
this.name = folder.getName();
if (this.name.equalsIgnoreCase(K9.INBOX))
{
this.displayName = context.getString(R.string.special_mailbox_name_inbox);
}
else
{
this.displayName = folder.getName();
}
if (this.name.equals(mAccount.getOutboxFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_outbox_fmt), this.name);
this.outbox = true;
}
if (this.name.equals(mAccount.getDraftsFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_drafts_fmt), this.name);
}
if (this.name.equals(mAccount.getTrashFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_trash_fmt), this.name);
}
if (this.name.equals(mAccount.getSentFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_sent_fmt), this.name);
}
if (this.name.equals(mAccount.getArchiveFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_archive_fmt), this.name);
}
if (this.name.equals(mAccount.getSpamFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_spam_fmt), this.name);
}
this.lastChecked = folder.getLastUpdate();
String mess = truncateStatus(folder.getStatus());
this.status = mess;
this.unreadMessageCount = unreadCount;
try
{
this.flaggedMessageCount = folder.getFlaggedMessageCount();
}
catch (Exception e)
{
Log.e(K9.LOG_TAG, "Unable to get flaggedMessageCount", e);
}
folder.close();
}
public void populate(Context context, Folder folder, Account account)
{
this.folder = folder;
this.name = folder.getName();
if (this.name.equalsIgnoreCase(K9.INBOX))
{
this.displayName = context.getString(R.string.special_mailbox_name_inbox);
}
else
{
this.displayName = this.name;
}
if (this.name.equals(account.getOutboxFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_outbox_fmt), this.name);
this.outbox = true;
}
if (this.name.equals(account.getDraftsFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_drafts_fmt), this.name);
}
if (this.name.equals(account.getTrashFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_trash_fmt), this.name);
}
if (this.name.equals(account.getSentFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_sent_fmt), this.name);
}
if (this.name.equals(account.getArchiveFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_archive_fmt), this.name);
}
if (this.name.equals(account.getSpamFolderName()))
{
this.displayName = String.format(context.getString(R.string.special_mailbox_name_spam_fmt), this.name);
}
}
}

View File

@ -20,6 +20,7 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import com.fsck.k9.*;
import com.fsck.k9.Account.FolderMode;
import com.fsck.k9.activity.FolderInfoHolder;
import com.fsck.k9.activity.setup.Prefs;
import com.fsck.k9.activity.setup.AccountSettings;
import com.fsck.k9.activity.setup.FolderSettings;
@ -69,6 +70,7 @@ public class FolderList extends K9ListActivity
private int mUnreadMessageCount;
private FontSizes mFontSizes = K9.getFontSizes();
private Context context;
class FolderListHandler extends Handler
{
@ -293,6 +295,8 @@ public class FolderList extends K9ListActivity
mInflater = getLayoutInflater();
onNewIntent(getIntent());
context = this;
}
@Override
@ -776,16 +780,6 @@ public class FolderList extends K9ListActivity
menu.setHeaderTitle(folder.displayName);
}
private String truncateStatus(String mess)
{
if (mess != null && mess.length() > 27)
{
mess = mess.substring(0, 27);
}
return mess;
}
class FolderListAdapter extends BaseAdapter
{
private ArrayList<FolderInfoHolder> mFolders = new ArrayList<FolderInfoHolder>();
@ -932,11 +926,11 @@ public class FolderList extends K9ListActivity
if (holder == null)
{
holder = new FolderInfoHolder(folder, unreadMessageCount);
holder = new FolderInfoHolder(context, folder, mAccount, unreadMessageCount);
}
else
{
holder.populate(folder, unreadMessageCount);
holder.populate(context, folder, mAccount, unreadMessageCount);
}
if (folder.isInTopGroup())
@ -1039,7 +1033,7 @@ public class FolderList extends K9ListActivity
FolderInfoHolder folderHolder = getFolder(folderName);
if (folderHolder != null)
{
folderHolder.populate(localFolder, unreadMessageCount);
folderHolder.populate(context, localFolder, mAccount, unreadMessageCount);
mHandler.dataChanged();
}
}
@ -1385,147 +1379,6 @@ public class FolderList extends K9ListActivity
}
public class FolderInfoHolder implements Comparable<FolderInfoHolder>
{
public String name;
public String displayName;
public long lastChecked;
public int unreadMessageCount;
public int flaggedMessageCount;
public boolean loading;
public String status;
public boolean pushActive;
public boolean lastCheckFailed;
/**
* Outbox is handled differently from any other folder.
*/
public boolean outbox;
@Override
public boolean equals(Object o)
{
return this.name.equals(((FolderInfoHolder)o).name);
}
@Override
public int hashCode()
{
return name.hashCode();
}
public int compareTo(FolderInfoHolder o)
{
String s1 = this.name;
String s2 = o.name;
int ret = s1.compareToIgnoreCase(s2);
if (ret != 0)
{
return ret;
}
else
{
return s1.compareTo(s2);
}
}
// constructor for an empty object for comparisons
public FolderInfoHolder()
{
}
public FolderInfoHolder(Folder folder, int unreadCount)
{
populate(folder, unreadCount);
}
public void populate(Folder folder, int unreadCount)
{
try
{
folder.open(Folder.OpenMode.READ_WRITE);
// unreadCount = folder.getUnreadMessageCount();
}
catch (MessagingException me)
{
Log.e(K9.LOG_TAG, "Folder.getUnreadMessageCount() failed", me);
}
this.name = folder.getName();
if (this.name.equalsIgnoreCase(K9.INBOX))
{
this.displayName = getString(R.string.special_mailbox_name_inbox);
}
else
{
this.displayName = folder.getName();
}
if (this.name.equals(mAccount.getOutboxFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_outbox_fmt), this.name);
this.outbox = true;
}
if (this.name.equals(mAccount.getDraftsFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_drafts_fmt), this.name);
}
if (this.name.equals(mAccount.getTrashFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_trash_fmt), this.name);
}
if (this.name.equals(mAccount.getSentFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_sent_fmt), this.name);
}
if (this.name.equals(mAccount.getArchiveFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_archive_fmt), this.name);
}
if (this.name.equals(mAccount.getSpamFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_spam_fmt), this.name);
}
this.lastChecked = folder.getLastUpdate();
String mess = truncateStatus(folder.getStatus());
this.status = mess;
this.unreadMessageCount = unreadCount;
try
{
this.flaggedMessageCount = folder.getFlaggedMessageCount();
}
catch (Exception e)
{
Log.e(K9.LOG_TAG, "Unable to get flaggedMessageCount", e);
}
folder.close();
}
}
class FolderViewHolder
{
public TextView folderName;

View File

@ -0,0 +1,310 @@
package com.fsck.k9.activity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.text.Spannable;
import android.text.style.TextAppearanceSpan;
import android.util.Config;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.text.format.DateFormat;
import com.fsck.k9.Account;
import com.fsck.k9.AccountStats;
import com.fsck.k9.FontSizes;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.R;
import com.fsck.k9.SearchSpecification;
import com.fsck.k9.activity.setup.AccountSettings;
import com.fsck.k9.activity.setup.FolderSettings;
import com.fsck.k9.activity.setup.Prefs;
import com.fsck.k9.activity.FolderInfoHolder;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingController.SORT_TYPE;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
public class MessageInfoHolder implements Comparable<MessageInfoHolder>
{
public String subject;
public String date;
public String fullDate;
public Date compareDate;
public String compareSubject;
public String sender;
public String senderAddress;
public String compareCounterparty;
public String preview;
public String[] recipients;
public boolean hasAttachments;
public String uid;
public boolean read;
public boolean answered;
public boolean flagged;
public boolean downloaded;
public boolean partially_downloaded;
public Message message;
public FolderInfoHolder folder;
public boolean selected;
public String account;
public String uri;
private SORT_TYPE sortType = SORT_TYPE.SORT_DATE;
private boolean sortAscending = true;
private boolean sortDateAscending = false;
private MessagingController mController;
// Empty constructor for comparison
public MessageInfoHolder()
{
this.selected = false;
}
public MessageInfoHolder(Context context, Message m)
{
this();
Account account = m.getFolder().getAccount();
mController = MessagingController.getInstance(K9.app);
sortType = mController.getSortType();
sortAscending = mController.isSortAscending(sortType);
sortDateAscending = mController.isSortAscending(SORT_TYPE.SORT_DATE);
populate(context, m, new FolderInfoHolder(context, m.getFolder(), m.getFolder().getAccount()), account);
}
public MessageInfoHolder(Context context ,Message m, SORT_TYPE t_sort, boolean asc)
{
this();
Account account = m.getFolder().getAccount();
mController = MessagingController.getInstance(K9.app);
sortType = t_sort;
sortAscending = asc;
sortDateAscending = asc;
populate(context, m, new FolderInfoHolder(context, m.getFolder(), m.getFolder().getAccount()), account);
}
public MessageInfoHolder(Context context, Message m, FolderInfoHolder folder, Account account)
{
this();
mController = MessagingController.getInstance(K9.app);
sortType = mController.getSortType();
sortAscending = mController.isSortAscending(sortType);
sortDateAscending = mController.isSortAscending(SORT_TYPE.SORT_DATE);
populate(context, m, folder, account);
}
public void populate(Context context, Message m, FolderInfoHolder folder, Account account)
{
try
{
LocalMessage message = (LocalMessage) m;
Date date = message.getSentDate();
this.compareDate = message.getSentDate();
if (this.compareDate == null)
{
this.compareDate = message.getInternalDate();
}
this.folder = folder;
if (Utility.isDateToday(date))
{
this.date = android.text.format.DateFormat.getTimeFormat(context).format(date);
}
else
{
this.date = DateFormatter.getDateFormat(context).format(date);
}
this.hasAttachments = message.getAttachmentCount() > 0;
this.read = message.isSet(Flag.SEEN);
this.answered = message.isSet(Flag.ANSWERED);
this.flagged = message.isSet(Flag.FLAGGED);
this.downloaded = message.isSet(Flag.X_DOWNLOADED_FULL);
this.partially_downloaded = message.isSet(Flag.X_DOWNLOADED_PARTIAL);
Address[] addrs = message.getFrom();
if (addrs.length > 0 && account.isAnIdentity(addrs[0]))
{
this.compareCounterparty = Address.toFriendly(message .getRecipients(RecipientType.TO));
this.sender = String.format(context.getString(R.string.message_list_to_fmt), this.compareCounterparty);
}
else
{
this.sender = Address.toFriendly(addrs);
this.compareCounterparty = this.sender;
}
if (addrs.length > 0)
{
this.senderAddress = addrs[0].getAddress();
}
else
{
// a reasonable fallback "whomever we were corresponding with
this.senderAddress = this.compareCounterparty;
}
this.subject = message.getSubject();
this.uid = message.getUid();
this.message = m;
this.preview = message.getPreview();
this.fullDate = DateFormatter.getDateFormat(context).format(date)+" "+android.text.format.DateFormat.getTimeFormat(context).format(date);
this.account = account.getDescription();
this.uri = "email://messages/"+account.getAccountNumber()+"/"+m.getFolder().getName()+"/"+m.getUid();
}
catch (MessagingException me)
{
if (Config.LOGV)
{
Log.v(K9.LOG_TAG, "Unable to load message info", me);
}
}
}
@Override
public boolean equals(Object o)
{
if (o instanceof MessageInfoHolder == false)
{
return false;
}
MessageInfoHolder other = (MessageInfoHolder)o;
return message.equals(other.message);
}
@Override
public int hashCode()
{
return uid.hashCode();
}
public int compareTo(MessageInfoHolder o)
{
int ascender = (sortAscending ? 1 : -1);
int comparison = 0;
if (sortType == SORT_TYPE.SORT_SUBJECT)
{
if (compareSubject == null)
{
compareSubject = stripPrefixes(subject).toLowerCase();
}
if (o.compareSubject == null)
{
o.compareSubject = stripPrefixes(o.subject).toLowerCase();
}
comparison = this.compareSubject.compareTo(o.compareSubject);
}
else if (sortType == SORT_TYPE.SORT_SENDER)
{
comparison = this.compareCounterparty.toLowerCase().compareTo(o.compareCounterparty.toLowerCase());
}
else if (sortType == SORT_TYPE.SORT_FLAGGED)
{
comparison = (this.flagged ? 0 : 1) - (o.flagged ? 0 : 1);
}
else if (sortType == SORT_TYPE.SORT_UNREAD)
{
comparison = (this.read ? 1 : 0) - (o.read ? 1 : 0);
}
else if (sortType == SORT_TYPE.SORT_ATTACHMENT)
{
comparison = (this.hasAttachments ? 0 : 1) - (o.hasAttachments ? 0 : 1);
}
if (comparison != 0)
{
return comparison * ascender;
}
int dateAscender = (sortDateAscending ? 1 : -1);
return this.compareDate.compareTo(o.compareDate) * dateAscender;
}
Pattern pattern = null;
String patternString = "^ *(re|aw|fw|fwd): *";
private String stripPrefixes(String in)
{
synchronized (patternString)
{
if (pattern == null)
{
pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
}
}
Matcher matcher = pattern.matcher(in);
int lastPrefix = -1;
while (matcher.find())
{
lastPrefix = matcher.end();
}
if (lastPrefix > -1 && lastPrefix < in.length() - 1)
{
return in.substring(lastPrefix);
}
else
{
return in;
}
}
}

View File

@ -44,6 +44,7 @@ import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.text.format.DateFormat;
import com.fsck.k9.Account;
import com.fsck.k9.AccountStats;
@ -68,7 +69,8 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.fsck.k9.activity.MessageInfoHolder;
import com.fsck.k9.activity.FolderInfoHolder;
/**
* MessageList is the primary user interface for the program. This Activity
@ -159,6 +161,8 @@ public class MessageList
private Bundle mState = null;
private MessageInfoHolder mSelectedMessage = null;
private Context context = null;
class MessageListHandler
{
public void removeMessage(final List<MessageInfoHolder> messages)
@ -437,6 +441,7 @@ public class MessageList
mInflater = getLayoutInflater();
initializeLayout();
onNewIntent(getIntent());
context=this;
}
@Override
@ -2029,7 +2034,7 @@ public class MessageList
{
if (updateForMe(account, folder))
{
m = new MessageInfoHolder(message);
m = new MessageInfoHolder(context, message);
messagesToAdd.add(m);
}
else
@ -2042,7 +2047,7 @@ public class MessageList
}
else
{
m = new MessageInfoHolder(message);
m = new MessageInfoHolder(context, message);
messagesToAdd.add(m);
}
}
@ -2050,7 +2055,7 @@ public class MessageList
}
else
{
m.populate(message, new FolderInfoHolder(message.getFolder(), account), account);
m.populate(context, message, new FolderInfoHolder(context, message.getFolder(), account), account);
needsSort = true;
}
}
@ -2121,7 +2126,7 @@ public class MessageList
{
LocalStore localStore = account.getLocalStore();
local_folder = localStore.getFolder(folder);
return new FolderInfoHolder((Folder)local_folder, account);
return new FolderInfoHolder(context, (Folder)local_folder, account);
}
catch (Exception e)
{
@ -2473,213 +2478,6 @@ public class MessageList
}
}
public class MessageInfoHolder implements Comparable<MessageInfoHolder>
{
public String subject;
public String date;
public Date compareDate;
public String compareSubject;
public String sender;
public String senderAddress;
public String compareCounterparty;
public String preview;
public String[] recipients;
public boolean hasAttachments;
public String uid;
public boolean read;
public boolean answered;
public boolean flagged;
public boolean downloaded;
public boolean partially_downloaded;
public Message message;
public FolderInfoHolder folder;
public boolean selected;
// Empty constructor for comparison
public MessageInfoHolder()
{
this.selected = false;
}
public MessageInfoHolder(Message m)
{
this();
Account account = m.getFolder().getAccount();
populate(m, new FolderInfoHolder(m.getFolder(), m.getFolder().getAccount()), account);
}
public MessageInfoHolder(Message m, FolderInfoHolder folder, Account account)
{
this();
populate(m, folder, account);
}
public void populate(Message m, FolderInfoHolder folder, Account account)
{
try
{
LocalMessage message = (LocalMessage) m;
Date date = message.getSentDate();
this.compareDate = message.getSentDate();
if (this.compareDate == null)
{
this.compareDate = message.getInternalDate();
}
this.folder = folder;
if (Utility.isDateToday(date))
{
this.date = getTimeFormat().format(date);
}
else
{
this.date = getDateFormat().format(date);
}
this.hasAttachments = message.getAttachmentCount() > 0;
this.read = message.isSet(Flag.SEEN);
this.answered = message.isSet(Flag.ANSWERED);
this.flagged = message.isSet(Flag.FLAGGED);
this.downloaded = message.isSet(Flag.X_DOWNLOADED_FULL);
this.partially_downloaded = message.isSet(Flag.X_DOWNLOADED_PARTIAL);
Address[] addrs = message.getFrom();
if (addrs.length > 0 && account.isAnIdentity(addrs[0]))
{
this.compareCounterparty = Address.toFriendly(message .getRecipients(RecipientType.TO));
this.sender = String.format(getString(R.string.message_list_to_fmt), this.compareCounterparty);
}
else
{
this.sender = Address.toFriendly(addrs);
this.compareCounterparty = this.sender;
}
if (addrs.length > 0)
{
this.senderAddress = addrs[0].getAddress();
}
else
{
// a reasonable fallback "whomever we were corresponding with
this.senderAddress = this.compareCounterparty;
}
this.subject = message.getSubject();
this.uid = message.getUid();
this.message = m;
this.preview = message.getPreview();
}
catch (MessagingException me)
{
if (Config.LOGV)
{
Log.v(K9.LOG_TAG, "Unable to load message info", me);
}
}
}
@Override
public boolean equals(Object o)
{
if (o instanceof MessageInfoHolder == false)
{
return false;
}
MessageInfoHolder other = (MessageInfoHolder)o;
return message.equals(other.message);
}
@Override
public int hashCode()
{
return uid.hashCode();
}
@Override
public int compareTo(MessageInfoHolder o)
{
int ascender = (sortAscending ? 1 : -1);
int comparison = 0;
if (sortType == SORT_TYPE.SORT_SUBJECT)
{
if (compareSubject == null)
{
compareSubject = stripPrefixes(subject).toLowerCase();
}
if (o.compareSubject == null)
{
o.compareSubject = stripPrefixes(o.subject).toLowerCase();
}
comparison = this.compareSubject.compareTo(o.compareSubject);
}
else if (sortType == SORT_TYPE.SORT_SENDER)
{
comparison = this.compareCounterparty.toLowerCase().compareTo(o.compareCounterparty.toLowerCase());
}
else if (sortType == SORT_TYPE.SORT_FLAGGED)
{
comparison = (this.flagged ? 0 : 1) - (o.flagged ? 0 : 1);
}
else if (sortType == SORT_TYPE.SORT_UNREAD)
{
comparison = (this.read ? 1 : 0) - (o.read ? 1 : 0);
}
else if (sortType == SORT_TYPE.SORT_ATTACHMENT)
{
comparison = (this.hasAttachments ? 0 : 1) - (o.hasAttachments ? 0 : 1);
}
if (comparison != 0)
{
return comparison * ascender;
}
int dateAscender = (sortDateAscending ? 1 : -1);
return this.compareDate.compareTo(o.compareDate) * dateAscender;
}
Pattern pattern = null;
String patternString = "^ *(re|aw|fw|fwd): *";
private String stripPrefixes(String in)
{
synchronized (patternString)
{
if (pattern == null)
{
pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
}
}
Matcher matcher = pattern.matcher(in);
int lastPrefix = -1;
while (matcher.find())
{
lastPrefix = matcher.end();
}
if (lastPrefix > -1 && lastPrefix < in.length() - 1)
{
return in.substring(lastPrefix);
}
else
{
return in;
}
}
}
class MessageViewHolder
implements OnCheckedChangeListener
{
@ -2791,70 +2589,6 @@ public class MessageList
public TextView main;
}
public class FolderInfoHolder
{
public String name;
public String displayName;
public boolean loading;
public boolean lastCheckFailed;
public Folder folder;
/**
* Outbox is handled differently from any other folder.
*/
public boolean outbox;
public FolderInfoHolder(Folder folder, Account account)
{
populate(folder, account);
}
public void populate(Folder folder, Account account)
{
this.folder = folder;
this.name = folder.getName();
if (this.name.equalsIgnoreCase(K9.INBOX))
{
this.displayName = getString(R.string.special_mailbox_name_inbox);
}
else
{
this.displayName = this.name;
}
if (this.name.equals(account.getOutboxFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_outbox_fmt), this.name);
this.outbox = true;
}
if (this.name.equals(account.getDraftsFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_drafts_fmt), this.name);
}
if (this.name.equals(account.getTrashFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_trash_fmt), this.name);
}
if (this.name.equals(account.getSentFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_sent_fmt), this.name);
}
if (this.name.equals(account.getArchiveFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_archive_fmt), this.name);
}
if (this.name.equals(account.getSpamFolderName()))
{
this.displayName = String.format(getString(R.string.special_mailbox_name_spam_fmt), this.name);
}
}
}
private boolean computeBatchDirection(boolean flagged)
{

View File

@ -0,0 +1,390 @@
package com.fsck.k9.provider;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Date;
import java.text.SimpleDateFormat;
import android.app.Application;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.Resources;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;
import android.os.Bundle;
import android.util.Config;
import android.text.format.DateFormat;
import android.provider.Settings;
import android.content.Intent;
import com.fsck.k9.Account;
import com.fsck.k9.AccountStats;
import com.fsck.k9.K9;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.Preferences;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.SearchAccount;
import com.fsck.k9.Account;
import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.R;
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.fsck.k9.AccountStats;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.controller.MessagingController.SORT_TYPE;
import com.fsck.k9.activity.DateFormatter;
import com.fsck.k9.activity.MessageInfoHolder;
import com.fsck.k9.controller.MessagingController.SORT_TYPE;
public class MessageProvider extends ContentProvider
{
public static final String AUTHORITY = "com.fsck.k9.messageprovider";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final int URI_INBOX_MESSAGES = 0;
private static final int URI_DELETE_MESSAGE = 1;
private static final int URI_ACCOUNTS = 2;
private static final int URI_ACCOUNT_UNREAD = 3;
private static String mCurrentEmailAccount = "";
private static Context context = null;
private static boolean mIsListenerRegister = false;
private static boolean inSync = false;
private static Application mApp;
private List<MessageInfoHolder> glb_messages;
private static MatrixCursor mCursor;
static
{
URI_MATCHER.addURI(AUTHORITY, "inbox_messages/", URI_INBOX_MESSAGES);
URI_MATCHER.addURI(AUTHORITY, "delete_message/", URI_DELETE_MESSAGE);
URI_MATCHER.addURI(AUTHORITY, "accounts", URI_ACCOUNTS);
URI_MATCHER.addURI(AUTHORITY, "account_unread/#", URI_ACCOUNT_UNREAD);
}
static String[] messages_projection = new String[]
{
"id",
"date",
"sender",
"subject",
"preview",
"account",
"uri",
"delUri"
};
MessagingListener mListener = new MessagingListener()
{
public void messageDeleted(Account account, String folder, Message message)
{
}
public void folderStatusChanged(Account account, String folderName, int unreadMessageCount)
{
if (inSync == false)
{
inSync = true;
glb_messages = new ArrayList<MessageInfoHolder>();
SearchAccount integratedInboxAccount = new SearchAccount(getContext(), true, null, null);
MessagingController msgController = MessagingController.getInstance(mApp);
msgController.searchLocalMessages(integratedInboxAccount, null, mListener);
}
}
public void listLocalMessagesStarted(Account account, String folder)
{
}
public void listLocalMessagesFinished(Account account, String folder)
{
}
public void searchStats(AccountStats stats)
{
int id = -1;
Collections.sort(glb_messages);
MatrixCursor tmpCur = new MatrixCursor(messages_projection);
for (MessageInfoHolder mi : glb_messages)
{
++id;
Message msg = mi.message;
tmpCur.addRow(new Object[] {id,mi.fullDate,mi.sender,mi.subject,mi.preview,mi.account,mi.uri,CONTENT_URI+"/delete_message/"+msg.getFolder().getAccount().getAccountNumber()+"/"+msg.getFolder().getName()+"/"+msg.getUid()});
}
mCursor = tmpCur;
inSync=false;
notifyDatabaseModification();
}
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages)
{
// We will by default sort by DATE desc
SORT_TYPE t_sort = SORT_TYPE.SORT_DATE;
for (Message m : messages)
{
MessageInfoHolder m1 = new MessageInfoHolder(context,m,t_sort,false);
glb_messages.add(m1);
}
}
};
public Cursor getAllAccounts()
{
String[] projection = new String[] { "accountNumber", "accountName" };
MatrixCursor ret = new MatrixCursor(projection);
for (Account account : Preferences.getPreferences(getContext()).getAccounts())
{
Object[] values = new Object[2];
values[0] = account.getAccountNumber();
values[1] = account.getDescription();
ret.addRow(values);
}
return ret;
}
public Cursor getAccountUnread(int accountNumber)
{
String[] projection = new String[] { "accountName", "unread" };
MatrixCursor ret = new MatrixCursor(projection);
Account myAccount;
AccountStats myAccountStats = null;
Object[] values = new Object[2];
for (Account account : Preferences.getPreferences(getContext()).getAccounts())
{
if (account.getAccountNumber()==accountNumber)
{
myAccount = account;
try
{
myAccountStats = account.getStats(getContext());
values[0] = myAccount.getDescription();
values[1] = myAccountStats.unreadMessageCount;
ret.addRow(values);
}
catch (MessagingException e)
{
Log.e(K9.LOG_TAG, e.getMessage());
values[0] = "Unknown";
values[1] = 0;
}
}
}
return ret;
}
public void setApplication(Application app)
{
if (app != null)
{
mApp = app;
MessagingController msgController = MessagingController.getInstance(mApp);
if ((msgController != null) && (!mIsListenerRegister))
{
msgController.addListener(mListener);
mIsListenerRegister = true;
}
}
}
@Override
public boolean onCreate()
{
context = getContext();
if (mApp != null)
{
MessagingController msgController = MessagingController.getInstance(mApp);
if ((msgController != null) && (!mIsListenerRegister))
{
msgController.addListener(mListener);
mIsListenerRegister = true;
}
}
return false;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "delete");
if (mApp == null)
{
Log.d(K9.LOG_TAG, "K9 not ready");
return 0;
}
// Nota : can only delete a message
List<String> segments = null;
int accountId = -1;
String folderName = null;
String msgUid = null;
segments = uri.getPathSegments();
accountId = Integer.parseInt(segments.get(1));
folderName = segments.get(2);
msgUid = segments.get(3);
// get account
Account myAccount = null;
for (Account account : Preferences.getPreferences(getContext()).getAccounts())
{
if (account.getAccountNumber() == accountId)
{
myAccount = account;
}
}
// get localstore parameter
Message msg = null;
try
{
Folder lf = LocalStore.getLocalInstance(myAccount, mApp).getFolder(folderName);
int msgCount = lf.getMessageCount();
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "folder msg count = " + msgCount);
msg = lf.getMessage(msgUid);
}
catch (MessagingException e)
{
Log.e(K9.LOG_TAG, e.getMessage());
}
// launch command to delete the message
if ((myAccount != null) && (msg != null))
{
MessagingController.getInstance(mApp).deleteMessages(new Message[] { msg }, mListener);
}
return 0;
}
@Override
public String getType(Uri uri)
{
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values)
{
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "query");
if (mApp == null)
{
Log.d(K9.LOG_TAG, "K9 not ready");
return null;
}
Cursor cursor;
switch (URI_MATCHER.match(uri))
{
case URI_INBOX_MESSAGES:
if (mCursor == null)
{
mCursor = new MatrixCursor(messages_projection);
// new code for integrated inbox, only execute this once as it will be processed afterwards via the listener
glb_messages = new ArrayList<MessageInfoHolder>();
SearchAccount integratedInboxAccount = new SearchAccount(getContext(), true, null, null);
MessagingController msgController = MessagingController.getInstance(mApp);
msgController.searchLocalMessages(integratedInboxAccount, null, mListener);
}
int id = -1;
// Process messages
//cursor = getAllMessages(projection, selection, selectionArgs, sortOrder);
cursor = (Cursor)mCursor;
break;
case URI_ACCOUNTS:
cursor = getAllAccounts();
break;
case URI_ACCOUNT_UNREAD:
List<String> segments = null;
int accountId = -1;
segments = uri.getPathSegments();
accountId = Integer.parseInt(segments.get(1));
cursor = getAccountUnread(accountId);
break;
default:
throw new IllegalStateException("Unrecognized URI:" + uri);
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "update");
//TBD
return 0;
}
public static void notifyDatabaseModification()
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "notifyDatabaseModification -> UPDATE");
Intent intent = new Intent(K9.Intents.EmailReceived.ACTION_REFRESH_OBSERVER, null);
context.sendBroadcast(intent);
context.getContentResolver().notifyChange(CONTENT_URI, null);
}
}