Contacts to display: hide accounts without raw contacts
- Hide extension accounts with no raw contacts.
- Now that building the list hits the database we need to use AsyncTaskLoader.
- Did a little refactoring (e.g. moving mFilter to the adpter) so the code will
work better with a loader.
Bug 5160471
Change-Id: I780985a73325d4d453962e8ea5dca0d68c3c869e
diff --git a/src/com/android/contacts/list/AccountFilterActivity.java b/src/com/android/contacts/list/AccountFilterActivity.java
index fb0cf9e..02abb53 100644
--- a/src/com/android/contacts/list/AccountFilterActivity.java
+++ b/src/com/android/contacts/list/AccountFilterActivity.java
@@ -22,13 +22,24 @@
import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.AccountWithDataSet;
+import com.google.android.collect.Lists;
import android.app.ActionBar;
import android.app.Activity;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.AsyncTaskLoader;
import android.content.Context;
import android.content.Intent;
+import android.content.Loader;
+import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -53,9 +64,13 @@
public static final String KEY_EXTRA_CONTACT_LIST_FILTER = "contactListFilter";
+ private static final int FILTER_LOADER_ID = 0;
+
private ListView mListView;
- private List<ContactListFilter> mFilters = new ArrayList<ContactListFilter>();
+ private static final String[] ID_PROJECTION = new String[] {BaseColumns._ID};
+ private static final Uri RAW_CONTACTS_URI_LIMIT_1 = RawContacts.CONTENT_URI.buildUpon()
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, "1").build();
@Override
protected void onCreate(Bundle icicle) {
@@ -70,38 +85,118 @@
actionBar.setDisplayHomeAsUpEnabled(true);
}
- loadAccountFilters();
+ getLoaderManager().initLoader(FILTER_LOADER_ID, null, new MyLoaderCallbacks());
}
- private void loadAccountFilters() {
- ArrayList<ContactListFilter> accountFilters = new ArrayList<ContactListFilter>();
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
+ private static class FilterLoader extends AsyncTaskLoader<List<ContactListFilter>> {
+ private Context mContext;
+
+ public FilterLoader(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public List<ContactListFilter> loadInBackground() {
+ return loadAccountFilters(mContext);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ forceLoad();
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ onStopLoading();
+ }
+ }
+
+ private static List<ContactListFilter> loadAccountFilters(Context context) {
+ final ArrayList<ContactListFilter> result = Lists.newArrayList();
+ final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList();
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
List<AccountWithDataSet> accounts = accountTypes.getAccounts(false);
for (AccountWithDataSet account : accounts) {
AccountType accountType = accountTypes.getAccountType(account.type, account.dataSet);
- Drawable icon = accountType != null ? accountType.getDisplayIcon(this) : null;
+ if (accountType.isExtension() && !hasAccountData(context, account)) {
+ // Hide extensions with no raw_contacts.
+ continue;
+ }
+ Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
accountFilters.add(ContactListFilter.createAccountFilter(account.type, account.name,
account.dataSet, icon, account.name));
}
- final int count = accountFilters.size();
+ // Always show "All", even when there's no accounts. (We may have local contacts)
+ result.add(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
+
+ final int count = accountFilters.size();
if (count >= 1) {
- mFilters.add(ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
// If we only have one account, don't show it as "account", instead show it as "all"
if (count > 1) {
- mFilters.addAll(accountFilters);
+ result.addAll(accountFilters);
}
- mFilters.add(ContactListFilter.createFilterWithType(
+ result.add(ContactListFilter.createFilterWithType(
ContactListFilter.FILTER_TYPE_CUSTOM));
}
+ return result;
+ }
- mListView.setAdapter(new FilterListAdapter(this));
+ private static boolean hasAccountData(Context context, AccountWithDataSet account) {
+ final String BASE_SELECTION =
+ RawContacts.ACCOUNT_TYPE + " = ?" + " AND " + RawContacts.ACCOUNT_NAME + " = ?";
+ final String selection;
+ final String[] args;
+ if (TextUtils.isEmpty(account.dataSet)) {
+ selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " IS NULL";
+ args = new String[] {account.type, account.name};
+ } else {
+ selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " = ?";
+ args = new String[] {account.type, account.name, account.dataSet};
+ }
+
+ final Cursor c = context.getContentResolver().query(RAW_CONTACTS_URI_LIMIT_1,
+ ID_PROJECTION, selection, args, null);
+ if (c == null) return false;
+ try {
+ return c.moveToFirst();
+ } finally {
+ c.close();
+ }
+ }
+
+ private class MyLoaderCallbacks implements LoaderCallbacks<List<ContactListFilter>> {
+ @Override
+ public Loader<List<ContactListFilter>> onCreateLoader(int id, Bundle args) {
+ return new FilterLoader(AccountFilterActivity.this);
+ }
+
+ @Override
+ public void onLoadFinished(
+ Loader<List<ContactListFilter>> loader, List<ContactListFilter> data) {
+ if (data == null) { // Just in case...
+ Log.e(TAG, "Failed to load filters");
+ return;
+ }
+ mListView.setAdapter(new FilterListAdapter(AccountFilterActivity.this, data));
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<ContactListFilter>> loader) {
+ }
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- ContactListFilter filter = mFilters.get(position);
+ final ContactListFilter filter = (ContactListFilter) view.getTag();
+ if (filter == null) return; // Just in case
if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
final Intent intent = new Intent(this,
CustomContactListFilterActivity.class);
@@ -143,12 +238,14 @@
}
}
- private class FilterListAdapter extends BaseAdapter {
- private LayoutInflater mLayoutInflater;
+ private static class FilterListAdapter extends BaseAdapter {
+ private final List<ContactListFilter> mFilters;
+ private final LayoutInflater mLayoutInflater;
- public FilterListAdapter(Context context) {
+ public FilterListAdapter(Context context, List<ContactListFilter> filters) {
mLayoutInflater = (LayoutInflater) context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
+ mFilters = filters;
}
@Override
@@ -167,7 +264,7 @@
}
public View getView(int position, View convertView, ViewGroup parent) {
- ContactListFilterView view;
+ final ContactListFilterView view;
if (convertView != null) {
view = (ContactListFilterView) convertView;
} else {
@@ -175,9 +272,10 @@
R.layout.contact_list_filter_item, parent, false);
}
view.setSingleAccount(mFilters.size() == 1);
- ContactListFilter filter = mFilters.get(position);
+ final ContactListFilter filter = mFilters.get(position);
view.setContactListFilter(filter);
view.bindView(true);
+ view.setTag(filter);
return view;
}
}
diff --git a/src/com/android/contacts/model/AccountType.java b/src/com/android/contacts/model/AccountType.java
index 8ee1aa1..879a89f 100644
--- a/src/com/android/contacts/model/AccountType.java
+++ b/src/com/android/contacts/model/AccountType.java
@@ -87,6 +87,10 @@
return false;
}
+ public boolean isExtension() {
+ return false;
+ }
+
/**
* Returns an optional custom edit activity. The activity class should reside
* in the sync adapter package as determined by {@link #resPackageName}.
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 2d821e6..d28d5bb 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -309,7 +309,7 @@
// TODO: use syncadapter package instead, since it provides resources
Log.d(TAG, "Registering external account type=" + type
+ ", packageName=" + auth.packageName);
- accountType = new ExternalAccountType(mContext, auth.packageName);
+ accountType = new ExternalAccountType(mContext, auth.packageName, false);
if (!((ExternalAccountType) accountType).isInitialized()) {
// Skip external account types that couldn't be initialized.
continue;
@@ -333,7 +333,7 @@
Log.d(TAG, "Registering " + extensionPackages.size() + " extension packages");
for (String extensionPackage : extensionPackages) {
ExternalAccountType accountType =
- new ExternalAccountType(mContext, extensionPackage);
+ new ExternalAccountType(mContext, extensionPackage, true);
if (!accountType.isInitialized()) {
// Skip external account types that couldn't be initialized.
continue;
diff --git a/src/com/android/contacts/model/ExternalAccountType.java b/src/com/android/contacts/model/ExternalAccountType.java
index b6649c9..7fefc44 100644
--- a/src/com/android/contacts/model/ExternalAccountType.java
+++ b/src/com/android/contacts/model/ExternalAccountType.java
@@ -69,6 +69,8 @@
private static final String ATTR_ACCOUNT_LABEL = "accountTypeLabel";
private static final String ATTR_ACCOUNT_ICON = "accountTypeIcon";
+ private final boolean mIsExtension;
+
private String mEditContactActivityClassName;
private String mCreateContactActivityClassName;
private String mInviteContactActivity;
@@ -84,7 +86,8 @@
private boolean mInitSuccessful;
private boolean mHasContactsMetadata;
- public ExternalAccountType(Context context, String resPackageName) {
+ public ExternalAccountType(Context context, String resPackageName, boolean isExtension) {
+ this.mIsExtension = isExtension;
this.resPackageName = resPackageName;
this.summaryResPackageName = resPackageName;
@@ -127,6 +130,11 @@
return true;
}
+ @Override
+ public boolean isExtension() {
+ return mIsExtension;
+ }
+
/**
* Whether this account type was able to be fully initialized. This may be false if
* (for example) the package name associated with the account type could not be found.