Add support for the UIprovider to return a smaller list of accounts

Change-Id: I6e7e0f6f0d32b38b5551545056025ce6987685c4
diff --git a/src/com/android/mail/providers/AccountCacheProvider.java b/src/com/android/mail/providers/AccountCacheProvider.java
index 84754d5..986bd42 100644
--- a/src/com/android/mail/providers/AccountCacheProvider.java
+++ b/src/com/android/mail/providers/AccountCacheProvider.java
@@ -29,8 +29,10 @@
 
 import com.google.common.base.Objects;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 import java.util.Map;
+import java.util.Set;
 
 
 /**
@@ -48,6 +50,9 @@
 
     private final static Map<Uri, CachedAccount> ACCOUNT_CACHE = Maps.newHashMap();
 
+    // Map from content provider query uri to the set of account uri that resulted from that query
+    private final static Map<Uri, Set<Uri>> QUERY_URI_ACCOUNT_URIS_MAP = Maps.newHashMap();
+
     private ContentResolver mResolver;
     private static String sAuthority;
     private static AccountCacheProvider sInstance;
@@ -168,7 +173,8 @@
      * @param resolver
      * @param accountsQueryUri
      */
-    public static void addAccountsForUri(ContentResolver resolver, Uri accountsQueryUri) {
+    public static synchronized void addAccountsForUri(
+            ContentResolver resolver, Uri accountsQueryUri) {
         final Cursor c = resolver.query(accountsQueryUri, UIProvider.ACCOUNTS_PROJECTION,
                 null, null, null);
         if (c == null) {
@@ -177,17 +183,38 @@
         }
 
         // TODO(pwestbro):
-        // 1) Keep a map of queryUri -> Accounts to make it easy to remove deleted accounts
-        // 2) Keep a cache of Cursors which would allow changes to be observered.
+        // 1) Keep a cache of Cursors which would allow changes to be observered.
+        final Set<Uri> previousQueryUriMap = QUERY_URI_ACCOUNT_URIS_MAP.get(accountsQueryUri);
 
+        final Set<Uri> newQueryUriMap = Sets.newHashSet();
         try {
             while (c.moveToNext()) {
                 final Account account = new Account(c);
+                final Uri accountUri = account.uri;
+                newQueryUriMap.add(accountUri);
                 addAccount(new CachedAccount(account));
             }
         } finally {
             c.close();
         }
+
+        // Save the new set, or remove the previous entry if it is empty
+        if (newQueryUriMap.size() > 0) {
+            QUERY_URI_ACCOUNT_URIS_MAP.put(accountsQueryUri, newQueryUriMap);
+        } else {
+            QUERY_URI_ACCOUNT_URIS_MAP.remove(accountsQueryUri);
+        }
+
+        if (previousQueryUriMap != null) {
+            // Remove all of the accounts that are in the new result set
+            previousQueryUriMap.removeAll(newQueryUriMap);
+
+            // For all of the entries that had been in the previous result set, and are not
+            // in the new result set, remove them from the cache
+            if (previousQueryUriMap.size() > 0) {
+                removeAccounts(previousQueryUriMap);
+            }
+        }
     }
 
     public static void addAccount(CachedAccount account) {
@@ -201,12 +228,20 @@
         broadcastAccountChange();
     }
 
-    public static void removeAccount(String accountUri) {
+    public static void removeAccount(Uri accountUri) {
         synchronized (ACCOUNT_CACHE) {
-            final CachedAccount account = ACCOUNT_CACHE.get(accountUri);
+            ACCOUNT_CACHE.remove(accountUri);
+        }
 
-            if (account != null) {
-                ACCOUNT_CACHE.remove(account);
+        // Explicitly calling this out of the synchronized block in case any of the observers get
+        // called synchronously.
+        broadcastAccountChange();
+    }
+
+    private static void removeAccounts(Set<Uri> uris) {
+        synchronized (ACCOUNT_CACHE) {
+            for (Uri accountUri : uris) {
+                ACCOUNT_CACHE.remove(accountUri);
             }
         }