Merge "Import translations. DO NOT MERGE" into jb-ub-mail-ur10
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 24fa2b2..130700b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -111,6 +111,16 @@
android:label="@string/app_name"
android:theme="@style/PhotoViewTheme" >
</activity>
+ <activity
+ android:name=".browse.EmlViewerActivity"
+ android:label="@string/app_name"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="message/rfc822" />
+ </intent-filter>
+ </activity>
<provider
android:authorities="com.android.mail.mockprovider"
diff --git a/res/layout/eml_viewer_activity.xml b/res/layout/eml_viewer_activity.xml
new file mode 100644
index 0000000..751a4fa
--- /dev/null
+++ b/res/layout/eml_viewer_activity.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <WebView
+ android:id="@+id/eml_web_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+</LinearLayout>
\ No newline at end of file
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 0afe96c..a13fdad 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -24,7 +24,6 @@
import android.content.ClipData.Item;
import android.content.Context;
import android.content.res.Resources;
-import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -426,13 +425,6 @@
mAttachmentPreviewsCanvas = new DividedImageCanvas(context, this);
}
- public void bind(Cursor cursor, ControllableActivity activity, ConversationSelectionSet set,
- Folder folder, int checkboxOrSenderImage, boolean swipeEnabled,
- boolean priorityArrowEnabled, AnimatedAdapter adapter) {
- bind(ConversationItemViewModel.forCursor(mAccount, cursor), activity, set, folder,
- checkboxOrSenderImage, swipeEnabled, priorityArrowEnabled, adapter);
- }
-
public void bind(Conversation conversation, ControllableActivity activity,
ConversationSelectionSet set, Folder folder, int checkboxOrSenderImage,
boolean swipeEnabled, boolean priorityArrowEnabled, AnimatedAdapter adapter) {
diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index d83ce74..fa01322 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -17,12 +17,7 @@
package com.android.mail.browse;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-
import android.content.Context;
-import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.text.SpannableString;
@@ -39,6 +34,9 @@
import com.android.mail.providers.Folder;
import com.android.mail.providers.MessageInfo;
import com.android.mail.providers.UIProvider;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
@@ -148,10 +146,6 @@
}
}
- static ConversationItemViewModel forCursor(String account, Cursor cursor) {
- return forConversation(account, new Conversation(cursor));
- }
-
static ConversationItemViewModel forConversation(String account, Conversation conv) {
ConversationItemViewModel header = ConversationItemViewModel.forConversationId(account,
conv.id);
diff --git a/src/com/android/mail/browse/ConversationPagerAdapter.java b/src/com/android/mail/browse/ConversationPagerAdapter.java
index 25a7aab..56810e7 100644
--- a/src/com/android/mail/browse/ConversationPagerAdapter.java
+++ b/src/com/android/mail/browse/ConversationPagerAdapter.java
@@ -186,9 +186,7 @@
return null;
}
cursor.notifyUIPositionChange();
- // TODO: switch to something like MessageCursor or AttachmentCursor
- // to re-use these models
- c = new Conversation(cursor);
+ c = cursor.getConversation();
c.position = position;
}
final AbstractConversationViewFragment f = getConversationViewFragment(c);
@@ -343,7 +341,7 @@
if (mController != null && !mDetachedMode && mPager != null) {
final Conversation currConversation = mController.getCurrentConversation();
final int pos = getConversationPosition(currConversation);
- final Cursor cursor = getCursor();
+ final ConversationCursor cursor = getCursor();
if (pos == POSITION_NONE && cursor != null && currConversation != null) {
// enable detached mode and do no more here. the fragment itself will figure out
// if the conversation is empty (using message list cursor) and back out if needed.
@@ -370,7 +368,7 @@
(AbstractConversationViewFragment) getFragmentAt(pos);
if (frag != null && cursor.moveToPosition(pos) && frag.isUserVisible()) {
// reload what we think is in the current position.
- final Conversation conv = new Conversation(cursor);
+ final Conversation conv = cursor.getConversation();
conv.position = pos;
frag.onConversationUpdated(conv);
mController.setCurrentConversation(conv);
@@ -494,12 +492,12 @@
if (mController == null) {
return;
}
- final Cursor cursor = getCursor();
+ final ConversationCursor cursor = getCursor();
if (cursor == null || !cursor.moveToPosition(position)) {
// No valid cursor or it doesn't have the position we want. Bail.
return;
}
- final Conversation c = new Conversation(cursor);
+ final Conversation c = cursor.getConversation();
c.position = position;
LogUtils.d(LOG_TAG, "pager adapter setting current conv: %s", c);
mController.setCurrentConversation(c);
diff --git a/src/com/android/mail/browse/EmlViewerActivity.java b/src/com/android/mail/browse/EmlViewerActivity.java
new file mode 100644
index 0000000..a102424
--- /dev/null
+++ b/src/com/android/mail/browse/EmlViewerActivity.java
@@ -0,0 +1,65 @@
+package com.android.mail.browse;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.webkit.WebView;
+import android.widget.TextView;
+
+import com.android.mail.R;
+import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
+import com.android.mail.utils.MimeType;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class EmlViewerActivity extends Activity {
+ private static final String LOG_TAG = LogTag.getLogTag();
+
+ private WebView mWebView;
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.eml_viewer_activity);
+ mWebView = (WebView) findViewById(R.id.eml_web_view);
+
+ final Intent intent = getIntent();
+ final String action = intent.getAction();
+ final String type = intent.getType();
+
+ if (Intent.ACTION_VIEW.equals(action) &&
+ MimeType.EML_ATTACHMENT_CONTENT_TYPE.equals(type)) {
+ openEmlFile(intent.getData());
+ } else {
+ LogUtils.wtf(LOG_TAG,
+ "Entered EmlViewerActivity with wrong intent action or type: %s, %s",
+ action, type);
+ finish(); // we should not be here. bail out. bail out.
+ }
+ }
+
+ private void openEmlFile(Uri uri) {
+ final ContentResolver resolver = getContentResolver();
+ try {
+ final InputStream stream = resolver.openInputStream(uri);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+ StringBuilder builder = new StringBuilder(stream.available());
+ String line = reader.readLine();
+ while (line != null) {
+ builder.append(line);
+ line = reader.readLine();
+ }
+ mWebView.loadDataWithBaseURL("", builder.toString(), "text/html", "utf-8", null);
+ } catch (FileNotFoundException e) {
+ // TODO handle exceptions
+ } catch (IOException e) {
+ // TODO handle exception
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/mail/browse/SwipeableConversationItemView.java b/src/com/android/mail/browse/SwipeableConversationItemView.java
index 27730cc..a675b8d 100644
--- a/src/com/android/mail/browse/SwipeableConversationItemView.java
+++ b/src/com/android/mail/browse/SwipeableConversationItemView.java
@@ -20,7 +20,6 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.content.Context;
-import android.database.Cursor;
import android.widget.FrameLayout;
import android.widget.ListView;
@@ -59,13 +58,6 @@
swipeEnabled, priorityArrowsEnabled, animatedAdapter);
}
- public void bind(Cursor cursor, ControllableActivity activity, ConversationSelectionSet set,
- Folder folder, int checkboxOrSenderImage, boolean swipeEnabled,
- boolean priorityArrowsEnabled, AnimatedAdapter animatedAdapter) {
- mConversationItemView.bind(cursor, activity, set, folder, checkboxOrSenderImage,
- swipeEnabled, priorityArrowsEnabled, animatedAdapter);
- }
-
public void startUndoAnimation(AnimatorListener listener, boolean swipe) {
final Animator a = (swipe) ? mConversationItemView.createSwipeUndoAnimation()
: mConversationItemView.createUndoAnimation();
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index 3ee79f7..98fad35 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -211,6 +211,8 @@
private static final String MIME_TYPE_PHOTO = "image/*";
private static final String MIME_TYPE_VIDEO = "video/*";
+ private static final String KEY_INNER_SAVED_STATE = "compose_state";
+
/**
* A single thread for running tasks in the background.
*/
@@ -264,7 +266,7 @@
private RecipientTextWatcher mBccListener;
private Uri mRefMessageUri;
private boolean mShowQuotedText = false;
- private Bundle mSavedInstanceState;
+ private Bundle mInnerSavedState;
// Array of the outstanding send or save tasks. Access is synchronized
@@ -370,12 +372,13 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.compose);
- mSavedInstanceState = savedInstanceState;
+ mInnerSavedState = (savedInstanceState != null) ?
+ savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null;
checkValidAccounts();
}
private void finishCreate() {
- Bundle savedInstanceState = mSavedInstanceState;
+ final Bundle savedState = mInnerSavedState;
findViews();
Intent intent = getIntent();
Message message;
@@ -384,13 +387,13 @@
int action;
// Check for any of the possibly supplied accounts.;
Account account = null;
- if (hadSavedInstanceStateMessage(savedInstanceState)) {
- action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE);
- account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT);
- message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE);
+ if (hadSavedInstanceStateMessage(savedState)) {
+ action = savedState.getInt(EXTRA_ACTION, COMPOSE);
+ account = savedState.getParcelable(Utils.EXTRA_ACCOUNT);
+ message = (Message) savedState.getParcelable(EXTRA_MESSAGE);
- previews = savedInstanceState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
- mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
+ previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
+ mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
} else {
account = obtainAccount(intent);
action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
@@ -439,7 +442,7 @@
} else if (message != null && action != EDIT_DRAFT) {
initFromDraftMessage(message);
initQuotedTextFromRefMessage(mRefMessage, action);
- showCcBcc(savedInstanceState);
+ showCcBcc(savedState);
mShowQuotedText = message.appendRefMessageContent;
} else if (action == EDIT_DRAFT) {
initFromDraftMessage(message);
@@ -484,7 +487,7 @@
}
mComposeMode = action;
- finishSetup(action, intent, savedInstanceState);
+ finishSetup(action, intent, savedState);
}
private void checkValidAccounts() {
@@ -593,8 +596,8 @@
updateHideOrShowCcBcc();
updateHideOrShowQuotedText(mShowQuotedText);
- mRespondedInline = mSavedInstanceState != null ?
- mSavedInstanceState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
+ mRespondedInline = mInnerSavedState != null ?
+ mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
if (mRespondedInline) {
mQuotedTextView.setVisibility(View.GONE);
}
@@ -710,10 +713,10 @@
clearChangeListeners();
}
super.onRestoreInstanceState(savedInstanceState);
- if (savedInstanceState != null) {
- if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
- int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START);
- int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END);
+ if (mInnerSavedState != null) {
+ if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
+ int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START);
+ int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END);
// There should be a focus and it should be an EditText since we
// only save these extras if these conditions are true.
EditText focusEditText = (EditText) getCurrentFocus();
@@ -731,6 +734,12 @@
@Override
public final void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
+ final Bundle inner = new Bundle();
+ saveState(inner);
+ state.putBundle(KEY_INNER_SAVED_STATE, inner);
+ }
+
+ private void saveState(Bundle state) {
// We have no accounts so there is nothing to compose, and therefore, nothing to save.
if (mAccounts == null || mAccounts.length == 0) {
return;
@@ -1812,8 +1821,8 @@
*/
mSave = menu.findItem(R.id.save);
String action = getIntent() != null ? getIntent().getAction() : null;
- enableSave(mSavedInstanceState != null ?
- mSavedInstanceState.getBoolean(EXTRA_SAVE_ENABLED)
+ enableSave(mInnerSavedState != null ?
+ mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED)
: (Intent.ACTION_SEND.equals(action)
|| Intent.ACTION_SEND_MULTIPLE.equals(action)
|| Intent.ACTION_SENDTO.equals(action)
@@ -3169,7 +3178,7 @@
if (data != null && data.moveToFirst()) {
mRefMessage = new Message(data);
}
- finishSetup(mComposeMode, getIntent(), mSavedInstanceState);
+ finishSetup(mComposeMode, getIntent(), mInnerSavedState);
break;
case LOADER_ACCOUNT_CURSOR:
if (data != null && data.moveToFirst()) {
diff --git a/src/com/android/mail/ui/AccountController.java b/src/com/android/mail/ui/AccountController.java
index f2b36f9..3d8ab2f 100644
--- a/src/com/android/mail/ui/AccountController.java
+++ b/src/com/android/mail/ui/AccountController.java
@@ -19,6 +19,7 @@
import android.database.DataSetObservable;
import android.database.DataSetObserver;
+import android.widget.ListView;
import com.android.mail.providers.Account;
import com.android.mail.providers.AccountObserver;
@@ -108,4 +109,10 @@
* @return <code>true</code> if the drawer pull action is enabled, <code>false</code> otherwise
*/
boolean isDrawerPullEnabled();
+
+ /**
+ * @return the choice mode to use in the {@link ListView} in the default folder list (subclasses
+ * of {@link FolderListFragment} may override this
+ */
+ int getFolderListViewChoiceMode();
}
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 868f6d5..fd387a6 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -675,11 +675,8 @@
@Override
public void bindView(View view, Context context, Cursor cursor) {
- if (! (view instanceof SwipeableConversationItemView)) {
- return;
- }
- ((SwipeableConversationItemView) view).bind(cursor, mActivity, mBatchConversations, mFolder,
- getCheckboxSetting(), mSwipeEnabled, mPriorityMarkersEnabled, this);
+ // no-op. we only get here from newConversationItemView(), which will immediately bind
+ // on its own.
}
private SwipeableConversationItemView newConversationItemView(int position, ViewGroup parent,
diff --git a/src/com/android/mail/ui/ConversationPositionTracker.java b/src/com/android/mail/ui/ConversationPositionTracker.java
index 46ca0a0..7be0f23 100644
--- a/src/com/android/mail/ui/ConversationPositionTracker.java
+++ b/src/com/android/mail/ui/ConversationPositionTracker.java
@@ -57,7 +57,7 @@
private Conversation conversationAtPosition(int position){
final ConversationCursor cursor = mCallbacks.getConversationListCursor();
cursor.moveToPosition(position);
- final Conversation conv = new Conversation(cursor);
+ final Conversation conv = cursor.getConversation();
conv.position = position;
return conv;
}
diff --git a/src/com/android/mail/ui/DrawerFragment.java b/src/com/android/mail/ui/DrawerFragment.java
index 85436e4..c83a7a9 100644
--- a/src/com/android/mail/ui/DrawerFragment.java
+++ b/src/com/android/mail/ui/DrawerFragment.java
@@ -17,6 +17,8 @@
package com.android.mail.ui;
+import android.widget.ListView;
+
/**
* A drawer that is shown in one pane mode, as a pull-out from the left. All the
* implementation is inherited from the FolderListFragment.
@@ -27,4 +29,10 @@
// Drawer is always sectioned.
mIsSectioned = true;
}
+
+ @Override
+ protected int getListViewChoiceMode() {
+ // Always let one item be selected
+ return ListView.CHOICE_MODE_SINGLE;
+ }
}
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
index 6e10fa3..0755ae2 100644
--- a/src/com/android/mail/ui/FolderListFragment.java
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -21,7 +21,6 @@
import android.app.ListFragment;
import android.app.LoaderManager;
import android.content.Loader;
-import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -75,7 +74,7 @@
/** Object that changes folders on our behalf. */
private FolderListSelectionListener mFolderChanger;
/** Object that changes accounts on our behalf */
- private AccountController mAccountChanger;
+ private AccountController mAccountController;
/** The currently selected folder (the folder being viewed). This is never null. */
private Uri mSelectedFolderUri = Uri.EMPTY;
@@ -87,7 +86,9 @@
/** Parent of the current folder, or null if the current folder is not a child. */
private Folder mParentFolder;
- private static final int FOLDER_LOADER_ID = 0;
+ private static final int FOLDER_LIST_LOADER_ID = 0;
+ /** Loader id for the full list of folders in the account */
+ private static final int FULL_FOLDER_LIST_LOADER_ID = 1;
/** Key to store {@link #mParentFolder}. */
private static final String ARG_PARENT_FOLDER = "arg-parent-folder";
/** Key to store {@link #mIsSectioned} */
@@ -292,7 +293,7 @@
}
};
mAllAccountsObserver.initialize(accountController);
- mAccountChanger = accountController;
+ mAccountController = accountController;
// Observer for when the drawer is closed
mDrawerObserver = new DrawerClosedObserver() {
@@ -301,12 +302,11 @@
// First, check if there's a folder to change to
if (mNextFolder != null) {
mFolderChanger.onFolderSelected(mNextFolder);
- // Wait for an update to the current folder. When we get the next folder,
- // then we null it out.
+ mNextFolder = null;
}
// Next, check if there's an account to change to
if (mNextAccount != null) {
- mAccountChanger.switchToDefaultInboxOrChangeAccount(mNextAccount);
+ mAccountController.switchToDefaultInboxOrChangeAccount(mNextAccount);
mNextAccount = null;
}
}
@@ -319,6 +319,8 @@
return;
}
+ mListView.setChoiceMode(getListViewChoiceMode());
+
setListAdapter(mCursorAdapter);
}
@@ -346,13 +348,10 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedState) {
- final Bundle args = getArguments();
- if (args != null) {
- mHideAccounts = args.getBoolean(ARG_HIDE_ACCOUNTS, false);
- }
+ setInstanceFromBundle(getArguments());
+
final View rootView = inflater.inflate(R.layout.folder_list, null);
mListView = (ListView) rootView.findViewById(android.R.id.list);
- mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
mListView.setEmptyView(null);
mListView.setDivider(null);
if (savedState != null && savedState.containsKey(BUNDLE_LIST_STATE)) {
@@ -438,7 +437,7 @@
// Switching accounts takes you to the default inbox for that account.
mSelectedFolderType = DrawerItem.FOLDER_INBOX;
mNextAccount = account;
- mAccountChanger.closeDrawer(true, mNextAccount, getDefaultInbox(mNextAccount));
+ mAccountController.closeDrawer(true, mNextAccount, getDefaultInbox(mNextAccount));
}
/**
@@ -465,7 +464,7 @@
mListView.setItemChecked(defaultInboxPosition, true);
}
// ... and close the drawer (no new target folders/accounts)
- mAccountChanger.closeDrawer(false, mNextAccount,
+ mAccountController.closeDrawer(false, mNextAccount,
getDefaultInbox(mNextAccount));
} else {
changeAccount(account);
@@ -502,10 +501,10 @@
// Go to the conversation list for this folder.
if (!folder.uri.equals(mSelectedFolderUri)) {
mNextFolder = folder;
- mAccountChanger.closeDrawer(true, nextAccount, folder);
+ mAccountController.closeDrawer(true, nextAccount, folder);
} else {
// Clicked on same folder, just close drawer
- mAccountChanger.closeDrawer(false, nextAccount, folder);
+ mAccountController.closeDrawer(false, nextAccount, folder);
}
}
}
@@ -514,10 +513,10 @@
public Loader<ObjectCursor<Folder>> onCreateLoader(int id, Bundle args) {
mListView.setEmptyView(null);
final Uri folderListUri;
- if (mType == TYPE_TREE) {
+ if (id == FOLDER_LIST_LOADER_ID && mType == TYPE_TREE) {
// Folder trees, they specify a URI at construction time.
folderListUri = mFolderListUri;
- } else if (mType == TYPE_DRAWER) {
+ } else if (id == FOLDER_LIST_LOADER_ID && mType == TYPE_DRAWER) {
// Drawers should have a valid account
if (mCurrentAccount != null) {
folderListUri = mCurrentAccount.folderListUri;
@@ -525,6 +524,8 @@
LogUtils.wtf(LOG_TAG, "FLF.onCreateLoader() for Drawer with null account");
return null;
}
+ } else if (id == FULL_FOLDER_LIST_LOADER_ID) {
+ folderListUri = mCurrentAccount.fullFolderListUri;
} else {
LogUtils.wtf(LOG_TAG, "FLF.onCreateLoader() with weird type");
return null;
@@ -536,14 +537,22 @@
@Override
public void onLoadFinished(Loader<ObjectCursor<Folder>> loader, ObjectCursor<Folder> data) {
if (mCursorAdapter != null) {
- mCursorAdapter.setCursor(data);
+ if (loader.getId() == FOLDER_LIST_LOADER_ID) {
+ mCursorAdapter.setCursor(data);
+ } else if (loader.getId() == FULL_FOLDER_LIST_LOADER_ID) {
+ mCursorAdapter.setFullFolderListCursor(data);
+ }
}
}
@Override
public void onLoaderReset(Loader<ObjectCursor<Folder>> loader) {
if (mCursorAdapter != null) {
- mCursorAdapter.setCursor(null);
+ if (loader.getId() == FOLDER_LIST_LOADER_ID) {
+ mCursorAdapter.setCursor(null);
+ } else if (loader.getId() == FULL_FOLDER_LIST_LOADER_ID) {
+ mCursorAdapter.setFullFolderListCursor(null);
+ }
}
}
@@ -565,6 +574,8 @@
private interface FolderListFragmentCursorAdapter extends ListAdapter {
/** Update the folder list cursor with the cursor given here. */
void setCursor(ObjectCursor<Folder> cursor);
+ /** Update the full folder list cursor with the cursor given here. */
+ void setFullFolderListCursor(ObjectCursor<Folder> cursor);
/**
* Given an item, find the type of the item, which should only be {@link
* DrawerItem#VIEW_FOLDER} or {@link DrawerItem#VIEW_ACCOUNT}
@@ -591,7 +602,7 @@
private final RecentFolderObserver mRecentFolderObserver = new RecentFolderObserver() {
@Override
public void onChanged() {
- if (!isCursorInvalid(mCursor)) {
+ if (!isCursorInvalid()) {
recalculateList();
}
}
@@ -606,6 +617,8 @@
private List<DrawerItem> mItemList = new ArrayList<DrawerItem>();
/** Cursor into the folder list. This might be null. */
private ObjectCursor<Folder> mCursor = null;
+ /** Cursor into the full folder list. This might be null. */
+ private ObjectCursor<Folder> mFullFolderListCursor = null;
/** Watcher for tracking and receiving unread counts for mail */
private FolderWatcher mFolderWatcher = null;
private boolean mRegistered = false;
@@ -630,9 +643,9 @@
@Override
public void notifyAllAccountsChanged() {
- if (!mRegistered && mAccountChanger != null) {
+ if (!mRegistered && mAccountController != null) {
// TODO(viki): Round-about way of setting the watcher. http://b/8750610
- mAccountChanger.setFolderWatcher(mFolderWatcher);
+ mAccountController.setFolderWatcher(mFolderWatcher);
mRegistered = true;
}
mFolderWatcher.updateAccountList(getAllAccounts());
@@ -764,7 +777,7 @@
// If we are waiting for folder initialization, we don't have any kinds of folders,
// just the "Waiting for initialization" item. Note, this should only be done
// when we're waiting for account initialization or initial sync.
- if (isCursorInvalid(mCursor)) {
+ if (isCursorInvalid()) {
if(!mCurrentAccount.isAccountReady()) {
itemList.add(DrawerItem.forWaitView(mActivity));
}
@@ -787,7 +800,6 @@
// Otherwise, this is an adapter for a sectioned list.
final List<DrawerItem> allFoldersList = new ArrayList<DrawerItem>();
final List<DrawerItem> inboxFolders = new ArrayList<DrawerItem>();
- boolean currentFolderFound = false;
do {
final Folder f = mCursor.getModel();
if (!isFolderTypeExcluded(f)) {
@@ -798,18 +810,36 @@
allFoldersList.add(DrawerItem.ofFolder(
mActivity, f, DrawerItem.FOLDER_OTHER, mCursor.getPosition()));
}
- if (f.equals(mCurrentFolderForUnreadCheck)) {
- currentFolderFound = true;
- }
}
} while (mCursor.moveToNext());
- if (!currentFolderFound && mCurrentFolderForUnreadCheck != null
- && mCurrentAccount != null && mAccountChanger != null
- && mAccountChanger.isDrawerPullEnabled()) {
- LogUtils.d(LOG_TAG, "Current folder (%1$s) has disappeared for %2$s",
- mCurrentFolderForUnreadCheck.name, mCurrentAccount.name);
- changeAccount(mCurrentAccount);
+ // If we have the full folder list, verify that the current folder exists
+ boolean currentFolderFound = false;
+ if (mFullFolderListCursor != null) {
+ final String folderName = mCurrentFolderForUnreadCheck == null
+ ? "null" : mCurrentFolderForUnreadCheck.name;
+ LogUtils.d(LOG_TAG, "Checking if full folder list contains %s", folderName);
+
+ if (mFullFolderListCursor.moveToFirst()) {
+ LogUtils.d(LOG_TAG, "Cursor for %s seems reasonably valid", folderName);
+ do {
+ final Folder f = mFullFolderListCursor.getModel();
+ if (!isFolderTypeExcluded(f)) {
+ if (f.equals(mCurrentFolderForUnreadCheck)) {
+ LogUtils.d(LOG_TAG, "Found %s !", folderName);
+ currentFolderFound = true;
+ }
+ }
+ } while (mFullFolderListCursor.moveToNext());
+ }
+
+ if (!currentFolderFound && mCurrentFolderForUnreadCheck != null
+ && mCurrentAccount != null && mAccountController != null
+ && mAccountController.isDrawerPullEnabled()) {
+ LogUtils.d(LOG_TAG, "Current folder (%1$s) has disappeared for %2$s",
+ mCurrentFolderForUnreadCheck.name, mCurrentAccount.name);
+ changeAccount(mCurrentAccount);
+ }
}
// Add all inboxes (sectioned included) before recents.
@@ -875,10 +905,9 @@
/**
* Check if the cursor provided is valid.
- * @param mCursor
* @return True if cursor is invalid, false otherwise
*/
- private boolean isCursorInvalid(Cursor mCursor) {
+ private boolean isCursorInvalid() {
return mCursor == null || mCursor.isClosed()|| mCursor.getCount() <= 0
|| !mCursor.moveToFirst();
}
@@ -890,6 +919,12 @@
}
@Override
+ public void setFullFolderListCursor(final ObjectCursor<Folder> cursor) {
+ mFullFolderListCursor = cursor;
+ recalculateList();
+ }
+
+ @Override
public Object getItem(int position) {
// Is there an attempt made to access outside of the drawer item list?
if (position >= mItemList.size()) {
@@ -940,7 +975,7 @@
}
private class HierarchicalFolderListAdapter extends ArrayAdapter<Folder>
- implements FolderListFragmentCursorAdapter{
+ implements FolderListFragmentCursorAdapter {
private static final int PARENT = 0;
private static final int CHILD = 1;
@@ -1015,6 +1050,11 @@
}
@Override
+ public void setFullFolderListCursor(final ObjectCursor<Folder> cursor) {
+ // Not necessary in HierarchicalFolderListAdapter
+ }
+
+ @Override
public void destroy() {
// Do nothing.
}
@@ -1065,12 +1105,6 @@
LogUtils.e(LOG_TAG, "FolderListFragment.setSelectedFolder(null) called!");
return;
}
- // Is this the folder we changed to previously? If not, ignore the update
- if (mNextFolder != null && !folder.uri.equals(mNextFolder.uri)) {
- // Update to a folder that we don't care about. Ignore
- return;
- }
- mNextFolder = null;
final boolean viewChanged =
!FolderItemView.areSameViews(folder, mCurrentFolderForUnreadCheck);
@@ -1110,8 +1144,10 @@
// comment on {@link AbstractActivityController#restartOptionalLoader} to see why we
// don't just do restartLoader.
final LoaderManager manager = getLoaderManager();
- manager.destroyLoader(FOLDER_LOADER_ID);
- manager.restartLoader(FOLDER_LOADER_ID, Bundle.EMPTY, this);
+ manager.destroyLoader(FOLDER_LIST_LOADER_ID);
+ manager.restartLoader(FOLDER_LIST_LOADER_ID, Bundle.EMPTY, this);
+ manager.destroyLoader(FULL_FOLDER_LIST_LOADER_ID);
+ manager.restartLoader(FULL_FOLDER_LIST_LOADER_ID, Bundle.EMPTY, this);
// An updated cursor causes the entire list to refresh. No need to refresh the list.
// But we do need to blank out the current folder, since the account might not be
// synced.
@@ -1122,7 +1158,8 @@
// non-null account -> null account transition.
LogUtils.e(LOG_TAG, "FLF.setSelectedAccount(null) called! Destroying existing loader.");
final LoaderManager manager = getLoaderManager();
- manager.destroyLoader(FOLDER_LOADER_ID);
+ manager.destroyLoader(FOLDER_LIST_LOADER_ID);
+ manager.destroyLoader(FULL_FOLDER_LIST_LOADER_ID);
}
}
@@ -1154,4 +1191,11 @@
return false;
}
+
+ /**
+ * @return the choice mode to use for the {@link ListView}
+ */
+ protected int getListViewChoiceMode() {
+ return mAccountController.getFolderListViewChoiceMode();
+ }
}
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index be2608e..c96ddfc 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -32,6 +32,7 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
+import android.widget.ListView;
import com.android.mail.R;
import com.android.mail.providers.Account;
@@ -149,6 +150,11 @@
// Unsupported
return false;
}
+
+ @Override
+ public int getFolderListViewChoiceMode() {
+ return ListView.CHOICE_MODE_NONE;
+ }
};
@Override
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 527513a..ed62708 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -24,6 +24,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
+import android.widget.ListView;
import com.android.mail.ConversationListContext;
import com.android.mail.R;
@@ -374,6 +375,12 @@
mActivity.finish();
} else if (mViewMode.isListMode() && !inInbox(mAccount, mConvListContext)) {
if (mLastFolderListTransactionId != INVALID_ID) {
+ // Set the hierarchy folder to what it will be once we go up
+ final Folder hierarchyFolder = getHierarchyFolder();
+ if (hierarchyFolder != null && hierarchyFolder.parent != null) {
+ setHierarchyFolder(hierarchyFolder.parent);
+ }
+
// If the user got here by navigating via the folder list, back
// should bring them back to the folder list.
mViewMode.enterFolderListMode();
@@ -434,6 +441,7 @@
FolderListFragment.ofTree(folder, false),
FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST, R.id.content_pane);
} else {
+ setHierarchyFolder(folder);
super.onFolderSelected(folder);
}
}
@@ -652,4 +660,10 @@
// The drawer is enabled for one pane mode
return true;
}
+
+ @Override
+ public int getFolderListViewChoiceMode() {
+ // By default, we do not want to allow any item to be selected in the folder list
+ return ListView.CHOICE_MODE_NONE;
+ }
}
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index da71cb4..5294a61 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -24,6 +24,7 @@
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.widget.FrameLayout;
+import android.widget.ListView;
import com.android.mail.ConversationListContext;
import com.android.mail.R;
@@ -431,6 +432,15 @@
createFolderListFragment(FolderListFragment.ofDrawer());
loadAccountInbox();
}
+ // Otherwise, if we are in the conversation list but not in the default
+ // inbox and not on expansive layouts, we want to switch back to the default
+ // inbox. This fixes b/9006969 so that on smaller tablets where we have this
+ // hybrid one and two-pane mode, we will return to the inbox. On larger tablets,
+ // we will instead exit the app.
+ } else if (mode == ViewMode.CONVERSATION_LIST
+ && !mAccount.settings.defaultInbox.equals(mFolder.uri)
+ && !mLayout.isExpansiveLayout()) {
+ loadAccountInbox();
} else if (!preventClose) {
// There is nothing else to pop off the stack.
mActivity.finish();
@@ -564,4 +574,10 @@
public boolean isDrawerEnabled() {
return mLayout.isDrawerEnabled();
}
+
+ @Override
+ public int getFolderListViewChoiceMode() {
+ // By default, we want to allow one item to be selected in the folder list
+ return ListView.CHOICE_MODE_SINGLE;
+ }
}
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index 29e0547..779d73e 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -586,4 +586,7 @@
return !mIsExpansiveLayout && mDrawerInitialSetupComplete;
}
+ public boolean isExpansiveLayout() {
+ return mIsExpansiveLayout;
+ }
}
diff --git a/src/com/android/mail/utils/MimeType.java b/src/com/android/mail/utils/MimeType.java
index 8f0ca96..0f6a18c 100644
--- a/src/com/android/mail/utils/MimeType.java
+++ b/src/com/android/mail/utils/MimeType.java
@@ -43,7 +43,7 @@
static final String GENERIC_MIMETYPE = "application/octet-stream";
@VisibleForTesting
- static final String EML_ATTACHMENT_CONTENT_TYPE = "application/eml";
+ public static final String EML_ATTACHMENT_CONTENT_TYPE = "message/rfc822";
private static final String NULL_ATTACHMENT_CONTENT_TYPE = "null";
private static final Set<String> UNACCEPTABLE_ATTACHMENT_TYPES = ImmutableSet.of(
"application/zip", "application/x-gzip", "application/x-bzip2",
@@ -151,7 +151,7 @@
* Returns the mime type of the attachment based on its name and
* original mime type. This is an workaround for bugs where Gmail
* server doesn't set content-type for certain types correctly.
- * 1) EML files -> "application/eml".
+ * 1) EML files -> "message/rfc822".
* @param name name of the attachment.
* @param mimeType original mime type of the attachment.
* @return the inferred mime type of the attachment.
@@ -174,7 +174,7 @@
if (!TextUtils.isEmpty(type)) {
return type;
} if (extension.equals("eml")) {
- // Extension is ".eml", return mime type "application/eml"
+ // Extension is ".eml", return mime type "message/rfc822"
return EML_ATTACHMENT_CONTENT_TYPE;
} else {
// Extension is not ".eml", just return original mime type.