Using content observer to update contact filter list
Bug: 3194334
Change-Id: I90aef198739622a4d4ab606fa94f5fd4da6b72f3
diff --git a/src/com/android/contacts/list/ContactListFilterController.java b/src/com/android/contacts/list/ContactListFilterController.java
index b9e3c59..a8c780b 100644
--- a/src/com/android/contacts/list/ContactListFilterController.java
+++ b/src/com/android/contacts/list/ContactListFilterController.java
@@ -25,9 +25,8 @@
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.preference.PreferenceManager;
+import android.text.TextUtils;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -53,37 +52,19 @@
void onContactListFilterCustomizationRequest();
}
- private static final int MESSAGE_REFRESH_FILTERS = 0;
-
- /**
- * The delay before the contact filter list is refreshed. This is needed because
- * during contact sync we will get lots of notifications in rapid succession. This
- * delay will prevent the slowly changing list of filters from reloading too often.
- */
- private static final int FILTER_SPINNER_REFRESH_DELAY_MILLIS = 5000;
-
private Context mContext;
private LoaderManager mLoaderManager;
private boolean mEnabled = true;
private List<ContactListFilterListener> mListeners = new ArrayList<ContactListFilterListener>();
private ListPopupWindow mPopup;
private int mPopupWidth = -1;
+ private List<ContactListFilter> mCachedFilters;
private SparseArray<ContactListFilter> mFilters;
private int mNextFilterId = 1;
private View mAnchor;
private FilterListAdapter mFilterListAdapter;
private ContactListFilter mFilter;
private boolean mFiltersLoaded;
- private final Handler mHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MESSAGE_REFRESH_FILTERS) {
- loadFilters();
- }
- }
- };
-
private int mAccountCount;
public ContactListFilterController(Activity activity) {
@@ -121,22 +102,16 @@
}
public void startLoading() {
- // Set the "ready" flag right away - we only want to start the loader once
- mFiltersLoaded = false;
if (mFilter == null) {
mFilter = ContactListFilter.restoreFromPreferences(getSharedPreferences());
}
- loadFilters();
+ mLoaderManager.initLoader(R.id.contact_list_filter_loader, null, this);
}
private SharedPreferences getSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(mContext);
}
- private void loadFilters() {
- mLoaderManager.restartLoader(R.id.contact_list_filter_loader, null, this);
- }
-
@Override
public ContactListFilterLoader onCreateLoader(int id, Bundle args) {
return new ContactListFilterLoader(mContext);
@@ -145,6 +120,34 @@
@Override
public void onLoadFinished(
Loader<List<ContactListFilter>> loader, List<ContactListFilter> filters) {
+ int count = filters.size();
+ if (mCachedFilters != null && mCachedFilters.size() == count) {
+ boolean changed = false;
+ for (int i = 0; i < filters.size(); i++) {
+ ContactListFilter filter1 = mCachedFilters.get(i);
+ ContactListFilter filter2 = filters.get(i);
+ if (!filter1.equals(filter2)) {
+ changed = true;
+ break;
+ }
+
+ // Group title is intentionally not included in the "equals" algorithm for
+ // ContactListFilter, because we want stability of filter identity
+ // across label changes. However, here we do care about the label changes.
+ if (filter1.filterType == ContactListFilter.FILTER_TYPE_GROUP &&
+ !TextUtils.equals(filter1.title, filter2.title)) {
+ changed = true;
+ break;
+ }
+ }
+
+ if (!changed) {
+ return;
+ }
+ }
+
+ mCachedFilters = filters;
+
if (mFilters == null) {
mFilters = new SparseArray<ContactListFilter>(filters.size());
} else {
@@ -154,7 +157,6 @@
boolean filterValid = mFilter != null && !mFilter.isValidationRequired();
mAccountCount = 0;
- int count = filters.size();
for (int index = 0; index < count; index++) {
if (filters.get(index).filterType == ContactListFilter.FILTER_TYPE_ACCOUNT) {
mAccountCount++;
@@ -210,19 +212,11 @@
mFilterListAdapter.notifyDataSetChanged();
}
- if (filterChanged) {
- mFiltersLoaded = true;
- notifyContactListFilterChanged();
- } else if (!mFiltersLoaded) {
- mFiltersLoaded = true;
- notifyContacListFiltersLoaded();
- }
- }
+ mFiltersLoaded = true;
+ notifyContacListFiltersLoaded();
- public void postDelayedRefresh() {
- if (!mHandler.hasMessages(MESSAGE_REFRESH_FILTERS)) {
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_REFRESH_FILTERS, FILTER_SPINNER_REFRESH_DELAY_MILLIS);
+ if (filterChanged) {
+ notifyContactListFilterChanged();
}
}
diff --git a/src/com/android/contacts/list/ContactListFilterLoader.java b/src/com/android/contacts/list/ContactListFilterLoader.java
index c0c2fac..adb7c7f 100644
--- a/src/com/android/contacts/list/ContactListFilterLoader.java
+++ b/src/com/android/contacts/list/ContactListFilterLoader.java
@@ -16,8 +16,8 @@
package com.android.contacts.list;
-import com.android.contacts.model.AccountTypes;
import com.android.contacts.model.AccountType;
+import com.android.contacts.model.AccountTypes;
import android.accounts.Account;
import android.content.AsyncTaskLoader;
@@ -25,6 +25,7 @@
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Groups;
import java.util.ArrayList;
@@ -57,6 +58,10 @@
Groups.DELETED + "=0 AND " + Groups.FAVORITES + "=0";
}
+ private boolean mStopped;
+ private ForceLoadContentObserver mObserver;
+ private ArrayList<ContactListFilter> mResults;
+
public ContactListFilterLoader(Context context) {
super(context);
}
@@ -111,22 +116,53 @@
Collections.sort(results);
+ mResults = results;
return results;
}
+ /* Runs on the UI thread */
+ @Override
+ public void deliverResult(List<ContactListFilter> results) {
+ if (!mStopped) {
+ super.deliverResult(results);
+ }
+ }
+
+ @Override
+ public void startLoading() {
+ if (mObserver == null) {
+ mObserver = new ForceLoadContentObserver();
+ getContext().getContentResolver().registerContentObserver(
+ Contacts.CONTENT_URI, true, mObserver);
+ }
+
+ mStopped = false;
+
+ if (mResults != null) {
+ deliverResult(mResults);
+ } else {
+ forceLoad();
+ }
+ }
+
+ @Override
+ public void stopLoading() {
+ if (mObserver != null) {
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ mObserver = null;
+ }
+
+ mResults = null;
+
+ // Attempt to cancel the current load task if possible.
+ cancelLoad();
+
+ // Make sure that any outstanding loads clean themselves up properly
+ mStopped = true;
+ }
+
@Override
public void destroy() {
stopLoading();
}
-
- @Override
- public void startLoading() {
- cancelLoad();
- forceLoad();
- }
-
- @Override
- public void stopLoading() {
- cancelLoad();
- }
}