GoogleSearch.java revision 18c681a8ab3c5227fb536501572c96b92c914a07
1/*
2 * Copyright (C) 2008 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;
20
21import com.google.android.providers.GoogleSettings.Partner;
22
23import android.app.Activity;
24import android.app.SearchManager;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.location.Location;
29import android.location.LocationManager;
30import android.net.Uri;
31import android.os.Bundle;
32import android.provider.Browser;
33import android.provider.Settings;
34import android.text.TextUtils;
35import android.util.Log;
36
37import java.io.UnsupportedEncodingException;
38import java.net.URLEncoder;
39import java.util.Locale;
40
41/**
42 * This class is purely here to get search queries and route them to
43 * the global {@link Intent#ACTION_WEB_SEARCH}.
44 */
45public class GoogleSearch extends Activity {
46    private static final String TAG = "GoogleSearch";
47
48    // The template URL we should use to format google search requests.
49    private String googleSearchUrlBase = null;
50
51    // "source" parameter for Google search requests from unknown sources (e.g. apps). This will get
52    // prefixed with the string 'android-' before being sent on the wire.
53    final static String GOOGLE_SEARCH_SOURCE_UNKNOWN = "unknown";
54
55    private LocationUtils mLocationUtils;
56
57    @Override
58    protected void onCreate(Bundle savedInstanceState) {
59        super.onCreate(savedInstanceState);
60        mLocationUtils = LocationUtils.getLocationUtils(this);
61        Intent intent = getIntent();
62        String action = intent != null ? intent.getAction() : null;
63        if (Intent.ACTION_WEB_SEARCH.equals(action) || Intent.ACTION_SEARCH.equals(action)) {
64            handleWebSearchIntent(intent);
65        }
66        finish();
67    }
68
69    /**
70     * NOTE: This function is similar to the one found in
71     * com.google.android.providers.enhancedgooglesearch.Launcher. If you are changing this
72     * make sure you change both.
73     */
74    private void handleWebSearchIntent(Intent intent) {
75        String query = intent.getStringExtra(SearchManager.QUERY);
76        if (TextUtils.isEmpty(query)) {
77            Log.w(TAG, "Got search intent with no query.");
78            return;
79        }
80
81        if (googleSearchUrlBase == null) {
82            Locale l = Locale.getDefault();
83            String language = l.getLanguage();
84            String country = l.getCountry().toLowerCase();
85            // Chinese and Portuguese have two langauge variants.
86            if ("zh".equals(language)) {
87                if ("cn".equals(country)) {
88                    language = "zh-CN";
89                } else if ("tw".equals(country)) {
90                    language = "zh-TW";
91                }
92            } else if ("pt".equals(language)) {
93                if ("br".equals(country)) {
94                    language = "pt-BR";
95                } else if ("pt".equals(country)) {
96                    language = "pt-PT";
97                }
98            }
99            googleSearchUrlBase = getResources().getString(
100                    R.string.google_search_base, language, country)
101                    + "client=ms-"
102                    + Partner.getString(this.getContentResolver(), Partner.CLIENT_ID);
103        }
104
105        // If the caller specified a 'source' url parameter, use that and if not use default.
106        Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA);
107        String source = GOOGLE_SEARCH_SOURCE_UNKNOWN;
108        if (appSearchData != null) {
109            source = appSearchData.getString(SearchManager.SOURCE);
110        }
111
112        // The browser can pass along an application id which it uses to figure out which
113        // window to place a new search into. So if this exists, we'll pass it back to
114        // the browser. Otherwise, add our own package name as the application id, so that
115        // the browser can organize all searches launched from this provider together.
116        String applicationId = intent.getStringExtra(Browser.EXTRA_APPLICATION_ID);
117        if (applicationId == null) {
118            applicationId = getPackageName();
119        }
120
121        try {
122            String searchUri = googleSearchUrlBase
123                    + "&source=android-" + source
124                    + "&q=" + URLEncoder.encode(query, "UTF-8");
125            Intent launchUriIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri));
126            launchUriIntent.putExtra(Browser.EXTRA_APPLICATION_ID, applicationId);
127            launchUriIntent.putExtra(Browser.EXTRA_POST_DATA, getLocationData());
128            launchUriIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
129            startActivity(launchUriIntent);
130        } catch (UnsupportedEncodingException e) {
131            Log.w(TAG, "Error", e);
132        }
133    }
134
135    private byte[] getLocationData() {
136        byte[] postData = null;
137        ContentResolver cr = getContentResolver();
138
139        // Don't send any location if the system does not have GoogleSettingsProvider.
140        if (!mLocationUtils.systemHasGoogleSettingsProvider()) return postData;
141
142        if (!mLocationUtils.userRespondedToLocationOptIn()) {
143            // Bring up the consent dialog if it the user has yet responded to it. We
144            // will not send the location info for this query.
145            mLocationUtils.showLocationOptIn();
146        } else if (mLocationUtils.userAcceptedLocationOptIn() &&
147                isLocationProviderEnabled(cr, LocationManager.NETWORK_PROVIDER)) {
148            Location location = ((LocationManager) getSystemService(
149                    Context.LOCATION_SERVICE)).getLastKnownLocation(
150                            LocationManager.NETWORK_PROVIDER);
151            if (location != null) {
152                StringBuilder str = new StringBuilder("action=devloc&sll=");
153                str.append(location.getLatitude()).append(',').append(location.getLongitude());
154                postData = str.toString().getBytes();
155            }
156        }
157        return postData;
158    }
159
160    /**
161     * Utility method copied from android.provider.Settings.Secure.
162     *
163     * Helper method for determining if a location provider is enabled.
164     * @param cr the content resolver to use
165     * @param provider the location provider to query
166     * @return true if the provider is enabled
167     */
168    private static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
169        String allowedProviders = Settings.Secure.getString(cr,
170                Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
171        if (allowedProviders != null) {
172            return (allowedProviders.equals(provider) ||
173                    allowedProviders.contains("," + provider + ",") ||
174                    allowedProviders.startsWith(provider + ",") ||
175                    allowedProviders.endsWith("," + provider));
176        }
177        return false;
178    }
179
180}
181