From d26706538834e0ed58bf28f08d9a2885c0e7efcb Mon Sep 17 00:00:00 2001 From: Bjorn Bringert Date: Mon, 13 Sep 2010 14:06:41 +0100 Subject: Add user-selected search providers to browser The lists of search providers are taken from Chrome. Change-Id: I7af6dc1258950d1fc5cf86013f8be9f3c5db0f1a --- AndroidManifest.xml | 1 + res/values-cs-rCZ/search_engines.xml | 31 + res/values-da-rDK/search_engines.xml | 29 + res/values-de-rAT/search_engines.xml | 29 + res/values-de-rCH/search_engines.xml | 32 + res/values-de-rDE/search_engines.xml | 30 + res/values-el-rGR/search_engines.xml | 30 + res/values-en-rAU/search_engines.xml | 29 + res/values-en-rGB/search_engines.xml | 30 + res/values-en-rIE/search_engines.xml | 29 + res/values-en-rNZ/search_engines.xml | 29 + res/values-en-rSG/search_engines.xml | 30 + res/values-en-rZA/search_engines.xml | 29 + res/values-es-rES/search_engines.xml | 32 + res/values-fr-rBE/search_engines.xml | 30 + res/values-fr-rFR/search_engines.xml | 29 + res/values-it-rIT/search_engines.xml | 32 + res/values-ja-rJP/search_engines.xml | 30 + res/values-ko-rKR/search_engines.xml | 31 + res/values-nb-rNO/search_engines.xml | 31 + res/values-nl-rBE/search_engines.xml | 30 + res/values-nl-rNL/search_engines.xml | 30 + res/values-pl-rPL/search_engines.xml | 32 + res/values-pt-rBR/search_engines.xml | 30 + res/values-pt-rPT/search_engines.xml | 30 + res/values-ru-rRU/search_engines.xml | 32 + res/values-sv-rSE/search_engines.xml | 32 + res/values-tr-rTR/search_engines.xml | 30 + res/values-zh-rCN/search_engines.xml | 30 + res/values-zh-rHK/search_engines.xml | 30 + res/values-zh-rTW/search_engines.xml | 29 + res/values/all_search_engines.xml | 752 +++++++++++++++++++++ res/values/search_engines.xml | 29 + res/values/strings.xml | 10 + res/xml/browser_preferences.xml | 14 + src/com/android/browser/BrowserActivity.java | 15 +- .../android/browser/BrowserPreferencesPage.java | 12 +- src/com/android/browser/BrowserProvider.java | 77 +-- src/com/android/browser/BrowserSettings.java | 64 +- .../browser/search/DefaultSearchEngine.java | 118 ++++ .../browser/search/OpenSearchSearchEngine.java | 295 ++++++++ src/com/android/browser/search/SearchEngine.java | 57 ++ .../android/browser/search/SearchEngineInfo.java | 169 +++++ .../browser/search/SearchEnginePreference.java | 62 ++ src/com/android/browser/search/SearchEngines.java | 73 ++ tools/all_search_engines.template.xml | 40 ++ tools/get_search_engines.py | 258 +++++++ tools/search_engines.template.xml | 24 + 48 files changed, 2889 insertions(+), 88 deletions(-) create mode 100644 res/values-cs-rCZ/search_engines.xml create mode 100644 res/values-da-rDK/search_engines.xml create mode 100644 res/values-de-rAT/search_engines.xml create mode 100644 res/values-de-rCH/search_engines.xml create mode 100644 res/values-de-rDE/search_engines.xml create mode 100644 res/values-el-rGR/search_engines.xml create mode 100644 res/values-en-rAU/search_engines.xml create mode 100644 res/values-en-rGB/search_engines.xml create mode 100644 res/values-en-rIE/search_engines.xml create mode 100644 res/values-en-rNZ/search_engines.xml create mode 100644 res/values-en-rSG/search_engines.xml create mode 100644 res/values-en-rZA/search_engines.xml create mode 100644 res/values-es-rES/search_engines.xml create mode 100644 res/values-fr-rBE/search_engines.xml create mode 100644 res/values-fr-rFR/search_engines.xml create mode 100644 res/values-it-rIT/search_engines.xml create mode 100644 res/values-ja-rJP/search_engines.xml create mode 100644 res/values-ko-rKR/search_engines.xml create mode 100644 res/values-nb-rNO/search_engines.xml create mode 100644 res/values-nl-rBE/search_engines.xml create mode 100644 res/values-nl-rNL/search_engines.xml create mode 100644 res/values-pl-rPL/search_engines.xml create mode 100644 res/values-pt-rBR/search_engines.xml create mode 100644 res/values-pt-rPT/search_engines.xml create mode 100644 res/values-ru-rRU/search_engines.xml create mode 100644 res/values-sv-rSE/search_engines.xml create mode 100644 res/values-tr-rTR/search_engines.xml create mode 100644 res/values-zh-rCN/search_engines.xml create mode 100644 res/values-zh-rHK/search_engines.xml create mode 100644 res/values-zh-rTW/search_engines.xml create mode 100644 res/values/all_search_engines.xml create mode 100644 res/values/search_engines.xml create mode 100644 src/com/android/browser/search/DefaultSearchEngine.java create mode 100644 src/com/android/browser/search/OpenSearchSearchEngine.java create mode 100644 src/com/android/browser/search/SearchEngine.java create mode 100644 src/com/android/browser/search/SearchEngineInfo.java create mode 100644 src/com/android/browser/search/SearchEnginePreference.java create mode 100644 src/com/android/browser/search/SearchEngines.java create mode 100644 tools/all_search_engines.template.xml create mode 100755 tools/get_search_engines.py create mode 100755 tools/search_engines.template.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7e98019..36e2820 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -30,6 +30,7 @@ + diff --git a/res/values-cs-rCZ/search_engines.xml b/res/values-cs-rCZ/search_engines.xml new file mode 100644 index 0000000..5aea8c8 --- /dev/null +++ b/res/values-cs-rCZ/search_engines.xml @@ -0,0 +1,31 @@ + + + + + + google + seznam + bing_cs_CZ + centrum_cz + atlas_cz + + diff --git a/res/values-da-rDK/search_engines.xml b/res/values-da-rDK/search_engines.xml new file mode 100644 index 0000000..73360b1 --- /dev/null +++ b/res/values-da-rDK/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + bing_da_DK + yahoo_dk + + diff --git a/res/values-de-rAT/search_engines.xml b/res/values-de-rAT/search_engines.xml new file mode 100644 index 0000000..708d7ed --- /dev/null +++ b/res/values-de-rAT/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + yahoo_at + bing_de_AT + + diff --git a/res/values-de-rCH/search_engines.xml b/res/values-de-rCH/search_engines.xml new file mode 100644 index 0000000..4e2360e --- /dev/null +++ b/res/values-de-rCH/search_engines.xml @@ -0,0 +1,32 @@ + + + + + + google + yahoo_ch + bing_de_CH + bing_fr_CH + search_de_CH + search_fr_CH + + diff --git a/res/values-de-rDE/search_engines.xml b/res/values-de-rDE/search_engines.xml new file mode 100644 index 0000000..5fdde69 --- /dev/null +++ b/res/values-de-rDE/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + ask_de + bing_de_DE + yahoo_de + + diff --git a/res/values-el-rGR/search_engines.xml b/res/values-el-rGR/search_engines.xml new file mode 100644 index 0000000..8185cf3 --- /dev/null +++ b/res/values-el-rGR/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + yahoo + in + bing_el_GR + + diff --git a/res/values-en-rAU/search_engines.xml b/res/values-en-rAU/search_engines.xml new file mode 100644 index 0000000..08765ac --- /dev/null +++ b/res/values-en-rAU/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + bing_en_AU + yahoo_au + + diff --git a/res/values-en-rGB/search_engines.xml b/res/values-en-rGB/search_engines.xml new file mode 100644 index 0000000..b2ee93c --- /dev/null +++ b/res/values-en-rGB/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + ask_uk + yahoo_uk + bing_en_GB + + diff --git a/res/values-en-rIE/search_engines.xml b/res/values-en-rIE/search_engines.xml new file mode 100644 index 0000000..25f3f29 --- /dev/null +++ b/res/values-en-rIE/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + yahoo_uk + bing_en_IE + + diff --git a/res/values-en-rNZ/search_engines.xml b/res/values-en-rNZ/search_engines.xml new file mode 100644 index 0000000..2044c37 --- /dev/null +++ b/res/values-en-rNZ/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + yahoo_nz + bing_en_NZ + + diff --git a/res/values-en-rSG/search_engines.xml b/res/values-en-rSG/search_engines.xml new file mode 100644 index 0000000..74d6939 --- /dev/null +++ b/res/values-en-rSG/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + yahoo_sg + bing_en_SG + rednano + + diff --git a/res/values-en-rZA/search_engines.xml b/res/values-en-rZA/search_engines.xml new file mode 100644 index 0000000..bab95c4 --- /dev/null +++ b/res/values-en-rZA/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + yahoo + bing_en_ZA + + diff --git a/res/values-es-rES/search_engines.xml b/res/values-es-rES/search_engines.xml new file mode 100644 index 0000000..053d786 --- /dev/null +++ b/res/values-es-rES/search_engines.xml @@ -0,0 +1,32 @@ + + + + + + google + ask_es + bing_es_ES + yahoo_es + terra_es + hispavista + + diff --git a/res/values-fr-rBE/search_engines.xml b/res/values-fr-rBE/search_engines.xml new file mode 100644 index 0000000..d743fc0 --- /dev/null +++ b/res/values-fr-rBE/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + bing_nl_BE + yahoo + bing_fr_BE + + diff --git a/res/values-fr-rFR/search_engines.xml b/res/values-fr-rFR/search_engines.xml new file mode 100644 index 0000000..4a75e4c --- /dev/null +++ b/res/values-fr-rFR/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + yahoo_fr + bing_fr_FR + + diff --git a/res/values-it-rIT/search_engines.xml b/res/values-it-rIT/search_engines.xml new file mode 100644 index 0000000..c2be0d4 --- /dev/null +++ b/res/values-it-rIT/search_engines.xml @@ -0,0 +1,32 @@ + + + + + + google + ask_it + virgilio + bing_it_IT + yahoo_it + libero + + diff --git a/res/values-ja-rJP/search_engines.xml b/res/values-ja-rJP/search_engines.xml new file mode 100644 index 0000000..03c23f4 --- /dev/null +++ b/res/values-ja-rJP/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + yahoo_jp + bing_ja_JP + goo + + diff --git a/res/values-ko-rKR/search_engines.xml b/res/values-ko-rKR/search_engines.xml new file mode 100644 index 0000000..4f24631 --- /dev/null +++ b/res/values-ko-rKR/search_engines.xml @@ -0,0 +1,31 @@ + + + + + + google + naver + daum + yahoo_kr + nate + + diff --git a/res/values-nb-rNO/search_engines.xml b/res/values-nb-rNO/search_engines.xml new file mode 100644 index 0000000..418f6d2 --- /dev/null +++ b/res/values-nb-rNO/search_engines.xml @@ -0,0 +1,31 @@ + + + + + + google + bing_nb_NO + abcsok + yahoo_no + kvasir + + diff --git a/res/values-nl-rBE/search_engines.xml b/res/values-nl-rBE/search_engines.xml new file mode 100644 index 0000000..d743fc0 --- /dev/null +++ b/res/values-nl-rBE/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + bing_nl_BE + yahoo + bing_fr_BE + + diff --git a/res/values-nl-rNL/search_engines.xml b/res/values-nl-rNL/search_engines.xml new file mode 100644 index 0000000..b9c1b40 --- /dev/null +++ b/res/values-nl-rNL/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + bing_nl_NL + yahoo_nl + ask_nl + + diff --git a/res/values-pl-rPL/search_engines.xml b/res/values-pl-rPL/search_engines.xml new file mode 100644 index 0000000..ddc262e --- /dev/null +++ b/res/values-pl-rPL/search_engines.xml @@ -0,0 +1,32 @@ + + + + + + google + bing_pl_PL + netsprint + yahoo_uk + onet + wp + + diff --git a/res/values-pt-rBR/search_engines.xml b/res/values-pt-rBR/search_engines.xml new file mode 100644 index 0000000..56cda34 --- /dev/null +++ b/res/values-pt-rBR/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + bing_pt_BR + yahoo_br + uol + + diff --git a/res/values-pt-rPT/search_engines.xml b/res/values-pt-rPT/search_engines.xml new file mode 100644 index 0000000..3780d73 --- /dev/null +++ b/res/values-pt-rPT/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + sapo + bing_pt_PT + yahoo + + diff --git a/res/values-ru-rRU/search_engines.xml b/res/values-ru-rRU/search_engines.xml new file mode 100644 index 0000000..80ff214 --- /dev/null +++ b/res/values-ru-rRU/search_engines.xml @@ -0,0 +1,32 @@ + + + + + + google + yandex_ru + mail_ru + tut + rambler + bing_ru_RU + + diff --git a/res/values-sv-rSE/search_engines.xml b/res/values-sv-rSE/search_engines.xml new file mode 100644 index 0000000..f216357 --- /dev/null +++ b/res/values-sv-rSE/search_engines.xml @@ -0,0 +1,32 @@ + + + + + + google + bing_sv_SE + yahoo_se + altavista_se + spray + eniro_se + + diff --git a/res/values-tr-rTR/search_engines.xml b/res/values-tr-rTR/search_engines.xml new file mode 100644 index 0000000..06cdb12 --- /dev/null +++ b/res/values-tr-rTR/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + bing_tr_TR + yahoo + mynet + + diff --git a/res/values-zh-rCN/search_engines.xml b/res/values-zh-rCN/search_engines.xml new file mode 100644 index 0000000..c38055c --- /dev/null +++ b/res/values-zh-rCN/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + baidu + yahoo_cn + bing_zh_CN + + diff --git a/res/values-zh-rHK/search_engines.xml b/res/values-zh-rHK/search_engines.xml new file mode 100644 index 0000000..eaf35d5 --- /dev/null +++ b/res/values-zh-rHK/search_engines.xml @@ -0,0 +1,30 @@ + + + + + + google + yahoo_hk + bing_zh_HK + baidu + + diff --git a/res/values-zh-rTW/search_engines.xml b/res/values-zh-rTW/search_engines.xml new file mode 100644 index 0000000..6d02b43 --- /dev/null +++ b/res/values-zh-rTW/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + yahoo_tw + bing_zh_TW + + diff --git a/res/values/all_search_engines.xml b/res/values/all_search_engines.xml new file mode 100644 index 0000000..3a17bd9 --- /dev/null +++ b/res/values/all_search_engines.xml @@ -0,0 +1,752 @@ + + + + + + + + + Yahoo! UK & Ireland + uk.yahoo.com + http://uk.search.yahoo.com/favicon.ico + http://uk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://uk-sayt.ff.search.yahoo.com/gossip-uk-sayt?output=fxjson&command={searchTerms} + + + Yahoo! JAPAN + yahoo.co.jp + http://search.yahoo.co.jp/favicon.ico + http://search.yahoo.co.jp/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Rambler + rambler.ru + http://www.rambler.ru/favicon.ico + http://www.rambler.ru/srch?words={searchTerms} + windows-1251 + + + + Yahoo! Brasil + br.yahoo.com + http://br.search.yahoo.com/favicon.ico + http://br.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://br-sayt.ff.search.yahoo.com/gossip-br-sayt?output=fxjson&command={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=zh-HK&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=el-GR&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=tr-TR&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Ask Jeeves + uk.ask.com + http://uk.ask.com/favicon.ico + http://uk.ask.com/web?q={searchTerms} + UTF-8 + http://ss.uk.ask.com/query?q={searchTerms}&li=ff + + + 네이트닷컴 + nate.com + http://nate.search.empas.com/favicon.ico + http://nate.search.empas.com/search/all.html?q={searchTerms} + EUC-KR + + + + UOL Busca + busca.uol.com.br + http://busca.uol.com.br/favicon.ico + http://busca.uol.com.br/www/index.html?q={searchTerms} + ISO-8859-1 + + + + 百度 + baidu.com + http://www.baidu.com/favicon.ico + http://www.baidu.com/s?wd={searchTerms} + GB2312 + + + + Yahoo! Suche + ch.yahoo.com + http://ch.search.yahoo.com/favicon.ico + http://ch.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=nl-BE&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + 中国雅虎 + cn.yahoo.com + http://search.cn.yahoo.com/favicon.ico + http://search.cn.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + GB2312 + + + + Onet.pl + onet.pl + http://szukaj.onet.pl/favicon.ico + http://szukaj.onet.pl/query.html?qt={searchTerms} + ISO-8859-2 + + + + Ask.com Espa༚ + es.ask.com + http://es.ask.com/favicon.ico + http://es.ask.com/web?q={searchTerms} + UTF-8 + http://ss.es.ask.com/query?q={searchTerms}&li=ff + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=cs-CZ&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + AltaVista + se.altavista.com + http://se.altavista.com/favicon.ico + http://se.altavista.com/web/results?q={searchTerms} + UTF-8 + + + + \@MAIL.RU + mail.ru + http://img.go.mail.ru/favicon.ico + http://go.mail.ru/search?q={searchTerms} + windows-1251 + + + + hispavista + hispavista.com + http://buscar.hispavista.com/favicon.ico + http://buscar.hispavista.com/?cadena={searchTerms} + iso-8859-1 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=zh-CN&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Google + + http://www.google.com/favicon.ico + {google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms} + UTF-8 + {google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=en-NZ&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=fr-BE&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Rednano + rednano.sg + http://rednano.sg/favicon.ico + http://rednano.sg/sfe/lwi.action?querystring={searchTerms} + UTF-8 + + + + goo + search.goo.ne.jp + http://goo.ne.jp/favicon.ico + http://search.goo.ne.jp/web.jsp?MT={searchTerms}&IE={inputEncoding} + UTF-8 + + + + SAPO + sapo.pt + http://imgs.sapo.pt/images/sapo.ico + http://pesquisa.sapo.pt/?q={searchTerms} + UTF-8 + http://pesquisa.sapo.pt/livesapo?q={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=it-IT&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=es-ES&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + ABC Søk + abcsok.no + http://abcsok.no/favicon.ico + http://abcsok.no/index.html?q={searchTerms} + UTF-8 + + + + Yahoo! Danmark + dk.yahoo.com + http://dk.search.yahoo.com/favicon.ico + http://dk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Yahoo! Deutschland + de.yahoo.com + http://de.search.yahoo.com/favicon.ico + http://de.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://de-sayt.ff.search.yahoo.com/gossip-de-sayt?output=fxjson&command={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=de-AT&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=pl-PL&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + TUT.BY + tut.by + http://www.tut.by/favicon.ico + http://search.tut.by/?query={searchTerms} + windows-1251 + + + + Spray + spray.se + http://www.eniro.se/favicon.ico + http://www.eniro.se/query?ax=spray&search_word={searchTerms}&what=web + ISO-8859-1 + + + + Wirtualna Polska + wp.pl + http://szukaj.wp.pl/favicon.ico + http://szukaj.wp.pl/szukaj.html?szukaj={searchTerms} + ISO-8859-2 + + + + Yahoo!奇摩 + tw.yahoo.com + http://tw.search.yahoo.com/favicon.ico + http://tw.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Atlas + atlas.cz + http://img.atlas.cz/favicon.ico + http://search.atlas.cz/?q={searchTerms} + windows-1250 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=en-GB&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Yahoo! Espa༚ + es.yahoo.com + http://es.search.yahoo.com/favicon.ico + http://es.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://es-sayt.ff.search.yahoo.com/gossip-es-sayt?output=fxjson&command={searchTerms} + + + Libero + libero.it + http://arianna.libero.it/favicon.ico + http://arianna.libero.it/search/abin/integrata.cgi?query={searchTerms} + ISO-8859-1 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=sv-SE&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Yahoo!Xtra + nz.yahoo.com + http://nz.search.yahoo.com/favicon.ico + http://nz.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://aue-sayt.ff.search.yahoo.com/gossip-nz-sayt?output=fxjson&command={searchTerms} + + + Terra + terra.es + http://buscador.terra.es/favicon.ico + http://buscador.terra.es/Default.aspx?query={searchTerms}&source=Search + ISO-8859-1 + + + + Yahoo! Nederland + nl.yahoo.com + http://nl.search.yahoo.com/favicon.ico + http://nl.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Yahoo! Norge + no.yahoo.com + http://no.search.yahoo.com/favicon.ico + http://no.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Daum + daum.net + http://search.daum.net/favicon.ico + http://search.daum.net/search?q={searchTerms} + EUC-KR + http://sug.search.daum.net/search_nsuggest?mod=fxjson&q={searchTerms} + + + Yahoo! France + fr.yahoo.com + http://fr.search.yahoo.com/favicon.ico + http://fr.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://fr-sayt.ff.search.yahoo.com/gossip-fr-sayt?output=fxjson&command={searchTerms} + + + Ask.com Nederland + nl.ask.com + http://nl.ask.com/favicon.ico + http://nl.ask.com/web?q={searchTerms} + UTF-8 + http://ss.nl.ask.com/query?q={searchTerms}&li=ff + + + Seznam + seznam.cz + http://1.im.cz/szn/img/favicon.ico + http://search.seznam.cz/?q={searchTerms} + UTF-8 + http:///suggest.fulltext.seznam.cz/?dict=fulltext_ff&phrase={searchTerms}&encoding={inputEncoding}&response_encoding=utf-8 + + + Centrum.cz + centrum.cz + http://img.centrum.cz/6/vy2/o/favicon.ico + http://search.centrum.cz/index.php?charset={inputEncoding}&q={searchTerms} + UTF-8 + + + + Eniro + eniro.se + http://eniro.se/favicon.ico + http://eniro.se/query?search_word={searchTerms}&what=web_local + ISO-8859-1 + + + + Kvasir + kvasir.no + http://www.kvasir.no/img/favicon.ico + http://www.kvasir.no/nettsok/searchResult.html?searchExpr={searchTerms} + ISO-8859-1 + + + + Yahoo! + yahoo.com + http://search.yahoo.com/favicon.ico + http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=en-IE&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=pt-PT&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=de-CH&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=nl-NL&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=fr-CH&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=zh-TW&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=ru-RU&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=en-AU&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=da-DK&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Ask.com Italia + it.ask.com + http://it.ask.com/favicon.ico + http://it.ask.com/web?q={searchTerms} + UTF-8 + http://ss.it.ask.com/query?q={searchTerms}&li=ff + + + Яндекс + yandex.ru + http://yandex.ru/favicon.ico + http://yandex.ru/yandsearch?text={searchTerms} + UTF-8 + http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=ja-JP&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + 야후! 코리아 + kr.yahoo.com + http://kr.search.yahoo.com/favicon.ico + http://kr.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://kr.atc.search.yahoo.com/atcx.php?property=main&ot=fxjson&ei=utf8&eo=utf8&command={searchTerms} + + + Ask.com Deutschland + de.ask.com + http://de.ask.com/favicon.ico + http://de.ask.com/web?q={searchTerms} + UTF-8 + http://ss.de.ask.com/query?q={searchTerms}&li=ff + + + Yahoo! Hong Kong + hk.yahoo.com + http://hk.search.yahoo.com/favicon.ico + http://hk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=fr-FR&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + in.gr + in.gr + http://www.in.gr/favicon.ico + http://find.in.gr/?qs={searchTerms} + ISO-8859-7 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=nb-NO&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Yahoo! Singapore + sg.yahoo.com + http://sg.search.yahoo.com/favicon.ico + http://sg.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://sg-sayt.ff.search.yahoo.com/gossip-sg-sayt?output=fxjson&command={searchTerms} + + + Yahoo! Sverige + se.yahoo.com + http://se.search.yahoo.com/favicon.ico + http://se.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=de-DE&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + search.ch + search.ch + http://www.search.ch/favicon.ico + http://www.search.ch/index.de.html?q={searchTerms} + ISO-8859-1 + + + + MYNET + mynet.com + http://img.mynet.com/mynetfavori.ico + http://arama.mynet.com/search.aspx?q={searchTerms}&pg=q + windows-1254 + + + + search.ch + + http://www.search.ch/favicon.ico + http://www.search.ch/index.fr.html?q={searchTerms} + ISO-8859-1 + + + + Virgilio + virgilio.it + http://ricerca.alice.it/favicon.ico + http://ricerca.alice.it/ricerca?qs={searchTerms} + ISO-8859-1 + + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=en-SG&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Yahoo! Italia + it.yahoo.com + http://it.search.yahoo.com/favicon.ico + http://it.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://it-sayt.ff.search.yahoo.com/gossip-it-sayt?output=fxjson&command={searchTerms} + + + Yahoo! Suche + at.yahoo.com + http://at.search.yahoo.com/favicon.ico + http://at.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + + + + Yahoo!7 + au.yahoo.com + http://au.search.yahoo.com/favicon.ico + http://au.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms} + UTF-8 + http://aue-sayt.ff.search.yahoo.com/gossip-au-sayt?output=fxjson&command={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=pt-BR&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + NetSprint + netsprint.pl + http://netsprint.pl/favicon.ico + http://www.netsprint.pl/serwis/search?q={searchTerms} + UTF-8 + + + + 네이버 + naver.com + http://search.naver.com/favicon.ico + http://search.naver.com/search.naver?ie={inputEncoding}&query={searchTerms} + UTF-8 + http://ac.search.naver.com/autocompl?m=s&ie={inputEncoding}&oe=utf-8&q={searchTerms} + + + Bing + bing.com + http://www.bing.com/s/wlflag.ico + http://www.bing.com/search?setmkt=en-ZA&q={searchTerms} + UTF-8 + http://api.bing.com/osjson.aspx?query={searchTerms}&language={language} + + + diff --git a/res/values/search_engines.xml b/res/values/search_engines.xml new file mode 100644 index 0000000..c6ed9ca --- /dev/null +++ b/res/values/search_engines.xml @@ -0,0 +1,29 @@ + + + + + + google + yahoo + bing + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 18a2144..f852167 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -305,6 +305,16 @@ Open new windows behind the current one Set home page + + Set search engine + + Select a search engine + + Show web suggestions + + Show web suggestions as you type + + Don\'t show web suggestions as you type Use current page diff --git a/res/xml/browser_preferences.xml b/res/xml/browser_preferences.xml index ee1b306..fd994e8 100644 --- a/res/xml/browser_preferences.xml +++ b/res/xml/browser_preferences.xml @@ -98,6 +98,20 @@ android:hint="@string/http" android:inputType="textUri|textMultiLine" /> + + + + + 1 - && mSearchableInfo != null + && mSettings.getShowSearchSuggestions() && c.getCount() < (MAX_SUGGESTION_SHORT_ENTRIES - 1)) { - Cursor sc = mSearchManager.getSuggestions(mSearchableInfo, selectionArgs[0]); - return new MySuggestionCursor(c, sc, selectionArgs[0]); + SearchEngine searchEngine = mSettings.getSearchEngine(); + if (searchEngine != null && searchEngine.supportsSuggestions()) { + Cursor sc = searchEngine.getSuggestions(getContext(), selectionArgs[0]); + return new MySuggestionCursor(c, sc, selectionArgs[0]); + } } return new MySuggestionCursor(c, null, selectionArgs[0]); } diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java index 51b4eaa..6263eb3 100644 --- a/src/com/android/browser/BrowserSettings.java +++ b/src/com/android/browser/BrowserSettings.java @@ -17,14 +17,22 @@ package com.android.browser; +import com.android.browser.search.SearchEngine; +import com.android.browser.search.SearchEngines; + import android.app.ActivityManager; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.database.ContentObserver; +import android.os.Handler; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; +import android.provider.Settings; +import android.util.Log; import android.webkit.CookieManager; import android.webkit.GeolocationPermissions; import android.webkit.ValueCallback; @@ -71,6 +79,8 @@ class BrowserSettings extends Observable { private boolean openInBackground; private String defaultTextEncodingName; private String homeUrl = ""; + private SearchEngine searchEngine; + private boolean showSearchSuggestions; private boolean autoFitPage; private boolean landscapeOnly; private boolean loadsPageInOverviewMode; @@ -121,6 +131,8 @@ class BrowserSettings extends Observable { public final static String PREF_CLEAR_COOKIES = "privacy_clear_cookies"; public final static String PREF_CLEAR_HISTORY = "privacy_clear_history"; public final static String PREF_HOMEPAGE = "homepage"; + public final static String PREF_SEARCH_ENGINE = "search_engine"; + public final static String PREF_SHOW_SEARCH_SUGGESTIONS = "show_search_suggestions"; public final static String PREF_CLEAR_FORM_DATA = "privacy_clear_form_data"; public final static String PREF_CLEAR_PASSWORDS = @@ -234,7 +246,7 @@ class BrowserSettings extends Observable { * stored in this BrowserSettings object. This will update all * observers of this object. */ - public void loadFromDb(Context ctx) { + public void loadFromDb(final Context ctx) { SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(ctx); // Set the default value for the Application Caches path. @@ -266,17 +278,41 @@ class BrowserSettings extends Observable { pageCacheCapacity = 1; } - // Load the defaults from the xml + final ContentResolver cr = ctx.getContentResolver(); + cr.registerContentObserver( + Settings.System.getUriFor(Settings.System.SHOW_WEB_SUGGESTIONS), false, + new ContentObserver(new Handler()) { + @Override + public void onChange(boolean selfChange) { + SharedPreferences p = + PreferenceManager.getDefaultSharedPreferences(ctx); + updateShowWebSuggestions(cr, p); + } + }); + updateShowWebSuggestions(cr, p); + + // Load the defaults from the xml // This call is TOO SLOW, need to manually keep the defaults // in sync //PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences); - syncSharedPreferences(p); + syncSharedPreferences(ctx, p); } - /* package */ void syncSharedPreferences(SharedPreferences p) { + /* package */ void syncSharedPreferences(Context ctx, SharedPreferences p) { homeUrl = p.getString(PREF_HOMEPAGE, homeUrl); + String searchEngineName = p.getString(PREF_SEARCH_ENGINE, null); + if (searchEngine == null || !searchEngine.getName().equals(searchEngineName)) { + if (searchEngine != null) { + searchEngine.close(); + } + searchEngine = SearchEngines.get(ctx, searchEngineName); + } + Log.i(TAG, "Selected search engine: " + searchEngine); + showSearchSuggestions = p.getBoolean(PREF_SHOW_SEARCH_SUGGESTIONS, true); + // Persist to system settings + saveShowWebSuggestions(ctx.getContentResolver()); loadsImagesAutomatically = p.getBoolean("load_images", loadsImagesAutomatically); @@ -365,10 +401,30 @@ class BrowserSettings extends Observable { update(); } + private void saveShowWebSuggestions(ContentResolver cr) { + int value = showSearchSuggestions ? 1 : 0; + Settings.System.putInt(cr, Settings.System.SHOW_WEB_SUGGESTIONS, value); + } + + private void updateShowWebSuggestions(ContentResolver cr, SharedPreferences p) { + showSearchSuggestions = + Settings.System.getInt(cr, + Settings.System.SHOW_WEB_SUGGESTIONS, 1) == 1; + p.edit().putBoolean(PREF_SHOW_SEARCH_SUGGESTIONS, showSearchSuggestions).commit(); + } + public String getHomePage() { return homeUrl; } + public SearchEngine getSearchEngine() { + return searchEngine; + } + + public boolean getShowSearchSuggestions() { + return showSearchSuggestions; + } + public String getJsFlags() { return jsFlags; } diff --git a/src/com/android/browser/search/DefaultSearchEngine.java b/src/com/android/browser/search/DefaultSearchEngine.java new file mode 100644 index 0000000..42d274d --- /dev/null +++ b/src/com/android/browser/search/DefaultSearchEngine.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser.search; + +import android.app.SearchManager; +import android.app.SearchableInfo; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.os.Bundle; +import android.provider.Browser; +import android.text.TextUtils; +import android.util.Log; + +public class DefaultSearchEngine implements SearchEngine { + + private static final String TAG = "DefaultSearchEngine"; + + private final SearchableInfo mSearchable; + + private final CharSequence mLabel; + + private DefaultSearchEngine(Context context, SearchableInfo searchable) { + mSearchable = searchable; + mLabel = loadLabel(context, mSearchable.getSearchActivity()); + } + + public static DefaultSearchEngine create(Context context) { + SearchManager searchManager = + (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); + ComponentName name = searchManager.getWebSearchActivity(); + if (name == null) return null; + SearchableInfo searchable = searchManager.getSearchableInfo(name); + if (searchable == null) return null; + return new DefaultSearchEngine(context, searchable); + } + + private CharSequence loadLabel(Context context, ComponentName activityName) { + PackageManager pm = context.getPackageManager(); + try { + ActivityInfo ai = pm.getActivityInfo(activityName, 0); + return ai.loadLabel(pm); + } catch (PackageManager.NameNotFoundException ex) { + Log.e(TAG, "Web search activity not found: " + activityName); + return null; + } + } + + public String getName() { + String packageName = mSearchable.getSearchActivity().getPackageName(); + // Use "google" as name to avoid showing Google twice (app + OpenSearch) + if ("com.google.android.googlequicksearchbox".equals(packageName)) { + return "google"; + } else if ("com.android.quicksearchbox".equals(packageName)) { + return "google"; + } else { + return packageName; + } + } + + public CharSequence getLabel() { + return mLabel; + } + + public void startSearch(Context context, String query, Bundle appData, String extraData) { + try { + Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.putExtra(SearchManager.QUERY, query); + if (appData != null) { + intent.putExtra(SearchManager.APP_DATA, appData); + } + if (extraData != null) { + intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); + } + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); + context.startActivity(intent); + } catch (ActivityNotFoundException ex) { + Log.e(TAG, "Web search activity not found: " + mSearchable.getSearchActivity()); + } + } + + public Cursor getSuggestions(Context context, String query) { + SearchManager searchManager = + (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); + return searchManager.getSuggestions(mSearchable, query); + } + + public boolean supportsSuggestions() { + return !TextUtils.isEmpty(mSearchable.getSuggestAuthority()); + } + + public void close() { + } + + @Override + public String toString() { + return "ActivitySearchEngine{" + mSearchable + "}"; + } + +} diff --git a/src/com/android/browser/search/OpenSearchSearchEngine.java b/src/com/android/browser/search/OpenSearchSearchEngine.java new file mode 100644 index 0000000..e78a93c --- /dev/null +++ b/src/com/android/browser/search/OpenSearchSearchEngine.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser.search; + +import com.android.browser.R; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.params.HttpParams; +import org.apache.http.util.EntityUtils; +import org.json.JSONArray; +import org.json.JSONException; + +import android.app.SearchManager; +import android.content.Context; +import android.content.Intent; +import android.database.AbstractCursor; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.net.http.AndroidHttpClient; +import android.os.Bundle; +import android.provider.Browser; +import android.text.TextUtils; +import android.util.Log; + +import java.io.IOException; + +/** + * Provides search suggestions, if any, for a given web search provider. + */ +public class OpenSearchSearchEngine implements SearchEngine { + + private static final String TAG = "OpenSearchSearchEngine"; + + private static final String USER_AGENT = "Android/1.0"; + private static final int HTTP_TIMEOUT_MS = 1000; + + // TODO: this should be defined somewhere + private static final String HTTP_TIMEOUT = "http.connection-manager.timeout"; + + // Indices of the columns in the below arrays. + private static final int COLUMN_INDEX_ID = 0; + private static final int COLUMN_INDEX_QUERY = 1; + private static final int COLUMN_INDEX_ICON = 2; + private static final int COLUMN_INDEX_TEXT_1 = 3; + private static final int COLUMN_INDEX_TEXT_2 = 4; + + // The suggestion columns used. If you are adding a new entry to these arrays make sure to + // update the list of indices declared above. + private static final String[] COLUMNS = new String[] { + "_id", + SearchManager.SUGGEST_COLUMN_QUERY, + SearchManager.SUGGEST_COLUMN_ICON_1, + SearchManager.SUGGEST_COLUMN_TEXT_1, + SearchManager.SUGGEST_COLUMN_TEXT_2, + }; + + private static final String[] COLUMNS_WITHOUT_DESCRIPTION = new String[] { + "_id", + SearchManager.SUGGEST_COLUMN_QUERY, + SearchManager.SUGGEST_COLUMN_ICON_1, + SearchManager.SUGGEST_COLUMN_TEXT_1, + }; + + private final SearchEngineInfo mSearchEngineInfo; + + private final AndroidHttpClient mHttpClient; + + public OpenSearchSearchEngine(Context context, SearchEngineInfo searchEngineInfo) { + mSearchEngineInfo = searchEngineInfo; + mHttpClient = AndroidHttpClient.newInstance(USER_AGENT); + HttpParams params = mHttpClient.getParams(); + params.setLongParameter(HTTP_TIMEOUT, HTTP_TIMEOUT_MS); + } + + public String getName() { + return mSearchEngineInfo.getName(); + } + + public CharSequence getLabel() { + return mSearchEngineInfo.getLabel(); + } + + public void startSearch(Context context, String query, Bundle appData, String extraData) { + String uri = mSearchEngineInfo.getSearchUriForQuery(query); + if (uri == null) { + Log.e(TAG, "Unable to get search URI for " + mSearchEngineInfo); + } else { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri)); + // Make sure the intent goes to the Browser itself + intent.setPackage(context.getPackageName()); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.putExtra(SearchManager.QUERY, query); + if (appData != null) { + intent.putExtra(SearchManager.APP_DATA, appData); + } + if (extraData != null) { + intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); + } + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); + context.startActivity(intent); + } + } + + /** + * Queries for a given search term and returns a cursor containing + * suggestions ordered by best match. + */ + public Cursor getSuggestions(Context context, String query) { + if (TextUtils.isEmpty(query)) { + return null; + } + if (!isNetworkConnected(context)) { + Log.i(TAG, "Not connected to network."); + return null; + } + + String suggestUri = mSearchEngineInfo.getSuggestUriForQuery(query); + if (TextUtils.isEmpty(suggestUri)) { + // No suggest URI available for this engine + return null; + } + + try { + String content = readUrl(suggestUri); + if (content == null) return null; + /* The data format is a JSON array with items being regular strings or JSON arrays + * themselves. We are interested in the second and third elements, both of which + * should be JSON arrays. The second element/array contains the suggestions and the + * third element contains the descriptions. Some search engines don't support + * suggestion descriptions so the third element is optional. + */ + JSONArray results = new JSONArray(content); + JSONArray suggestions = results.getJSONArray(1); + JSONArray descriptions = null; + if (results.length() > 2) { + descriptions = results.getJSONArray(2); + // Some search engines given an empty array "[]" for descriptions instead of + // not including it in the response. + if (descriptions.length() == 0) { + descriptions = null; + } + } + return new SuggestionsCursor(suggestions, descriptions); + } catch (JSONException e) { + Log.w(TAG, "Error", e); + } + return null; + } + + /** + * Executes a GET request and returns the response content. + * + * @param url Request URI. + * @param requestHeaders Request headers. + * @return The response content. This is the empty string if the response + * contained no content. + */ + public String readUrl(String url) { + try { + HttpGet method = new HttpGet(url); + HttpResponse response = mHttpClient.execute(method); + if (response.getStatusLine().getStatusCode() == 200) { + return EntityUtils.toString(response.getEntity()); + } else { + Log.i(TAG, "Suggestion request failed"); + return null; + } + } catch (IOException e) { + Log.w(TAG, "Error", e); + return null; + } + } + + public boolean supportsSuggestions() { + return mSearchEngineInfo.supportsSuggestions(); + } + + public void close() { + mHttpClient.close(); + } + + private boolean isNetworkConnected(Context context) { + NetworkInfo networkInfo = getActiveNetworkInfo(context); + return networkInfo != null && networkInfo.isConnected(); + } + + private NetworkInfo getActiveNetworkInfo(Context context) { + ConnectivityManager connectivity = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity == null) { + return null; + } + return connectivity.getActiveNetworkInfo(); + } + + private static class SuggestionsCursor extends AbstractCursor { + + private final JSONArray mSuggestions; + + private final JSONArray mDescriptions; + + public SuggestionsCursor(JSONArray suggestions, JSONArray descriptions) { + mSuggestions = suggestions; + mDescriptions = descriptions; + } + + @Override + public int getCount() { + return mSuggestions.length(); + } + + @Override + public String[] getColumnNames() { + return (mDescriptions != null ? COLUMNS : COLUMNS_WITHOUT_DESCRIPTION); + } + + @Override + public String getString(int column) { + if (mPos != -1) { + if ((column == COLUMN_INDEX_QUERY) || (column == COLUMN_INDEX_TEXT_1)) { + try { + return mSuggestions.getString(mPos); + } catch (JSONException e) { + Log.w(TAG, "Error", e); + } + } else if (column == COLUMN_INDEX_TEXT_2) { + try { + return mDescriptions.getString(mPos); + } catch (JSONException e) { + Log.w(TAG, "Error", e); + } + } else if (column == COLUMN_INDEX_ICON) { + return String.valueOf(R.drawable.magnifying_glass); + } + } + return null; + } + + @Override + public double getDouble(int column) { + throw new UnsupportedOperationException(); + } + + @Override + public float getFloat(int column) { + throw new UnsupportedOperationException(); + } + + @Override + public int getInt(int column) { + throw new UnsupportedOperationException(); + } + + @Override + public long getLong(int column) { + if (column == COLUMN_INDEX_ID) { + return mPos; // use row# as the _Id + } + throw new UnsupportedOperationException(); + } + + @Override + public short getShort(int column) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isNull(int column) { + throw new UnsupportedOperationException(); + } + } + + @Override + public String toString() { + return "OpenSearchSearchEngine{" + mSearchEngineInfo + "}"; + } + +} diff --git a/src/com/android/browser/search/SearchEngine.java b/src/com/android/browser/search/SearchEngine.java new file mode 100644 index 0000000..3d24d2e --- /dev/null +++ b/src/com/android/browser/search/SearchEngine.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser.search; + +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; + +/** + * Interface for search engines. + */ +public interface SearchEngine { + + /** + * Gets the unique name of this search engine. + */ + public String getName(); + + /** + * Gets the human-readable name of this search engine. + */ + public CharSequence getLabel(); + + /** + * Starts a search. + */ + public void startSearch(Context context, String query, Bundle appData, String extraData); + + /** + * Gets search suggestions. + */ + public Cursor getSuggestions(Context context, String query); + + /** + * Checks whether this search engine supports search suggestions. + */ + public boolean supportsSuggestions(); + + /** + * Closes this search engine. + */ + public void close(); + +} diff --git a/src/com/android/browser/search/SearchEngineInfo.java b/src/com/android/browser/search/SearchEngineInfo.java new file mode 100644 index 0000000..6f0b1d5 --- /dev/null +++ b/src/com/android/browser/search/SearchEngineInfo.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser.search; + +import android.content.Context; +import android.content.res.Resources; +import android.text.TextUtils; +import android.util.Log; + +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.Locale; + +/** + * Loads and holds data for a given web search engine. + */ +public class SearchEngineInfo { + + private static String TAG = "SearchEngineInfo"; + + // The fields of a search engine data array, defined in the same order as they appear in the + // all_search_engines.xml file. + // If you are adding/removing to this list, remember to update NUM_FIELDS below. + private static final int FIELD_LABEL = 0; + private static final int FIELD_KEYWORD = 1; + private static final int FIELD_FAVICON_URI = 2; + private static final int FIELD_SEARCH_URI = 3; + private static final int FIELD_ENCODING = 4; + private static final int FIELD_SUGGEST_URI = 5; + private static final int NUM_FIELDS = 6; + + // The OpenSearch URI template parameters that we support. + private static final String PARAMETER_LANGUAGE = "{language}"; + private static final String PARAMETER_SEARCH_TERMS = "{searchTerms}"; + private static final String PARAMETER_INPUT_ENCODING = "{inputEncoding}"; + + private final String mName; + + // The array of strings defining this search engine. The array values are in the same order as + // the above enumeration definition. + private final String[] mSearchEngineData; + + /** + * @throws IllegalArgumentException If the name does not refer to a valid search engine + */ + public SearchEngineInfo(Context context, String name) throws IllegalArgumentException { + mName = name; + + Resources res = context.getResources(); + int id_data = res.getIdentifier(name, "array", context.getPackageName()); + mSearchEngineData = res.getStringArray(id_data); + + if (mSearchEngineData == null) { + throw new IllegalArgumentException("No data found for " + name); + } + if (mSearchEngineData.length != NUM_FIELDS) { + throw new IllegalArgumentException( + name + " has invalid number of fields - " + mSearchEngineData.length); + } + if (TextUtils.isEmpty(mSearchEngineData[FIELD_SEARCH_URI])) { + throw new IllegalArgumentException(name + " has an empty search URI"); + } + + // Add the current language/country information to the URIs. + Locale locale = context.getResources().getConfiguration().locale; + StringBuilder language = new StringBuilder(locale.getLanguage()); + if (!TextUtils.isEmpty(locale.getCountry())) { + language.append('-'); + language.append(locale.getCountry()); + } + + String language_str = language.toString(); + mSearchEngineData[FIELD_SEARCH_URI] = + mSearchEngineData[FIELD_SEARCH_URI].replace(PARAMETER_LANGUAGE, language_str); + mSearchEngineData[FIELD_SUGGEST_URI] = + mSearchEngineData[FIELD_SUGGEST_URI].replace(PARAMETER_LANGUAGE, language_str); + + // Default to UTF-8 if not specified. + String enc = mSearchEngineData[FIELD_ENCODING]; + if (TextUtils.isEmpty(enc)) { + enc = "UTF-8"; + mSearchEngineData[FIELD_ENCODING] = enc; + } + + // Add the input encoding method to the URI. + mSearchEngineData[FIELD_SEARCH_URI] = + mSearchEngineData[FIELD_SEARCH_URI].replace(PARAMETER_INPUT_ENCODING, enc); + mSearchEngineData[FIELD_SUGGEST_URI] = + mSearchEngineData[FIELD_SUGGEST_URI].replace(PARAMETER_INPUT_ENCODING, enc); + } + + public String getName() { + return mName; + } + + public String getLabel() { + return mSearchEngineData[FIELD_LABEL]; + } + + /** + * Returns the URI for launching a web search with the given query (or null if there was no + * data available for this search engine). + */ + public String getSearchUriForQuery(String query) { + return getFormattedUri(searchUri(), query); + } + + /** + * Returns the URI for retrieving web search suggestions for the given query (or null if there + * was no data available for this search engine). + */ + public String getSuggestUriForQuery(String query) { + return getFormattedUri(suggestUri(), query); + } + + public boolean supportsSuggestions() { + return !TextUtils.isEmpty(suggestUri()); + } + + public String faviconUri() { + return mSearchEngineData[FIELD_FAVICON_URI]; + } + + private String suggestUri() { + return mSearchEngineData[FIELD_SUGGEST_URI]; + } + + private String searchUri() { + return mSearchEngineData[FIELD_SEARCH_URI]; + } + + /** + * Formats a launchable uri out of the template uri by replacing the template parameters with + * actual values. + */ + private String getFormattedUri(String templateUri, String query) { + if (TextUtils.isEmpty(templateUri)) { + return null; + } + + // Encode the query terms in the requested encoding (and fallback to UTF-8 if not). + String enc = mSearchEngineData[FIELD_ENCODING]; + try { + return templateUri.replace(PARAMETER_SEARCH_TERMS, URLEncoder.encode(query, enc)); + } catch (java.io.UnsupportedEncodingException e) { + Log.e(TAG, "Exception occured when encoding query " + query + " to " + enc); + return null; + } + } + + @Override + public String toString() { + return "SearchEngineInfo{" + Arrays.toString(mSearchEngineData) + "}"; + } + +} diff --git a/src/com/android/browser/search/SearchEnginePreference.java b/src/com/android/browser/search/SearchEnginePreference.java new file mode 100644 index 0000000..18ce495 --- /dev/null +++ b/src/com/android/browser/search/SearchEnginePreference.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser.search; + +import com.android.browser.R; + +import android.app.SearchManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.preference.ListPreference; +import android.util.AttributeSet; +import android.util.Log; + +import java.util.ArrayList; + +class SearchEnginePreference extends ListPreference { + + private static final String TAG = "SearchEnginePreference"; + + public SearchEnginePreference(Context context, AttributeSet attrs) { + super(context, attrs); + + ArrayList entryValues = new ArrayList(); + ArrayList entries = new ArrayList(); + + SearchEngine defaultSearchEngine = SearchEngines.getDefaultSearchEngine(context); + String defaultSearchEngineName = null; + if (defaultSearchEngine != null) { + defaultSearchEngineName = defaultSearchEngine.getName(); + entryValues.add(defaultSearchEngineName); + entries.add(defaultSearchEngine.getLabel()); + } + for (SearchEngineInfo searchEngineInfo : SearchEngines.getSearchEngineInfos(context)) { + String name = searchEngineInfo.getName(); + // Skip entry with same name as default provider + if (!name.equals(defaultSearchEngineName)) { + entryValues.add(name); + entries.add(searchEngineInfo.getLabel()); + } + } + + setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()])); + setEntries(entries.toArray(new CharSequence[entries.size()])); + } + +} diff --git a/src/com/android/browser/search/SearchEngines.java b/src/com/android/browser/search/SearchEngines.java new file mode 100644 index 0000000..62690e7 --- /dev/null +++ b/src/com/android/browser/search/SearchEngines.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser.search; + +import com.android.browser.R; + +import android.app.SearchManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +public class SearchEngines { + + private static final String TAG = "SearchEngines"; + + public static SearchEngine getDefaultSearchEngine(Context context) { + return DefaultSearchEngine.create(context); + } + + public static List getSearchEngineInfos(Context context) { + ArrayList searchEngineInfos = new ArrayList(); + Resources res = context.getResources(); + String[] searchEngines = res.getStringArray(R.array.search_engines); + for (int i = 0; i < searchEngines.length; i++) { + String name = searchEngines[i]; + SearchEngineInfo info = new SearchEngineInfo(context, name); + searchEngineInfos.add(info); + } + return searchEngineInfos; + } + + public static SearchEngine get(Context context, String name) { + // TODO: cache + SearchEngine defaultSearchEngine = getDefaultSearchEngine(context); + if (TextUtils.isEmpty(name) + || (defaultSearchEngine != null && name.equals(defaultSearchEngine.getName()))) { + return defaultSearchEngine; + } + SearchEngineInfo searchEngineInfo = getSearchEngineInfo(context, name); + if (searchEngineInfo == null) return defaultSearchEngine; + return new OpenSearchSearchEngine(context, searchEngineInfo); + } + + private static SearchEngineInfo getSearchEngineInfo(Context context, String name) { + try { + return new SearchEngineInfo(context, name); + } catch (IllegalArgumentException exception) { + Log.e(TAG, "Cannot load search engine " + name, exception); + return null; + } + } + +} diff --git a/tools/all_search_engines.template.xml b/tools/all_search_engines.template.xml new file mode 100644 index 0000000..a8d0c89 --- /dev/null +++ b/tools/all_search_engines.template.xml @@ -0,0 +1,40 @@ + + + + + + + + + diff --git a/tools/get_search_engines.py b/tools/get_search_engines.py new file mode 100755 index 0000000..2eecec3 --- /dev/null +++ b/tools/get_search_engines.py @@ -0,0 +1,258 @@ +#!/usr/bin/python2.4 +# +# Copyright (C) 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +""" +Creates the list of search engines + +The created list is placed in the res/values- directory. Also updates +res/values/all_search_engines.xml if required with new data. + +Usage: get_search_engines.py + +Copyright (C) 2010 The Android Open Source Project +""" + +import os +import re +import sys +import urllib +from xml.dom import minidom + +# Locales to generate search engine lists for +locales = ["cs-CZ", "da-DK", "de-AT", "de-CH", "de-DE", "el-GR", "en-AU", + "en-GB", "en-IE", "en-NZ", "en-SG", "en-ZA", "es-ES", "fr-BE", "fr-FR", + "it-IT", "ja-JP", "ko-KR", "nb-NO", "nl-BE", "nl-NL", "pl-PL", "pt-PT", + "pt-BR", "ru-RU", "sv-SE", "tr-TR", "zh-CN", "zh-HK", "zh-MO", "zh-TW"] + +class SearchEngineManager(object): + """Manages list of search engines and creates locale specific lists. + + The main method useful for the caller is generateListForLocale(), which + creates a locale specific search_engines.xml file suitable for use by the + Android WebSearchProvider implementation. + """ + + def __init__(self): + """Inits SearchEngineManager with relevant search engine data. + + The search engine data is downloaded from the Chrome source repository. + """ + self.chrome_data = urllib.urlopen( + 'http://src.chromium.org/viewvc/chrome/trunk/src/chrome/' + 'browser/search_engines/template_url_prepopulate_data.cc').read() + if self.chrome_data.lower().find('repository not found') != -1: + print 'Unable to get Chrome source data for search engine list.\nExiting.' + sys.exit(2) + + self.resdir = os.path.normpath(os.path.join(sys.path[0], '../res')) + + self.all_engines = set() + + def getXmlString(self, str): + """Returns an XML-safe string for the given string. + + Given a string from the search engine data structure, convert it to a + string suitable to write to our XML data file by stripping away NULLs, + unwanted quotes, wide-string declarations (L"") and replacing C-style + unicode characters with XML equivalents. + """ + str = str.strip() + if str.upper() == 'NULL': + return '' + + if str.startswith('L"'): + str = str[2:] + if str.startswith('@') or str.startswith('?'): + str = '\\' + str + + str = str.strip('"') + str = str.replace('&', '&').replace('<', '<').replace('>', '>') + str = str.replace('"', '"').replace('\'', ''') + str = re.sub(r'\\x([a-fA-F0-9]+)', r'&#x\1;', str) + + return str + + def getEngineData(self, name): + """Returns an array of strings describing the specified search engine. + + The returned strings are in the same order as in the Chrome source data file + except that the internal name of the search engine is inserted at the + beginning of the list. + """ + # Find the first occurance of this search engine name in the form + # " =" in the chrome data file. + re_exp = '\s' + name + '\s*=' + search_obj = re.search(re_exp, self.chrome_data) + if not search_obj: + print ('Unable to find data for search engine ' + name + + '. Please check the chrome data file for format changes.') + return None + + # Extract the struct declaration between the curly braces. + start_pos = self.chrome_data.find('{', search_obj.start()) + 1; + end_pos = self.chrome_data.find('};', start_pos); + engine_data_str = self.chrome_data[start_pos:end_pos] + + # Remove c++ style '//' comments at the ends of each line + engine_data_lines = engine_data_str.split('\n') + engine_data_str = "" + for line in engine_data_lines: + start_pos = line.find(' // ') + if start_pos != -1: + line = line[:start_pos] + engine_data_str = engine_data_str + line + '\n' + + # Join multiple line strings into a single string. + engine_data_str = re.sub('\"\s+\"', '', engine_data_str) + engine_data_str = re.sub('\"\s+L\"', '', engine_data_str) + engine_data_str = engine_data_str.replace('"L"', '') + + engine_data = engine_data_str.split(',') + for i in range(len(engine_data)): + engine_data[i] = self.getXmlString(engine_data[i]) + + # If the last element was an empty string (due to an extra comma at the + # end), ignore it. + if not engine_data[len(engine_data) - 1]: + engine_data.pop() + + engine_data.insert(0, name) + + return engine_data + + def getSearchEnginesForCountry(self, country): + """Returns the list of search engine names for the given country. + + The data comes from the Chrome data file. + """ + # The Chrome data file has an array defined with the name 'engines_XX' + # where XX = country. + pos = self.chrome_data.find('engines_' + country) + if pos == -1: + print ('Unable to find search engine data for country ' + country + '.') + return + + # Extract the text between the curly braces for this array declaration + engines_start = self.chrome_data.find('{', pos) + 1; + engines_end = self.chrome_data.find('}', engines_start); + engines_str = self.chrome_data[engines_start:engines_end] + + # Remove embedded /**/ style comments, white spaces, address-of operators + # and the trailing comma if any. + engines_str = re.sub('\/\*.+\*\/', '', engines_str) + engines_str = re.sub('\s+', '', engines_str) + engines_str = engines_str.replace('&','') + engines_str = engines_str.rstrip(',') + + # Split the array into it's elements + engines = engines_str.split(',') + + return engines + + def writeAllEngines(self): + """Writes all search engines to the all_search_engines.xml file. + """ + + all_search_engines_path = os.path.join(self.resdir, 'values/all_search_engines.xml') + + text = [] + + for engine_name in self.all_engines: + engine_data = self.getEngineData(engine_name) + text.append(' \n' % (engine_data[0])) + for i in range(1, 7): + text.append(' %s\n' % (engine_data[i])) + text.append(' \n') + print engine_data[1] + " added to all_search_engines.xml" + + self.generateXmlFromTemplate(os.path.join(sys.path[0], 'all_search_engines.template.xml'), + all_search_engines_path, text) + + def generateDefaultList(self): + self.writeEngineList(os.path.join(self.resdir, 'values'), "default") + + def generateListForLocale(self, locale): + """Creates a new locale specific search_engines.xml file. + + The new file contains search engines specific to that country. If required + this function updates all_search_engines.xml file with any new search + engine data necessary. + """ + separator_pos = locale.find('-') + if separator_pos == -1: + print ('Locale must be of format -. For e.g.' + ' "es-US" or "en-GB"') + return + + language = locale[0:separator_pos] + country = locale[separator_pos + 1:].upper() + dir_path = os.path.join(self.resdir, 'values-' + language + '-r' + country) + + self.writeEngineList(dir_path, country) + + def writeEngineList(self, dir_path, country): + if os.path.exists(dir_path) and not os.path.isdir(dir_path): + print "File exists in output directory path " + dir_path + ". Please remove it and try again." + return + + engines = self.getSearchEnginesForCountry(country) + if not engines: + return + for engine in engines: + self.all_engines.add(engine) + + # Create the locale specific search_engines.xml file. Each + # search_engines.xml file has a hardcoded list of 7 items. If there are less + # than 7 search engines for this country, the remaining items are marked as + # enabled=false. + text = [] + text.append(' \n'); + for engine in engines: + engine_data = self.getEngineData(engine) + name = engine_data[0] + text.append(' %s\n' % (name)) + text.append(' \n'); + + self.generateXmlFromTemplate(os.path.join(sys.path[0], 'search_engines.template.xml'), + os.path.join(dir_path, 'search_engines.xml'), + text) + + def generateXmlFromTemplate(self, template_path, out_path, text): + # Load the template file and insert the new contents before the last line. + template_text = open(template_path).read() + pos = template_text.rfind('\n', 0, -2) + 1 + contents = template_text[0:pos] + ''.join(text) + template_text[pos:] + + # Make sure what we have created is valid XML :) No need to check for errors + # as the script will terminate with an exception if the XML was malformed. + engines_dom = minidom.parseString(contents) + + dir_path = os.path.dirname(out_path) + if not os.path.exists(dir_path): + os.makedirs(dir_path) + print 'Created directory ' + dir_path + file = open(out_path, 'w') + file.write(contents) + file.close() + print 'Wrote ' + out_path + +if __name__ == "__main__": + manager = SearchEngineManager() + manager.generateDefaultList() + for locale in locales: + manager.generateListForLocale(locale) + manager.writeAllEngines() + diff --git a/tools/search_engines.template.xml b/tools/search_engines.template.xml new file mode 100755 index 0000000..553d333 --- /dev/null +++ b/tools/search_engines.template.xml @@ -0,0 +1,24 @@ + + + + + -- cgit v1.1