From 29e297f18e007db47050ec5dcd6d571ee3731ab9 Mon Sep 17 00:00:00 2001 From: Brian Nicholson Date: Tue, 2 Oct 2012 10:51:48 -0700 Subject: [PATCH] Bug 769145 - Part 4: Add search suggestions opt-in prompt. r=mfinkle --- mobile/android/app/mobile.js | 1 + mobile/android/base/Makefile.in | 2 + .../android/base/awesomebar/AllPagesTab.java | 80 ++++++++++++++++--- .../base/locales/en-US/android_strings.dtd | 8 +- .../layout/awesomebar_allpages_list.xml | 14 ++++ .../layout/awesomebar_suggestion_prompt.xml | 48 +++++++++++ mobile/android/base/strings.xml.in | 6 +- mobile/android/chrome/content/browser.js | 16 +++- 8 files changed, 157 insertions(+), 18 deletions(-) create mode 100644 mobile/android/base/resources/layout/awesomebar_allpages_list.xml create mode 100644 mobile/android/base/resources/layout/awesomebar_suggestion_prompt.xml diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 508e777df32f..39bf6bcbf1be 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -250,6 +250,7 @@ pref("browser.search.updateinterval", 6); // disable search suggestions by default pref("browser.search.suggest.enabled", false); +pref("browser.search.suggest.prompted", false); // Tell the search service to load search plugins from the locale JAR pref("browser.search.loadFromJars", true); diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 0cb1ffbb9583..2ff2ff4bef77 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -322,9 +322,11 @@ RES_LAYOUT = \ res/layout/awesomebar_expandable_list.xml \ res/layout/awesomebar_folder_row.xml \ res/layout/awesomebar_header_row.xml \ + res/layout/awesomebar_allpages_list.xml \ res/layout/awesomebar_list.xml \ res/layout/awesomebar_row.xml \ res/layout/awesomebar_suggestion_item.xml \ + res/layout/awesomebar_suggestion_prompt.xml \ res/layout/awesomebar_suggestion_row.xml \ res/layout/awesomebar_search.xml \ res/layout/awesomebar_tab_indicator.xml \ diff --git a/mobile/android/base/awesomebar/AllPagesTab.java b/mobile/android/base/awesomebar/AllPagesTab.java index f2a09a448c4e..034d46333bfb 100644 --- a/mobile/android/base/awesomebar/AllPagesTab.java +++ b/mobile/android/base/awesomebar/AllPagesTab.java @@ -58,6 +58,8 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { private AsyncTask> mSuggestTask; private AwesomeBarCursorAdapter mCursorAdapter = null; private boolean mTelemetrySent = false; + private LinearLayout mAllPagesView; + private View mSuggestionsOptInPrompt; private class SearchEntryViewHolder { public FlowLayout suggestionView; @@ -81,13 +83,12 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { public TabContentFactory getFactory() { return new TabContentFactory() { public View createTabContent(String tag) { - final ListView list = getListView(); - list.setOnItemClickListener(new AdapterView.OnItemClickListener() { + getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { handleItemClick(parent, view, position, id); } }); - return list; + return getAllPagesView(); } }; } @@ -100,9 +101,16 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { return TAG; } + private LinearLayout getAllPagesView() { + if (mAllPagesView == null) { + mAllPagesView = (LinearLayout) (LayoutInflater.from(mContext).inflate(R.layout.awesomebar_allpages_list, null)); + } + return mAllPagesView; + } + public ListView getListView() { if (mView == null) { - mView = (ListView) (LayoutInflater.from(mContext).inflate(R.layout.awesomebar_list, null)); + mView = getAllPagesView().findViewById(R.id.awesomebar_list); ((Activity)mContext).registerForContextMenu(mView); mView.setTag(TAG); AwesomeBarCursorAdapter adapter = getCursorAdapter(); @@ -129,6 +137,12 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { adapter.filter(searchTerm); filterSuggestions(searchTerm); + if (mSuggestionsOptInPrompt != null) { + int visibility = searchTerm.isEmpty() ? View.GONE : View.VISIBLE; + if (mSuggestionsOptInPrompt.getVisibility() != visibility) { + mSuggestionsOptInPrompt.setVisibility(visibility); + } + } } private void filterSuggestions(String searchTerm) { @@ -408,8 +422,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { // add additional suggestions given by this engine int recycledSuggestionCount = suggestionView.getChildCount(); int suggestionCount = engine.suggestions.size(); - int i = 0; - for (i = 0; i < suggestionCount; i++) { + for (int i = 0; i < suggestionCount; i++) { String suggestion = engine.suggestions.get(i); View suggestionItem = null; @@ -429,7 +442,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { } // hide extra suggestions that have been recycled - for (++i; i < recycledSuggestionCount; i++) { + for (int i = suggestionCount + 1; i < recycledSuggestionCount; i++) { suggestionView.getChildAt(i).setVisibility(View.GONE); } } @@ -455,7 +468,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { * Sets suggestions associated with the current suggest engine. * If there is no suggest engine, this does nothing. */ - public void setSuggestions(final ArrayList suggestions) { + private void setSuggestions(final ArrayList suggestions) { if (mSuggestClient != null) { mSearchEngines.get(0).suggestions = suggestions; getCursorAdapter().notifyDataSetChanged(); @@ -465,12 +478,14 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { /** * Sets search engines to be shown for user-entered queries. */ - public void setSearchEngines(JSONObject data) { + private void setSearchEngines(JSONObject data) { try { - String suggestEngine = data.isNull("suggestEngine") ? null : data.getString("suggestEngine"); - String suggestTemplate = data.isNull("suggestTemplate") ? null : data.getString("suggestTemplate"); + JSONObject suggest = data.getJSONObject("suggest"); + String suggestEngine = suggest.isNull("engine") ? null : suggest.getString("engine"); + String suggestTemplate = suggest.isNull("template") ? null : suggest.getString("template"); + mSuggestionsEnabled = suggest.getBoolean("enabled"); + boolean suggestionsPrompted = suggest.getBoolean("prompted"); JSONArray engines = data.getJSONArray("searchEngines"); - mSuggestionsEnabled = data.getBoolean("suggestEnabled"); mSearchEngines = new ArrayList(); for (int i = 0; i < engines.length(); i++) { @@ -486,6 +501,11 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { mSearchEngines.add(new SearchEngine(name, icon)); } } + + // show suggestions opt-in if user hasn't been prompted + if (!suggestionsPrompted && mSuggestClient != null) { + showSuggestionsOptIn(); + } } catch (JSONException e) { Log.e(LOGTAG, "Error getting search engine JSON", e); } @@ -507,6 +527,42 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener { return drawable; } + private void showSuggestionsOptIn() { + mSuggestionsOptInPrompt = LayoutInflater.from(mContext).inflate(R.layout.awesomebar_suggestion_prompt, getAllPagesView(), false); + ((TextView) mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_title)) + .setText(getResources().getString(R.string.suggestions_prompt, mSearchEngines.get(0).name)); + mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_yes).setOnClickListener(new OnClickListener() { + public void onClick(View v) { + setSuggestionsEnabled(true); + } + }); + mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_no).setOnClickListener(new OnClickListener() { + public void onClick(View v) { + setSuggestionsEnabled(false); + } + }); + mSuggestionsOptInPrompt.setVisibility(View.GONE); + getAllPagesView().addView(mSuggestionsOptInPrompt, 0); + } + + private void setSuggestionsEnabled(final boolean enabled) { + // Pref observer in gecko will also set prompted = true + PrefsHelper.setPref("browser.search.suggest.enabled", enabled); + + getAllPagesView().post(new Runnable() { + public void run() { + getAllPagesView().removeView(mSuggestionsOptInPrompt); + mSuggestionsOptInPrompt = null; + + if (enabled) { + mSuggestionsEnabled = enabled; + getCursorAdapter().notifyDataSetChanged(); + filterSuggestions(mSearchTerm); + } + } + }); + } + public void handleMessage(String event, final JSONObject message) { if (event.equals("SearchEngines:Data")) { GeckoAppShell.getMainHandler().post(new Runnable() { diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index bda35167cab6..91b9934781c9 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -12,7 +12,6 @@ - @@ -171,6 +170,8 @@ size. --> + + @@ -227,6 +228,11 @@ just addresses the organization to follow, e.g. "This site is run by " --> from Android"> + + + diff --git a/mobile/android/base/resources/layout/awesomebar_allpages_list.xml b/mobile/android/base/resources/layout/awesomebar_allpages_list.xml new file mode 100644 index 000000000000..c5c924893344 --- /dev/null +++ b/mobile/android/base/resources/layout/awesomebar_allpages_list.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/mobile/android/base/resources/layout/awesomebar_suggestion_prompt.xml b/mobile/android/base/resources/layout/awesomebar_suggestion_prompt.xml new file mode 100644 index 000000000000..29a7f305c06f --- /dev/null +++ b/mobile/android/base/resources/layout/awesomebar_suggestion_prompt.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in index 3d0fd977f5bc..b38e01416ac1 100644 --- a/mobile/android/base/strings.xml.in +++ b/mobile/android/base/strings.xml.in @@ -20,7 +20,6 @@ &awesomebar_all_pages_title; &awesomebar_bookmarks_title; &awesomebar_history_title; - &awesomebar_search_engine; &crash_reporter_title; &crash_message; @@ -167,6 +166,8 @@ &button_clear_data; &button_set; &button_clear; + &button_yes; + &button_no; &abouthome_addons_title; &abouthome_addons_browse; @@ -231,4 +232,7 @@ &updater_apply_ticker; &updater_apply_select; + + &suggestions_prompt; + diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index a9f5e56946ea..fae377654eed 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -922,6 +922,9 @@ var BrowserApp = { else MasterPassword.setPassword(json.value); return; + } else if (json.name == SearchEngines.PREF_SUGGEST_ENABLED) { + // Enabling or disabling suggestions will prevent future prompts + Services.prefs.setBoolPref(SearchEngines.PREF_SUGGEST_PROMPTED, true); } // when sending to java, we normalized special preferences that use @@ -6102,6 +6105,8 @@ 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:Get", false); @@ -6115,7 +6120,7 @@ var SearchEngines = { }, uninit: function uninit() { - Services.obs.removeObserver(this, "SearchEngines:Get", false); + Services.obs.removeObserver(this, "SearchEngines:Get"); if (this._contextMenuId != null) NativeWindow.contextmenus.remove(this._contextMenuId); }, @@ -6145,9 +6150,12 @@ var SearchEngines = { gecko: { type: "SearchEngines:Data", searchEngines: searchEngines, - suggestEngine: suggestEngine, - suggestTemplate: suggestTemplate, - suggestEnabled: Services.prefs.getBoolPref("browser.search.suggest.enabled") + suggest: { + engine: suggestEngine, + template: suggestTemplate, + enabled: Services.prefs.getBoolPref(this.PREF_SUGGEST_ENABLED), + prompted: Services.prefs.getBoolPref(this.PREF_SUGGEST_PROMPTED) + } } }); },