Correct from.
Change-Id: I5c4f10fbc1079c8a465fe864dd983c49f5a01139
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index a7a0e2c..3c67ee6 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -83,6 +83,8 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import org.json.JSONException;
+
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
@@ -368,7 +370,7 @@
// Update the from spinner as other accounts
// may now be available.
if (mFromSpinner != null && mAccount != null) {
- mFromSpinner.asyncInitFromSpinner();
+ mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount);
}
}
@@ -416,29 +418,140 @@
}
private void initFromSpinner(int action) {
- mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
- mAccount.name, true, false);
- if (action == COMPOSE ||
- (action == EDIT_DRAFT
- && mDraft.draftType == UIProvider.DraftType.COMPOSE)) {
- mFromSpinner.setCurrentAccount(mReplyFromAccount);
- mFromSpinner.asyncInitFromSpinner();
- boolean showSpinner = mFromSpinner.getCount() > 1;
+ if (action == EDIT_DRAFT &&
+ mDraft.draftType == UIProvider.DraftType.COMPOSE) {
+ action = COMPOSE;
+ }
+ mFromSpinner.asyncInitFromSpinner(action, mAccount);
+ if (mDraft != null) {
+ mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
+ } else if (mRefMessage != null) {
+ mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
+ }
+ if (mReplyFromAccount == null) {
+ mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
+ mAccount.name, true, false);
+ }
+ mFromSpinner.setCurrentAccount(mReplyFromAccount);
+ if (mFromSpinner.getCount() > 1) {
// If there is only 1 account, just show that account.
// Otherwise, give the user the ability to choose which account to
- // send
- // mail from / save drafts to.
- mFromStatic.setVisibility(showSpinner ? View.GONE : View.VISIBLE);
+ // send mail from / save drafts to.
+ mFromStatic.setVisibility(View.GONE);
mFromStaticText.setText(mAccount.name);
- mFromSpinnerWrapper.setVisibility(showSpinner ? View.VISIBLE : View.GONE);
+ mFromSpinnerWrapper.setVisibility(View.VISIBLE);
} else {
mFromStatic.setVisibility(View.VISIBLE);
mFromStaticText.setText(mAccount.name);
mFromSpinnerWrapper.setVisibility(View.GONE);
- mFromSpinner.setCurrentAccount(mReplyFromAccount);
}
}
+ private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
+ if (refMessage.accountUri != null) {
+ // This must be from combined inbox.
+ List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
+ for (ReplyFromAccount from : replyFromAccounts) {
+ if (from.account.uri.equals(refMessage.accountUri)) {
+ return from;
+ }
+ }
+ return null;
+ } else {
+ return getReplyFromAccount(account, refMessage);
+ }
+ }
+
+ /**
+ * Given an account and which email address the message was sent to,
+ * return who the message should be sent from.
+ * @param account Account in which the message arrived.
+ * @param sentTo Email address to which the message was sent.
+ * @return the address from which to reply.
+ */
+ public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
+ // First see if we are supposed to use the default address or
+ // the address it was sentTo.
+ if (false) { //mCachedSettings.forceReplyFromDefault) {
+ return getDefaultReplyFromAccount(account);
+ } else {
+ // If we aren't explicityly told which account to look for, look at
+ // all the message recipients and find one that matches
+ // a custom from or account.
+ List<String> allRecipients = new ArrayList<String>();
+ allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.to)));
+ allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.cc)));
+ return getMatchingRecipient(account, allRecipients);
+ }
+ }
+
+ /**
+ * Compare all the recipients of an email to the current account and all
+ * custom addresses associated with that account. Return the match if there
+ * is one, or the default account if there isn't.
+ */
+ protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
+ // Tokenize the list and place in a hashmap.
+ ReplyFromAccount matchingReplyFrom = null;
+ Rfc822Token[] tokens;
+ HashSet<String> recipientsMap = new HashSet<String>();
+ for (String address : sentTo) {
+ tokens = Rfc822Tokenizer.tokenize(address);
+ for (int i = 0; i < tokens.length; i++) {
+ recipientsMap.add(tokens[i].getAddress());
+ }
+ }
+
+ int matchingAddressCount = 0;
+ List<ReplyFromAccount> customFroms;
+ try {
+ customFroms = FromAddressSpinner.getAccountSpecificFroms(account);
+ if (customFroms != null) {
+ for (ReplyFromAccount entry : customFroms) {
+ if (recipientsMap.contains(entry.address)) {
+ matchingReplyFrom = entry;
+ matchingAddressCount++;
+ }
+ }
+ }
+ } catch (JSONException e) {
+ LogUtils.wtf(LOG_TAG, "Exception parsing from addresses for account %s",
+ account.name);
+ }
+ if (matchingAddressCount > 1) {
+ matchingReplyFrom = getDefaultReplyFromAccount(account);
+ }
+ return matchingReplyFrom;
+ }
+
+ private ReplyFromAccount getDefaultReplyFromAccount(Account account) {
+ List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
+ for (ReplyFromAccount from : replyFromAccounts) {
+ if (from.isDefault) {
+ return from;
+ }
+ }
+ return new ReplyFromAccount(account, account.uri, account.name, account.name, true, false);
+ }
+
+ private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message draft) {
+ String sender = draft.from;
+ ReplyFromAccount replyFromAccount = null;
+ List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
+ if (TextUtils.equals(account.name, sender)) {
+ replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
+ mAccount.name, true, false);
+ } else {
+ for (ReplyFromAccount fromAccount : replyFromAccounts) {
+ if (TextUtils.equals(fromAccount.name, sender)) {
+ replyFromAccount = fromAccount;
+ break;
+ }
+ }
+ }
+ return replyFromAccount;
+ }
+
private void findViews() {
mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
if (mCcBccButton != null) {
diff --git a/src/com/android/mail/compose/FromAddressSpinner.java b/src/com/android/mail/compose/FromAddressSpinner.java
index da25bca..8b91c1a 100644
--- a/src/com/android/mail/compose/FromAddressSpinner.java
+++ b/src/com/android/mail/compose/FromAddressSpinner.java
@@ -26,6 +26,8 @@
import com.android.mail.providers.Account;
import com.android.mail.providers.ReplyFromAccount;
import com.android.mail.utils.AccountUtils;
+import com.android.mail.utils.LogUtils;
+import com.google.common.collect.ImmutableList;
import org.json.JSONArray;
import org.json.JSONException;
@@ -39,6 +41,7 @@
private ReplyFromAccount mAccount;
private List<ReplyFromAccount> mReplyFromAccounts;
private OnAccountChangedListener mAccountChangedListener;
+ private static final String LOG_TAG = new LogUtils().getLogTag();
public FromAddressSpinner(Context context) {
this(context, null);
@@ -50,16 +53,34 @@
public void setCurrentAccount(ReplyFromAccount account) {
mAccount = account;
+ int currentIndex = 0;
+ for (ReplyFromAccount acct : mReplyFromAccounts) {
+ if (mAccount.name.equals(acct.account.name)) {
+ setSelection(currentIndex);
+ break;
+ }
+ currentIndex++;
+ }
}
public ReplyFromAccount getCurrentAccount() {
return mAccount;
}
- public void asyncInitFromSpinner() {
- Account[] result = AccountUtils.getSyncingAccounts(getContext());
- mAccounts = AccountUtils.mergeAccountLists(mAccounts, result,
- true /* prioritizeAccountList */);
+ /**
+ * @param action Action being performed; if this is COMPOSE, show all
+ * accounts. Otherwise, show just the account this was launched
+ * with.
+ * @param currentAccount Account used to launch activity.
+ */
+ public void asyncInitFromSpinner(int action, Account currentAccount) {
+ if (action == ComposeActivity.COMPOSE) {
+ Account[] result = AccountUtils.getSyncingAccounts(getContext());
+ mAccounts = AccountUtils
+ .mergeAccountLists(mAccounts, result, true /* prioritizeAccountList */);
+ } else {
+ mAccounts = ImmutableList.of(currentAccount);
+ }
initFromSpinner();
}
@@ -72,41 +93,46 @@
return;
}
FromAddressSpinnerAdapter adapter = new FromAddressSpinnerAdapter(getContext());
- int currentAccountIndex = 0;
mReplyFromAccounts = new ArrayList<ReplyFromAccount>();
for (Account account : mAccounts) {
- ReplyFromAccount replyFrom = new ReplyFromAccount(account, account.uri, account.name,
- account.name, false, false);
- if (replyFrom != null) {
- mReplyFromAccounts.add(replyFrom);
+ try {
+ mReplyFromAccounts.addAll(getAccountSpecificFroms(account));
+ } catch (JSONException e) {
+ LogUtils.wtf(LOG_TAG, "Failed parsing from addresses associated with account %s",
+ account.name);
}
- if (!TextUtils.isEmpty(account.accountFromAddresses)) {
- // Parse and create an entry for each.
- try {
- JSONArray accounts = new JSONArray(account.accountFromAddresses);
- JSONObject accountString;
- for (int i = 0; i < accounts.length(); i++) {
- accountString = (JSONObject) accounts.get(i);
- ReplyFromAccount a = ReplyFromAccount.deserialize(account, accountString);
- if (a != null) {
- mReplyFromAccounts.add(a);
- }
- }
- } catch (JSONException e) {
+ }
+ adapter.addAccounts(mReplyFromAccounts);
+ setAdapter(adapter);
+ setOnItemSelectedListener(this);
+ }
+
+ public static List<ReplyFromAccount> getAccountSpecificFroms(Account account)
+ throws JSONException {
+ List<ReplyFromAccount> froms = new ArrayList<ReplyFromAccount>();
+ ReplyFromAccount replyFrom = new ReplyFromAccount(account, account.uri, account.name,
+ account.name, false, false);
+ if (replyFrom != null) {
+ froms.add(replyFrom);
+ }
+ if (!TextUtils.isEmpty(account.accountFromAddresses)) {
+ JSONArray accounts = new JSONArray(account.accountFromAddresses);
+ JSONObject accountString;
+ for (int i = 0; i < accounts.length(); i++) {
+ accountString = (JSONObject) accounts.get(i);
+ ReplyFromAccount a = ReplyFromAccount.deserialize(account, accountString);
+ if (a != null) {
+ froms.add(a);
}
}
}
- currentAccountIndex = adapter.addAccounts(mAccount, mReplyFromAccounts);
+ return froms;
+ }
- setAdapter(adapter);
- setSelection(currentAccountIndex, false);
- setOnItemSelectedListener(this);
- if (currentAccountIndex >= mReplyFromAccounts.size()) {
- currentAccountIndex = 0;
- }
- mAccount = mReplyFromAccounts.get(currentAccountIndex);
+ public List<ReplyFromAccount> getReplyFromAccounts() {
+ return mReplyFromAccounts;
}
public void setOnAccountChangedListener(OnAccountChangedListener listener) {
diff --git a/src/com/android/mail/compose/FromAddressSpinnerAdapter.java b/src/com/android/mail/compose/FromAddressSpinnerAdapter.java
index 448a750..e5d0b81 100644
--- a/src/com/android/mail/compose/FromAddressSpinnerAdapter.java
+++ b/src/com/android/mail/compose/FromAddressSpinnerAdapter.java
@@ -75,21 +75,11 @@
return fromEntry;
}
- public int addAccounts(ReplyFromAccount selectedAccount,
- List<ReplyFromAccount> replyFromAccounts) {
- int currentIndex = 0;
- int currentAccountIndex = 0;
+ public void addAccounts(List<ReplyFromAccount> replyFromAccounts) {
// Get the position of the current account
for (ReplyFromAccount account : replyFromAccounts) {
// Add the account to the Adapter
add(account);
- // See if we have located the selected account.
- if (selectedAccount.name.equals(account.name)) {
- currentAccountIndex = currentIndex;
- }
-
- currentIndex++;
}
- return currentAccountIndex;
}
}
diff --git a/src/com/android/mail/providers/Message.java b/src/com/android/mail/providers/Message.java
index 0859a1c..b149549 100644
--- a/src/com/android/mail/providers/Message.java
+++ b/src/com/android/mail/providers/Message.java
@@ -64,6 +64,7 @@
public boolean starred;
public int quotedTextOffset;
public String attachmentsJson;
+ public Uri accountUri;
private transient String[] mToAddresses = null;
private transient String[] mCcAddresses = null;
@@ -126,6 +127,7 @@
dest.writeInt(alwaysShowImages ? 1 : 0);
dest.writeInt(quotedTextOffset);
dest.writeString(attachmentsJson);
+ dest.writeParcelable(accountUri, 0);
}
private Message(Parcel in) {
@@ -156,6 +158,7 @@
alwaysShowImages = in.readInt() != 0;
quotedTextOffset = in.readInt();
attachmentsJson = in.readString();
+ accountUri = in.readParcelable(null);
}
public Message() {
@@ -227,6 +230,8 @@
starred = cursor.getInt(UIProvider.MESSAGE_STARRED_COLUMN) != 0;
quotedTextOffset = cursor.getInt(UIProvider.QUOTED_TEXT_OFFSET_COLUMN);
attachmentsJson = cursor.getString(UIProvider.MESSAGE_ATTACHMENTS_COLUMN);
+ String accountUriString = cursor.getString(UIProvider.MESSAGE_ACCOUNT_URI_COLUMN);
+ accountUri = !TextUtils.isEmpty(accountUriString) ? Uri.parse(accountUriString) : null;
}
}
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 4fb30c0..2b5e745 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -884,7 +884,8 @@
MessageColumns.STARRED,
MessageColumns.QUOTE_START_POS,
MessageColumns.ATTACHMENTS,
- MessageColumns.CUSTOM_FROM_ADDRESS
+ MessageColumns.CUSTOM_FROM_ADDRESS,
+ MessageColumns.MESSAGE_ACCOUNT_URI
};
/** Separates attachment info parts in strings in a message. */
@@ -924,6 +925,7 @@
public static final int QUOTED_TEXT_OFFSET_COLUMN = 27;
public static final int MESSAGE_ATTACHMENTS_COLUMN = 28;
public static final int MESSAGE_CUSTOM_FROM_ADDRESS_COLUMN = 29;
+ public static final int MESSAGE_ACCOUNT_URI_COLUMN = 30;
public static final class CursorStatus {
@@ -1103,7 +1105,11 @@
*/
public static final String ATTACHMENTS = "attachments";
public static final String CUSTOM_FROM_ADDRESS = "customFrom";
-
+ /**
+ * Uri of the account associated with this message. Except in the case
+ * of showing a combined view, this column is almost always empty.
+ */
+ public static final String MESSAGE_ACCOUNT_URI = "messageAccountUri";
private MessageColumns() {}
}