Bug 892094 - Create "Search" page in settings. r=liuche
authorChris Kitching <ckitching@mozilla.com>
Tue, 16 Jul 2013 18:44:42 -0700
changeset 146374 f1028e173331ac1bf96929a1ea540925c1c58d82
parent 146373 75ae4e009a0c1050e321ef7c3f7fa77ab6fe9754
child 146375 a9ff16ddd0e5fa4a9f6a7bf5085a1f61212f6c06
push idunknown
push userunknown
push dateunknown
reviewersliuche
bugs892094
milestone25.0a1
Bug 892094 - Create "Search" page in settings. r=liuche
mobile/android/base/Makefile.in
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/preferences/SearchPreferenceCategory.java
mobile/android/base/resources/values/dimens.xml
mobile/android/base/resources/xml-v11/preferences_customize.xml
mobile/android/base/resources/xml-v11/preferences_customize_tablet.xml
mobile/android/base/resources/xml/preferences_customize.xml
mobile/android/base/resources/xml/preferences_customize.xml.in
mobile/android/base/resources/xml/preferences_search.xml
mobile/android/base/strings.xml.in
mobile/android/base/tests/testSettingsMenuItems.java.in
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -229,16 +229,17 @@ FENNEC_JAVA_FILES = \
   menu/GeckoMenuInflater.java \
   menu/GeckoMenuItem.java \
   menu/GeckoSubMenu.java \
   menu/MenuItemActionBar.java \
   menu/MenuItemActionView.java \
   menu/MenuItemDefault.java \
   menu/MenuPanel.java \
   menu/MenuPopup.java \
+  preferences/SearchPreferenceCategory.java \
   widget/AboutHome.java \
   widget/AboutHomeView.java \
   widget/AboutHomeSection.java \
   widget/ActivityChooserModel.java \
   widget/AddonsSection.java \
   widget/ButtonToast.java \
   widget/ArrowPopup.java \
   widget/DateTimePicker.java \
@@ -305,16 +306,17 @@ FENNEC_PP_JAVA_FILES = \
   AppConstants.java \
   SysInfo.java \
   WebApp.java \
   WebApps.java \
   $(NULL)
 
 FENNEC_PP_XML_FILES = \
   res/xml/preferences.xml \
+  res/xml/preferences_customize.xml \
   res/xml/searchable.xml \
   $(NULL)
 
 ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
 MIN_CPU_VERSION=7
 else
 MIN_CPU_VERSION=5
 endif
@@ -568,24 +570,25 @@ RES_VALUES_XLARGE_V11 = \
   res/values-xlarge-v11/styles.xml \
   $(NULL)
 
 RES_VALUES_V14 = \
   res/values-v14/styles.xml \
   $(NULL)
 
 RES_XML = \
-  res/xml/preferences_customize.xml \
   res/xml/preferences_display.xml \
+  res/xml/preferences_search.xml \
   res/xml/preferences_privacy.xml \
   res/xml/preferences_vendor.xml \
   $(SYNC_RES_XML) \
   $(NULL)
 
 RES_XML_V11 = \
+  res/xml-v11/preferences_customize.xml \
   res/xml-v11/preference_headers.xml \
   res/xml-v11/preferences_customize_tablet.xml \
   res/xml-v11/preferences.xml \
   $(NULL)
 
 RES_ANIM = \
   res/anim/awesomebar_fade_in.xml \
   res/anim/popup_show.xml \
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -63,20 +63,22 @@
 <!-- Localization note (num_tabs2) : Number of tabs is always more than one.
      We can't use android plural forms, sadly. See bug #753859. -->
 <!ENTITY num_tabs2 "&formatD; tabs">
 <!ENTITY new_tab_opened "New tab opened">
 
 <!ENTITY settings "Settings">
 <!ENTITY settings_title "Settings">
 <!ENTITY pref_category_customize "Customize">
+<!ENTITY pref_category_search "Search">
 <!ENTITY pref_category_display "Display">
 <!ENTITY pref_category_privacy_short "Privacy">
 <!ENTITY pref_category_vendor "&vendorShortName;">
 <!ENTITY pref_category_datareporting "Data choices">
+<!ENTITY pref_category_installed_search_engines "Installed search engines">
 
 <!-- collected old strings - remove after determining final strings
      as part of Bug 877791 -->
 <!ENTITY pref_category_general "General">
 <!ENTITY pref_category_privacy "Privacy &amp; Security">
 <!ENTITY pref_category_content "Content">
 <!-- Localization note (datareporting_title) : This string matches
      (dataChoicesTab.label) in chrome/browser/preferences/advanced.dtd except in
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/preferences/SearchPreferenceCategory.java
@@ -0,0 +1,89 @@
+package org.mozilla.gecko.preferences;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Build;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.util.AttributeSet;
+import android.util.Log;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoEvent;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.util.GeckoEventListener;
+
+public class SearchPreferenceCategory extends PreferenceCategory implements GeckoEventListener {
+    public static final String LOGTAG = "SearchPrefCategory";
+
+    private static int sIconSize;
+
+    public SearchPreferenceCategory(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+    public SearchPreferenceCategory(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public SearchPreferenceCategory(Context context) {
+        super(context);
+        init();
+    }
+
+    private void init() {
+        sIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.searchpreferences_icon_size);
+    }
+
+    @Override
+    protected void onAttachedToActivity() {
+        super.onAttachedToActivity();
+
+        // Request list of search engines from Gecko
+        GeckoAppShell.registerEventListener("SearchEngines:Data", this);
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null));
+    }
+
+    @Override
+    public void handleMessage(String event, final JSONObject data) {
+        if (event.equals("SearchEngines:Data")) {
+            JSONArray engines;
+            try {
+                engines = data.getJSONArray("searchEngines");
+            } catch (JSONException e) {
+                Log.e(LOGTAG, "Unable to decode search engine data from Gecko.", e);
+                return;
+            }
+
+            // 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");
+
+                    Preference engine = new Preference(getContext());
+                    engine.setTitle(engineName);
+                    engine.setKey(engineName);
+
+                    // The setIcon feature is not available prior to API 11.
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+                        String iconURI = engineJSON.getString("iconURI");
+                        Bitmap iconBitmap = BitmapUtils.getBitmapFromDataURI(iconURI);
+                        Bitmap scaledIconBitmap = Bitmap.createScaledBitmap(iconBitmap, sIconSize, sIconSize, false);
+                        BitmapDrawable drawable = new BitmapDrawable(scaledIconBitmap);
+                        engine.setIcon(drawable);
+                    }
+                    addPreference(engine);
+                    // TODO: Bug 892113 - Add event listener here for tapping on each element. Produce a dialog to provide options.
+                } catch (JSONException e) {
+                    Log.e(LOGTAG, "JSONException parsing engine at index " + i, e);
+                }
+            }
+        }
+    }
+}
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -56,16 +56,17 @@
     <dimen name="prompt_service_icon_size">72dp</dimen>
     <dimen name="prompt_service_icon_text_padding">10dp</dimen>
     <dimen name="prompt_service_inputs_padding">16dp</dimen>
     <dimen name="prompt_service_left_right_text_with_icon_padding">10dp</dimen>
     <dimen name="prompt_service_top_bottom_text_with_icon_padding">8dp</dimen>
     <dimen name="prompt_service_min_list_item_height">48dp</dimen>
     <dimen name="remote_tab_child_row_height">64dp</dimen>
     <dimen name="remote_tab_group_row_height">26dp</dimen>
+    <dimen name="searchpreferences_icon_size">32dp</dimen>
     <dimen name="tab_thumbnail_height">90dp</dimen>
     <dimen name="tab_thumbnail_width">160dp</dimen>
     <dimen name="tabs_counter_size">22sp</dimen>
     <dimen name="tabs_panel_indicator_width">60dp</dimen>
     <dimen name="tabs_panel_list_padding">16dip</dimen>
     <dimen name="tabs_list_divider_height">2dp</dimen>
     <dimen name="tabs_sidebar_width">200dp</dimen>
     <dimen name="tabs_tray_horizontal_height">156dp</dimen>
rename from mobile/android/base/resources/xml/preferences_customize.xml
rename to mobile/android/base/resources/xml-v11/preferences_customize.xml
--- a/mobile/android/base/resources/xml/preferences_customize.xml
+++ b/mobile/android/base/resources/xml-v11/preferences_customize.xml
@@ -2,31 +2,32 @@
 <!-- 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/. -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                   xmlns:gecko="http://schemas.android.com/apk/res-auto"
                   android:enabled="false">
 
+     <PreferenceScreen android:title="@string/pref_category_search"
+                       android:fragment="org.mozilla.gecko.GeckoPreferenceFragment" >
+         <extra android:name="resource"
+                android:value="preferences_search"/>
+     </PreferenceScreen>
+
     <org.mozilla.gecko.AndroidImportPreference
                   android:key="android.not_a_preference.import_android"
                   gecko:entries="@array/pref_import_android_entries"
                   gecko:entryKeys="@array/pref_import_android_keys"
                   gecko:initialValues="@array/pref_import_android_values"
                   android:title="@string/pref_import_android"
                   android:positiveButtonText="@string/bookmarkhistory_button_import"
                   android:negativeButtonText="@string/button_cancel"
                   android:persistent="false" />
 
-    <CheckBoxPreference android:key="browser.search.suggest.enabled"
-                        android:title="@string/pref_search_suggestions"
-                        android:defaultValue="true"
-                        android:persistent="false" />
-
     <CheckBoxPreference android:key="android.not_a_preference.restoreSession"
                         android:title="@string/pref_restore_session"
                         android:defaultValue="false"
                         android:persistent="true" />
 
    <ListPreference android:key="app.update.autodownload"
                    android:title="@string/pref_update_autodownload"
                    android:entries="@array/pref_update_autodownload_entries"
--- a/mobile/android/base/resources/xml-v11/preferences_customize_tablet.xml
+++ b/mobile/android/base/resources/xml-v11/preferences_customize_tablet.xml
@@ -9,30 +9,36 @@
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                   xmlns:gecko="http://schemas.android.com/apk/res-auto"
                   android:title="@string/pref_category_customize"
                   android:enabled="false">
 
     <org.mozilla.gecko.SyncPreference android:title="@string/pref_sync"
                                       android:persistent="false" />
 
+    <PreferenceScreen android:title="@string/pref_category_search"
+                      android:fragment="org.mozilla.gecko.GeckoPreferenceFragment" >
+        <extra android:name="resource"
+               android:value="preferences_search"/>
+    </PreferenceScreen>
+
     <org.mozilla.gecko.AndroidImportPreference
             android:key="android.not_a_preference.import_android"
             gecko:entries="@array/pref_import_android_entries"
             gecko:entryKeys="@array/pref_import_android_keys"
             gecko:initialValues="@array/pref_import_android_values"
             android:title="@string/pref_import_android"
             android:positiveButtonText="@string/bookmarkhistory_button_import"
             android:negativeButtonText="@string/button_cancel"
             android:persistent="false" />
 
-    <CheckBoxPreference android:key="browser.search.suggest.enabled"
-                        android:title="@string/pref_search_suggestions"
-                        android:defaultValue="true"
-                        android:persistent="false" />
+    <CheckBoxPreference android:key="android.not_a_preference.restoreSession"
+                        android:title="@string/pref_restore_session"
+                        android:defaultValue="false"
+                        android:persistent="true" />
 
     <ListPreference android:key="app.update.autodownload"
                     android:title="@string/pref_update_autodownload"
                     android:entries="@array/pref_update_autodownload_entries"
                     android:entryValues="@array/pref_update_autodownload_values"
                     android:persistent="false" />
 
 </PreferenceScreen>
copy from mobile/android/base/resources/xml/preferences_customize.xml
copy to mobile/android/base/resources/xml/preferences_customize.xml.in
--- a/mobile/android/base/resources/xml/preferences_customize.xml
+++ b/mobile/android/base/resources/xml/preferences_customize.xml.in
@@ -1,32 +1,37 @@
+#filter substitution
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                   xmlns:gecko="http://schemas.android.com/apk/res-auto"
                   android:enabled="false">
+    <PreferenceScreen android:title="@string/pref_category_search" >
+        <intent android:action="android.intent.action.VIEW"
+                android:targetPackage="@ANDROID_PACKAGE_NAME@"
+                android:targetClass="org.mozilla.gecko.GeckoPreferences" >
+            <extra
+                android:name="resource"
+                android:value="preferences_search" />
+        </intent>
+    </PreferenceScreen>
 
     <org.mozilla.gecko.AndroidImportPreference
                   android:key="android.not_a_preference.import_android"
                   gecko:entries="@array/pref_import_android_entries"
                   gecko:entryKeys="@array/pref_import_android_keys"
                   gecko:initialValues="@array/pref_import_android_values"
                   android:title="@string/pref_import_android"
                   android:positiveButtonText="@string/bookmarkhistory_button_import"
                   android:negativeButtonText="@string/button_cancel"
                   android:persistent="false" />
 
-    <CheckBoxPreference android:key="browser.search.suggest.enabled"
-                        android:title="@string/pref_search_suggestions"
-                        android:defaultValue="true"
-                        android:persistent="false" />
-
     <CheckBoxPreference android:key="android.not_a_preference.restoreSession"
                         android:title="@string/pref_restore_session"
                         android:defaultValue="false"
                         android:persistent="true" />
 
    <ListPreference android:key="app.update.autodownload"
                    android:title="@string/pref_update_autodownload"
                    android:entries="@array/pref_update_autodownload_entries"
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/xml/preferences_search.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:gecko="http://schemas.android.com/apk/res-auto"
+                  android:title="@string/pref_category_search"
+                  android:enabled="false">
+
+    <CheckBoxPreference android:key="browser.search.suggest.enabled"
+                        android:title="@string/pref_search_suggestions"
+                        android:defaultValue="false"
+                        android:persistent="false" />
+
+    <org.mozilla.gecko.preferences.SearchPreferenceCategory
+                        android:title="@string/pref_category_installed_search_engines"/>
+</PreferenceScreen>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -75,20 +75,22 @@
   <string name="find_text">&find_text;</string>
   <string name="find_prev">&find_prev;</string>
   <string name="find_next">&find_next;</string>
   <string name="find_close">&find_close;</string>
 
   <string name="settings">&settings;</string>
   <string name="settings_title">&settings_title;</string>
   <string name="pref_category_customize">&pref_category_customize;</string>
+  <string name="pref_category_search">&pref_category_search;</string>
   <string name="pref_category_display">&pref_category_display;</string>
   <string name="pref_category_privacy_short">&pref_category_privacy_short;</string>
   <string name="pref_category_vendor">&pref_category_vendor;</string>
   <string name="pref_category_datareporting">&pref_category_datareporting;</string>
+  <string name="pref_category_installed_search_engines">&pref_category_installed_search_engines;</string>
 
   <string name="pref_header_customize">&pref_header_customize;</string>
   <string name="pref_header_display">&pref_header_display;</string>
   <string name="pref_header_privacy_short">&pref_header_privacy_short;</string>
   <string name="pref_header_vendor">&pref_header_vendor;</string>
 
   <string name="pref_remember_signons">&pref_remember_signons;</string>
 
--- a/mobile/android/base/tests/testSettingsMenuItems.java.in
+++ b/mobile/android/base/tests/testSettingsMenuItems.java.in
@@ -19,18 +19,19 @@ public class testSettingsMenuItems exten
     // Each String[] (array) represents the menu items/choices in the following order:
     //
     //     itemTitle { defaultValue [options] }
     //
     // where defaultValue is optional, and there can be multiple options.
     //
     // This test assumes menu items are in order (scrolling down for off-screen items).
     String[][] OPTIONS_CUSTOMIZE = {
+         { "Search", "", "Show search suggestions", "Installed search engines" },
          { "Import from Android", "", "Bookmarks", "History", "Import" },
-         { "Show search suggestions" },
+         { "Always restore tabs" },
          { "Automatic updates", "Only over Wi-Fi", "Enabled", "Only over Wi-Fi", "Disabled" },
      };
 
     String[][] OPTIONS_DISPLAY = {
         { "Text size" },
         { "Double tap to reflow text" },
         { "Title bar", "Show page title", "Show page title", "Show page address" },
         { "Character encoding", "Don't show menu", "Show menu", "Don't show menu" },
@@ -158,18 +159,22 @@ public class testSettingsMenuItems exten
                           // If we don't see the item, scroll down once in case it's off-screen.
                           scrollDown();
                       }
                       mAsserter.ok(mSolo.waitForText(itemChoice), "Waiting for settings item choice " + itemChoice
                                    + " in section " + section,
                                    "The " + itemChoice + " choice is present in section " + section);
                   }
                   // Leave submenu after checking.
-                  waitForText("^Cancel$");
-                  mSolo.clickOnText("^Cancel$");
+                  if (waitForText("^Cancel$")) {
+                      mSolo.clickOnText("^Cancel$");
+                  } else {
+                      // Some submenus aren't dialogs, but are nested screens; exit using "back".
+                      mActions.sendSpecialKey(Actions.SpecialKey.BACK);
+                  }
                 }
             }
             // Navigate back a screen if on a phone.
             if (mDevice.type.equals("phone")) {
                 // Click back to return to previous menu. Tablets shouldn't do this because they use headers and fragments.
                 mActions.sendSpecialKey(Actions.SpecialKey.BACK);
             }
         }