Moving package installation and account update listeners in the bg
Bug: 3228687
Change-Id: Id082dac2c2b21f09ccfc30afb5f734e8c36cb2d8
diff --git a/src/com/android/contacts/list/ContactListFilter.java b/src/com/android/contacts/list/ContactListFilter.java
index dcaf608..2a2caf7 100644
--- a/src/com/android/contacts/list/ContactListFilter.java
+++ b/src/com/android/contacts/list/ContactListFilter.java
@@ -97,12 +97,12 @@
@Override
public int compareTo(ContactListFilter another) {
- int res = accountType.compareTo(another.accountType);
+ int res = accountName.compareTo(another.accountName);
if (res != 0) {
return res;
}
- res = accountName.compareTo(another.accountName);
+ res = accountType.compareTo(another.accountType);
if (res != 0) {
return res;
}
diff --git a/src/com/android/contacts/model/AccountTypes.java b/src/com/android/contacts/model/AccountTypes.java
index 9b282fb..4e94248 100644
--- a/src/com/android/contacts/model/AccountTypes.java
+++ b/src/com/android/contacts/model/AccountTypes.java
@@ -32,14 +32,19 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SyncAdapterType;
+import android.content.SyncStatusObserver;
import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
-import java.lang.ref.SoftReference;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -47,7 +52,8 @@
* Singleton holder for all parsed {@link AccountType} available on the
* system, typically filled through {@link PackageManager} queries.
*/
-public class AccountTypes extends BroadcastReceiver implements OnAccountsUpdateListener {
+public class AccountTypes extends BroadcastReceiver
+ implements OnAccountsUpdateListener, SyncStatusObserver {
private static final String TAG = "AccountTypes";
private Context mContext;
@@ -56,22 +62,40 @@
private AccountType mFallbackSource = null;
+ private ArrayList<Account> mAccounts = Lists.newArrayList();
+ private ArrayList<Account> mWritableAccounts = Lists.newArrayList();
private HashMap<String, AccountType> mSources = Maps.newHashMap();
private HashSet<String> mKnownPackages = Sets.newHashSet();
- private static SoftReference<AccountTypes> sInstance = null;
+ private static final int MESSAGE_PROCESS_BROADCAST_INTENT = 0;
+ private static final int MESSAGE_SYNC_STATUS_CHANGED = 1;
+
+ private HandlerThread mListenerThread;
+ private Handler mListenerHandler;
+
+ private static AccountTypes sInstance = null;
+
+ private static final Comparator<Account> ACCOUNT_COMPARATOR = new Comparator<Account>() {
+
+ @Override
+ public int compare(Account account1, Account account2) {
+ int diff = account1.name.compareTo(account2.name);
+ if (diff != 0) {
+ return diff;
+ }
+ return account1.type.compareTo(account2.type);
+ }
+ };
/**
* Requests the singleton instance of {@link AccountTypes} with data bound from
* the available authenticators. This method can safely be called from the UI thread.
*/
public static synchronized AccountTypes getInstance(Context context) {
- AccountTypes sources = sInstance == null ? null : sInstance.get();
- if (sources == null) {
- sources = new AccountTypes(context);
- sInstance = new SoftReference<AccountTypes>(sources);
+ if (sInstance == null) {
+ sInstance = new AccountTypes(context);
}
- return sources;
+ return sInstance;
}
/**
@@ -87,6 +111,22 @@
queryAccounts();
+ mListenerThread = new HandlerThread("AccountChangeListener");
+ mListenerThread.start();
+ mListenerHandler = new Handler(mListenerThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_PROCESS_BROADCAST_INTENT:
+ processBroadcastIntent((Intent) msg.obj);
+ break;
+ case MESSAGE_SYNC_STATUS_CHANGED:
+ queryAccounts();
+ break;
+ }
+ }
+ };
+
// Request updates when packages or accounts change
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -103,7 +143,9 @@
filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
mApplicationContext.registerReceiver(this, filter);
- mAccountManager.addOnAccountsUpdatedListener(this, null, false);
+ mAccountManager.addOnAccountsUpdatedListener(this, mListenerHandler, false);
+
+ ContentResolver.addStatusChangeListener(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, this);
}
/** @hide exposed for unit tests */
@@ -118,9 +160,18 @@
mKnownPackages.add(source.resPackageName);
}
- /** {@inheritDoc} */
@Override
public void onReceive(Context context, Intent intent) {
+ Message msg = mListenerHandler.obtainMessage(MESSAGE_PROCESS_BROADCAST_INTENT, intent);
+ mListenerHandler.sendMessage(msg);
+ }
+
+ @Override
+ public void onStatusChanged(int which) {
+ mListenerHandler.sendEmptyMessage(MESSAGE_SYNC_STATUS_CHANGED);
+ }
+
+ public void processBroadcastIntent(Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
@@ -170,7 +221,7 @@
}
}
- /** {@inheritDoc} */
+ /* This notification will arrive on the background thread */
public void onAccountsUpdated(Account[] accounts) {
// Refresh to catch any changed accounts
queryAccounts();
@@ -182,6 +233,8 @@
protected synchronized void queryAccounts() {
mSources.clear();
mKnownPackages.clear();
+ mAccounts.clear();
+ mWritableAccounts.clear();
final AccountManager am = mAccountManager;
final IContentService cs = ContentResolver.getContentService();
@@ -223,6 +276,34 @@
} catch (RemoteException e) {
Log.w(TAG, "Problem loading accounts: " + e.toString());
}
+
+ Account[] accounts = mAccountManager.getAccounts();
+ for (Account account : accounts) {
+ boolean syncable = false;
+ try {
+ int isSyncable = cs.getIsSyncable(account, ContactsContract.AUTHORITY);
+ if (isSyncable > 0) {
+ syncable = true;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot obtain sync flag for account: " + account, e);
+ }
+
+ if (syncable) {
+ // Ensure we have details loaded for each account
+ final AccountType accountType = getInflatedSource(
+ account.type, AccountType.LEVEL_SUMMARY);
+ if (accountType != null) {
+ mAccounts.add(account);
+ if (!accountType.readOnly) {
+ mWritableAccounts.add(account);
+ }
+ }
+ }
+ }
+
+ Collections.sort(mAccounts, ACCOUNT_COMPARATOR);
+ Collections.sort(mWritableAccounts, ACCOUNT_COMPARATOR);
}
/**
@@ -240,40 +321,10 @@
}
/**
- * Return list of all known, writable {@link AccountType}. AccountTypes
- * returned may require inflation before they can be used.
+ * Return list of all known, writable {@link Account}'s.
*/
- public ArrayList<Account> getAccounts(boolean writableOnly) {
- final AccountManager am = mAccountManager;
- final Account[] accounts = am.getAccounts();
- final ArrayList<Account> matching = Lists.newArrayList();
- final IContentService cs = ContentResolver.getContentService();
-
- for (Account account : accounts) {
- boolean syncable = false;
- try {
- int isSyncable = cs.getIsSyncable(account, ContactsContract.AUTHORITY);
- if (isSyncable > 0) {
- syncable = true;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot obtain sync flag for account: " + account, e);
- }
- // Log.v(TAG, String.format("found account (name: %s, type: %s, syncable: %b",
- // account.name, account.type, syncable));
- if (syncable) {
- // Ensure we have details loaded for each account
- final AccountType accountType = getInflatedSource(account.type,
- AccountType.LEVEL_SUMMARY);
- final boolean hasContacts = accountType != null;
- final boolean matchesWritable =
- (!writableOnly || (writableOnly && !accountType.readOnly));
- if (hasContacts && matchesWritable) {
- matching.add(account);
- }
- }
- }
- return matching;
+ public synchronized ArrayList<Account> getAccounts(boolean writableOnly) {
+ return writableOnly ? mWritableAccounts : mAccounts;
}
/**