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 */
16package com.android.browser.search;
17
18import android.content.Context;
19import android.content.res.Resources;
20import android.content.res.Resources.NotFoundException;
21import android.text.TextUtils;
22import android.util.Log;
23
24import com.android.browser.R;
25
26import java.net.URLEncoder;
27import java.util.Arrays;
28import java.util.Locale;
29
30/**
31 * Loads and holds data for a given web search engine.
32 */
33public 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     */
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
112    public String getName() {
113        return mName;
114    }
115
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     */
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     */
132    public String getSuggestUriForQuery(String query) {
133        return getFormattedUri(suggestUri(), query);
134    }
135
136    public boolean supportsSuggestions() {
137        return !TextUtils.isEmpty(suggestUri());
138    }
139
140    public String faviconUri() {
141        return mSearchEngineData[FIELD_FAVICON_URI];
142    }
143
144    private String suggestUri() {
145        return mSearchEngineData[FIELD_SUGGEST_URI];
146    }
147
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     */
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
172    public String toString() {
173        return "SearchEngineInfo{" + Arrays.toString(mSearchEngineData) + "}";
174    }
175
176}
177