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