App changes for handling profile DB split.
- Added a custom loader to load in the profile and contact list.
- Made the CursorLoader for ContactEntryListFragment and its
subclasses pluggable, so the default one could substitute in
the combined profile-and-contact list loader.
- The photo manager needs some awareness of the profile ID-space,
since it's doing bulk photo queries using a custom selection.
- Adapted Isaac's change to the section indexer to handle the
profile being out of consideration when doing the address book
index query.
- Removed uses of the ALLOW_PROFILE param, since it no longer exists.
Bug 5204577
Bug 5136432
Bug 5140891
Change-Id: I676b4cdeabe87b1b585c6c8df2cde51605777106
diff --git a/src/com/android/contacts/ContactPhotoManager.java b/src/com/android/contacts/ContactPhotoManager.java
index 0f7065d..fd2e6a2 100644
--- a/src/com/android/contacts/ContactPhotoManager.java
+++ b/src/com/android/contacts/ContactPhotoManager.java
@@ -21,6 +21,7 @@
import com.google.android.collect.Sets;
import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
@@ -642,7 +643,6 @@
ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
String.valueOf(MAX_PHOTOS_TO_PRELOAD))
- .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1")
.build();
cursor = mResolver.query(uri, new String[] { Contacts.PHOTO_ID },
Contacts.PHOTO_ID + " NOT NULL AND " + Contacts.PHOTO_ID + "!=0",
@@ -698,8 +698,7 @@
Cursor cursor = null;
try {
- cursor = mResolver.query(Data.CONTENT_URI.buildUpon()
- .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1").build(),
+ cursor = mResolver.query(Data.CONTENT_URI,
COLUMNS,
mStringBuilder.toString(),
mPhotoIdsAsStrings.toArray(EMPTY_STRING_ARRAY),
@@ -719,9 +718,30 @@
}
}
- // Remaining photos were not found in the database - mark the cache accordingly.
+ // Remaining photos were not found in the contacts database (but might be in profile).
for (Long id : mPhotoIds) {
- cacheBitmap(id, null, preloading);
+ if (ContactsContract.isProfileId(id)) {
+ Cursor profileCursor = null;
+ try {
+ profileCursor = mResolver.query(
+ ContentUris.withAppendedId(Data.CONTENT_URI, id),
+ COLUMNS, null, null, null);
+ if (profileCursor != null && profileCursor.moveToFirst()) {
+ cacheBitmap(profileCursor.getLong(0), profileCursor.getBlob(1),
+ preloading);
+ } else {
+ // Couldn't load a photo this way either.
+ cacheBitmap(id, null, preloading);
+ }
+ } finally {
+ if (profileCursor != null) {
+ profileCursor.close();
+ }
+ }
+ } else {
+ // Not a profile photo and not found - mark the cache accordingly
+ cacheBitmap(id, null, preloading);
+ }
}
mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index a4163fd..528e246 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -351,7 +351,7 @@
mAdapter.configureDirectoryLoader(loader);
return loader;
} else {
- CursorLoader loader = new CursorLoader(mContext, null, null, null, null, null);
+ CursorLoader loader = createCursorLoader();
long directoryId = args != null && args.containsKey(DIRECTORY_ID_ARG_KEY)
? args.getLong(DIRECTORY_ID_ARG_KEY)
: Directory.DEFAULT;
@@ -360,6 +360,10 @@
}
}
+ public CursorLoader createCursorLoader() {
+ return new CursorLoader(mContext, null, null, null, null, null);
+ }
+
private void startLoadingDirectoryPartition(int partitionIndex) {
DirectoryPartition partition = (DirectoryPartition)mAdapter.getPartition(partitionIndex);
partition.setStatus(DirectoryPartition.STATUS_LOADING);
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index c057a48..0553909 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -144,11 +144,6 @@
.appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
}
- protected static Uri includeProfileEntry(Uri uri) {
- return uri.buildUpon()
- .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "true").build();
- }
-
public boolean getHasPhoneNumber(int position) {
return ((Cursor)getItem(position)).getInt(CONTACT_HAS_PHONE_COLUMN_INDEX) != 0;
}
diff --git a/src/com/android/contacts/list/ContactsSectionIndexer.java b/src/com/android/contacts/list/ContactsSectionIndexer.java
index 109b8ba..5ecb31c 100644
--- a/src/com/android/contacts/list/ContactsSectionIndexer.java
+++ b/src/com/android/contacts/list/ContactsSectionIndexer.java
@@ -26,9 +26,9 @@
*/
public class ContactsSectionIndexer implements SectionIndexer {
- private final String[] mSections;
- private final int[] mPositions;
- private final int mCount;
+ private String[] mSections;
+ private int[] mPositions;
+ private int mCount;
/**
* Constructor.
@@ -95,8 +95,25 @@
}
public void setProfileHeader(String header) {
- if (mSections != null && mSections.length > 0) {
- mSections[0] = header;
+ if (mSections != null) {
+ // Don't do anything if the header is already set properly.
+ if (mSections.length > 0 && header.equals(mSections[0])) {
+ return;
+ }
+
+ // Since the section indexer isn't aware of the profile at the top, we need to add a
+ // special section at the top for it and shift everything else down.
+ String[] tempSections = new String[mSections.length + 1];
+ int[] tempPositions = new int[mPositions.length + 1];
+ tempSections[0] = header;
+ tempPositions[0] = 0;
+ for (int i = 1; i <= mPositions.length; i++) {
+ tempSections[i] = mSections[i - 1];
+ tempPositions[i] = mPositions[i - 1] + 1;
+ }
+ mSections = tempSections;
+ mPositions = tempPositions;
+ mCount++;
}
}
}
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 306e244..9ddc4b7 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -18,6 +18,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.ContactEditorFragment;
+import android.content.CursorLoader;
import android.content.Intent;
import android.database.Cursor;
import android.provider.ContactsContract.Contacts;
@@ -56,6 +57,11 @@
}
@Override
+ public CursorLoader createCursorLoader() {
+ return new ProfileAndContactsLoader(getActivity());
+ }
+
+ @Override
protected void onItemClick(int position, long id) {
viewContact(getAdapter().getContactUri(position));
}
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index 007af6c..9a3f05e 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -57,6 +57,9 @@
@Override
public void configureLoader(CursorLoader loader, long directoryId) {
+ if (loader instanceof ProfileAndContactsLoader) {
+ ((ProfileAndContactsLoader) loader).setLoadProfile(shouldIncludeProfile());
+ }
ContactListFilter filter = getFilter();
if (isSearchMode()) {
@@ -129,11 +132,6 @@
.build();
}
- // Include the user's personal profile.
- if (shouldIncludeProfile()) {
- uri = includeProfileEntry(uri);
- }
-
loader.setUri(uri);
}
diff --git a/src/com/android/contacts/list/ProfileAndContactsLoader.java b/src/com/android/contacts/list/ProfileAndContactsLoader.java
new file mode 100644
index 0000000..7f85ea6
--- /dev/null
+++ b/src/com/android/contacts/list/ProfileAndContactsLoader.java
@@ -0,0 +1,90 @@
+/*
+ * 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.contacts.list;
+
+import com.google.android.collect.Lists;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MergeCursor;
+import android.os.Bundle;
+import android.provider.ContactsContract.Profile;
+
+import java.util.List;
+
+/**
+ * A loader for use in the default contact list, which will also query for the user's profile
+ * if configured to do so.
+ */
+public class ProfileAndContactsLoader extends CursorLoader {
+
+ private boolean mLoadProfile;
+ private String[] mProjection;
+
+ public ProfileAndContactsLoader(Context context) {
+ super(context);
+ }
+
+ public void setLoadProfile(boolean flag) {
+ mLoadProfile = flag;
+ }
+
+ public void setProjection(String[] projection) {
+ super.setProjection(projection);
+ mProjection = projection;
+ }
+
+ @Override
+ public Cursor loadInBackground() {
+ // First load the profile, if enabled.
+ List<Cursor> cursors = Lists.newArrayList();
+ if (mLoadProfile) {
+ cursors.add(loadProfile());
+ }
+ final Cursor contactsCursor = super.loadInBackground();
+ cursors.add(contactsCursor);
+ return new MergeCursor(cursors.toArray(new Cursor[cursors.size()])) {
+ @Override
+ public Bundle getExtras() {
+ // Need to get the extras from the contacts cursor.
+ return contactsCursor.getExtras();
+ }
+ };
+ }
+
+ /**
+ * Loads the profile into a MatrixCursor.
+ */
+ private MatrixCursor loadProfile() {
+ Cursor cursor = getContext().getContentResolver().query(Profile.CONTENT_URI, mProjection,
+ null, null, null);
+ try {
+ MatrixCursor matrix = new MatrixCursor(mProjection);
+ Object[] row = new Object[mProjection.length];
+ while (cursor.moveToNext()) {
+ for (int i = 0; i < row.length; i++) {
+ row[i] = cursor.getString(i);
+ }
+ matrix.addRow(row);
+ }
+ return matrix;
+ } finally {
+ cursor.close();
+ }
+ }
+}