Merge "Change ActionBar to allow reading real accounts."
diff --git a/res/layout/conversation_list.xml b/res/layout/conversation_list.xml
index 8ec0a67..c42311a 100644
--- a/res/layout/conversation_list.xml
+++ b/res/layout/conversation_list.xml
@@ -44,12 +44,12 @@
android:fadingEdge="none"
android:layout_alignParentTop="true"/>
- <com.android.mail.UndoBarView
+ <com.android.mail.ui.UndoBarView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:id="@+id/undo_view"
android:layout_alignParentBottom="true">
<include layout="@layout/undo_bar"/>
- </com.android.mail.UndoBarView>
+ </com.android.mail.ui.UndoBarView>
</RelativeLayout>
diff --git a/src/com/android/mail/AccountSpinnerAdapter.java b/src/com/android/mail/AccountSpinnerAdapter.java
index 018b8fb..7ad3e9c 100644
--- a/src/com/android/mail/AccountSpinnerAdapter.java
+++ b/src/com/android/mail/AccountSpinnerAdapter.java
@@ -17,8 +17,11 @@
package com.android.mail;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.Cursor;
import android.database.DataSetObserver;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -27,6 +30,10 @@
import android.widget.SpinnerAdapter;
import android.widget.TextView;
+import com.android.mail.providers.AccountCacheProvider;
+import com.android.mail.providers.UIProvider;
+import com.android.mail.utils.LogUtils;
+
/**
* An adapter to return the list of accounts and labels for the Account Spinner.
* This class gets a merge cursor and returns views that are appropriate for the
@@ -35,10 +42,37 @@
*
*/
public class AccountSpinnerAdapter implements SpinnerAdapter,ListAdapter {
- private String mLabels[];
- private Integer mUnreadCounts[];
- private LayoutInflater mInflater;
+ private final LayoutInflater mInflater;
+ /**
+ * The current account being viewed
+ */
private String mCurrentAccount;
+ private final ContentResolver mResolver;
+
+ /**
+ * Total number of accounts.
+ */
+ private int numAccounts;
+
+ /**
+ * Cursor into the accounts database
+ */
+ private final Cursor mAccountCursor;
+
+ /**
+ * The name of the account is the 2nd column in UIProvider.ACCOUNTS_PROJECTION
+ */
+ static final int NAME_COLUMN = 2;
+ /**
+ * Fake labels for now
+ */
+ private final String[] mFolders;
+ /**
+ * Fake unread counts
+ */
+ private final int[] mUnreadCounts = {
+ 0, 2, 42
+ };
/**
* When the user selects the spinner, a dropdown list of objects is shown. Each item in the
@@ -50,7 +84,7 @@
}
/**
- * The first dropdown item is a header.
+ * After the accounts, the dropdown item is a header.
*/
private static class HeaderHolder {
TextView account;
@@ -65,29 +99,54 @@
TextView unread_count;
}
+ private static final int TYPE_ACCOUNT = 0;
+ private static final int TYPE_HEADER = 1;
+ private static final int TYPE_FOLDER = 2;
+
+ private int getType(int position) {
+ // First the accounts
+ if (position < numAccounts) {
+ return TYPE_ACCOUNT;
+ }
+ // Then the header
+ if (position == numAccounts) {
+ return TYPE_HEADER;
+ }
+ // Finally, the recent folders.
+ return TYPE_FOLDER;
+ }
+
public AccountSpinnerAdapter(Context context) {
mInflater = LayoutInflater.from(context);
- // Fake data.
- mLabels = new String[3];
- mLabels[0] = "Inbox";
- mLabels[1] = "Outbox";
- mLabels[2] = "Drafts";
- mUnreadCounts = new Integer[3];
- mUnreadCounts[0] = 13;
- mUnreadCounts[1] = 1;
- mUnreadCounts[2] = 0;
- mCurrentAccount = "test@android.com";
+
+ // Get the data from the system Accounts
+ mResolver = context.getContentResolver();
+ mAccountCursor = mResolver.query(AccountCacheProvider.getAccountsUri(),
+ UIProvider.ACCOUNTS_PROJECTION, null, null, null);
+ numAccounts = mAccountCursor.getCount();
+ // Fake folder information
+ mFolders = new String[3];
+ mFolders[0] = "Drafts -fake";
+ mFolders[1] = "Sent -fake";
+ mFolders[1] = "Starred -fake";
}
@Override
public int getCount() {
- // All the labels, plus one header.
- return mLabels.length + 1;
+ // All the accounts, plus one header, and optionally some labels
+ return numAccounts + 1 + mFolders.length;
}
@Override
public Object getItem(int position) {
- return mLabels[position - 1];
+ switch (getType(position)){
+ case TYPE_ACCOUNT:
+ return getAccount(position);
+ case TYPE_HEADER:
+ return "account spinner header";
+ default:
+ return mFolders[position - numAccounts - 1];
+ }
}
@Override
@@ -98,23 +157,43 @@
@Override
public int getItemViewType(int position) {
- if (position == 0) {
- return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+ // We have three different types of views: accounts, header and folders. The constants for
+ // account and folder are arbitrary, and we choose numbers 0 and 1.
+ switch (getType(position)) {
+ case TYPE_ACCOUNT:
+ return 0;
+ case TYPE_HEADER:
+ return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+ default:
+ return 1;
}
- // If there are a variety of views, this returns the kind of view that the position
- // represents. So if there are two views, and you have view types 0, and 1, then this
- // method returns which view type the 'position' represents.
-
- // Since we have a single view type, we always return zero.
- return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- if (position == 0) {
- // We can never select the header, and we want the default view to be the Inbox.
- return getView(1, convertView, parent);
+ String folderName = "";
+ String accountName = "";
+ int unreadCount = 0;
+ switch (getType(position)) {
+ case TYPE_ACCOUNT:
+ // The default Inbox for the given account
+ accountName = getAccount(position);
+ folderName = "Inbox";
+ break;
+ case TYPE_HEADER:
+ // We can never select the header, and we want the default view to be the Inbox.
+ accountName = getAccount(0);
+ folderName = "Inbox";
+ break;
+ default:
+ // Change the name of the current label
+ final int offset = position - numAccounts - 1;
+ accountName = mCurrentAccount;
+ folderName = mFolders[offset];
+ unreadCount = mUnreadCounts[offset];
+ break;
}
+
// Return a view with the label on the first line and the account name on the second.
ViewHolder holder;
if (convertView == null) {
@@ -130,10 +209,14 @@
} else {
holder = (ViewHolder) convertView.getTag();
}
- holder.label.setText(mLabels[position - 1]);
- holder.account.setText(mCurrentAccount);
- holder.unread_count.setText(mUnreadCounts[position - 1].toString());
- if (mUnreadCounts[position - 1] == 0) {
+ // TODO(viki): Fill with a real label here.
+ // TODO(viki): Also rename label to folder.
+ holder.label.setText(folderName);
+ holder.account.setText(accountName);
+ // Fake unread counts for now.
+ holder.unread_count.setText(String.valueOf(unreadCount));
+ // Keep the unread count logic here for the future.
+ if (unreadCount == 0) {
holder.unread_count.setVisibility(View.GONE);
} else {
holder.unread_count.setVisibility(View.VISIBLE);
@@ -141,87 +224,114 @@
return convertView;
}
+
@Override
public int getViewTypeCount() {
- // One view, and one header
- return 2;
+ // Two views, and one header
+ return 3;
}
+
@Override
public boolean hasStableIds() {
- // The data generated is static for now, the IDs are stable. However, in the future this
- // won't be the case
- return true;
- }
-
- @Override
- public boolean isEmpty() {
- // Will always contain something.
+ // The account manager could add new accounts, so don't claim that the IDs are stable.
return false;
}
+
+ @Override
+ public boolean isEmpty() {
+ // No item will be empty.
+ return false;
+ }
+
+
@Override
public void registerDataSetObserver(DataSetObserver observer) {
- // Don't do anything for now, since the data is mocked.
+ // Don't do anything for now. In the future, we will want to re-read the account
+ // information. In particular: recalculating the total number of accounts.
}
+
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
- // Don't do anything for now, since the data is mocked.
+ // Don't do anything for now.
}
+
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
- // At the top, we show a header. This is a special view.
- if (position == 0) {
- HeaderHolder holder;
- if (convertView == null ||
- !(convertView.getTag() instanceof HeaderHolder)) {
- convertView =
- mInflater.inflate(R.layout.account_switch_spinner_dropdown_header, null);
- holder = new HeaderHolder();
- holder.account =
- (TextView) convertView.findViewById(R.id.account_spinner_header_account);
- convertView.setTag(holder);
- } else {
- holder = (HeaderHolder) convertView.getTag();
- }
- holder.account.setText(mCurrentAccount);
- return convertView;
+ String textLabel = "";
+ int unreadCount = 0;
+ switch (getType(position)) {
+ case TYPE_HEADER:
+ HeaderHolder header;
+ if (convertView == null || !(convertView.getTag() instanceof HeaderHolder)) {
+ convertView = mInflater.inflate(
+ R.layout.account_switch_spinner_dropdown_header, null);
+ header = new HeaderHolder();
+ header.account = (TextView) convertView.findViewById(
+ R.id.account_spinner_header_account);
+ convertView.setTag(header);
+ } else {
+ header = (HeaderHolder) convertView.getTag();
+ }
+ header.account.setText(mCurrentAccount);
+ return convertView;
+ case TYPE_ACCOUNT:
+ textLabel = getAccount(position);
+ break;
+ case TYPE_FOLDER:
+ final int offset = position - numAccounts - 1;
+ textLabel = mFolders[offset];
+ unreadCount = mUnreadCounts[offset];
+ break;
}
- DropdownHolder holder;
- if (convertView == null ||
- !(convertView.getTag() instanceof DropdownHolder)) {
+ DropdownHolder dropdown;
+ if (convertView == null || !(convertView.getTag() instanceof DropdownHolder)) {
convertView = mInflater.inflate(R.layout.account_switch_spinner_dropdown_item, null);
- holder = new DropdownHolder();
- holder.label = (TextView) convertView.findViewById(R.id.account_spinner_accountname);
- holder.unread_count =
+ dropdown = new DropdownHolder();
+ dropdown.label = (TextView) convertView.findViewById(R.id.account_spinner_accountname);
+ dropdown.unread_count =
(TextView) convertView.findViewById(R.id.account_spinner_unread_count);
- convertView.setTag(holder);
+ convertView.setTag(dropdown);
} else {
- holder = (DropdownHolder) convertView.getTag();
+ dropdown = (DropdownHolder) convertView.getTag();
}
- holder.label.setText(mLabels[position - 1]);
- holder.unread_count.setText(mUnreadCounts[position - 1].toString());
- if (mUnreadCounts[position - 1] == 0) {
- holder.unread_count.setVisibility(View.GONE);
+ dropdown.label.setText(textLabel);
+ dropdown.unread_count.setText(String.valueOf(unreadCount));
+ if (unreadCount == 0) {
+ dropdown.unread_count.setVisibility(View.GONE);
} else {
- holder.unread_count.setVisibility(View.VISIBLE);
+ dropdown.unread_count.setVisibility(View.VISIBLE);
}
return convertView;
+
}
+ /**
+ * Returns the name of the label at the given position in the spinner.
+ * @param position
+ * @return
+ */
+ private String getAccount(int position) {
+ mAccountCursor.moveToPosition(position);
+ final int accountNameCol = mAccountCursor.getColumnIndex(UIProvider.AccountColumns.NAME);
+ return mAccountCursor.getString(accountNameCol);
+ }
+
+
@Override
public boolean isEnabled(int position) {
// Don't want the user selecting the header.
- return position != 0;
+ return (getType(position) != TYPE_HEADER);
}
@Override
public boolean areAllItemsEnabled() {
- // The header is the only non-enabled item.
+ // The header is not enabled, so return false here.
return false;
}
}
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 92b87cf..3d35b8b 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -67,6 +67,9 @@
protected Account mAccount;
protected ActionBarView mActionBarView;
protected final RestrictedActivity mActivity;
+ /**
+ * The currently selected conversations, if any.
+ */
private ConversationSelectionSet mBatchConversations = new ConversationSelectionSet();
protected final Context mContext;
protected ConversationListContext mConversationListContext;
@@ -123,8 +126,7 @@
@Override
public ConversationSelectionSet getBatchConversations() {
- // TODO(viki): Auto-generated method stub
- return null;
+ return mBatchConversations;
}
@Override
@@ -250,9 +252,6 @@
@Override
public boolean onCreate(Bundle savedState) {
- // Request opaque actionbar
- mActivity.getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
-
// Initialize the action bar view.
initCustomActionBarView();
@@ -334,8 +333,9 @@
@Override
public void onSaveInstanceState(Bundle outState) {
- // TODO(viki): Auto-generated method stub
-
+ if (mConversationListContext != null) {
+ outState.putBundle(SAVED_LIST_CONTEXT, mConversationListContext.toBundle());
+ }
}
@Override
@@ -425,7 +425,10 @@
*/
protected void restoreListContext(Bundle savedState) {
// TODO(viki): Auto-generated method stub
-
+ Bundle listContextBundle = savedState.getBundle(SAVED_LIST_CONTEXT);
+ if (listContextBundle != null) {
+ mConversationListContext = ConversationListContext.forBundle(listContextBundle);
+ }
}
/**
@@ -456,6 +459,9 @@
protected void restoreState(Bundle savedState) {
if (savedState != null) {
restoreListContext(savedState);
+ // Restore the list context
+ restoreListContext(savedState);
+
// Attach the menu handler here.
// Restore the view mode
@@ -463,6 +469,8 @@
} else {
final Intent intent = mActivity.getIntent();
// TODO(viki): Show the list context from Intent
+ mConversationListContext = ConversationListContext.forIntent(
+ mContext, mAccount, intent);
// Instead of this, switch to the conversation list mode and have that do the right
// things automatically.
// showConversationList(ConversationListContext.forIntent(mContext, mAccount, intent));
diff --git a/src/com/android/mail/ui/ActionBarView.java b/src/com/android/mail/ui/ActionBarView.java
index be76edc..a1899a7 100644
--- a/src/com/android/mail/ui/ActionBarView.java
+++ b/src/com/android/mail/ui/ActionBarView.java
@@ -92,8 +92,10 @@
/**
* Change the mode of the actionbar.
+ * <p> TODO(viki): Why does the Actionbar have its own mode? The actionbar should use the view
+ * mode, just like everyone else.
* @param mode
- * @return true if the change in mode was successful
+ * @return true if the change in mode was successful.
*/
boolean setMode(Mode mode);
diff --git a/src/com/android/mail/ui/ControllableActivity.java b/src/com/android/mail/ui/ControllableActivity.java
index 067080a..15e9e41 100644
--- a/src/com/android/mail/ui/ControllableActivity.java
+++ b/src/com/android/mail/ui/ControllableActivity.java
@@ -17,6 +17,7 @@
package com.android.mail.ui;
+import com.android.mail.browse.ConversationItemView.StarHandler;
import com.android.mail.ui.ViewMode.ModeChangeListener;
@@ -24,7 +25,8 @@
* A controllable activity is an Activity that has a Controller attached. This activity must be
* able to attach the various view fragments and delegate the method calls between them.
*/
-public interface ControllableActivity extends HelpCallback, RestrictedActivity {
+public interface ControllableActivity extends HelpCallback, RestrictedActivity,
+ ConversationListCallbacks, StarHandler {
/**
* Attaches the conversation list fragment to the activity controller. This callback is
* currently required because the Activity Controller directly calls methods on the conversation
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 528b503..4260dcd 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -106,6 +106,11 @@
}
@Override
+ public void onConversationSelected(int position) {
+ // Do nothing for now. Allow the mController to handle these changes.
+ }
+
+ @Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
@@ -210,6 +215,12 @@
}
@Override
+ public void toggleStar(boolean toggleOn, long conversationId, long maxMessageId) {
+ // TODO(viki): Auto-generated method stub
+ // Do nothing for now, and let the mController handle this too.
+ }
+
+ @Override
public void unsetViewModeListener(ModeChangeListener listener) {
mViewMode.removeListener(listener);
}
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 07625c2..005f047 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -34,8 +34,6 @@
// Called OnePaneActivityController in Gmail.
public final class OnePaneController extends AbstractActivityController {
- private ConversationListContext mConversationListContext;
-
/**
* @param activity
* @param viewMode