1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.browser.search;
17 
18 import android.content.Context;
19 import android.content.res.Resources;
20 import android.content.res.Resources.NotFoundException;
21 import android.text.TextUtils;
22 import android.util.Log;
23 
24 import com.android.browser.R;
25 
26 import java.net.URLEncoder;
27 import java.util.Arrays;
28 import java.util.Locale;
29 
30 /**
31  * Loads and holds data for a given web search engine.
32  */
33 public class SearchEngineInfo {
34 
35     private static String TAG = "SearchEngineInfo";
36 
37     // The fields of a search engine data array, defined in the same order as they appear in the
38     // all_search_engines.xml file.
39     // If you are adding/removing to this list, remember to update NUM_FIELDS below.
40     private static final int FIELD_LABEL = 0;
41     private static final int FIELD_KEYWORD = 1;
42     private static final int FIELD_FAVICON_URI = 2;
43     private static final int FIELD_SEARCH_URI = 3;
44     private static final int FIELD_ENCODING = 4;
45     private static final int FIELD_SUGGEST_URI = 5;
46     private static final int NUM_FIELDS = 6;
47 
48     // The OpenSearch URI template parameters that we support.
49     private static final String PARAMETER_LANGUAGE = "{language}";
50     private static final String PARAMETER_SEARCH_TERMS = "{searchTerms}";
51     private static final String PARAMETER_INPUT_ENCODING = "{inputEncoding}";
52 
53     private final String mName;
54 
55     // The array of strings defining this search engine. The array values are in the same order as
56     // the above enumeration definition.
57     private final String[] mSearchEngineData;
58 
59     /**
60      * @throws IllegalArgumentException If the name does not refer to a valid search engine
61      */
SearchEngineInfo(Context context, String name)62     public SearchEngineInfo(Context context, String name) throws IllegalArgumentException {
63         mName = name;
64         Resources res = context.getResources();
65 
66         String packageName = R.class.getPackage().getName();
67         int id_data = res.getIdentifier(name, "array", packageName);
68         if (id_data == 0) {
69             throw new IllegalArgumentException("No resources found for " + name);
70         }
71         mSearchEngineData = res.getStringArray(id_data);
72 
73         if (mSearchEngineData == null) {
74             throw new IllegalArgumentException("No data found for " + name);
75         }
76         if (mSearchEngineData.length != NUM_FIELDS) {
77                 throw new IllegalArgumentException(
78                         name + " has invalid number of fields - " + mSearchEngineData.length);
79         }
80         if (TextUtils.isEmpty(mSearchEngineData[FIELD_SEARCH_URI])) {
81             throw new IllegalArgumentException(name + " has an empty search URI");
82         }
83 
84         // Add the current language/country information to the URIs.
85         Locale locale = context.getResources().getConfiguration().locale;
86         StringBuilder language = new StringBuilder(locale.getLanguage());
87         if (!TextUtils.isEmpty(locale.getCountry())) {
88             language.append('-');
89             language.append(locale.getCountry());
90         }
91 
92         String language_str = language.toString();
93         mSearchEngineData[FIELD_SEARCH_URI] =
94                 mSearchEngineData[FIELD_SEARCH_URI].replace(PARAMETER_LANGUAGE, language_str);
95         mSearchEngineData[FIELD_SUGGEST_URI] =
96                 mSearchEngineData[FIELD_SUGGEST_URI].replace(PARAMETER_LANGUAGE, language_str);
97 
98         // Default to UTF-8 if not specified.
99         String enc = mSearchEngineData[FIELD_ENCODING];
100         if (TextUtils.isEmpty(enc)) {
101             enc = "UTF-8";
102             mSearchEngineData[FIELD_ENCODING] = enc;
103         }
104 
105         // Add the input encoding method to the URI.
106         mSearchEngineData[FIELD_SEARCH_URI] =
107                 mSearchEngineData[FIELD_SEARCH_URI].replace(PARAMETER_INPUT_ENCODING, enc);
108         mSearchEngineData[FIELD_SUGGEST_URI] =
109                 mSearchEngineData[FIELD_SUGGEST_URI].replace(PARAMETER_INPUT_ENCODING, enc);
110     }
111 
getName()112     public String getName() {
113         return mName;
114     }
115 
getLabel()116     public String getLabel() {
117         return mSearchEngineData[FIELD_LABEL];
118     }
119 
120     /**
121      * Returns the URI for launching a web search with the given query (or null if there was no
122      * data available for this search engine).
123      */
getSearchUriForQuery(String query)124     public String getSearchUriForQuery(String query) {
125         return getFormattedUri(searchUri(), query);
126     }
127 
128     /**
129      * Returns the URI for retrieving web search suggestions for the given query (or null if there
130      * was no data available for this search engine).
131      */
getSuggestUriForQuery(String query)132     public String getSuggestUriForQuery(String query) {
133         return getFormattedUri(suggestUri(), query);
134     }
135 
supportsSuggestions()136     public boolean supportsSuggestions() {
137         return !TextUtils.isEmpty(suggestUri());
138     }
139 
faviconUri()140     public String faviconUri() {
141         return mSearchEngineData[FIELD_FAVICON_URI];
142     }
143 
suggestUri()144     private String suggestUri() {
145         return mSearchEngineData[FIELD_SUGGEST_URI];
146     }
147 
searchUri()148     private String searchUri() {
149         return mSearchEngineData[FIELD_SEARCH_URI];
150     }
151 
152     /**
153      * Formats a launchable uri out of the template uri by replacing the template parameters with
154      * actual values.
155      */
getFormattedUri(String templateUri, String query)156     private String getFormattedUri(String templateUri, String query) {
157         if (TextUtils.isEmpty(templateUri)) {
158             return null;
159         }
160 
161         // Encode the query terms in the requested encoding (and fallback to UTF-8 if not).
162         String enc = mSearchEngineData[FIELD_ENCODING];
163         try {
164             return templateUri.replace(PARAMETER_SEARCH_TERMS, URLEncoder.encode(query, enc));
165         } catch (java.io.UnsupportedEncodingException e) {
166             Log.e(TAG, "Exception occured when encoding query " + query + " to " + enc);
167             return null;
168         }
169     }
170 
171     @Override
toString()172     public String toString() {
173         return "SearchEngineInfo{" + Arrays.toString(mSearchEngineData) + "}";
174     }
175 
176 }
177