diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in
index d575b02da9bd..94b2f7db233e 100644
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -234,6 +234,7 @@ FENNEC_JAVA_FILES = \
menu/MenuItemDefault.java \
menu/MenuPanel.java \
menu/MenuPopup.java \
+ preferences/SearchPreferenceCategory.java \
widget/AboutHome.java \
widget/AboutHomeView.java \
widget/AboutHomeSection.java \
@@ -310,6 +311,7 @@ FENNEC_PP_JAVA_FILES = \
FENNEC_PP_XML_FILES = \
res/xml/preferences.xml \
+ res/xml/preferences_customize.xml \
res/xml/searchable.xml \
$(NULL)
@@ -573,14 +575,15 @@ RES_VALUES_V14 = \
$(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 \
diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd
index de7b3db80474..aeadc707ebf2 100644
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -68,10 +68,12 @@
+
+
diff --git a/mobile/android/base/preferences/SearchPreferenceCategory.java b/mobile/android/base/preferences/SearchPreferenceCategory.java
new file mode 100644
index 000000000000..313787485912
--- /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);
+ }
+ }
+ }
+ }
+}
diff --git a/mobile/android/base/resources/values/dimens.xml b/mobile/android/base/resources/values/dimens.xml
index 592d6278a904..8d9670aa1b40 100644
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -61,6 +61,7 @@
48dp
64dp
26dp
+ 32dp
90dp
160dp
22sp
diff --git a/mobile/android/base/resources/xml/preferences_customize.xml b/mobile/android/base/resources/xml-v11/preferences_customize.xml
similarity index 85%
rename from mobile/android/base/resources/xml/preferences_customize.xml
rename to mobile/android/base/resources/xml-v11/preferences_customize.xml
index a1494da03d12..3898b575ba7e 100644
--- a/mobile/android/base/resources/xml/preferences_customize.xml
+++ b/mobile/android/base/resources/xml-v11/preferences_customize.xml
@@ -7,6 +7,12 @@
xmlns:gecko="http://schemas.android.com/apk/res-auto"
android:enabled="false">
+
+
+
+
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/android/base/resources/xml/preferences_search.xml b/mobile/android/base/resources/xml/preferences_search.xml
new file mode 100644
index 000000000000..721aefbfda00
--- /dev/null
+++ b/mobile/android/base/resources/xml/preferences_search.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in
index efa1ec131cfb..428dc4e223ec 100644
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -80,10 +80,12 @@
&settings;
&settings_title;
&pref_category_customize;
+ &pref_category_search;
&pref_category_display;
&pref_category_privacy_short;
&pref_category_vendor;
&pref_category_datareporting;
+ &pref_category_installed_search_engines;
&pref_header_customize;
&pref_header_display;
diff --git a/mobile/android/base/tests/testSettingsMenuItems.java.in b/mobile/android/base/tests/testSettingsMenuItems.java.in
index fc0165a791f7..b0e25d05ef94 100644
--- a/mobile/android/base/tests/testSettingsMenuItems.java.in
+++ b/mobile/android/base/tests/testSettingsMenuItems.java.in
@@ -24,8 +24,9 @@ public class testSettingsMenuItems extends PixelTest {
//
// 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" },
};
@@ -163,8 +164,12 @@ public class testSettingsMenuItems extends PixelTest {
"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.