Bug 910189: Part 3 - Restore default search engines (no dialog). r=margaret
authorChenxia Liu <liuche@mozilla.com>
Fri, 20 Dec 2013 10:35:48 -0800
changeset 161573 7d81c48b9dfac59b2564031ba5743c060a9fc1f4
parent 161572 4dd56dde7f8b69383516cb483d1986eaf9f674ce
child 161574 ffc142af3ca99dcc98b2a6c15e053cb52dd07280
push id25886
push userkwierso@gmail.com
push dateSat, 21 Dec 2013 02:28:37 +0000
treeherdermozilla-central@4a1cc256b563 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret
bugs910189
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 910189: Part 3 - Restore default search engines (no dialog). r=margaret
CLOBBER
mobile/android/base/preferences/GeckoPreferenceFragment.java
mobile/android/base/preferences/GeckoPreferences.java
mobile/android/base/preferences/SearchPreferenceCategory.java
mobile/android/chrome/content/browser.js
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 878935 landed without a UUID change (and was since backed out)
+Bug 910189 requires a clobber due to Proguard inner class errors from bug 946083.
--- a/mobile/android/base/preferences/GeckoPreferenceFragment.java
+++ b/mobile/android/base/preferences/GeckoPreferenceFragment.java
@@ -15,16 +15,17 @@ import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.ViewConfiguration;
 
 /* A simple implementation of PreferenceFragment for large screen devices
  * This will strip category headers (so that they aren't shown to the user twice)
  * as well as initializing Gecko prefs when a fragment is shown.
 */
 public class GeckoPreferenceFragment extends PreferenceFragment {
 
--- a/mobile/android/base/preferences/GeckoPreferences.java
+++ b/mobile/android/base/preferences/GeckoPreferences.java
@@ -72,17 +72,19 @@ public class GeckoPreferences
     private static final String NON_PREF_PREFIX = "android.not_a_preference.";
     public static final String INTENT_EXTRA_RESOURCES = "resource";
     public static String PREFS_HEALTHREPORT_UPLOAD_ENABLED = NON_PREF_PREFIX + "healthreport.uploadEnabled";
 
     private static boolean sIsCharEncodingEnabled = false;
     private boolean mInitialized = false;
     private int mPrefsRequestId = 0;
 
-    // These match keys in resources/xml/preferences.xml.in.
+    // These match keys in resources/xml*/preferences*.xml
+    private static String PREFS_SEARCH_RESTORE_DEFAULTS = NON_PREF_PREFIX + "search.restore_defaults";
+
     private static String PREFS_ANNOUNCEMENTS_ENABLED = NON_PREF_PREFIX + "privacy.announcements.enabled";
     private static String PREFS_DATA_REPORTING_PREFERENCES = NON_PREF_PREFIX + "datareporting.preferences";
     private static String PREFS_TELEMETRY_ENABLED = "datareporting.telemetry.enabled";
     private static String PREFS_CRASHREPORTER_ENABLED = "datareporting.crashreporter.submitEnabled";
     private static String PREFS_MENU_CHAR_ENCODING = "browser.menu.showCharacterEncoding";
     private static String PREFS_MP_ENABLED = "privacy.masterpassword.enabled";
     private static String PREFS_UPDATER_AUTODOWNLOAD = "app.update.autodownload";
     private static String PREFS_GEO_REPORTING = "app.geo.reportdata";
@@ -384,39 +386,64 @@ public class GeckoPreferences
                     CharSequence selectedEntry = listPref.getEntry();
                     listPref.setSummary(selectedEntry);
                     continue;
                 } else if (PREFS_SYNC.equals(key) && GeckoProfile.get(this).inGuestMode()) {
                     // Don't show sync prefs while in guest mode.
                     preferences.removePreference(pref);
                     i--;
                     continue;
+                } else if (PREFS_SEARCH_RESTORE_DEFAULTS.equals(key)) {
+                    pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+                        @Override
+                        public boolean onPreferenceClick(Preference preference) {
+                            GeckoPreferences.this.restoreDefaultSearchEngines();
+                            return true;
+                        }
+                    });
                 }
 
                 // Some Preference UI elements are not actually preferences,
                 // but they require a key to work correctly. For example,
                 // "Clear private data" requires a key for its state to be
                 // saved when the orientation changes. It uses the
                 // "android.not_a_preference.privacy.clear" key - which doesn't
                 // exist in Gecko - to satisfy this requirement.
                 if (key != null && !key.startsWith(NON_PREF_PREFIX)) {
                     prefs.add(key);
                 }
             }
         }
     }
 
+    /**
+     * Restore default search engines in Gecko and retrigger a search engine refresh.
+     */
+    protected void restoreDefaultSearchEngines() {
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:RestoreDefaults", null));
+
+        // Send message to Gecko to get engines. SearchPreferenceCategory listens for the response.
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
+        int itemId = item.getItemId();
+        switch (itemId) {
             case android.R.id.home:
                 finish();
                 return true;
         }
 
+        // Generated R.id.* apparently aren't constant expressions, so they can't be switched.
+        if (itemId == R.id.restore_defaults) {
+            restoreDefaultSearchEngines();
+            return true;
+       }
+
         return super.onOptionsItemSelected(item);
     }
 
     final private int DIALOG_CREATE_MASTER_PASSWORD = 0;
     final private int DIALOG_REMOVE_MASTER_PASSWORD = 1;
 
     public static void setCharEncodingState(boolean enabled) {
         sIsCharEncodingEnabled = enabled;
--- a/mobile/android/base/preferences/SearchPreferenceCategory.java
+++ b/mobile/android/base/preferences/SearchPreferenceCategory.java
@@ -38,37 +38,41 @@ public class SearchPreferenceCategory ex
 
     @Override
     protected void onAttachedToActivity() {
         super.onAttachedToActivity();
 
         // Ensures default engine remains at top of list.
         setOrderingAsAdded(true);
 
-        // Request list of search engines from Gecko.
+        // Register for SearchEngines messages and request list of search engines from Gecko.
         GeckoAppShell.registerEventListener("SearchEngines:Data", this);
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
     }
 
     @Override
+    protected void onPrepareForRemoval() {
+        GeckoAppShell.unregisterEventListener("SearchEngines:Data", this);
+    }
+
+    @Override
     public void handleMessage(String event, final JSONObject data) {
         if (event.equals("SearchEngines:Data")) {
-            // We are no longer interested in this event from Gecko, as we do not request it again with
-            // this instance.
-            GeckoAppShell.unregisterEventListener("SearchEngines:Data", this);
-
             // Parse engines array from JSON.
             JSONArray engines;
             try {
                 engines = data.getJSONArray("searchEngines");
             } catch (JSONException e) {
                 Log.e(LOGTAG, "Unable to decode search engine data from Gecko.", e);
                 return;
             }
 
+            // Clear the preferences category from this thread.
+            this.removeAll();
+
             // Create an element in this PreferenceCategory for each engine.
             for (int i = 0; i < engines.length(); i++) {
                 try {
                     JSONObject engineJSON = engines.getJSONObject(i);
                     final String engineName = engineJSON.getString("name");
 
                     SearchEnginePreference enginePreference = new SearchEnginePreference(getContext(), this);
                     enginePreference.setSearchEngineFromJSON(engineJSON);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6662,18 +6662,19 @@ OverscrollController.prototype = {
 var SearchEngines = {
   _contextMenuId: null,
   PREF_SUGGEST_ENABLED: "browser.search.suggest.enabled",
   PREF_SUGGEST_PROMPTED: "browser.search.suggest.prompted",
 
   init: function init() {
     Services.obs.addObserver(this, "SearchEngines:Add", false);
     Services.obs.addObserver(this, "SearchEngines:GetVisible", false);
+    Services.obs.addObserver(this, "SearchEngines:Remove", false);
+    Services.obs.addObserver(this, "SearchEngines:RestoreDefaults", false);
     Services.obs.addObserver(this, "SearchEngines:SetDefault", false);
-    Services.obs.addObserver(this, "SearchEngines:Remove", false);
 
     let filter = {
       matches: function (aElement) {
         // Copied from body of isTargetAKeywordField function in nsContextMenu.js
         if(!(aElement instanceof HTMLInputElement))
           return false;
         let form = aElement.form;
         if (!form || aElement.type == "password")
@@ -6704,18 +6705,19 @@ var SearchEngines = {
         SearchEngines.addEngine(aElement);
       }
     });
   },
 
   uninit: function uninit() {
     Services.obs.removeObserver(this, "SearchEngines:Add");
     Services.obs.removeObserver(this, "SearchEngines:GetVisible");
+    Services.obs.removeObserver(this, "SearchEngines:Remove");
+    Services.obs.removeObserver(this, "SearchEngines:RestoreDefaults");
     Services.obs.removeObserver(this, "SearchEngines:SetDefault");
-    Services.obs.removeObserver(this, "SearchEngines:Remove");
     if (this._contextMenuId != null)
       NativeWindow.contextmenus.remove(this._contextMenuId);
   },
 
   // Fetch list of search engines. all ? All engines : Visible engines only.
   _handleSearchEnginesGetVisible: function _handleSearchEnginesGetVisible(rv, all) {
     if (!Components.isSuccessCode(rv)) {
       Cu.reportError("Could not initialize search service, bailing out.");
@@ -6775,29 +6777,34 @@ var SearchEngines = {
     let engine;
     switch(aTopic) {
       case "SearchEngines:Add":
         this.displaySearchEnginesList(aData);
         break;
       case "SearchEngines:GetVisible":
         Services.search.init(this._handleSearchEnginesGetVisible.bind(this));
         break;
-      case "SearchEngines:SetDefault":
-        engine = this._extractEngineFromJSON(aData);
-        // Move the new default search engine to the top of the search engine list.
-        Services.search.moveEngine(engine, 0);
-        Services.search.defaultEngine = engine;
-        break;
       case "SearchEngines:Remove":
         // Make sure the engine isn't hidden before removing it, to make sure it's
         // visible if the user later re-adds it (works around bug 341833)
         engine = this._extractEngineFromJSON(aData);
         engine.hidden = false;
         Services.search.removeEngine(engine);
         break;
+      case "SearchEngines:RestoreDefaults":
+        // Un-hides all default engines.
+        Services.search.restoreDefaultEngines();
+        break;
+      case "SearchEngines:SetDefault":
+        engine = this._extractEngineFromJSON(aData);
+        // Move the new default search engine to the top of the search engine list.
+        Services.search.moveEngine(engine, 0);
+        Services.search.defaultEngine = engine;
+        break;
+
       default:
         dump("Unexpected message type observed: " + aTopic);
         break;
     }
   },
 
   // Display context menu listing names of the search engines available to be added.
   displaySearchEnginesList: function displaySearchEnginesList(aData) {