Bug 972098 - Refresh DynamicPanels with the dataset changes. r=margaret a=lsblakk
authorLucas Rocha <lucasr@mozilla.com>
Thu, 20 Mar 2014 15:28:21 +0000
changeset 193154 e3c2a55f23e3fcf1f7d936a20d485d777fd51536
parent 193153 6c64db9f01a37517210a073b30caac24d297941e
child 193155 6eb15f7225985fdbf30337955b4a34f1fdd925c4
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret, lsblakk
bugs972098
milestone30.0a2
Bug 972098 - Refresh DynamicPanels with the dataset changes. r=margaret a=lsblakk * * * Bug 972098 - Factor out code to restart a dataset loader (r=margaret) * * * Bug 972098 - Refresh DynamicPanels when the dataset changes (r=margaret)
mobile/android/base/home/DynamicPanel.java
mobile/android/modules/HomeProvider.jsm
--- a/mobile/android/base/home/DynamicPanel.java
+++ b/mobile/android/base/home/DynamicPanel.java
@@ -1,21 +1,27 @@
 /* -*- 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.home;
 
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.db.BrowserContract.HomeItems;
 import org.mozilla.gecko.db.DBUtils;
 import org.mozilla.gecko.home.HomeConfig.PanelConfig;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.home.PanelLayout.DatasetHandler;
 import org.mozilla.gecko.home.PanelLayout.DatasetRequest;
+import org.mozilla.gecko.util.GeckoEventListener;
+import org.mozilla.gecko.util.ThreadUtils;
 
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.support.v4.app.LoaderManager;
@@ -40,17 +46,18 @@ import android.view.ViewGroup;
  * the provided {@code DatasetHandler}. This way it doesn't need to know the
  * details of how datasets are loaded and reset. Each time a dataset is
  * requested, {@code DynamicPanel} restarts a Loader with the respective ID (see
  * {@code PanelDatasetHandler}).
  *
  * See {@code PanelLayout} for more details on how {@code DynamicPanel}
  * receives dataset requests and delivers them back to the {@code PanelLayout}.
  */
-public class DynamicPanel extends HomeFragment {
+public class DynamicPanel extends HomeFragment
+                          implements GeckoEventListener {
     private static final String LOGTAG = "GeckoDynamicPanel";
 
     // Dataset ID to be used by the loader
     private static final String DATASET_REQUEST = "dataset_request";
 
     // The panel layout associated with this panel
     private PanelLayout mLayout;
 
@@ -111,22 +118,25 @@ public class DynamicPanel extends HomeFr
         Log.d(LOGTAG, "Created layout of type: " + mPanelConfig.getLayoutType());
 
         return mLayout;
     }
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
+        GeckoAppShell.registerEventListener("HomePanels:RefreshDataset", this);
     }
 
     @Override
     public void onDestroyView() {
         super.onDestroyView();
         mLayout = null;
+
+        GeckoAppShell.unregisterEventListener("HomePanels:RefreshDataset", this);
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
         // Detach and reattach the fragment as the layout changes.
         if (isVisible()) {
@@ -147,41 +157,95 @@ public class DynamicPanel extends HomeFr
     }
 
     @Override
     protected void load() {
         Log.d(LOGTAG, "Loading layout");
         mLayout.load();
     }
 
+    @Override
+    public void handleMessage(String event, final JSONObject message) {
+        if (event.equals("HomePanels:RefreshDataset")) {
+            ThreadUtils.postToUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    handleDatasetRefreshRequest(message);
+                }
+            });
+        }
+    }
+
     private static int generateLoaderId(String datasetId) {
         return datasetId.hashCode();
     }
 
     /**
+     * Handles a dataset refresh request from Gecko. This is usually
+     * triggered by a HomeStorage.save() call in an add-on.
+     */
+    private void handleDatasetRefreshRequest(JSONObject message) {
+        final String datasetId;
+        try {
+            datasetId = message.getString("datasetId");
+        } catch (JSONException e) {
+            Log.e(LOGTAG, "Failed to handle dataset refresh", e);
+            return;
+        }
+
+        Log.d(LOGTAG, "Refresh request for dataset: " + datasetId);
+
+        final int loaderId = generateLoaderId(datasetId);
+
+        final LoaderManager lm = getLoaderManager();
+        final Loader<?> loader = (Loader<?>) lm.getLoader(loaderId);
+
+        // Only restart a loader if there's already an active one
+        // for the given dataset ID. Do nothing otherwise.
+        if (loader != null) {
+            final PanelDatasetLoader datasetLoader = (PanelDatasetLoader) loader;
+            final DatasetRequest request = datasetLoader.getRequest();
+
+            // Ensure the refresh request doesn't affect the view's filter
+            // stack (i.e. use DATASET_LOAD type) but keep the current
+            // dataset ID and filter.
+            final DatasetRequest newRequest =
+                   new DatasetRequest(DatasetRequest.Type.DATASET_LOAD,
+                                      request.getDatasetId(),
+                                      request.getFilterDetail());
+
+            restartDatasetLoader(newRequest);
+        }
+    }
+
+    private void restartDatasetLoader(DatasetRequest request) {
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(DATASET_REQUEST, request);
+
+        // Ensure one loader per dataset
+        final int loaderId = generateLoaderId(request.getDatasetId());
+        getLoaderManager().restartLoader(loaderId, bundle, mLoaderCallbacks);
+    }
+
+    /**
      * Used by the PanelLayout to make load and reset requests to
      * the holding fragment.
      */
     private class PanelDatasetHandler implements DatasetHandler {
         @Override
         public void requestDataset(DatasetRequest request) {
             Log.d(LOGTAG, "Requesting request: " + request);
 
             // Ignore dataset requests while the fragment is not
             // allowed to load its content.
             if (!getCanLoadHint()) {
                 return;
             }
 
-            final Bundle bundle = new Bundle();
-            bundle.putParcelable(DATASET_REQUEST, request);
-
-            // Ensure one loader per dataset
-            final int loaderId = generateLoaderId(request.getDatasetId());
-            getLoaderManager().restartLoader(loaderId, bundle, mLoaderCallbacks);
+            restartDatasetLoader(request);
         }
 
         @Override
         public void resetDataset(String datasetId) {
             Log.d(LOGTAG, "Resetting dataset: " + datasetId);
 
             final LoaderManager lm = getLoaderManager();
             final int loaderId = generateLoaderId(datasetId);
--- a/mobile/android/modules/HomeProvider.jsm
+++ b/mobile/android/modules/HomeProvider.jsm
@@ -4,16 +4,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = [ "HomeProvider" ];
 
 const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
 
+Cu.import("resource://gre/modules/Messaging.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Sqlite.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 /*
@@ -310,16 +311,21 @@ HomeStorage.prototype = {
               created: Date.now()
             };
             yield db.executeCached(SQL.insertItem, params);
           }
         }.bind(this));
       } finally {
         yield db.close();
       }
+
+      sendMessageToJava({
+        type: "HomePanels:RefreshDataset",
+        datasetId: this.datasetId,
+      });
     }.bind(this));
   },
 
   /**
    * Deletes all rows associated with this storage.
    *
    * @return Promise
    * @resolves When the operation has completed.
@@ -328,11 +334,16 @@ HomeStorage.prototype = {
     return Task.spawn(function delete_all_task() {
       let db = yield getDatabaseConnection();
       try {
         let params = { dataset_id: this.datasetId };
         yield db.executeCached(SQL.deleteFromDataset, params);
       } finally {
         yield db.close();
       }
+
+      sendMessageToJava({
+        type: "HomePanels:RefreshDataset",
+        datasetId: this.datasetId,
+      });
     }.bind(this));
   }
 };