Merge "Add from accounts dropdown."
diff --git a/res/layout/compose_from.xml b/res/layout/compose_from.xml
index 154ff31..92ee5cb 100644
--- a/res/layout/compose_from.xml
+++ b/res/layout/compose_from.xml
@@ -24,7 +24,8 @@
     <LinearLayout android:id="@+id/spinner_from_content"
         style="@style/RecipientComposeFieldLayout"
         android:background="@android:color/transparent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:visibility="gone">
 
         <Spinner android:id="@+id/from_picker"
             android:layout_width="match_parent"
diff --git a/res/layout/from_dropdown_item.xml b/res/layout/from_dropdown_item.xml
new file mode 100644
index 0000000..934f22d
--- /dev/null
+++ b/res/layout/from_dropdown_item.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2011 Google Inc.
+     Licensed to 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent">
+
+    <TextView
+        android:id="@+id/spinner_account_name"
+        android:singleLine="true"
+        android:layout_width="wrap_content"
+        android:layout_height="?android:attr/listPreferredItemHeight"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:layout_weight="1"
+        android:ellipsize="end"
+        android:paddingLeft="8dip"
+        android:gravity="center_vertical" />
+
+</LinearLayout>
diff --git a/res/layout/from_item.xml b/res/layout/from_item.xml
new file mode 100644
index 0000000..56662da
--- /dev/null
+++ b/res/layout/from_item.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2011 Google Inc.
+     Licensed to 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/spinner_account_name"
+    android:layout_width="wrap_content"
+    android:layout_height="48dip"
+    android:singleLine="true"
+    android:ellipsize="end"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:paddingLeft="8dip"
+    android:gravity="center_vertical"/>
\ No newline at end of file
diff --git a/src/com/android/email/compose/ComposeActivity.java b/src/com/android/email/compose/ComposeActivity.java
index f3ea16d..37ac859 100644
--- a/src/com/android/email/compose/ComposeActivity.java
+++ b/src/com/android/email/compose/ComposeActivity.java
@@ -41,9 +41,12 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.Spinner;
 import android.widget.TextView;
 
 import com.android.common.Rfc822Validator;
@@ -52,6 +55,7 @@
 import com.android.email.providers.Attachment;
 import com.android.email.providers.protos.mock.MockAttachment;
 import com.android.email.R;
+import com.android.email.utils.AccountUtils;
 import com.android.email.utils.MimeType;
 import com.android.email.utils.Utils;
 import com.android.ex.chips.RecipientEditTextView;
@@ -61,12 +65,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 
 public class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
-        RespondInlineListener {
+        RespondInlineListener, OnItemSelectedListener {
     // Identifiers for which type of composition this is
     static final int COMPOSE = -1;  // also used for editing a draft
     static final int REPLY = 0;
@@ -122,6 +127,14 @@
     private boolean mAttachmentsChanged;
     private QuotedTextView mQuotedTextView;
     private TextView mBodyText;
+    private View mFromStatic;
+    private View mFromSpinner;
+    private Spinner mFrom;
+    private List<String[]> mReplyFromAccounts;
+    private boolean mAccountSpinnerReady;
+    private String[] mCurrentReplyFromAccount;
+    private boolean mMessageIsForwardOrReply;
+    private List<String> mAccounts;
 
     /**
      * Can be called from a non-UI thread.
@@ -174,13 +187,123 @@
         findViews();
         Intent intent = getIntent();
         int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
-        initActionBar(action);
         if (action == REPLY || action == REPLY_ALL || action == FORWARD) {
             mRefMessageUri = Uri.parse(intent.getStringExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI));
             initFromRefMessage(action, mAccount);
         } else {
             setQuotedTextVisibility(false);
         }
+        initActionBar(action);
+        asyncInitFromSpinner();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        // Update the from spinner as other accounts
+        // may now be available.
+        asyncInitFromSpinner();
+    }
+
+    private void asyncInitFromSpinner() {
+        Account[] result = AccountUtils.getSyncingAccounts(this, null, null, null);
+        mAccounts = AccountUtils
+                .mergeAccountLists(mAccounts, result, true /* prioritizeAccountList */);
+        createReplyFromCache();
+        initFromSpinner();
+    }
+
+    /**
+     * Create a cache of all accounts a user could send mail from
+     */
+    private void createReplyFromCache() {
+        // Check for replyFroms.
+        List<String> accounts = null;
+        mReplyFromAccounts = new ArrayList<String[]>();
+
+        if (mMessageIsForwardOrReply) {
+            accounts = Collections.singletonList(mAccount);
+        } else {
+            accounts = mAccounts;
+        }
+        for (String account : accounts) {
+            // First add the account. First position is account, second
+            // is display of account, 3rd position is the REAL account this
+            // is being sent from / synced to.
+            mReplyFromAccounts.add(new String[] {
+                    account, account, account, "false"
+            });
+        }
+    }
+
+    private void initFromSpinner() {
+        // If there are not yet any accounts in the cached synced accounts
+        // because this is the first time Gmail was opened, and it was opened directly
+        // to the compose activity,don't bother populating the reply from spinner yet.
+        if (mReplyFromAccounts == null || mReplyFromAccounts.size() == 0) {
+            mAccountSpinnerReady = false;
+            return;
+        }
+        FromAddressSpinnerAdapter adapter = new FromAddressSpinnerAdapter(this);
+        int currentAccountIndex = 0;
+        String replyFromAccount = mAccount;
+
+        boolean checkRealAccount = mRecipient == null || mAccount.equals(mRecipient);
+
+        currentAccountIndex = addAccountsToAdapter(adapter, checkRealAccount, replyFromAccount);
+
+        mFrom.setAdapter(adapter);
+        mFrom.setSelection(currentAccountIndex, false);
+        mFrom.setOnItemSelectedListener(this);
+        mCurrentReplyFromAccount = mReplyFromAccounts.get(currentAccountIndex);
+
+        hideOrShowFromSpinner();
+        mAccountSpinnerReady = true;
+        adapter.setSpinner(mFrom);
+    }
+
+    private void hideOrShowFromSpinner() {
+        // Determine whether the from account spinner or the static
+        // from text should be show
+        // When the spinner is shown, the static from text
+        // is hidden
+        showFromSpinner(mFrom.getCount() > 1);
+    }
+
+    private int addAccountsToAdapter(FromAddressSpinnerAdapter adapter, boolean checkRealAccount,
+            String replyFromAccount) {
+        int currentIndex = 0;
+        int currentAccountIndex = 0;
+        // Get the position of the current account
+        for (String[] account : mReplyFromAccounts) {
+            // Add the account to the Adapter
+            // The reason that we are not adding the Account array, but adding
+            // the names of each account, is because Account returns a string
+            // that we don't want to display on toString()
+            adapter.add(account);
+            // Compare to the account address, not the real account being
+            // sent from.
+            if (checkRealAccount) {
+                // Need to check the real account and the account address
+                // so that we can send from the correct address on the
+                // correct account when the same address may exist across
+                // multiple accounts.
+                if (account[FromAddressSpinnerAdapter.REAL_ACCOUNT].equals(mAccount)
+                        && account[FromAddressSpinnerAdapter.ACCOUNT_ADDRESS]
+                                .equals(replyFromAccount)) {
+                    currentAccountIndex = currentIndex;
+                }
+            } else {
+                // Just need to check the account address.
+                if (replyFromAccount.equals(
+                        account[FromAddressSpinnerAdapter.ACCOUNT_ADDRESS])) {
+                    currentAccountIndex = currentIndex;
+                }
+            }
+
+            currentIndex++;
+        }
+        return currentAccountIndex;
     }
 
     private void findViews() {
@@ -197,6 +320,23 @@
         mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
         mQuotedTextView.setRespondInlineListener(this);
         mBodyText = (TextView) findViewById(R.id.body);
+        mFromStatic = findViewById(R.id.static_from_content);
+        mFromSpinner = findViewById(R.id.spinner_from_content);
+        mFrom = (Spinner) findViewById(R.id.from_picker);
+    }
+
+    /**
+     * Show the static from text view or the spinner
+     * @param showSpinner Whether the spinner should be shown
+     */
+    private void showFromSpinner(boolean showSpinner) {
+        // show/hide the static text
+        mFromStatic.setVisibility(
+                showSpinner ? View.GONE : View.VISIBLE);
+
+        // show/hide the spinner
+        mFromSpinner.setVisibility(
+                showSpinner ? View.VISIBLE : View.GONE);
     }
 
     private void setQuotedTextVisibility(boolean show) {
@@ -478,4 +618,14 @@
     public void setBody(CharSequence text, boolean withSignature) {
         mBodyText.setText(text);
     }
+
+    @Override
+    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+        // TODO
+    }
+
+    @Override
+    public void onNothingSelected(AdapterView<?> parent) {
+        // Do nothing.
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/email/compose/FromAddressSpinnerAdapter.java b/src/com/android/email/compose/FromAddressSpinnerAdapter.java
new file mode 100644
index 0000000..d9c0872
--- /dev/null
+++ b/src/com/android/email/compose/FromAddressSpinnerAdapter.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2011, Google Inc.
+ *
+ * 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.compose;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.android.email.R;
+
+/**
+ * FromAddressSpinnerAdapter returns the correct spinner adapter for reply from
+ * addresses based on device size.
+ *
+ * @author mindyp@google.com
+ */
+public class FromAddressSpinnerAdapter extends ArrayAdapter<String[]> {
+    public static int REAL_ACCOUNT = 2;
+
+    public static int ACCOUNT_DISPLAY = 0;
+
+    public static int ACCOUNT_ADDRESS = 1;
+
+    private LayoutInflater mInflater;
+
+    private Spinner mSpinner;
+
+    public FromAddressSpinnerAdapter(Context context) {
+        super(context, R.layout.from_item, R.id.spinner_account_name);
+    }
+
+    protected LayoutInflater getInflater() {
+        if (mInflater == null) {
+            mInflater = (LayoutInflater) getContext().getSystemService(
+                    Context.LAYOUT_INFLATER_SERVICE);
+        }
+        return mInflater;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        String[] fromItem = getItem(position);
+        View fromEntry = getInflater().inflate(R.layout.from_item, null);
+        ((TextView) fromEntry.findViewById(R.id.spinner_account_name))
+                .setText(fromItem[ACCOUNT_ADDRESS]);
+        return fromEntry;
+    }
+
+    @Override
+    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+        String[] fromItem = getItem(position);
+        View fromEntry = getInflater().inflate(R.layout.from_dropdown_item, null);
+        TextView acctName = ((TextView) fromEntry.
+                findViewById(R.id.spinner_account_name));
+        acctName.setText(fromItem[ACCOUNT_DISPLAY]);
+        return fromEntry;
+    }
+
+    /**
+     * Set the spinner this adapter for which this spinner is being used.
+     *
+     * @param spinner Spinner widget.
+     */
+    public void setSpinner(Spinner spinner) {
+        mSpinner = spinner;
+    }
+
+    /**
+     * Get the spinner associated with this adapter.
+     *
+     * @return Spinner widget.
+     */
+    public Spinner getSpinner() {
+        return mSpinner;
+    }
+
+    public int getSelectedItemPosition() {
+        return mSpinner != null ? mSpinner.getSelectedItemPosition() : -1;
+    }
+}
diff --git a/src/com/android/email/utils/AccountUtils.java b/src/com/android/email/utils/AccountUtils.java
new file mode 100644
index 0000000..998185d
--- /dev/null
+++ b/src/com/android/email/utils/AccountUtils.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 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.utils;
+
+import com.android.email.providers.UIProvider;
+import com.android.email.providers.protos.mock.MockUiProvider;
+
+import android.accounts.Account;
+import android.accounts.AccountManagerCallback;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AccountUtils {
+    /**
+     * Merge two lists of accounts into one list of accounts without duplicates.
+     *
+     * @param existingList List of accounts.
+     * @param accounts Accounts to merge in.
+     * @param prioritizeAccountList Boolean indicating whether this method
+     *            should prioritize the list of Account objects when merging the
+     *            lists
+     * @return Merged list of accounts.
+     */
+    public static List<String> mergeAccountLists(List<String> existingList, Account[] accounts,
+            boolean prioritizeAccountList) {
+
+        List<String> newAccountList = new ArrayList<String>();
+        // Make sure the accounts are actually synchronized
+        // (we won't be able to save/send for accounts that
+        // have never been synchronized)
+        for (int i = 0; i < accounts.length; i++) {
+            final String accountName = accounts[i].name;
+            // If the account is in the cached list or the caller requested
+            // that we prioritize the list of Account objects, put it in the new list
+            if (prioritizeAccountList
+                    || (existingList != null && existingList.contains(accountName))) {
+                newAccountList.add(accountName);
+            }
+        }
+        return newAccountList;
+    }
+
+    /**
+     * In the future, this will get syncing accounts from the account manager.
+     * Currently, it just gets all accounts from the UIProvider.
+     * @param context
+     * @param callback
+     * @param type
+     * @param features
+     * @return
+     */
+    public static Account[] getSyncingAccounts(Context context,
+            AccountManagerCallback<Account[]> callback, String type, String[] features) {
+        // TODO: use account manager.
+        // AccountManager.get(context).getAccountsByTypeAndFeatures(type, features, callback, null);
+        ContentResolver resolver = context.getContentResolver();
+        Cursor accountsCursor = resolver.query(MockUiProvider.getAccountsUri(),
+                UIProvider.ACCOUNTS_PROJECTION, null, null, null);
+        ArrayList<Account> accounts = new ArrayList<Account>();
+        if (accountsCursor != null) {
+            while (accountsCursor.moveToNext()) {
+                accounts.add(new Account(accountsCursor.getString(UIProvider.ACCOUNT_NAME_COLUMN),
+                        "unknown"));
+            }
+        }
+        return accounts.toArray(new Account[accounts.size()]);
+    }
+}
diff --git a/src/com/android/email/utils/AttachmentUtils.java b/src/com/android/email/utils/AttachmentUtils.java
index 2e9a03a..d115740 100644
--- a/src/com/android/email/utils/AttachmentUtils.java
+++ b/src/com/android/email/utils/AttachmentUtils.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2012 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.utils;
 
 import android.content.Context;