SearchBaseUrlHelper.java revision 964deade9111e08f22dce9c3c97b84e9c0f5b27a
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
17package com.android.quicksearchbox.google;
18
19import com.android.quicksearchbox.R;
20import com.android.quicksearchbox.SearchSettings;
21import com.android.quicksearchbox.SearchSettingsImpl;
22import com.android.quicksearchbox.util.HttpHelper;
23
24import android.content.Context;
25import android.content.SharedPreferences;
26import android.os.AsyncTask;
27import android.os.Handler;
28import android.text.TextUtils;
29import android.util.Log;
30
31import java.util.Locale;
32
33/**
34 * Helper to build the base URL for all search requests.
35 */
36public class SearchBaseUrlHelper implements SharedPreferences.OnSharedPreferenceChangeListener {
37    private static final boolean DBG = false;
38    private static final String TAG = "QSB.SearchBaseUrlHelper";
39
40    private static final String DOMAIN_CHECK_URL =
41            "https://www.google.com/searchdomaincheck?format=domain";
42
43    private static final long SEARCH_BASE_URL_EXPIRY_MS = 24 * 3600 * 1000L;
44
45    private final HttpHelper mHttpHelper;
46    private final Context mContext;
47    private final SearchSettings mSearchSettings;
48
49    /**
50     * Note that this constructor will spawn a thread to issue a HTTP
51     * request if shouldUseGoogleCom is false.
52     */
53    public SearchBaseUrlHelper(Context context, HttpHelper helper,
54            SearchSettings searchSettings, SharedPreferences prefs) {
55        mHttpHelper = helper;
56        mContext = context;
57        mSearchSettings = searchSettings;
58
59        // Note: This earlier used an inner class, but that causes issues
60        // because SharedPreferencesImpl uses a WeakHashMap< > and the listener
61        // will be GC'ed unless we keep a reference to it here.
62        prefs.registerOnSharedPreferenceChangeListener(this);
63
64        maybeUpdateBaseUrlSetting(false);
65    }
66
67    /**
68     * Update the base search url, either:
69     * (a) it has never been set (first run)
70     * (b) it has expired
71     * (c) if the caller forces an update by setting the "force" parameter.
72     *
73     * @param force if true, then the URL is reset whether or not it has
74     *     expired.
75     */
76    public void maybeUpdateBaseUrlSetting(boolean force) {
77        long lastUpdateTime = mSearchSettings.getSearchBaseUrlApplyTime();
78        long currentTime = System.currentTimeMillis();
79
80        if (force || lastUpdateTime == -1 ||
81                currentTime - lastUpdateTime >= SEARCH_BASE_URL_EXPIRY_MS) {
82            if (mSearchSettings.shouldUseGoogleCom()) {
83                setSearchBaseUrl(getDefaultBaseUrl());
84            } else {
85                checkSearchDomain();
86            }
87        }
88    }
89
90    /**
91     * @return the base url for searches.
92     */
93    public String getSearchBaseUrl() {
94        String domain = mSearchSettings.getSearchBaseUrl();
95        if (TextUtils.isEmpty(domain)) domain = getDefaultBaseUrl();
96        return domain;
97    }
98
99    /**
100     * @return the search domain. This is of the form "google.co.xx" or "google.com",
101     *     used by UI code.
102     */
103    public String getSearchDomain() {
104        String baseUrl = getSearchBaseUrl();
105
106        final int start = baseUrl.indexOf(".google.");
107        final int endMobile = baseUrl.indexOf("/m");
108        final int endDesktop = baseUrl.indexOf("/search");
109        if (start > 0) {
110            if (endMobile > 0) {
111                // This is a mobile URL. (/m)
112                return baseUrl.substring(start + 1, endMobile);
113            }
114            if (endDesktop > 0) {
115                // This is a desktop URL. (/search)
116                return baseUrl.substring(start + 1, endDesktop);
117            }
118        }
119
120        if (DBG) Log.w(TAG, "Unable to extract search domain from URL" + baseUrl);
121
122        return baseUrl;
123    }
124
125    /**
126     * Issue a request to google.com/searchdomaincheck to retrieve the base
127     * URL for search requests.
128     */
129    private void checkSearchDomain() {
130        final HttpHelper.GetRequest request = new HttpHelper.GetRequest(DOMAIN_CHECK_URL);
131
132        new AsyncTask<Void, Void, Void>() {
133            @Override
134            protected Void doInBackground(Void ... params) {
135                if (DBG) Log.d(TAG, "Starting request to /searchdomaincheck");
136                String domain;
137                try {
138                    domain = mHttpHelper.get(request);
139                } catch (Exception e) {
140                    if (DBG) Log.d(TAG, "Request to /searchdomaincheck failed : " + e);
141                    // Swallow any exceptions thrown by the HTTP helper, in
142                    // this rare case, we just use the default URL.
143                    setSearchBaseUrl(getDefaultBaseUrl());
144
145                    return null;
146                }
147
148                String searchDomain = mContext.getResources().getString(
149                        R.string.google_search_base_pattern, domain,
150                        GoogleSearch.getLanguage(Locale.getDefault()));
151
152                if (DBG) Log.d(TAG, "Request to /searchdomaincheck succeeded");
153                setSearchBaseUrl(searchDomain);
154                return null;
155            }
156        }.execute();
157    }
158
159    private String getDefaultBaseUrl() {
160        return (mContext.getResources().getString(
161                R.string.google_search_base,
162                GoogleSearch.getLanguage(Locale.getDefault())));
163    }
164
165    private void setSearchBaseUrl(String searchDomain) {
166        if (DBG) Log.d(TAG, "Setting search domain to : " + searchDomain);
167
168        mSearchSettings.setSearchBaseUrl(searchDomain);
169    }
170
171    @Override
172    public void onSharedPreferenceChanged(SharedPreferences pref, String key) {
173        // Listen for changes only to the SEARCH_BASE_URL preference.
174        if (DBG) Log.d(TAG, "Handling changed preference : " + key);
175        if (SearchSettingsImpl.USE_GOOGLE_COM_PREF.equals(key)) {
176            maybeUpdateBaseUrlSetting(true);
177        }
178    }
179}