Merge "Don't use negative IDs with ListView"

This commit is contained in:
Makoto Onuki 2010-10-14 14:45:23 -07:00 committed by Android (Google) Code Review
commit b0ffb3e39a
3 changed files with 159 additions and 9 deletions

View File

@ -308,7 +308,8 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mCallback.onMailboxSelected(mAccountId, id);
// Don't use the id parameter. See MailboxesAdapter.
mCallback.onMailboxSelected(mAccountId, mListAdapter.getMailboxId(position));
}
public void onRefresh() {
@ -334,7 +335,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
}
final int count = mListView.getCount();
for (int i = 0; i < count; i++) {
if (mListView.getItemIdAtPosition(i) != mSelectedMailboxId) {
if (mListAdapter.getMailboxId(i) != mSelectedMailboxId) {
continue;
}
mListView.setItemChecked(i, true);

View File

@ -41,9 +41,14 @@ import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.security.InvalidParameterException;
/**
* The adapter for displaying mailboxes.
*
* Do not use {@link #getItemId(int)} -- It's only for ListView. Use {@link #getMailboxId}
* instead. (See the comment below)
*
* TODO New UI will probably not distinguish unread counts from # of messages.
* i.e. we won't need two different viewes for them.
* TODO Show "Starred" per account? (Right now we have only "All Starred")
@ -53,14 +58,25 @@ import android.widget.TextView;
public static final int MODE_NORMAL = 0;
public static final int MODE_MOVE_TO_TARGET = 1;
private static final String[] PROJECTION = new String[] { MailboxColumns.ID,
/*
* Note here we have two ID columns. The first one is for ListView, which doesn't like ID
* values to be negative. The second one is the actual mailbox ID, which we use in the rest
* of code.
* ListView uses row IDs for some operations, including onSave/RestoreInstanceState,
* and if we use negative IDs they don't work as expected.
* Because ListView finds the ID column by name ("_id"), we rename the second column
* so that ListView gets the correct column.
*/
/* package */ static final String[] PROJECTION = new String[] { MailboxColumns.ID,
MailboxColumns.ID + " AS org_mailbox_id",
MailboxColumns.DISPLAY_NAME, MailboxColumns.TYPE, MailboxColumns.UNREAD_COUNT,
MailboxColumns.MESSAGE_COUNT};
private static final int COLUMN_ID = 0;
private static final int COLUMN_DISPLAY_NAME = 1;
private static final int COLUMN_TYPE = 2;
private static final int COLUMN_UNREAD_COUNT = 3;
private static final int COLUMN_MESSAGE_COUNT = 4;
// Column 0 is only for ListView; we don't use it in our code.
private static final int COLUMN_ID = 1;
private static final int COLUMN_DISPLAY_NAME = 2;
private static final int COLUMN_TYPE = 3;
private static final int COLUMN_UNREAD_COUNT = 4;
private static final int COLUMN_MESSAGE_COUNT = 5;
private static final String MAILBOX_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?" +
" AND " + MailboxColumns.TYPE + "<" + Mailbox.TYPE_NOT_EMAIL +
@ -89,6 +105,11 @@ import android.widget.TextView;
mMode = mode;
}
public long getMailboxId(int position) {
Cursor c = (Cursor) getItem(position);
return c.getLong(COLUMN_ID);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
switch (mMode) {
@ -271,13 +292,33 @@ import android.widget.TextView;
private static void addSummaryMailboxRow(Context context, MatrixCursor cursor,
long id, int type, int count, boolean showAlways) {
if (id >= 0) {
throw new InvalidParameterException(); // Must be QUERY_ALL_*, which are all negative.
}
if (showAlways || (count > 0)) {
RowBuilder row = cursor.newRow();
row.add(id);
row.add(Long.MAX_VALUE + id); // Map QUERY_ALL_* constants to positive ints.
row.add(id); // The real mailbox ID.
row.add(""); // Display name. We get it from FolderProperties.
row.add(type);
row.add(count);
row.add(count);
}
}
/* package */ static long getIdForTest(Cursor cursor) {
return cursor.getLong(COLUMN_ID);
}
/* package */ static int getTypeForTest(Cursor cursor) {
return cursor.getInt(COLUMN_TYPE);
}
/* package */ static int getMessageCountForTest(Cursor cursor) {
return cursor.getInt(COLUMN_MESSAGE_COUNT);
}
/* package */ static int getUnreadCountForTest(Cursor cursor) {
return cursor.getInt(COLUMN_UNREAD_COUNT);
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2010 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.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
import android.content.Context;
import android.database.Cursor;
import android.test.ProviderTestCase2;
import junit.framework.Assert;
public class MailboxesAdapterTest extends ProviderTestCase2<EmailProvider> {
private Context mMockContext;
public MailboxesAdapterTest() {
super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
}
@Override
public void setUp() throws Exception {
super.setUp();
mMockContext = getMockContext();
}
public void testAddSummaryMailboxRow() {
final Context c = mMockContext;
// Prepare test data
Account a1 = ProviderTestUtils.setupAccount("a1", true, c);
Account a2 = ProviderTestUtils.setupAccount("a2", true, c);
Mailbox b1i = ProviderTestUtils.setupMailbox("box1i", a1.mId, true, c, Mailbox.TYPE_INBOX);
Mailbox b2i = ProviderTestUtils.setupMailbox("box2i", a2.mId, true, c, Mailbox.TYPE_INBOX);
Mailbox b1o = ProviderTestUtils.setupMailbox("box1i", a1.mId, true, c, Mailbox.TYPE_OUTBOX);
Mailbox b2o = ProviderTestUtils.setupMailbox("box2i", a2.mId, true, c, Mailbox.TYPE_OUTBOX);
Mailbox b1d = ProviderTestUtils.setupMailbox("box1d", a1.mId, true, c, Mailbox.TYPE_DRAFTS);
Mailbox b2d = ProviderTestUtils.setupMailbox("box2d", a2.mId, true, c, Mailbox.TYPE_DRAFTS);
createMessage(c, b1i, false, false);
createMessage(c, b2i, true, true);
createMessage(c, b2i, true, false);
createMessage(c, b1o, true, true);
createMessage(c, b2o, false, true);
createMessage(c, b1d, false, true);
createMessage(c, b2d, false, true);
createMessage(c, b2d, false, true);
createMessage(c, b2d, false, true);
// Kick the method
Cursor cursor = MailboxesAdapter.getSpecialMailboxesCursor(c, true);
// Check the result
assertEquals(4, cursor.getCount());
// Row 1 -- combined inbox (with unread count)
assertTrue(cursor.moveToFirst());
checkSpecialMailboxRow(cursor, Mailbox.QUERY_ALL_INBOXES, Mailbox.TYPE_INBOX, 2);
// Row 2 -- all starred (with total count)
assertTrue(cursor.moveToNext());
checkSpecialMailboxRow(cursor, Mailbox.QUERY_ALL_FAVORITES, Mailbox.TYPE_MAIL, 3);
// Row 3 -- all drafts (with total count)
assertTrue(cursor.moveToNext());
checkSpecialMailboxRow(cursor, Mailbox.QUERY_ALL_DRAFTS, Mailbox.TYPE_DRAFTS, 4);
// Row 4 -- combined outbox (with total count)
assertTrue(cursor.moveToNext());
checkSpecialMailboxRow(cursor, Mailbox.QUERY_ALL_OUTBOX, Mailbox.TYPE_OUTBOX, 2);
}
private static Message createMessage(Context c, Mailbox b, boolean starred, boolean read) {
return ProviderTestUtils.setupMessage("m", b.mAccountKey, b.mId, false, true, c, starred,
read);
}
private static void checkSpecialMailboxRow(Cursor cursor, long id, int type,
int count) {
// _id must always be >= 0; otherwise ListView gets confused.
Assert.assertTrue(cursor.getLong(cursor.getColumnIndex("_id")) >= 0);
Assert.assertEquals(id, MailboxesAdapter.getIdForTest(cursor));
Assert.assertEquals(type, MailboxesAdapter.getTypeForTest(cursor));
Assert.assertEquals(count, MailboxesAdapter.getMessageCountForTest(cursor));
Assert.assertEquals(count, MailboxesAdapter.getUnreadCountForTest(cursor));
}
}