Merge "Import translations. DO NOT MERGE" into jb-ub-mail-ur11
diff --git a/res/raw/template_conversation_upper.html b/res/raw/template_conversation_upper.html
index 5ba3a84..cd448e3 100644
--- a/res/raw/template_conversation_upper.html
+++ b/res/raw/template_conversation_upper.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <meta id="meta-viewport" name="viewport" content="width=device-width initial-scale=1.0"
+ <meta id="meta-viewport" name="viewport" content="width=device-width"
data-zoom-on="maximum-scale=2" data-zoom-off="user-scalable=no" />
<style>
.elided-text,
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4f6f08e..d4106d6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -440,9 +440,9 @@
viewing it. [CHAR LIMIT=40] -->
<string name="add_label">Add folder</string>
- <!-- New Message notification text that appears over conversation view on incoming message. [CHAR LIMIT=30] -->
+ <!-- New Message notification text that appears over conversation view on incoming message. [CHAR LIMIT=40] -->
<string name="new_incoming_messages_one">New message from <xliff:g id="sender">%s</xliff:g>. Show.</string>
- <!-- New Message notification text that appears over conversation view on incoming messages. Will only be used if there is more than one new message. [CHAR LIMIT=30] -->
+ <!-- New Message notification text that appears over conversation view on incoming messages. Will only be used if there is more than one new message. [CHAR LIMIT=40] -->
<plurals name="new_incoming_messages_many">
<item quantity="other"><xliff:g id="count">%1$d</xliff:g> new messages. Show.</item>
</plurals>
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 46bf234..26c2241 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -822,7 +822,11 @@
mHeader.hasDraftMessage = mHeader.conversation.numDrafts() > 0;
// Parse senders fragments.
- if (mHeader.conversation.conversationInfo != null) {
+ if (mHeader.preserveSendersText) {
+ // This is a special view that doesn't need special sender formatting
+ mHeader.sendersDisplayText = new SpannableStringBuilder(mHeader.sendersText);
+ loadSenderImages();
+ } else if (mHeader.conversation.conversationInfo != null) {
// This is Gmail
Context context = getContext();
mHeader.messageInfoString = SendersView
diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index ea191a0..359f8f3 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -78,6 +78,9 @@
// Paperclip
Bitmap paperclip;
+ /** If <code>true</code>, we will not apply any formatting to {@link #sendersText}. */
+ public boolean preserveSendersText = false;
+
// Senders
public String sendersText;
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index bc2cc26..30d38c9 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -734,7 +734,8 @@
public static final class FolderCapabilities {
public static final int SYNCABLE = 0x0001;
public static final int PARENT = 0x0002;
- public static final int CAN_HOLD_MAIL = 0x0004;
+ // FEEL FREE TO USE 0x0004 - was previous CAN_HOLD_MAIL but that was true for all
+ // folders so we removed that value
public static final int CAN_ACCEPT_MOVED_MESSAGES = 0x0008;
/**
* For accounts that support archive, this will indicate that this folder supports
diff --git a/src/com/android/mail/providers/protos/mock/MockUiProvider.java b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
index c4cd785..1b1a4f0 100644
--- a/src/com/android/mail/providers/protos/mock/MockUiProvider.java
+++ b/src/com/android/mail/providers/protos/mock/MockUiProvider.java
@@ -294,7 +294,6 @@
Long.valueOf(
FolderCapabilities.SYNCABLE |
FolderCapabilities.PARENT |
- FolderCapabilities.CAN_HOLD_MAIL |
FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES));
folderMap.put(FolderColumns.UNREAD_COUNT, unread);
folderMap.put(FolderColumns.TOTAL_COUNT, total);
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 7bd5e79..26960c6 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -38,7 +38,6 @@
import android.content.Loader;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.database.Cursor;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.net.Uri;
@@ -157,8 +156,6 @@
private static final String SAVED_ACTION_FROM_SELECTED = "saved-action-from-selected";
/** Tag for {@link #mDetachedConvUri} */
private static final String SAVED_DETACHED_CONV_URI = "saved-detached-conv-uri";
- /** Key to store {@link #mInbox}. */
- private final static String SAVED_INBOX_KEY = "m-inbox";
/** Tag used when loading a wait fragment */
protected static final String TAG_WAIT = "wait-fragment";
@@ -174,7 +171,6 @@
protected Account mAccount;
protected Folder mFolder;
- protected Folder mInbox;
/** True when {@link #mFolder} is first shown to the user. */
private boolean mFolderChanged = false;
protected MailActionBarView mActionBarView;
@@ -831,7 +827,7 @@
}
@Override
- public void onFolderChanged(Folder folder, final boolean force) {
+ public void onFolderChanged(Folder folder) {
/** If the folder doesn't exist, or its parent URI is empty,
* this is not a child folder */
final boolean isTopLevel = (folder == null) || (folder.parent == Uri.EMPTY);
@@ -842,13 +838,7 @@
? DrawerLayout.LOCK_MODE_UNLOCKED : DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
mDrawerContainer.closeDrawers();
-
- if (mFolder == null || !mFolder.equals(folder)) {
- // We are actually changing the folder, so exit cab mode
- exitCabMode();
- }
-
- changeFolder(folder, null, force);
+ changeFolder(folder, null);
}
/**
@@ -871,14 +861,12 @@
* Changes the folder to the value provided here. This causes the view mode to change.
* @param folder the folder to change to
* @param query if non-null, this represents the search string that the folder represents.
- * @param force <code>true</code> to force a folder change, <code>false</code> to disallow
- * changing to the current folder
*/
- private void changeFolder(Folder folder, String query, final boolean force) {
+ private void changeFolder(Folder folder, String query) {
if (!Objects.equal(mFolder, folder)) {
commitDestructiveActions(false);
}
- if (folder != null && (!folder.equals(mFolder) || force)
+ if (folder != null && !folder.equals(mFolder)
|| (mViewMode.getMode() != ViewMode.CONVERSATION_LIST)) {
setListContext(folder, query);
showConversationList(mConvListContext);
@@ -890,7 +878,7 @@
@Override
public void onFolderSelected(Folder folder) {
- onFolderChanged(folder, false /* force */);
+ onFolderChanged(folder);
}
/**
@@ -923,7 +911,7 @@
if (mFolderWatcher != null) {
final Folder inbox = mFolderWatcher.getDefaultInbox(mAccount);
if (inbox != null) {
- onFolderChanged(inbox, false /* force */);
+ onFolderChanged(inbox);
handled = true;
}
}
@@ -2041,8 +2029,6 @@
outState.putParcelable(SAVED_HIERARCHICAL_FOLDER, mFolderListFolder);
mSafeToModifyFragments = false;
-
- outState.putParcelable(SAVED_INBOX_KEY, mInbox);
}
/**
@@ -2258,8 +2244,6 @@
if (mDialogAction != -1) {
makeDialogListener(mDialogAction, mDialogFromSelectedSet);
}
-
- mInbox = savedState.getParcelable(SAVED_INBOX_KEY);
}
/**
@@ -3155,8 +3139,6 @@
&& event.getClipDescription() != null
&& folder.supportsCapability
(UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)
- && folder.supportsCapability
- (UIProvider.FolderCapabilities.CAN_HOLD_MAIL)
&& !mFolder.equals(folder));
}
@@ -3497,7 +3479,7 @@
case LOADER_ACCOUNT_INBOX:
if (data != null && !data.isClosed() && data.moveToFirst()) {
final Folder inbox = data.getModel();
- onFolderChanged(inbox, false /* force */);
+ onFolderChanged(inbox);
// Just want to get the inbox, don't care about updates to it
// as this will be tracked by the folder change listener.
mActivity.getLoaderManager().destroyLoader(LOADER_ACCOUNT_INBOX);
@@ -3529,7 +3511,7 @@
final Folder folder = data.getModel();
boolean handled = false;
if (folder != null) {
- onFolderChanged(folder, false /* force */);
+ onFolderChanged(folder);
handled = true;
}
if (mConversationToShow != null) {
@@ -4260,57 +4242,4 @@
public boolean shouldHideMenuItems() {
return mHideMenuItems;
}
-
- protected void navigateUpFolderHierarchy() {
- new AsyncTask<Void, Void, Folder>() {
- @Override
- protected Folder doInBackground(final Void... params) {
- if (mInbox == null) {
- // We don't have an inbox, but we need it
- final Cursor cursor = mContext.getContentResolver().query(
- mAccount.settings.defaultInbox, UIProvider.FOLDERS_PROJECTION, null,
- null, null);
-
- if (cursor != null) {
- try {
- if (cursor.moveToFirst()) {
- mInbox = new Folder(cursor);
- }
- } finally {
- cursor.close();
- }
- }
- }
-
- // Now try to load our parent
- final Folder folder;
-
- if (mFolder != null) {
- final Cursor cursor = mContext.getContentResolver().query(mFolder.parent,
- UIProvider.FOLDERS_PROJECTION, null, null, null);
-
- if (cursor == null) {
- // We couldn't load the parent, so use the inbox
- folder = mInbox;
- } else {
- try {
- cursor.moveToFirst();
- folder = new Folder(cursor);
- } finally {
- cursor.close();
- }
- }
- } else {
- folder = mInbox;
- }
-
- return folder;
- }
-
- @Override
- protected void onPostExecute(final Folder result) {
- onFolderSelected(result);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
- }
}
diff --git a/src/com/android/mail/ui/FolderChangeListener.java b/src/com/android/mail/ui/FolderChangeListener.java
index 0968fa7..cc9c051 100644
--- a/src/com/android/mail/ui/FolderChangeListener.java
+++ b/src/com/android/mail/ui/FolderChangeListener.java
@@ -26,8 +26,6 @@
* Handles selecting a folder from within the {@link FolderListFragment}.
*
* @param folder the selected folder
- * @param force <code>true</code> to force a folder change, <code>false</code> to disallow
- * changing to the current folder
*/
- void onFolderChanged(Folder folder, boolean force);
+ void onFolderChanged(Folder folder);
}
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
index ea1dcdc..7eee145 100644
--- a/src/com/android/mail/ui/FolderListFragment.java
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -216,7 +216,7 @@
*/
private static Bundle getBundleFromArgs(Folder parentFolder, Uri folderListUri,
final ArrayList<Integer> excludedFolderTypes) {
- final Bundle args = new Bundle(3);
+ final Bundle args = new Bundle();
if (parentFolder != null) {
args.putParcelable(ARG_PARENT_FOLDER, parentFolder);
}
@@ -1077,6 +1077,10 @@
}
}
+ public Folder getParentFolder() {
+ return mParentFolder;
+ }
+
/**
* Sets the currently selected folder safely.
* @param folder the folder to change to. It is an error to pass null here.
@@ -1157,6 +1161,14 @@
}
/**
+ * Get whether the FolderListFragment is currently showing the hierarchy
+ * under a single parent.
+ */
+ public boolean showingHierarchy() {
+ return mParentFolder != null;
+ }
+
+ /**
* Checks if the specified {@link Folder} is a type that we want to exclude from displaying.
*/
private boolean isFolderTypeExcluded(final Folder folder) {
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index 16b74a5..14a1089 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -266,7 +266,7 @@
}
@Override
- public void onFolderChanged(Folder folder, final boolean force) {
+ public void onFolderChanged(Folder folder) {
if (!folder.equals(mSelectedFolder)) {
mSelectedFolder = folder;
Intent resultIntent = new Intent();
@@ -350,7 +350,7 @@
createFolderListFragment(FolderListFragment.ofTree(folder));
return;
}
- onFolderChanged(folder, false /* force */);
+ onFolderChanged(folder);
}
@Override
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 8ce5c0c..ffd1a04 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -20,7 +20,10 @@
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.database.Cursor;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.widget.ListView;
@@ -32,6 +35,7 @@
import com.android.mail.providers.Folder;
import com.android.mail.providers.UIProvider;
import com.android.mail.utils.FolderUri;
+import com.android.mail.utils.LogUtils;
import com.android.mail.utils.Utils;
/**
@@ -40,6 +44,9 @@
*/
public final class OnePaneController extends AbstractActivityController {
+ /** Key used to store {@link #mLastInboxConversationListTransactionId} */
+ private static final String INBOX_CONVERSATION_LIST_TRANSACTION_KEY =
+ "inbox_conversation-list-transaction";
/** Key used to store {@link #mLastConversationListTransactionId} */
private static final String CONVERSATION_LIST_TRANSACTION_KEY = "conversation-list-transaction";
/** Key used to store {@link #mLastConversationTransactionId}. */
@@ -48,11 +55,15 @@
private static final String CONVERSATION_LIST_VISIBLE_KEY = "conversation-list-visible";
/** Key used to store {@link #mConversationListNeverShown}. */
private static final String CONVERSATION_LIST_NEVER_SHOWN_KEY = "conversation-list-never-shown";
+ /** Key to store {@link #mInbox}. */
+ private final static String SAVED_INBOX_KEY = "m-inbox";
private static final int INVALID_ID = -1;
private boolean mConversationListVisible = false;
+ private int mLastInboxConversationListTransactionId = INVALID_ID;
private int mLastConversationListTransactionId = INVALID_ID;
private int mLastConversationTransactionId = INVALID_ID;
+ private Folder mInbox;
/** Whether a conversation list for this account has ever been shown.*/
private boolean mConversationListNeverShown = true;
@@ -66,20 +77,26 @@
if (inState == null) {
return;
}
+ mLastInboxConversationListTransactionId =
+ inState.getInt(INBOX_CONVERSATION_LIST_TRANSACTION_KEY, INVALID_ID);
mLastConversationListTransactionId =
inState.getInt(CONVERSATION_LIST_TRANSACTION_KEY, INVALID_ID);
mLastConversationTransactionId = inState.getInt(CONVERSATION_TRANSACTION_KEY, INVALID_ID);
mConversationListVisible = inState.getBoolean(CONVERSATION_LIST_VISIBLE_KEY);
mConversationListNeverShown = inState.getBoolean(CONVERSATION_LIST_NEVER_SHOWN_KEY);
+ mInbox = inState.getParcelable(SAVED_INBOX_KEY);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
+ outState.putInt(INBOX_CONVERSATION_LIST_TRANSACTION_KEY,
+ mLastInboxConversationListTransactionId);
outState.putInt(CONVERSATION_LIST_TRANSACTION_KEY, mLastConversationListTransactionId);
outState.putInt(CONVERSATION_TRANSACTION_KEY, mLastConversationTransactionId);
outState.putBoolean(CONVERSATION_LIST_VISIBLE_KEY, mConversationListVisible);
outState.putBoolean(CONVERSATION_LIST_NEVER_SHOWN_KEY, mConversationListNeverShown);
+ outState.putParcelable(SAVED_INBOX_KEY, mInbox);
}
@Override
@@ -158,6 +175,8 @@
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(super.toString());
+ sb.append(" lastInboxTransId=");
+ sb.append(mLastInboxConversationListTransactionId);
sb.append(" lastConvListTransId=");
sb.append(mLastConversationListTransactionId);
sb.append("}");
@@ -183,13 +202,13 @@
if (!inInbox(mAccount, listContext)) {
// Maintain fragment transaction history so we can get back to the
// fragment used to launch this list.
- mLastConversationListTransactionId = replaceFragment(conversationListFragment,
+ mLastConversationListTransactionId = replaceFragmentWithBack(conversationListFragment,
transition, TAG_CONVERSATION_LIST, R.id.content_pane);
} else {
// If going to the inbox, clear the folder list transaction history.
mInbox = listContext.folder;
- replaceFragment(conversationListFragment, transition, TAG_CONVERSATION_LIST,
- R.id.content_pane);
+ mLastInboxConversationListTransactionId = replaceFragmentWithBack(
+ conversationListFragment, transition, TAG_CONVERSATION_LIST, R.id.content_pane);
// If we ever to to the inbox, we want to unset the transation id for any other
// non-inbox folder.
@@ -208,7 +227,7 @@
super.showConversation(conversation, inLoaderCallbacks);
mConversationListVisible = false;
if (conversation == null) {
- transitionBackToConversationListMode();
+ transitionBackToConversationListMode(inLoaderCallbacks);
return;
}
disableCabMode();
@@ -277,17 +296,30 @@
/**
* Replace the content_pane with the fragment specified here. The tag is specified so that
* the {@link ActivityController} can look up the fragments through the
- * {@link android.app.FragmentManager}.
+ * {@link android.app.FragmentManager}. This action will be placed on the back stack.
* @param fragment the new fragment to put
* @param transition the transition to show
* @param tag a tag for the fragment manager.
* @param anchor ID of view to replace fragment in
* @return transaction ID returned when the transition is committed.
*/
- private int replaceFragment(Fragment fragment, int transition, String tag, int anchor) {
+ private int replaceFragmentWithBack(Fragment fragment, int transition, String tag, int anchor) {
+ return replaceFragment(fragment, transition, tag, anchor, true);
+ }
+
+ // (Not on the back stack -> no transaction ID to return.)
+ private void replaceFragment(Fragment fragment, int transition, String tag, int anchor) {
+ replaceFragment(fragment, transition, tag, anchor, false);
+ }
+
+ private int replaceFragment(Fragment fragment, int transition, String tag, int anchor,
+ boolean addToBackStack) {
final FragmentManager fm = mActivity.getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.setTransition(transition);
+ if (addToBackStack) {
+ fragmentTransaction.addToBackStack(null);
+ }
fragmentTransaction.replace(anchor, fragment, tag);
final int id = fragmentTransaction.commitAllowingStateLoss();
fm.executePendingTransactions();
@@ -315,9 +347,9 @@
if (mode == ViewMode.SEARCH_RESULTS_LIST) {
mActivity.finish();
} else if (mViewMode.isListMode() && !inInbox(mAccount, mConvListContext)) {
- navigateUpFolderHierarchy();
+ transitionToInbox();
} else if (mViewMode.isConversationMode() || mViewMode.isAdMode()) {
- transitionBackToConversationListMode();
+ transitionBackToConversationListMode(false /* inLoaderCallbacks */);
} else {
mActivity.finish();
}
@@ -325,6 +357,39 @@
return true;
}
+ private void goUpFolderHierarchy(Folder current) {
+ // This code is currently never called. Now that we have the URI, load the parent, if
+ // required. http://b/9694899
+ // onFolderSelected(current.parent);
+ }
+
+ private void navigateUp() {
+ new AsyncTask<Void, Void, Folder>() {
+ @Override
+ protected Folder doInBackground(final Void... params) {
+ final Folder folder;
+
+ final Cursor cursor = mContext.getContentResolver().query(mFolder.parent,
+ UIProvider.FOLDERS_PROJECTION, null, null, null);
+
+ if (cursor == null) {
+ folder = mInbox;
+ } else {
+ cursor.moveToFirst();
+ folder = new Folder(cursor);
+ cursor.close();
+ }
+
+ return folder;
+ }
+
+ @Override
+ protected void onPostExecute(final Folder result) {
+ onFolderSelected(result);
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+
/**
* Switch to the Inbox by creating a new conversation list context that loads the inbox.
*/
@@ -333,7 +398,7 @@
if (mInbox == null || !isDefaultInbox(mInbox.folderUri, mAccount)) {
loadAccountInbox();
} else {
- onFolderChanged(mInbox, false /* force */);
+ onFolderChanged(mInbox);
}
}
@@ -343,6 +408,10 @@
super.onFolderSelected(folder);
}
+ private static boolean isTransactionIdValid(int id) {
+ return id >= 0;
+ }
+
/**
* Up works as follows:
* 1) If the user is in a conversation list that is not the default account inbox,
@@ -365,7 +434,7 @@
// Show the drawer.
toggleDrawerState();
} else {
- navigateUpFolderHierarchy();
+ navigateUp();
}
} else if (mode == ViewMode.CONVERSATION || mode == ViewMode.SEARCH_RESULTS_CONVERSATION
|| mode == ViewMode.AD) {
@@ -375,7 +444,7 @@
return true;
}
- private void transitionBackToConversationListMode() {
+ private void transitionBackToConversationListMode(boolean inLoaderCallbacks) {
final int mode = mViewMode.getMode();
enableCabMode();
mConversationListVisible = true;
@@ -384,14 +453,50 @@
} else {
mViewMode.enterConversationListMode();
}
-
- final Folder folder = mFolder != null ? mFolder : mInbox;
- onFolderChanged(folder, true /* force */);
-
+ if (isTransactionIdValid(mLastConversationListTransactionId)) {
+ safelyPopBackStack(mLastConversationListTransactionId, inLoaderCallbacks);
+ } else if (isTransactionIdValid(mLastInboxConversationListTransactionId)) {
+ safelyPopBackStack(mLastInboxConversationListTransactionId, inLoaderCallbacks);
+ onFolderChanged(mInbox);
+ } else {
+ // TODO: revisit if this block is necessary
+ // Set the correct context for what the conversation view will be now.
+ onFolderChanged(mInbox);
+ }
onConversationVisibilityChanged(false);
onConversationListVisibilityChanged(true);
}
+ /**
+ * Pop to a specified point in the fragment back stack without causing IllegalStateExceptions
+ * from committing a fragment transaction "at the wrong time".
+ * <p>
+ * If the caller specifies that we are in
+ * the scope of an {@link LoaderCallbacks#onLoadFinished(android.content.Loader, Object)},
+ * this method will pop back in a Handler. The deferred job will also check that the Activity
+ * is in a valid state for fragment transactions, using {@link #safeToModifyFragments()}.
+ * Otherwise, this method will pop back immediately if safe. Finally, if we are not in
+ * onLoadFinished and it's not safe, this method will just ignore the request.
+ *
+ * @param transactionId back stack destination to pop to, or -1 to just pop the top
+ * @param inLoaderCallbacks whether we are in the scope of an onLoadFinished (when fragment
+ * transactions are disallowed)
+ */
+ private void safelyPopBackStack(int transactionId, boolean inLoaderCallbacks) {
+ final PopBackStackRunnable r = new PopBackStackRunnable(transactionId);
+ if (inLoaderCallbacks) {
+ // always run deferred. ensure deferred job checks safety.
+ mHandler.post(r);
+ } else if (safeToModifyFragments()) {
+ // run now
+ r.popBackStack();
+ } else {
+ // ignore
+ LogUtils.i(LOG_TAG, "Activity has been saved; ignoring unsafe immediate request"
+ + " to pop back stack");
+ }
+ }
+
@Override
public boolean shouldShowFirstConversation() {
return false;
@@ -453,6 +558,34 @@
}
}
+ private final class PopBackStackRunnable implements Runnable {
+
+ private final int mTransactionId;
+
+ public PopBackStackRunnable(int transactionId) {
+ mTransactionId = transactionId;
+ }
+
+ public void popBackStack() {
+ final FragmentManager fm = mActivity.getFragmentManager();
+ if (mTransactionId < 0) {
+ fm.popBackStackImmediate();
+ } else {
+ fm.popBackStackImmediate(mTransactionId, 0);
+ }
+ }
+
+ @Override
+ public void run() {
+ if (safeToModifyFragments()) {
+ popBackStack();
+ } else {
+ LogUtils.i(LOG_TAG, "Activity has been saved; ignoring unsafe deferred request"
+ + " to pop back stack");
+ }
+ }
+ }
+
@Override
public boolean isDrawerEnabled() {
// The drawer is enabled for one pane mode
@@ -467,7 +600,7 @@
@Override
public void launchFragment(final Fragment fragment, final int selectPosition) {
- replaceFragment(fragment, FragmentTransaction.TRANSIT_FRAGMENT_OPEN,
+ replaceFragmentWithBack(fragment, FragmentTransaction.TRANSIT_FRAGMENT_OPEN,
TAG_CUSTOM_FRAGMENT, R.id.content_pane);
}
}
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 28b01c9..ff022e2 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -159,13 +159,19 @@
}
@Override
+ public void onFolderChanged(Folder folder) {
+ super.onFolderChanged(folder);
+ exitCabMode();
+ }
+
+ @Override
public void onFolderSelected(Folder folder) {
// It's possible that we are not in conversation list mode
if (mViewMode.getMode() != ViewMode.CONVERSATION_LIST) {
mViewMode.enterConversationListMode();
}
- if (folder.parent != Uri.EMPTY) {
+ if (folder.hasChildren) {
// Show the up affordance when digging into child folders.
mActionBarView.setBackButton();
}
@@ -173,6 +179,15 @@
super.onFolderSelected(folder);
}
+ private void goUpFolderHierarchy(Folder current) {
+ // If the current folder is a child, up should show the parent folder.
+ // Fix this to load the parent folder: http://b/9694899
+// final Folder parent = current.parent;
+// if (parent != null) {
+// onFolderSelected(parent);
+// }
+ }
+
@Override
public void onViewModeChanged(int newMode) {
if (!mSavedMiscellaneousView && mMiscellaneousViewTransactionId >= 0) {
@@ -222,10 +237,9 @@
if (isDrawerEnabled()) {
return;
}
- // On two-pane, the back button is only removed in the conversation list mode for top level
- // folders, and shown for every other condition.
- if ((mViewMode.isListMode() && (mFolder == null || mFolder.parent == null
- || mFolder.parent == Uri.EMPTY)) || mViewMode.isWaitingForSync()) {
+ // On two-pane, the back button is only removed in the conversation list mode, and shown
+ // for every other condition.
+ if (mViewMode.isListMode() || mViewMode.isWaitingForSync()) {
mActionBarView.removeBackButton();
} else {
mActionBarView.setBackButton();
@@ -419,10 +433,19 @@
// folder list has had a chance to initialize.
final FolderListFragment folderList = getFolderListFragment();
if (mode == ViewMode.CONVERSATION_LIST && folderList != null
- && mFolder != null && mFolder.parent != Uri.EMPTY) {
+ && folderList.showingHierarchy()) {
// If the user navigated via the left folders list into a child folder,
// back should take the user up to the parent folder's conversation list.
- navigateUpFolderHierarchy();
+ // TODO: Clean this code up: http://b/9694899
+ final Folder hierarchyFolder = getHierarchyFolder();
+ if (hierarchyFolder.parent != Uri.EMPTY) {
+ goUpFolderHierarchy(hierarchyFolder);
+ } else {
+ // Show inbox; we are at the top of the hierarchy we were
+ // showing, and it doesn't have a parent, so we must want to
+ // the basic account folder list.
+ 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
@@ -574,11 +597,13 @@
final int containerViewId = TwoPaneLayout.MISCELLANEOUS_VIEW_ID;
final FragmentManager fragmentManager = mActivity.getFragmentManager();
- final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
- fragmentTransaction.addToBackStack(null);
- fragmentTransaction.replace(containerViewId, fragment, TAG_CUSTOM_FRAGMENT);
- mMiscellaneousViewTransactionId = fragmentTransaction.commitAllowingStateLoss();
- fragmentManager.executePendingTransactions();
+ if (fragmentManager.findFragmentByTag(TAG_CUSTOM_FRAGMENT) == null) {
+ final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ fragmentTransaction.addToBackStack(null);
+ fragmentTransaction.replace(containerViewId, fragment, TAG_CUSTOM_FRAGMENT);
+ mMiscellaneousViewTransactionId = fragmentTransaction.commitAllowingStateLoss();
+ fragmentManager.executePendingTransactions();
+ }
if (selectPosition >= 0) {
getConversationListFragment().setRawSelected(selectPosition, true);
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index f4276a3..98687be 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -450,7 +450,7 @@
break;
case ViewMode.AD:
dispatchConversationVisibilityChanged(false);
- dispatchConversationListVisibilityChange(false);
+ dispatchConversationListVisibilityChange(!isConversationListCollapsed());
break;
default: