Bug 1396941 - SuggestedSitePreparer: Update local cache if suggested sites change. r?mcomella draft
authorSebastian Kaspari <s.kaspari@gmail.com>
Wed, 13 Sep 2017 19:57:19 +0200
changeset 664718 566847ca63b3b12063aa348beac1f8d624348516
parent 663831 1888ec2f277f6bb26271b8808e08914a21db9efe
child 731518 f2e457e8b84e2048801e051f23eb4110ecd02a60
push id79778
push users.kaspari@gmail.com
push dateThu, 14 Sep 2017 09:12:30 +0000
reviewersmcomella
bugs1396941
milestone57.0a1
Bug 1396941 - SuggestedSitePreparer: Update local cache if suggested sites change. r?mcomella MozReview-Commit-ID: 2QMqGHQaBSP
mobile/android/base/java/org/mozilla/gecko/icons/preparation/SuggestedSitePreparer.java
--- a/mobile/android/base/java/org/mozilla/gecko/icons/preparation/SuggestedSitePreparer.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/preparation/SuggestedSitePreparer.java
@@ -1,38 +1,72 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 package org.mozilla.gecko.icons.preparation;
 
 import android.content.Context;
+import android.database.ContentObserver;
 import android.database.Cursor;
 
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.SuggestedSites;
 import org.mozilla.gecko.icons.IconDescriptor;
 import org.mozilla.gecko.icons.IconRequest;
 import org.mozilla.gecko.icons.loader.SuggestedSiteLoader;
+import org.mozilla.gecko.util.ThreadUtils;
 
 import java.util.HashSet;
 import java.util.Set;
 
 public class SuggestedSitePreparer implements Preparer {
-
     private boolean initialised = false;
     private final Set<String> siteFaviconMap = new HashSet<>();
 
+    private boolean initialise(final Context context) {
+        registerForSuggestedSitesUpdated(context.getApplicationContext());
+
+        return refreshSiteFaviconMap(context);
+    }
+
+    // Suggested sites can change at runtime - for example when a distribution is (down)loaded. In
+    // this case we need to refresh our local cache of suggested sites' favicons.
+    private void registerForSuggestedSitesUpdated(final Context context) {
+        context.getContentResolver().registerContentObserver(
+                BrowserContract.SuggestedSites.CONTENT_URI,
+                false,
+                new ContentObserver(null) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        // The list of suggested sites has changed. We need to update our local
+                        // mapping.
+                        refreshSiteFaviconMapOnBackgroundThread(context);
+                    }
+                });
+    }
+
+    private void refreshSiteFaviconMapOnBackgroundThread(final Context context) {
+        ThreadUtils.postToBackgroundThread(new Runnable() {
+            @Override
+            public void run() {
+                refreshSiteFaviconMap(context);
+            }
+        });
+    }
+
     // Loading suggested sites (and iterating over them) is potentially slow. The number of suggested
     // sites is low, and a HashSet containing them is therefore likely to be exceedingly small.
     // Hence we opt to iterate over the list once, and do an immediate lookup every time a favicon
     // is requested:
     // Loading can fail if suggested sites haven't been initialised yet, only proceed if we return true.
-    private boolean initialise(final Context context) {
+    private synchronized boolean refreshSiteFaviconMap(Context context) {
+        siteFaviconMap.clear();
+
         final SuggestedSites suggestedSites = BrowserDB.from(context).getSuggestedSites();
 
         // suggestedSites may not have been initialised yet if BrowserApp isn't running yet. Suggested
         // Sites are initialised in BrowserApp.onCreate(), but we might need to load icons when running
         // custom tabs, as geckoview, etc. (But we don't care as much about the bundled icons in those
         // scenarios.)
         if (suggestedSites == null) {
             return false;
@@ -48,18 +82,20 @@ public class SuggestedSitePreparer imple
             }
         } finally {
             cursor.close();
         }
 
         return true;
     }
 
+    // Synchronized so that asynchronous updates of the map (via content observer) are visible
+    // immediately and completely.
     @Override
-    public void prepare(final IconRequest request) {
+    public synchronized void prepare(final IconRequest request) {
         if (request.shouldSkipDisk()) {
             return;
         }
 
         if (!initialised) {
             initialised = initialise(request.getContext());
 
             if (!initialised) {