Bug 769145 - Part 4: Add search suggestions opt-in prompt. r=mfinkle

This commit is contained in:
Brian Nicholson 2012-10-02 10:51:48 -07:00
Родитель 84f54b9036
Коммит 29e297f18e
8 изменённых файлов: 157 добавлений и 18 удалений

Просмотреть файл

@ -250,6 +250,7 @@ pref("browser.search.updateinterval", 6);
// disable search suggestions by default // disable search suggestions by default
pref("browser.search.suggest.enabled", false); pref("browser.search.suggest.enabled", false);
pref("browser.search.suggest.prompted", false);
// Tell the search service to load search plugins from the locale JAR // Tell the search service to load search plugins from the locale JAR
pref("browser.search.loadFromJars", true); pref("browser.search.loadFromJars", true);

Просмотреть файл

@ -322,9 +322,11 @@ RES_LAYOUT = \
res/layout/awesomebar_expandable_list.xml \ res/layout/awesomebar_expandable_list.xml \
res/layout/awesomebar_folder_row.xml \ res/layout/awesomebar_folder_row.xml \
res/layout/awesomebar_header_row.xml \ res/layout/awesomebar_header_row.xml \
res/layout/awesomebar_allpages_list.xml \
res/layout/awesomebar_list.xml \ res/layout/awesomebar_list.xml \
res/layout/awesomebar_row.xml \ res/layout/awesomebar_row.xml \
res/layout/awesomebar_suggestion_item.xml \ res/layout/awesomebar_suggestion_item.xml \
res/layout/awesomebar_suggestion_prompt.xml \
res/layout/awesomebar_suggestion_row.xml \ res/layout/awesomebar_suggestion_row.xml \
res/layout/awesomebar_search.xml \ res/layout/awesomebar_search.xml \
res/layout/awesomebar_tab_indicator.xml \ res/layout/awesomebar_tab_indicator.xml \

Просмотреть файл

@ -58,6 +58,8 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
private AsyncTask<String, Void, ArrayList<String>> mSuggestTask; private AsyncTask<String, Void, ArrayList<String>> mSuggestTask;
private AwesomeBarCursorAdapter mCursorAdapter = null; private AwesomeBarCursorAdapter mCursorAdapter = null;
private boolean mTelemetrySent = false; private boolean mTelemetrySent = false;
private LinearLayout mAllPagesView;
private View mSuggestionsOptInPrompt;
private class SearchEntryViewHolder { private class SearchEntryViewHolder {
public FlowLayout suggestionView; public FlowLayout suggestionView;
@ -81,13 +83,12 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
public TabContentFactory getFactory() { public TabContentFactory getFactory() {
return new TabContentFactory() { return new TabContentFactory() {
public View createTabContent(String tag) { public View createTabContent(String tag) {
final ListView list = getListView(); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
handleItemClick(parent, view, position, id); handleItemClick(parent, view, position, id);
} }
}); });
return list; return getAllPagesView();
} }
}; };
} }
@ -100,9 +101,16 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
return TAG; 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() { public ListView getListView() {
if (mView == null) { 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); ((Activity)mContext).registerForContextMenu(mView);
mView.setTag(TAG); mView.setTag(TAG);
AwesomeBarCursorAdapter adapter = getCursorAdapter(); AwesomeBarCursorAdapter adapter = getCursorAdapter();
@ -129,6 +137,12 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
adapter.filter(searchTerm); adapter.filter(searchTerm);
filterSuggestions(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) { private void filterSuggestions(String searchTerm) {
@ -408,8 +422,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
// add additional suggestions given by this engine // add additional suggestions given by this engine
int recycledSuggestionCount = suggestionView.getChildCount(); int recycledSuggestionCount = suggestionView.getChildCount();
int suggestionCount = engine.suggestions.size(); int suggestionCount = engine.suggestions.size();
int i = 0; for (int i = 0; i < suggestionCount; i++) {
for (i = 0; i < suggestionCount; i++) {
String suggestion = engine.suggestions.get(i); String suggestion = engine.suggestions.get(i);
View suggestionItem = null; View suggestionItem = null;
@ -429,7 +442,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
} }
// hide extra suggestions that have been recycled // 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); 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. * Sets suggestions associated with the current suggest engine.
* If there is no suggest engine, this does nothing. * If there is no suggest engine, this does nothing.
*/ */
public void setSuggestions(final ArrayList<String> suggestions) { private void setSuggestions(final ArrayList<String> suggestions) {
if (mSuggestClient != null) { if (mSuggestClient != null) {
mSearchEngines.get(0).suggestions = suggestions; mSearchEngines.get(0).suggestions = suggestions;
getCursorAdapter().notifyDataSetChanged(); getCursorAdapter().notifyDataSetChanged();
@ -465,12 +478,14 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
/** /**
* Sets search engines to be shown for user-entered queries. * Sets search engines to be shown for user-entered queries.
*/ */
public void setSearchEngines(JSONObject data) { private void setSearchEngines(JSONObject data) {
try { try {
String suggestEngine = data.isNull("suggestEngine") ? null : data.getString("suggestEngine"); JSONObject suggest = data.getJSONObject("suggest");
String suggestTemplate = data.isNull("suggestTemplate") ? null : data.getString("suggestTemplate"); 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"); JSONArray engines = data.getJSONArray("searchEngines");
mSuggestionsEnabled = data.getBoolean("suggestEnabled");
mSearchEngines = new ArrayList<SearchEngine>(); mSearchEngines = new ArrayList<SearchEngine>();
for (int i = 0; i < engines.length(); i++) { 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)); mSearchEngines.add(new SearchEngine(name, icon));
} }
} }
// show suggestions opt-in if user hasn't been prompted
if (!suggestionsPrompted && mSuggestClient != null) {
showSuggestionsOptIn();
}
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOGTAG, "Error getting search engine JSON", e); Log.e(LOGTAG, "Error getting search engine JSON", e);
} }
@ -507,6 +527,42 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
return drawable; 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) { public void handleMessage(String event, final JSONObject message) {
if (event.equals("SearchEngines:Data")) { if (event.equals("SearchEngines:Data")) {
GeckoAppShell.getMainHandler().post(new Runnable() { GeckoAppShell.getMainHandler().post(new Runnable() {

Просмотреть файл

@ -12,7 +12,6 @@
<!ENTITY awesomebar_all_pages_title "Top Sites"> <!ENTITY awesomebar_all_pages_title "Top Sites">
<!ENTITY awesomebar_bookmarks_title "Bookmarks"> <!ENTITY awesomebar_bookmarks_title "Bookmarks">
<!ENTITY awesomebar_history_title "History"> <!ENTITY awesomebar_history_title "History">
<!ENTITY awesomebar_search_engine "Search for \&quot;&#037;s\&quot;">
<!ENTITY crash_reporter_title "&brandShortName; Crash Reporter"> <!ENTITY crash_reporter_title "&brandShortName; Crash Reporter">
<!ENTITY crash_message "&brandShortName; has crashed. Your tabs should be listed on the &brandShortName; Start page when you restart."> <!ENTITY crash_message "&brandShortName; has crashed. Your tabs should be listed on the &brandShortName; Start page when you restart.">
@ -171,6 +170,8 @@ size. -->
<!ENTITY button_ok "OK"> <!ENTITY button_ok "OK">
<!ENTITY button_cancel "Cancel"> <!ENTITY button_cancel "Cancel">
<!ENTITY button_yes "Yes">
<!ENTITY button_no "No">
<!ENTITY button_clear_data "Clear data"> <!ENTITY button_clear_data "Clear data">
<!ENTITY button_set "Set"> <!ENTITY button_set "Set">
<!ENTITY button_clear "Clear"> <!ENTITY button_clear "Clear">
@ -227,6 +228,11 @@ just addresses the organization to follow, e.g. "This site is run by " -->
from Android"> from Android">
<!ENTITY bookmarkhistory_import_wait "Please wait..."> <!ENTITY bookmarkhistory_import_wait "Please wait...">
<!-- Localization note (suggestions_prompt): The placeholder (&#037;s) should
be kept in the string; this will be replaced with the name of the search
engine. -->
<!ENTITY suggestions_prompt "Would you like to turn on &#037;s search suggestions?">
<!ENTITY webapp_generic_name "App"> <!ENTITY webapp_generic_name "App">
<!-- Updater notifications --> <!-- Updater notifications -->

Просмотреть файл

@ -0,0 +1,14 @@
<?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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<include layout="@layout/awesomebar_list"
android:id="@+id/awesomebar_list"/>
</LinearLayout>

Просмотреть файл

@ -0,0 +1,48 @@
<?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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/awesomebar_row_height"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="10dip">
<TextView android:id="@+id/suggestions_prompt_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginLeft="6dip"
android:textSize="13sp"
android:layout_weight="1" />
<TextView android:id="@+id/suggestions_prompt_yes"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="13sp"
android:layout_marginLeft="15dip"
android:background="@drawable/suggestion_selector"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:clickable="true"
android:text="@string/button_yes" />
<TextView android:id="@+id/suggestions_prompt_no"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="13sp"
android:layout_marginLeft="6dip"
android:background="@drawable/suggestion_selector"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:clickable="true"
android:text="@string/button_no" />
</LinearLayout>

Просмотреть файл

@ -20,7 +20,6 @@
<string name="awesomebar_all_pages_title">&awesomebar_all_pages_title;</string> <string name="awesomebar_all_pages_title">&awesomebar_all_pages_title;</string>
<string name="awesomebar_bookmarks_title">&awesomebar_bookmarks_title;</string> <string name="awesomebar_bookmarks_title">&awesomebar_bookmarks_title;</string>
<string name="awesomebar_history_title">&awesomebar_history_title;</string> <string name="awesomebar_history_title">&awesomebar_history_title;</string>
<string name="awesomebar_search_engine">&awesomebar_search_engine;</string>
<string name="crash_reporter_title">&crash_reporter_title;</string> <string name="crash_reporter_title">&crash_reporter_title;</string>
<string name="crash_message">&crash_message;</string> <string name="crash_message">&crash_message;</string>
@ -167,6 +166,8 @@
<string name="button_clear_data">&button_clear_data;</string> <string name="button_clear_data">&button_clear_data;</string>
<string name="button_set">&button_set;</string> <string name="button_set">&button_set;</string>
<string name="button_clear">&button_clear;</string> <string name="button_clear">&button_clear;</string>
<string name="button_yes">&button_yes;</string>
<string name="button_no">&button_no;</string>
<string name="abouthome_addons_title">&abouthome_addons_title;</string> <string name="abouthome_addons_title">&abouthome_addons_title;</string>
<string name="abouthome_addons_browse">&abouthome_addons_browse;</string> <string name="abouthome_addons_browse">&abouthome_addons_browse;</string>
@ -231,4 +232,7 @@
<string name="updater_apply_ticker">&updater_apply_ticker;</string> <string name="updater_apply_ticker">&updater_apply_ticker;</string>
<string name="updater_apply_select">&updater_apply_select;</string> <string name="updater_apply_select">&updater_apply_select;</string>
<!-- Search suggestions opt-in -->
<string name="suggestions_prompt">&suggestions_prompt;</string>
</resources> </resources>

Просмотреть файл

@ -922,6 +922,9 @@ var BrowserApp = {
else else
MasterPassword.setPassword(json.value); MasterPassword.setPassword(json.value);
return; 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 // when sending to java, we normalized special preferences that use
@ -6102,6 +6105,8 @@ OverscrollController.prototype = {
var SearchEngines = { var SearchEngines = {
_contextMenuId: null, _contextMenuId: null,
PREF_SUGGEST_ENABLED: "browser.search.suggest.enabled",
PREF_SUGGEST_PROMPTED: "browser.search.suggest.prompted",
init: function init() { init: function init() {
Services.obs.addObserver(this, "SearchEngines:Get", false); Services.obs.addObserver(this, "SearchEngines:Get", false);
@ -6115,7 +6120,7 @@ var SearchEngines = {
}, },
uninit: function uninit() { uninit: function uninit() {
Services.obs.removeObserver(this, "SearchEngines:Get", false); Services.obs.removeObserver(this, "SearchEngines:Get");
if (this._contextMenuId != null) if (this._contextMenuId != null)
NativeWindow.contextmenus.remove(this._contextMenuId); NativeWindow.contextmenus.remove(this._contextMenuId);
}, },
@ -6145,9 +6150,12 @@ var SearchEngines = {
gecko: { gecko: {
type: "SearchEngines:Data", type: "SearchEngines:Data",
searchEngines: searchEngines, searchEngines: searchEngines,
suggestEngine: suggestEngine, suggest: {
suggestTemplate: suggestTemplate, engine: suggestEngine,
suggestEnabled: Services.prefs.getBoolPref("browser.search.suggest.enabled") template: suggestTemplate,
enabled: Services.prefs.getBoolPref(this.PREF_SUGGEST_ENABLED),
prompted: Services.prefs.getBoolPref(this.PREF_SUGGEST_PROMPTED)
}
} }
}); });
}, },