parentKey
+ * Returns a cursor loader for the mailboxes of the given account. If parentKey
* refers to a valid mailbox ID [e.g. non-zero], restrict the loader to only those mailboxes
* contained by this parent mailbox.
+ *
+ * Note the returned loader always returns a {@link CursorWithExtras}.
*/
- public static Loader+ * Parameters: + * - Account ID. + * - Set via {@link #newInstance}. + * - Can be obtained with {@link #getAccountId()}. + * - Will not change throughout fragment lifecycle. + * - Either an actual account ID, or {@link Account#ACCOUNT_ID_COMBINED_VIEW}. + * + * - "Highlight enabled?" flag + * - Set via {@link #newInstance}. + * - Can be obtained with {@link #getEnableHighlight()}. + * - Will not change throughout fragment lifecycle. + * - If {@code true}, we highlight the "selected" mailbox (used only on 2-pane). + * - Note even if it's {@code true}, there may be no highlighted mailbox. + * (This usually happens on 2-pane before the UI controller finds the Inbox to highlight.) + * + * - "Parent" mailbox ID + * - Stored in {@link #mParentMailboxId} + * - Changes as the user navigates through nested mailboxes. + * - Initialized using the {@code mailboxId} parameter for {@link #newInstance} + * in {@link #setInitialParentAndHighlight()}. + * + * - "Highlighted" mailbox + * - Only used when highlighting is enabled. (Otherwise always {@link Mailbox#NO_MAILBOX}.) + * i.e. used only on two-pane. + * - Stored in {@link #mHighlightedMailboxId} + * - Initialized using the {@code mailboxId} parameter for {@link #newInstance} + * in {@link #setInitialParentAndHighlight()}. + * + * - Can be changed any time, using {@link #setHighlightedMailbox(long)}. + * + * - If set, it's considered "selected", and we highlight the list item. + * + * - (It should always be the ID of the list item selected in the list view, but we store it in + * a member for efficiency.) + * + * - Sometimes, we need to set the highlighted mailbox while we're still loading data. + * In this case, we can't update {@link #mHighlightedMailboxId} right away, but need to do so + * in when the next data set arrives, in + * {@link MailboxListFragment.MailboxListLoaderCallbacks#onLoadFinished}. For this, we use + * we store the mailbox ID in {@link #mNextHighlightedMailboxId} and update + * {@link #mHighlightedMailboxId} in onLoadFinished. + * + * + * The "selected" is defined using the "parent" and "highlighted" mailboxes. + * - "Selected" mailbox (also sometimes called "current".) + * - This is what the user thinks it's now selected. + * + * - Can be obtained with {@link #getSelectedMailboxId()} + * - If the "highlighted" mailbox exists, it's the "selected." Otherwise, the "parent" + * is considered "selected." + * - This is what is passed to {@link Callback#onMailboxSelected}. + *+ * + * + * This fragment shows the content in one of the three following views, depending on the + * parameters above. + * + *
+ * 1. Combined view + * - Used if the account ID == {@link Account#ACCOUNT_ID_COMBINED_VIEW}. + * - Parent mailbox is always {@link Mailbox#NO_MAILBOX}. + * - List contains: + * - combined mailboxes + * - all accounts + * + * 2. Root view for an account + * - Used if the account ID != {@link Account#ACCOUNT_ID_COMBINED_VIEW} and + * Parent mailbox == {@link Mailbox#NO_MAILBOX} + * - List contains + * - all the top level mailboxes for the selected account. + * + * 3. Root view for a mailbox. (nested view) + * - Used if the account ID != {@link Account#ACCOUNT_ID_COMBINED_VIEW} and + * Parent mailbox != {@link Mailbox#NO_MAILBOX} + * - List contains: + * - parent mailbox (determined by "parent" mailbox ID) + * - all child mailboxes of the parent mailbox. + *+ * * * Note that when a fragment is put in the back stack, it'll lose the content view but the fragment * itself is not destroyed. If you call {@link #getListView()} in this state it'll throw @@ -65,14 +150,20 @@ import java.util.TimerTask; * no views. * - Otherwise, make sure to check if the fragment has views with {@link #isViewCreated()} * before touching any views. + * + * TODO Remove the nested folder navigation code during drag&drop. */ public class MailboxListFragment extends ListFragment implements OnItemClickListener, OnDragListener { private static final String TAG = "MailboxListFragment"; - private static final String BUNDLE_KEY_SELECTED_MAILBOX_ID + + private static final String BUNDLE_KEY_PARENT_MAILBOX_ID + = "MailboxListFragment.state.parent_mailbox_id"; + private static final String BUNDLE_KEY_HIGHLIGHTED_MAILBOX_ID = "MailboxListFragment.state.selected_mailbox_id"; private static final String BUNDLE_LIST_STATE = "MailboxListFragment.state.listState"; private static final boolean DEBUG_DRAG_DROP = false; // MUST NOT SUBMIT SET TO TRUE + /** While in drag-n-drop, amount of time before it auto expands; in ms */ private static final long AUTO_EXPAND_DELAY = 750L; @@ -88,7 +179,10 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList /** Argument name(s) */ private static final String ARG_ACCOUNT_ID = "accountId"; - private static final String ARG_PARENT_MAILBOX_ID = "parentMailboxId"; + private static final String ARG_ENABLE_HIGHLIGHT = "enablehighlight"; + private static final String ARG_INITIAL_CURRENT_MAILBOX_ID = "initialParentMailboxId"; + + private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker(); /** Timer to auto-expand folder lists during drag-n-drop */ private static final Timer sDragTimer = new Timer(); @@ -106,8 +200,14 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList private static Integer sDropTrashColor; private static Drawable sDropActiveDrawable; - /** ID of the mailbox to hightlight. */ - private long mSelectedMailboxId = -1; + // See the class javadoc + private long mParentMailboxId; + private long mHighlightedMailboxId; + + /** + * ID of the mailbox that should be highlighted when the next cursor is loaded. + */ + private long mNextHighlightedMailboxId = Mailbox.NO_MAILBOX; // True if a drag is currently in progress private boolean mDragInProgress; @@ -147,28 +247,20 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList * @param mailboxId * The ID of the selected mailbox. This may be real mailbox ID [e.g. a number > 0], * or a combined mailbox ID [e.g. {@link Mailbox#QUERY_ALL_INBOXES}]. - * @param navigate navigate to the mailbox. + * @param nestedNavigation {@code true} if the event is caused by nested mailbox navigation, + * that is, going up or drilling-in to a child mailbox. */ - public void onMailboxSelected(long accountId, long mailboxId, boolean navigate); - - /** - * Called if the mailbox ID is being requested to change. This could occur for several - * reasons; such as if the current, navigated mailbox has no more children. - * @param newMailboxId The new mailbox ID to use for displaying in the mailbox list - * @param selectedMailboxId The new mailbox ID to highlight. If {@link Mailbox#NO_MAILBOX}, - * the receiver may select any mailbox it chooses. - */ - public void requestMailboxChange(long newMailboxId, long selectedMailboxId); - - /** - * Called when a mailbox is selected during D&D. - */ - public void onMailboxSelectedForDnD(long mailboxId); + public void onMailboxSelected(long accountId, long mailboxId, boolean nestedNavigation); /** Called when an account is selected on the combined view. */ public void onAccountSelected(long accountId); /** + * TODO Remove it. The behavior is not well-defined. (Won't get called when highlight is + * disabled.) + * It was added only to update the action bar with the current mailbox name and the + * message count. Remove it and make the action bar watch the mailbox by itself. + * * Called when the list updates to propagate the current mailbox name and the unread count * for it. * @@ -180,17 +272,22 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList * {@link MailboxListFragment#getAccountId()}. */ public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount); + + /** + * Called when the parent mailbox is changing. + */ + public void onParentMailboxChanged(); } private static class EmptyCallback implements Callback { public static final Callback INSTANCE = new EmptyCallback(); - @Override public void onMailboxSelected(long accountId, long mailboxId, boolean navigate) { - } - @Override public void onMailboxSelectedForDnD(long mailboxId) { } + @Override public void onMailboxSelected(long accountId, long mailboxId, + boolean nestedNavigation) { } @Override public void onAccountSelected(long accountId) { } @Override public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) { } - @Override public void requestMailboxChange(long newMailboxId, long selectedMailboxId) { } + @Override + public void onParentMailboxChanged() { } } /** @@ -217,17 +314,18 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList * This fragment should be created only with this method. (Arguments should always be set.) * * @param accountId The ID of the account we want to view - * @param parentMailboxId The ID of the parent mailbox. Use {@link Mailbox#NO_MAILBOX} - * to open the root. + * @param initialCurrentMailboxId ID of the mailbox of interest. + * Pass {@link Mailbox#NO_MAILBOX} to show top-level mailboxes. + * @param enableHighlight {@code true} if highlighting is enabled on the current screen + * configuration. (We don't highlight mailboxes on one-pane.) */ - public static MailboxListFragment newInstance(long accountId, long parentMailboxId) { - if (accountId == Account.NO_ACCOUNT) { - throw new IllegalArgumentException(); - } + public static MailboxListFragment newInstance(long accountId, long initialCurrentMailboxId, + boolean enableHighlight) { final MailboxListFragment instance = new MailboxListFragment(); final Bundle args = new Bundle(); args.putLong(ARG_ACCOUNT_ID, accountId); - args.putLong(ARG_PARENT_MAILBOX_ID, parentMailboxId); + args.putLong(ARG_INITIAL_CURRENT_MAILBOX_ID, initialCurrentMailboxId); + args.putBoolean(ARG_ENABLE_HIGHLIGHT, enableHighlight); instance.setArguments(args); return instance; } @@ -239,25 +337,32 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList * constructs, this must be considered immutable. */ private Long mImmutableAccountId; + /** - * We will display the children of this mailbox. May be {@link Mailbox#NO_MAILBOX} to display - * all of the top-level mailboxes. Do NOT use directly; instead, use - * {@link #getParentMailboxId()}. + * {@code initialCurrentMailboxId} passed to {@link #newInstance}. + * Do not use directly; instead, use {@link #getInitialCurrentMailboxId()}. *
NOTE: Although we cannot force these to be immutable using Java language * constructs, this must be considered immutable. */ - private Long mImmutableParentMailboxId; + private long mImmutableInitialCurrentMailboxId; + + /** + * {@code enableHighlight} passed to {@link #newInstance}. + * Do not use directly; instead, use {@link #getEnableHighlight()}. + *
NOTE: Although we cannot force these to be immutable using Java language
+ * constructs, this must be considered immutable.
+ */
+ private boolean mImmutableEnableHighlight;
private void initializeArgCache() {
if (mImmutableAccountId != null) return;
- mImmutableAccountId
- = getArguments().getLong(ARG_ACCOUNT_ID, Account.NO_ACCOUNT);
- mImmutableParentMailboxId
- = getArguments().getLong(ARG_PARENT_MAILBOX_ID, Mailbox.NO_MAILBOX);
+ mImmutableAccountId = getArguments().getLong(ARG_ACCOUNT_ID);
+ mImmutableInitialCurrentMailboxId = getArguments().getLong(ARG_INITIAL_CURRENT_MAILBOX_ID);
+ mImmutableEnableHighlight = getArguments().getBoolean(ARG_ENABLE_HIGHLIGHT);
}
/**
- * @return the account ID passed to {@link #newInstance}. Safe to call even before onCreate.
+ * @return {@code accountId} passed to {@link #newInstance}. Safe to call even before onCreate.
*/
public long getAccountId() {
initializeArgCache();
@@ -265,20 +370,21 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
}
/**
- * @return the mailbox ID passed to {@link #newInstance}. Safe to call even before onCreate.
+ * @return {@code initialCurrentMailboxId} passed to {@link #newInstance}.
+ * Safe to call even before onCreate.
*/
- public long getParentMailboxId() {
+ public long getInitialCurrentMailboxId() {
initializeArgCache();
- return mImmutableParentMailboxId;
+ return mImmutableInitialCurrentMailboxId;
}
/**
- * @return true if the top level mailboxes are shown. Safe to call even before onCreate.
+ * @return {@code enableHighlight} passed to {@link #newInstance}.
+ * Safe to call even before onCreate.
*/
- public boolean isRoot() {
- // TODO if we add meta-mailboxes to the database, remove special test for account ID
- return getParentMailboxId() == Mailbox.NO_MAILBOX
- || getAccountId() == Account.ACCOUNT_ID_COMBINED_VIEW;
+ public boolean getEnableHighlight() {
+ initializeArgCache();
+ return mImmutableEnableHighlight;
}
@Override
@@ -304,9 +410,13 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
mRefreshManager = RefreshManager.getInstance(mActivity);
mListAdapter = new MailboxFragmentAdapter(mActivity, mMailboxesAdapterCallback);
setListAdapter(mListAdapter); // It's safe to do even before the list view is created.
- if (savedInstanceState != null) {
+
+ if (savedInstanceState == null) {
+ setInitialParentAndHighlight();
+ } else {
restoreInstanceState(savedInstanceState);
}
+
if (sDropTrashColor == null) {
Resources res = getResources();
sDropTrashColor = res.getColor(R.color.mailbox_drop_destructive_bg_color);
@@ -314,6 +424,24 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
}
}
+ /**
+ * Set {@link #mParentMailboxId} and {@link #mHighlightedMailboxId} from the fragment arguments.
+ */
+ private void setInitialParentAndHighlight() {
+ if (getAccountId() == Account.ACCOUNT_ID_COMBINED_VIEW) {
+ // For the combined view, always show the top-level, but highlight the "current".
+ mParentMailboxId = Mailbox.NO_MAILBOX;
+ } else {
+ // Otherwise, try using the "current" as the "parent" (and also highlight it).
+ // If it has no children, we go up in onLoadFinished().
+ mParentMailboxId = getInitialCurrentMailboxId();
+ }
+ // Highlight the mailbox of interest
+ if (getEnableHighlight()) {
+ mHighlightedMailboxId = getInitialCurrentMailboxId();
+ }
+ }
+
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -345,7 +473,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
lv.setOnDragListener(this);
- startLoading();
+ startLoading(mParentMailboxId, mHighlightedMailboxId);
}
public void setCallback(Callback callback) {
@@ -368,15 +496,6 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
return false;
}
- /**
- * Sets the selected mailbox to the given ID. Sub-folders will not be loaded.
- * @param mailboxId The ID of the mailbox to select.
- */
- public void setSelectedMailbox(long mailboxId) {
- mSelectedMailboxId = mailboxId;
- highlightSelectedMailbox(true);
- }
-
/**
* Called when the Fragment is visible to the user.
*/
@@ -442,6 +561,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onDestroy");
}
+ mTaskTracker.cancellAllInterrupt();
super.onDestroy();
}
@@ -459,7 +579,8 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
Log.d(Logging.LOG_TAG, this + " onSaveInstanceState");
}
super.onSaveInstanceState(outState);
- outState.putLong(BUNDLE_KEY_SELECTED_MAILBOX_ID, mSelectedMailboxId);
+ outState.putLong(BUNDLE_KEY_PARENT_MAILBOX_ID, mParentMailboxId);
+ outState.putLong(BUNDLE_KEY_HIGHLIGHTED_MAILBOX_ID, mHighlightedMailboxId);
if (isViewCreated()) {
outState.putParcelable(BUNDLE_LIST_STATE, getListView().onSaveInstanceState());
}
@@ -469,23 +590,197 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " restoreInstanceState");
}
- mSelectedMailboxId = savedInstanceState.getLong(BUNDLE_KEY_SELECTED_MAILBOX_ID);
+ mParentMailboxId = savedInstanceState.getLong(BUNDLE_KEY_PARENT_MAILBOX_ID);
+ mHighlightedMailboxId = savedInstanceState.getLong(BUNDLE_KEY_HIGHLIGHTED_MAILBOX_ID);
mSavedListState = savedInstanceState.getParcelable(BUNDLE_LIST_STATE);
}
- private void startLoading() {
- if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
- Log.d(Logging.LOG_TAG, this + " startLoading");
+ /**
+ * @return "Selected" mailbox ID.
+ */
+ public long getSelectedMailboxId() {
+ return (mHighlightedMailboxId != Mailbox.NO_MAILBOX) ? mHighlightedMailboxId
+ : mParentMailboxId;
+ }
+
+ /**
+ * @return {@code true} if top-level mailboxes are shown. {@code false} otherwise.
+ */
+ public boolean isRoot() {
+ return mParentMailboxId == Mailbox.NO_MAILBOX;
+ }
+
+ /**
+ * Navigate one level up in the mailbox hierarchy. Does nothing if at the root account view.
+ */
+ public boolean navigateUp() {
+ if (isRoot()) {
+ return false;
+ }
+ FindParentMailboxTask.ResultCallback callback = new FindParentMailboxTask.ResultCallback() {
+ @Override public void onResult(long nextParentMailboxId,
+ long nextHighlightedMailboxId, long nextSelectedMailboxId) {
+
+ startLoading(nextParentMailboxId, nextHighlightedMailboxId);
+
+ if (nextSelectedMailboxId != Mailbox.NO_MAILBOX) {
+ mCallback.onMailboxSelected(getAccountId(), nextSelectedMailboxId, true);
+ }
+ }
+ };
+ new FindParentMailboxTask(
+ getActivity().getApplicationContext(), mTaskTracker, getAccountId(),
+ getEnableHighlight(), mParentMailboxId, mHighlightedMailboxId, callback
+ ).cancelPreviousAndExecuteParallel((Void[]) null);
+ return true;
+ }
+
+ /**
+ * A task to determine what parent mailbox ID/highlighted mailbox ID to use for the "UP"
+ * navigation, given the current parent mailbox ID, the highlighted mailbox ID, and {@link
+ * #mEnableHighlight}.
+ */
+ @VisibleForTesting
+ static class FindParentMailboxTask extends EmailAsyncTask TODO Use this instead of EmailWidgetLoader$CursorWithCounts.
- */
-public class CursorWithExtras extends CursorWrapper {
- /** The number of children in a mailbox. If set, must be a positive value. */
- public final static String EXTRA_MAILBOX_CHILD_COUNT = "mailboxChildCount";
- /** The ID of the next, immediate parent mailbox */
- public final static String EXTRA_MAILBOX_PARENT_ID = "mailboxParentId";
- /** The ID of the next mailbox in the hierarchy with at least one child */
- public final static String EXTRA_MAILBOX_NEXT_PARENT_ID = "mailboxNextParentId";
-
- private final Bundle mExtras;
-
- public CursorWithExtras(Cursor cursor, Bundle extras) {
- super(cursor);
- mExtras = extras;
- }
-
- public int getInt(String key) {
- return getInt(key, 0);
- }
-
- public int getInt(String key, int defaultValue) {
- return mExtras == null ? defaultValue : mExtras.getInt(key);
- }
-
- public long getLong(String key) {
- return getLong(key, 0L);
- }
-
- public long getLong(String key, long defaultValue) {
- return mExtras == null ? defaultValue : mExtras.getLong(key);
- }
-}
diff --git a/tests/src/com/android/email/activity/FindParentMailboxTaskTest.java b/tests/src/com/android/email/activity/FindParentMailboxTaskTest.java
new file mode 100644
index 000000000..4e28b917d
--- /dev/null
+++ b/tests/src/com/android/email/activity/FindParentMailboxTaskTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2011 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.activity;
+
+import com.android.email.DBTestHelper;
+import com.android.email.provider.ProviderTestUtils;
+import com.android.emailcommon.provider.EmailContent.Account;
+import com.android.emailcommon.provider.Mailbox;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+/**
+ * Unit tests for {@link MailboxListFragment.FindParentMailboxTask}.
+ */
+public class FindParentMailboxTaskTest extends AndroidTestCase {
+ private Context mProviderContext;
+
+ /** ID of the account created by {@link #setUpMailboxes}. */
+ private long mAccountId;
+
+ /**
+ * IDs for the mailboxes created by {@link #setUpMailboxes}.
+ *
+ * Mailbox hierarchy:
+ * forceReload
is true
.
*
* @param accountId ID of the account to load. Must never be {@link Account#NO_ACCOUNT}.
- * @param parentMailboxId ID of the mailbox to use as the parent mailbox. Pass
+ * @param mailboxId ID of the mailbox to use as the "selected". Pass
* {@link Mailbox#NO_MAILBOX} to show the root mailboxes.
* @param clearDependentPane if true, the message list and the message view will be cleared
*/
- private void updateMailboxList(long accountId, long parentMailboxId,
+ private void updateMailboxList(long accountId, long mailboxId,
boolean clearDependentPane) {
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " updateMailboxList accountId=" + accountId
- + " parentMailboxId=" + parentMailboxId);
+ + " mailboxId=" + mailboxId);
}
preFragmentTransactionCheck();
if (accountId == Account.NO_ACCOUNT) {
@@ -686,11 +659,11 @@ class UIControllerTwoPane extends UIControllerBase implements
final FragmentManager fm = mActivity.getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
- if ((getUIAccountId() != accountId)
- || (getMailboxListMailboxId() != parentMailboxId)) {
+
+ if ((getUIAccountId() != accountId) || (getMailboxListMailboxId() != mailboxId)) {
uninstallMailboxListFragment(ft);
ft.add(mThreePane.getLeftPaneId(),
- MailboxListFragment.newInstance(accountId, parentMailboxId));
+ MailboxListFragment.newInstance(accountId, mailboxId, true));
}
if (clearDependentPane) {
uninstallMessageListFragment(ft);
@@ -744,7 +717,7 @@ class UIControllerTwoPane extends UIControllerBase implements
}
commitFragmentTransaction(ft);
- mMailboxListFragment.setSelectedMailbox(mailboxId);
+ mMailboxListFragment.setHighlightedMailbox(mailboxId);
// Update action bar / menu
updateRefreshProgress();
@@ -896,20 +869,12 @@ class UIControllerTwoPane extends UIControllerBase implements
public boolean onBackPressed(boolean isSystemBackKey) {
if (mThreePane.onBackPressed(isSystemBackKey)) {
return true;
- } else if (navigateToParentMailboxList()) {
+ } else if (isMailboxListInstalled() && mMailboxListFragment.navigateUp()) {
return true;
}
return false;
}
- private boolean navigateToParentMailboxList() {
- if (!isMailboxListInstalled() || mMailboxListFragment.isRoot()) {
- return false;
- }
- super.navigateToParentMailboxList(mMailboxListFragment.getParentMailboxId());
- return true;
- }
-
/**
* Handles the "refresh" option item. Opens the settings activity.
* TODO used by experimental code in the activity -- otherwise can be private.
@@ -1073,7 +1038,8 @@ class UIControllerTwoPane extends UIControllerBase implements
public boolean shouldShowUp() {
final int visiblePanes = mThreePane.getVisiblePanes();
final boolean leftPaneHidden = ((visiblePanes & ThreePaneLayout.PANE_LEFT) == 0);
- return leftPaneHidden || (isMailboxListInstalled() && !mMailboxListFragment.isRoot());
+ return leftPaneHidden
+ || (isMailboxListInstalled() && !mMailboxListFragment.isRoot());
}
}
}
diff --git a/src/com/android/email/activity/Welcome.java b/src/com/android/email/activity/Welcome.java
index c4d4d4c91..af085bc30 100644
--- a/src/com/android/email/activity/Welcome.java
+++ b/src/com/android/email/activity/Welcome.java
@@ -64,8 +64,12 @@ public class Welcome extends Activity {
* Open a message (account id=1, mailbox id=2, message id=3)
adb shell am start -a android.intent.action.MAIN \
-d '"content://ui.email.android.com/view/mailbox?ACCOUNT_ID=1&MAILBOX_ID=2&MESSAGE_ID=3"' \
- -e DEBUG_PANE_MODE 2 \
+ -e DEBUG_PANE_MODE 2
+ * Open the combined starred on the combined view
+ adb shell am start -a android.intent.action.MAIN \
+ -d '"content://ui.email.android.com/view/mailbox?ACCOUNT_ID=1152921504606846976&MAILBOX_ID=-4"' \
+ -e DEBUG_PANE_MODE 2
*/
/**
diff --git a/src/com/android/email/data/CursorWithExtras.java b/src/com/android/email/data/CursorWithExtras.java
deleted file mode 100644
index 8cb624cb0..000000000
--- a/src/com/android/email/data/CursorWithExtras.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011 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.data;
-
-import android.database.Cursor;
-import android.database.CursorWrapper;
-import android.os.Bundle;
-
-/**
- * A special cursor that contains additional data.
- *
- *
+ * |-Inbox
+ * |-Parent
+ * |-Child1
+ * |-Child2
+ * |-GrandChild1
+ * |-GrandChild2
+ *
+ */
+ private long mIdInbox;
+ private long mIdParent;
+ private long mIdChild1;
+ private long mIdChild2;
+ private long mIdGrandChild1;
+ private long mIdGrandChild2;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mProviderContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(
+ getContext());
+ setUpMailboxes();
+ }
+
+ /**
+ * Set up a test account and mailboxes.
+ */
+ private void setUpMailboxes() {
+ Account a = ProviderTestUtils.setupAccount("a", true, mProviderContext);
+ mAccountId = a.mId;
+
+ mIdInbox = createMailboxAndGetId("Inbox", a, Mailbox.TYPE_INBOX, Mailbox.NO_MAILBOX);
+ mIdParent = createMailboxAndGetId("P", a, Mailbox.TYPE_MAIL, Mailbox.NO_MAILBOX);
+ mIdChild1 = createMailboxAndGetId("C1", a, Mailbox.TYPE_MAIL, mIdParent);
+ mIdChild2 = createMailboxAndGetId("C2", a, Mailbox.TYPE_MAIL, mIdParent);
+ mIdGrandChild1 = createMailboxAndGetId("G1", a, Mailbox.TYPE_MAIL, mIdChild2);
+ mIdGrandChild2 = createMailboxAndGetId("G2", a, Mailbox.TYPE_MAIL, mIdChild2);
+ }
+
+ private long createMailboxAndGetId(String name, Account account, int type,
+ long parentMailboxId) {
+ Mailbox m = ProviderTestUtils.setupMailbox(name, account.mId, false, mProviderContext,
+ type);
+ m.mParentKey = parentMailboxId;
+ m.save(mProviderContext);
+ return m.mId;
+ }
+
+ /**
+ * Tests for two-pane. (highlighting is enabled)
+ */
+ public void testWithHighlight() {
+ /*
+ * In the comments below, [MAILBOX] indicates "highlighted", and MAILBOX* indicates
+ * "selected".
+ */
+ /*
+ * from:
+ * - [Child2]
+ * - GChild1
+ * - GChild2
+ *
+ * to:
+ * - Parent
+ * - Child1
+ * - [Child2]*
+ */
+ doCheckWithHighlight(
+ mIdChild2, // Current parent
+ mIdChild2, // Current highlighted
+
+ mIdParent, // Next root
+ mIdChild2, // Next highlighted
+ mIdChild2 // Next selected
+ );
+
+ /*
+ * from:
+ * - Child2
+ * - [GChild1]
+ * - GChild2
+ *
+ * to:
+ * - [Parent]*
+ * - Child1
+ * - Child2
+ */
+ doCheckWithHighlight(
+ mIdChild2, // Current parent
+ mIdGrandChild1, // Current highlighted
+
+ mIdParent, // Next root
+ mIdParent, // Next highlighted
+ mIdParent // Next selected
+ );
+
+ /*
+ * from:
+ * - [Parent]
+ * - Child1
+ * - Child2
+ *
+ * to:
+ * - Inbox
+ * - [Parent]*
+ */
+ doCheckWithHighlight(
+ mIdParent, // Current parent
+ mIdParent, // Current highlighted
+
+ Mailbox.NO_MAILBOX, // Next root
+ mIdParent, // Next highlighted
+ mIdParent // Next selected
+ );
+
+ /*
+ * from:
+ * - Parent
+ * - [Child1]
+ * - Child2
+ *
+ * to:
+ * - [Inbox]*
+ * - Parent
+ */
+ doCheckWithHighlight(
+ mIdParent, // Current parent
+ mIdChild1, // Current highlighted
+
+ Mailbox.NO_MAILBOX, // Next root
+ mIdInbox, // Next highlighted
+ mIdInbox // Next selected
+ );
+
+ /*
+ * Special case.
+ * Up from root view, with "Parent" highlighted. "Up" will be disabled in this case, but
+ * if we were to run the task, it'd work as if the current parent mailbox is gone.
+ * i.e. just show the top level mailboxes, with Inbox highlighted.
+ *
+ * from:
+ * - Inbox
+ * - [Parent]
+ *
+ * to:
+ * - [Inbox]
+ * - Parent
+ */
+ doCheckWithHighlight(
+ Mailbox.NO_MAILBOX, // Current parent
+ mIdParent, // Current highlighted
+
+ Mailbox.NO_MAILBOX, // Next root
+ mIdInbox, // Next highlighted
+ mIdInbox // Next selected
+ );
+
+ /*
+ * Special case.
+ * Current parent mailbox is gone. The result should be same as the above.
+ *
+ * from:
+ * (current mailbox just removed)
+ *
+ * to:
+ * - [Inbox]
+ * - Parent
+ */
+ doCheckWithHighlight(
+ 12312234234L, // Current parent
+ mIdParent, // Current highlighted
+
+ Mailbox.NO_MAILBOX, // Next root
+ mIdInbox, // Next highlighted
+ mIdInbox // Next selected
+ );
+ }
+
+ private void doCheckWithHighlight(
+ long parentMailboxId, long highlightedMailboxId,
+ long expectedNextParent, long expectedNextHighlighted, long expectedNextSelected) {
+ doCheck(true, parentMailboxId, highlightedMailboxId,
+ expectedNextParent, expectedNextHighlighted, expectedNextSelected);
+ }
+
+ /**
+ * Tests for one-pane. (highlighting is disable)
+ */
+ public void testWithNoHighlight() {
+ /*
+ * from:
+ * - Child2
+ * - GChild1
+ * - GChild2
+ *
+ * to:
+ * - Parent
+ * - Child1
+ * - Child2
+ */
+ doCheckWithNoHighlight(
+ mIdChild2, // Current parent
+ mIdParent // Next root
+ );
+ /*
+ * from:
+ * - Parent
+ * - Child1
+ * - Child2
+ *
+ * to:
+ * - Inbox
+ * - Parent
+ */
+ doCheckWithNoHighlight(
+ mIdParent, // Current parent
+ Mailbox.NO_MAILBOX // Next root
+ );
+
+ /*
+ * Special case.
+ * Current parent mailbox is gone. The top-level mailboxes should be shown.
+ *
+ * from:
+ * (current mailbox just removed)
+ *
+ * to:
+ * - Inbox
+ * - Parent
+ */
+ doCheckWithNoHighlight(
+ 12312234234L, // Current parent
+ Mailbox.NO_MAILBOX // Next root
+ );
+ }
+
+ private void doCheckWithNoHighlight(long parentMailboxId, long expectedNextParent) {
+ doCheck(false, parentMailboxId, Mailbox.NO_MAILBOX,
+ expectedNextParent, Mailbox.NO_MAILBOX,
+ expectedNextParent /* parent should always be selected */);
+ }
+
+ private void doCheck(boolean enableHighlight,
+ long parentMailboxId, long highlightedMailboxId,
+ long expectedNextParent, long expectedNextHighlighted, long expectedNextSelected) {
+ ResultCallback result = new ResultCallback();
+
+ MailboxListFragment.FindParentMailboxTask task
+ = new MailboxListFragment.FindParentMailboxTask(
+ mProviderContext, null, mAccountId, enableHighlight, parentMailboxId,
+ highlightedMailboxId, result);
+
+ // Can't execute an async task on the test thread, so emulate execution...
+ task.onPostExecute(task.doInBackground((Void[]) null));
+
+ assertEquals("parent", expectedNextParent, result.mNextParentMailboxId);
+ assertEquals("highlighted", expectedNextHighlighted, result.mNextHighlightedMailboxId);
+ assertEquals("selected", expectedNextSelected, result.mNextSelectedMailboxId);
+ }
+
+ private static class ResultCallback
+ implements MailboxListFragment.FindParentMailboxTask.ResultCallback {
+ public long mNextParentMailboxId;
+ public long mNextHighlightedMailboxId;
+ public long mNextSelectedMailboxId;
+
+ @Override
+ public void onResult(long nextParentMailboxId, long nextHighlightedMailboxId,
+ long nextSelectedMailboxId) {
+ mNextParentMailboxId = nextParentMailboxId;
+ mNextHighlightedMailboxId = nextHighlightedMailboxId;
+ mNextSelectedMailboxId = nextSelectedMailboxId;
+ }
+ }
+}