Don't navigate to a shortcut mailbox

All shortcuts now have a mailbox associated with them. When launching
the app via shortcut, we want to show the messages within that mailbox, but,
we do not want to navigate into the mailbox; unless the mailbox has children.
Since we don't want to put too much informatin into the shortcut, we must
perform these checks at runtime. So, if ever we try to load a mailbox that
doesn't contain children, we load it's parent instead.

Change-Id: Idb5dbc7cd740b270a0068811abe685f963ca2c0b
This commit is contained in:
Todd Kennedy 2011-05-25 10:07:37 -07:00
parent 4ade29d6b0
commit ca6eca0466
5 changed files with 172 additions and 20 deletions

View File

@ -20,6 +20,7 @@ import com.android.email.Email;
import com.android.email.FolderProperties;
import com.android.email.R;
import com.android.email.data.ClosingMatrixCursor;
import com.android.email.data.CursorWithExtras;
import com.android.email.data.ThrottlingCursorLoader;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent;
@ -36,6 +37,7 @@ import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MatrixCursor.RowBuilder;
import android.database.MergeCursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@ -217,7 +219,7 @@ import android.widget.TextView;
}
/**
* Loader for mailboxes of an account.
* Loads mailboxes that are the children of a given mailbox ID.
*/
private static class MailboxFragmentLoader extends ThrottlingCursorLoader {
private final Context mContext;
@ -247,6 +249,17 @@ import android.widget.TextView;
@Override
public Cursor loadInBackground() {
final Cursor childMailboxCursor = super.loadInBackground();
final Cursor returnCursor;
final Bundle extras = new Bundle();
// Setup the extras to return along with the cursor
int cursorCount = childMailboxCursor.getCount();
extras.putInt(CursorWithExtras.EXTRA_MAILBOX_CHILD_COUNT, cursorCount);
long nextParentKey = findParentWithChildren(mParentKey);
extras.putLong(CursorWithExtras.EXTRA_MAILBOX_NEXT_PARENT_ID, nextParentKey);
Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mParentKey);
long grandParentKey = mailbox == null ? Mailbox.NO_MAILBOX : mailbox.mParentKey;
extras.putLong(CursorWithExtras.EXTRA_MAILBOX_PARENT_ID, grandParentKey);
// If we're not showing the top level mailboxes, add the "parent" mailbox.
if (mParentKey != Mailbox.NO_MAILBOX) {
@ -254,24 +267,47 @@ import android.widget.TextView;
Mailbox.CONTENT_URI, CURMAILBOX_PROJECTION, MAILBOX_SELECTION,
new String[] { Long.toString(mAccountId), Long.toString(mParentKey) },
null);
return Utility.CloseTraceCursorWrapper.get(new MergeCursor(
new Cursor[] { parentCursor, childMailboxCursor }));
returnCursor = new MergeCursor(new Cursor[] { parentCursor, childMailboxCursor });
} else {
// Add "Starred", only if the account has at least one starred message.
// TODO It's currently "combined starred", but the plan is to make it per-account
// starred.
final int accountStarredCount
= Message.getFavoriteMessageCount(mContext, mAccountId);
if (accountStarredCount > 0) {
final MatrixCursor starredCursor = new MatrixCursor(getProjection());
final int totalStarredCount = Message.getFavoriteMessageCount(mContext);
addCombinedMailboxRow(starredCursor, Mailbox.QUERY_ALL_FAVORITES,
Mailbox.TYPE_MAIL, totalStarredCount, true);
returnCursor
= new MergeCursor(new Cursor[] { starredCursor, childMailboxCursor });
} else {
returnCursor = childMailboxCursor; // no starred message
}
}
// Add "Starred", only if the account has at least one starred message.
// TODO It's currently "combined starred", but the plan is to make it per-account
// starred.
final int accountStarredCount = Message.getFavoriteMessageCount(mContext, mAccountId);
if (accountStarredCount > 0) {
final MatrixCursor starredCursor = new MatrixCursor(getProjection());
final int totalStarredCount = Message.getFavoriteMessageCount(mContext);
addCombinedMailboxRow(starredCursor, Mailbox.QUERY_ALL_FAVORITES, Mailbox.TYPE_MAIL,
totalStarredCount, true);
return Utility.CloseTraceCursorWrapper.get(
new MergeCursor(new Cursor[] { starredCursor, childMailboxCursor }));
}
return new CursorWithExtras(Utility.CloseTraceCursorWrapper.get(returnCursor), extras);
}
return Utility.CloseTraceCursorWrapper.get(childMailboxCursor); // no starred message
/**
* Returns the next parent mailbox with at least one child mailbox. If the given
* mailbox does not exist in the database, returns {@link Mailbox#NO_MAILBOX}. If
* we reach the root parent and we still don't have children, returns
* {@link Mailbox#NO_MAILBOX}.
*/
private long findParentWithChildren(long mailboxId) {
int childCount = Mailbox.count(mContext, Mailbox.CONTENT_URI,
MAILBOX_SELECTION_WITH_PARENT,
new String[] { Long.toString(mAccountId), Long.toString(mailboxId) });
if (childCount == 0 && mailboxId != Mailbox.NO_MAILBOX) {
// There are no children; select parent
Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId);
if (mailbox == null) {
return Mailbox.NO_MAILBOX;
}
return findParentWithChildren(mailbox.mParentKey);
}
return mailboxId;
}
}
@ -297,7 +333,7 @@ import android.widget.TextView;
final Cursor accounts = super.loadInBackground();
// Build combined mailbox rows.
final MatrixCursor combinedWithAccounts = buildCombinedMailboxes(mContext, accounts);
final MatrixCursor returnCursor = buildCombinedMailboxes(mContext, accounts);
// Add account rows.
accounts.moveToPosition(-1);
@ -306,11 +342,11 @@ import android.widget.TextView;
final String accountName = accounts.getString(COLUMN_ACCOUNT_DISPLAY_NAME);
final int unreadCount = Mailbox.getUnreadCountByAccountAndMailboxType(
mContext, accountId, Mailbox.TYPE_INBOX);
addMailboxRow(combinedWithAccounts, accountId, accountName, Mailbox.TYPE_NONE,
addMailboxRow(returnCursor, accountId, accountName, Mailbox.TYPE_NONE,
unreadCount, unreadCount, ROW_TYPE_ACCOUNT, Mailbox.FLAG_NONE,
accountId);
}
return Utility.CloseTraceCursorWrapper.get(combinedWithAccounts);
return Utility.CloseTraceCursorWrapper.get(returnCursor);
}
/*package*/ static MatrixCursor buildCombinedMailboxes(Context context,

View File

@ -20,6 +20,7 @@ import com.android.email.Controller;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.RefreshManager;
import com.android.email.data.CursorWithExtras;
import com.android.email.provider.EmailProvider;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent.Account;
@ -120,7 +121,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
private int mDragItemHeight = -1;
/** Task that actually does the work to auto-expand folder lists during drag-n-drop */
private TimerTask mDragTimerTask;
// True if we are currently scrolling under the drag item
/** {@code true} if we are currently scrolling under the drag item */
private boolean mTargetScrolling;
private Parcelable mSavedListState;
@ -150,6 +151,15 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
*/
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.
*/
@ -180,6 +190,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
@Override public void onAccountSelected(long accountId) { }
@Override public void onCurrentMailboxUpdated(long mailboxId, String mailboxName,
int unreadCount) { }
@Override public void requestMailboxChange(long newMailboxId, long selectedMailboxId) { }
}
/**
@ -461,6 +472,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
// TODO This class probably should be made static. There are many calls into the enclosing
// class and we need to be cautious about what we call while in these callbacks
private class MailboxListLoaderCallbacks implements LoaderCallbacks<Cursor> {
/** Whether or not the loader has finished at least once */
private boolean mIsFirstLoad;
@Override
@ -482,6 +494,28 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
// Note at this point we can assume the view is created.
// The loader manager doesn't deliver results when a fragment is stopped.
// Validate the cursor and make sure we're showing the "right thing"
if (cursor instanceof CursorWithExtras) {
CursorWithExtras c = (CursorWithExtras) cursor;
int childCount = c.getInt(CursorWithExtras.EXTRA_MAILBOX_CHILD_COUNT, -1);
if (childCount == 0) {
long nextParentId = c.getLong(CursorWithExtras.EXTRA_MAILBOX_NEXT_PARENT_ID);
long grandParentId = c.getLong(CursorWithExtras.EXTRA_MAILBOX_PARENT_ID);
long highlightId;
// Only set a mailbox highlight if we're choosing our immediate parent
if (grandParentId == nextParentId) {
highlightId = getParentMailboxId();
} else {
highlightId = Mailbox.NO_MAILBOX;
}
// If the next parent w/ children isn't us, request a change
if (nextParentId != getParentMailboxId()) {
mCallback.requestMailboxChange(nextParentId, highlightId);
return;
}
}
}
if (cursor.getCount() == 0) {
// If there's no row, don't set it to the ListView.
// Instead use setListShown(false) to make ListFragment show progress icon.

View File

@ -82,6 +82,10 @@ class UIControllerOnePane extends UIControllerBase {
public void onMailboxSelectedForDnD(long mailboxId) {
// No drag&drop on 1-pane
}
@Override
public void requestMailboxChange(long newMailboxId, long selectedMailboxId) {
}
};
private final MessageListFragment.Callback mMessageListFragmentCallback =

View File

@ -184,6 +184,7 @@ class UIControllerTwoPane extends UIControllerBase implements
}
}
@Override
public void onMailboxSelectedForDnD(long mailboxId) {
// STOPSHIP the new mailbox list created here doesn't know D&D is in progress. b/4332725
@ -191,6 +192,25 @@ class UIControllerTwoPane extends UIControllerBase implements
false /* don't clear message list and message view */);
}
@Override
public void requestMailboxChange(final long newMailboxId, final long selectedMailboxId) {
// Unfortunately if the screen rotates while the task is running, we just cancel the task
// so mailbox change request will be gone. But we'll live with it as it's not too critical.
new EmailAsyncTask<Void, Void, Void>(mTaskTracker) {
@Override protected Void doInBackground(Void... params) { return null; }
@Override protected void onPostExecute(Void mailboxId) {
if (selectedMailboxId == getMailboxListMailboxId()) {
// We're not changing selections; just the contents of the mailbox list
updateMailboxList(getActualAccountId(), newMailboxId, false);
mMailboxListFragment.setSelectedMailbox(selectedMailboxId);
} else {
// Select a whole new mailbox
openMailbox(getActualAccountId(), newMailboxId);
}
}
}.cancelPreviousAndExecuteSerial();
}
// MailboxListFragment$Callback
@Override
public void onAccountSelected(long accountId) {

View File

@ -0,0 +1,58 @@
/*
* 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.
*
* <p>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);
}
}