only allow navigating to mailboxes w/ children

If a mailbox doesn't have any sub-mailboxes, only allow selecting them to view
any contained messages. Do not update the mailbox list.

Change-Id: I6f469bf20a57dc440885402084c21ff184f13dff
diff --git a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
index c030df7..4f88cfb 100644
--- a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
+++ b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
@@ -2299,26 +2299,28 @@
 
         // Types of mailboxes.  The list is ordered to match a typical UI presentation, e.g.
         // placing the inbox at the top.
-        // The "main" mailbox for the account, almost always referred to as "Inbox"
         // Arrays of "special_mailbox_display_names" and "special_mailbox_icons" are depends on
         // types Id of mailboxes.
+        /** No type specified */
+        public static final int TYPE_NONE = -1;
+        /** The "main" mailbox for the account, almost always referred to as "Inbox" */
         public static final int TYPE_INBOX = 0;
         // Types of mailboxes
-        // Holds mail (generic)
+        /** Generic mailbox that holds mail */
         public static final int TYPE_MAIL = 1;
-        // Parent-only mailbox; holds no mail
+        /** Parent-only mailbox; does not hold any mail */
         public static final int TYPE_PARENT = 2;
-        // Holds drafts
+        /** Drafts mailbox */
         public static final int TYPE_DRAFTS = 3;
-        // The local outbox associated with the Account
+        /** Local mailbox associated with the account's outgoing mail */
         public static final int TYPE_OUTBOX = 4;
-        // Holds sent mail
+        /** Sent mail; mail that was sent from the account */
         public static final int TYPE_SENT = 5;
-        // Holds deleted mail
+        /** Deleted mail */
         public static final int TYPE_TRASH = 6;
-        // Holds junk mail
+        /** Junk mail */
         public static final int TYPE_JUNK = 7;
-        // A mailbox that holds search results
+        /** Search results */
         public static final int TYPE_SEARCH = 8;
 
         // Types after this are used for non-mail mailboxes (as in EAS)
@@ -2335,17 +2337,19 @@
 
         // Bit field flags; each is defined below
         // Warning: Do not read these flags until POP/IMAP/EAS all populate them
-        // This mailbox has children in the mailbox hierarchy
+        /** No flags set */
+        public static final int FLAG_NONE = 0;
+        /** Has children in the mailbox hierarchy */
         public static final int FLAG_HAS_CHILDREN = 1<<0;
-        // This mailbox's children are visible in the UI
+        /** Children are visible in the UI */
         public static final int FLAG_CHILDREN_VISIBLE = 1<<1;
-        // This mailbox cannot receive "pushed" mail
+        /** cannot receive "pushed" mail */
         public static final int FLAG_CANT_PUSH = 1<<2;
-        // This mailbox can hold emails (i.e. some parent mailboxes cannot themselves contain mail)
+        /** can hold emails (i.e. some parent mailboxes cannot themselves contain mail) */
         public static final int FLAG_HOLDS_MAIL = 1<<3;
-        // This mailbox is a valid target for moving messages within the account
+        /** can be used as a target for moving messages within the account */
         public static final int FLAG_ACCEPTS_MOVED_MAIL = 1<<4;
-        // This mailbox is a valid target for appending messages
+        /** can be used as a target for appending messages */
         public static final int FLAG_ACCEPTS_APPENDED_MAIL = 1<<5;
 
         // Magic mailbox ID's
diff --git a/src/com/android/email/activity/MailboxFragmentAdapter.java b/src/com/android/email/activity/MailboxFragmentAdapter.java
index 20b7029..dc3a300 100644
--- a/src/com/android/email/activity/MailboxFragmentAdapter.java
+++ b/src/com/android/email/activity/MailboxFragmentAdapter.java
@@ -74,7 +74,6 @@
         listItem.mMailboxType = type;
         listItem.mMailboxId = id;
         listItem.mAdapter = this;
-
         // Set the background depending on whether we're in drag mode, the mailbox is a valid
         // target, etc.
         mCallback.onBind(listItem);
@@ -108,8 +107,8 @@
                 folderIcon.setVisibility(View.INVISIBLE);
                 break;
             case ROW_TYPE_SUBMAILBOX:
-                if ((flags & Mailbox.FLAG_HAS_CHILDREN) != 0 &&
-                        (flags & Mailbox.FLAG_CHILDREN_VISIBLE) != 0) {
+                if ((flags & Mailbox.FLAG_HAS_CHILDREN) != 0
+                        && (flags & Mailbox.FLAG_CHILDREN_VISIBLE) != 0) {
                     mailboxExpandedIcon.setVisibility(View.VISIBLE);
                     mailboxExpandedIcon.setImageResource(
                             R.drawable.ic_mailbox_collapsed_holo_light);
@@ -204,7 +203,8 @@
             throw new IllegalArgumentException(); // Must be QUERY_ALL_*, which are all negative
         }
         if (showAlways || (count > 0)) {
-            addMailboxRow(cursor, id, "", mailboxType, count, count, ROW_TYPE_MAILBOX, 0);
+            addMailboxRow(
+                    cursor, id, "", mailboxType, count, count, ROW_TYPE_MAILBOX, Mailbox.FLAG_NONE);
         }
     }
 
@@ -314,17 +314,12 @@
 
             accounts.moveToPosition(-1);
             while (accounts.moveToNext()) {
-                RowBuilder row =  combinedWithAccounts.newRow();
                 final long accountId = accounts.getLong(COLUMN_ACCOUND_ID);
-                row.add(accountId);
-                row.add(accountId);
-                row.add(accounts.getString(COLUMN_ACCOUNT_DISPLAY_NAME));
-                row.add(-1); // No mailbox type.  Shouldn't really be used.
+                final String accountName = accounts.getString(COLUMN_ACCOUNT_DISPLAY_NAME);
                 final int unreadCount = Mailbox.getUnreadCountByAccountAndMailboxType(
                         mContext, accountId, Mailbox.TYPE_INBOX);
-                row.add(unreadCount);
-                row.add(unreadCount);
-                row.add(ROW_TYPE_ACCOUNT);
+                addMailboxRow(combinedWithAccounts, accountId, accountName, Mailbox.TYPE_NONE,
+                        unreadCount, unreadCount, ROW_TYPE_ACCOUNT, Mailbox.FLAG_NONE);
             }
             return Utility.CloseTraceCursorWrapper.get(combinedWithAccounts);
         }
diff --git a/src/com/android/email/activity/MailboxListFragment.java b/src/com/android/email/activity/MailboxListFragment.java
index bcb50da..2932c81 100644
--- a/src/com/android/email/activity/MailboxListFragment.java
+++ b/src/com/android/email/activity/MailboxListFragment.java
@@ -268,19 +268,35 @@
     }
 
     /**
-     * Selects the given mailbox ID and navigates to it. This loads any mailboxes contained
-     * within it. The mailbox is assumed to be associated with the account passed into
-     * {@link #openMailboxes(long)}
-     * @param mailboxId The ID of the mailbox to load.
+     * Selects the given mailbox ID and possibly navigates to it. This loads any mailboxes
+     * contained within it and may cause the mailbox list to be updated. If the current fragment
+     * is not in the resumed state or if the mailbox cannot be navigated to, the given mailbox
+     * will only be selected. The mailbox is assumed to be associated with the account passed
+     * into {@link #openMailboxes(long)}.
+     * @param mailboxId The ID of the mailbox to select and navigate to.
      */
     public void navigateToMailbox(long mailboxId) {
         setSelectedMailbox(mailboxId);
-        if (mResumed) {
+        if (mResumed && isNavigable(mailboxId)) {
             startLoading();
         }
     }
 
     /**
+     * Returns whether or not the specified mailbox can be navigated to.
+     */
+    private boolean isNavigable(long mailboxId) {
+        final int count = mListAdapter.getCount();
+        for (int i = 0; i < count; i++) {
+            if (mListAdapter.getId(i) != mSelectedMailboxId) {
+                continue;
+            }
+            return mListAdapter.isNavigable(i);
+        }
+        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.
      */
@@ -502,6 +518,7 @@
             // No mailbox selected
             mListView.clearChoices();
         } else {
+            // TODO Don't mix list view & list adapter indices. This is a recipe for disaster.
             final int count = mListView.getCount();
             for (int i = 0; i < count; i++) {
                 if (mListAdapter.getId(i) != mSelectedMailboxId) {
diff --git a/src/com/android/email/activity/MailboxListItem.java b/src/com/android/email/activity/MailboxListItem.java
index cecd7cf..cd6e336 100644
--- a/src/com/android/email/activity/MailboxListItem.java
+++ b/src/com/android/email/activity/MailboxListItem.java
@@ -69,6 +69,11 @@
         mLabelCount = (TextView)findViewById(R.id.message_count);
     }
 
+    /**
+     * Whether or not this mailbox item is a drop target. Only valid mailboxes or those
+     * not forbidden by the system (see {@link Mailbox#INVALID_DROP_TARGETS}) will return
+     * {@code true}.
+     */
     public boolean isDropTarget(long itemMailbox) {
         if ((mMailboxId < 0) || (itemMailbox == mMailboxId)) {
             return false;
diff --git a/src/com/android/email/activity/MailboxesAdapter.java b/src/com/android/email/activity/MailboxesAdapter.java
index a15db8c..b1e8d6b 100644
--- a/src/com/android/email/activity/MailboxesAdapter.java
+++ b/src/com/android/email/activity/MailboxesAdapter.java
@@ -220,8 +220,8 @@
     }
 
     /**
-     * @return ID of the mailbox (or account, if {@link #isAccountRow} == true) of the specified
-     * row.
+     * Returns the ID of the mailbox (or account, if {@link #isAccountRow} is {@code true})
+     * of the given row.
      */
     public long getId(int position) {
         Cursor c = (Cursor) getItem(position);
@@ -229,6 +229,16 @@
     }
 
     /**
+     * Returns whether or not the mailbox at the given row can be navigated to.
+     */
+    public boolean isNavigable(int row) {
+        final Cursor c = (Cursor) getItem(row);
+        final int flags = c.getInt(COLUMN_FLAGS);
+        return (flags & Mailbox.FLAG_HAS_CHILDREN) != 0
+                && (flags & Mailbox.FLAG_CHILDREN_VISIBLE) != 0;
+    }
+
+    /**
      * Turn on and off list updates; during a drag operation, we do NOT want to the list of
      * mailboxes to update, as this would be visually jarring
      * @param state whether or not the MailboxList can be updated