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() {}
     }