1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/home/SuggestClient.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,157 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.home; 1.9 + 1.10 +import org.mozilla.gecko.GeckoAppShell; 1.11 +import org.mozilla.gecko.mozglue.RobocopTarget; 1.12 + 1.13 +import org.json.JSONArray; 1.14 + 1.15 +import android.content.Context; 1.16 +import android.net.ConnectivityManager; 1.17 +import android.net.NetworkInfo; 1.18 +import android.text.TextUtils; 1.19 +import android.util.Log; 1.20 + 1.21 +import java.io.BufferedInputStream; 1.22 +import java.io.IOException; 1.23 +import java.io.InputStream; 1.24 +import java.net.HttpURLConnection; 1.25 +import java.net.URL; 1.26 +import java.net.URLEncoder; 1.27 +import java.util.ArrayList; 1.28 + 1.29 +/** 1.30 + * Use network-based search suggestions. 1.31 + */ 1.32 +public class SuggestClient { 1.33 + private static final String LOGTAG = "GeckoSuggestClient"; 1.34 + private static final String USER_AGENT = GeckoAppShell.getGeckoInterface().getDefaultUAString(); 1.35 + 1.36 + private final Context mContext; 1.37 + private final int mTimeout; 1.38 + 1.39 + // should contain the string "__searchTerms__", which is replaced with the query 1.40 + private final String mSuggestTemplate; 1.41 + 1.42 + // the maximum number of suggestions to return 1.43 + private final int mMaxResults; 1.44 + 1.45 + // used by robocop for testing 1.46 + private boolean mCheckNetwork; 1.47 + 1.48 + // used to make suggestions appear instantly after opt-in 1.49 + private String mPrevQuery; 1.50 + private ArrayList<String> mPrevResults; 1.51 + 1.52 + public SuggestClient(Context context, String suggestTemplate, int timeout, int maxResults) { 1.53 + mContext = context; 1.54 + mMaxResults = maxResults; 1.55 + mSuggestTemplate = suggestTemplate; 1.56 + mTimeout = timeout; 1.57 + mCheckNetwork = true; 1.58 + } 1.59 + 1.60 + /** 1.61 + * This constructor is used exclusively by Robocop. 1.62 + */ 1.63 + @RobocopTarget 1.64 + public SuggestClient(Context context, String suggestTemplate, int timeout) { 1.65 + this(context, suggestTemplate, timeout, Integer.MAX_VALUE); 1.66 + mCheckNetwork = false; 1.67 + } 1.68 + 1.69 + /** 1.70 + * Queries for a given search term and returns an ArrayList of suggestions. 1.71 + */ 1.72 + public ArrayList<String> query(String query) { 1.73 + if (query.equals(mPrevQuery)) 1.74 + return mPrevResults; 1.75 + 1.76 + ArrayList<String> suggestions = new ArrayList<String>(); 1.77 + if (TextUtils.isEmpty(mSuggestTemplate) || TextUtils.isEmpty(query)) { 1.78 + return suggestions; 1.79 + } 1.80 + 1.81 + if (!isNetworkConnected() && mCheckNetwork) { 1.82 + Log.i(LOGTAG, "Not connected to network"); 1.83 + return suggestions; 1.84 + } 1.85 + 1.86 + try { 1.87 + String encoded = URLEncoder.encode(query, "UTF-8"); 1.88 + String suggestUri = mSuggestTemplate.replace("__searchTerms__", encoded); 1.89 + 1.90 + URL url = new URL(suggestUri); 1.91 + String json = null; 1.92 + HttpURLConnection urlConnection = null; 1.93 + InputStream in = null; 1.94 + try { 1.95 + urlConnection = (HttpURLConnection) url.openConnection(); 1.96 + urlConnection.setConnectTimeout(mTimeout); 1.97 + urlConnection.setRequestProperty("User-Agent", USER_AGENT); 1.98 + in = new BufferedInputStream(urlConnection.getInputStream()); 1.99 + json = convertStreamToString(in); 1.100 + } finally { 1.101 + if (urlConnection != null) 1.102 + urlConnection.disconnect(); 1.103 + if (in != null) { 1.104 + try { 1.105 + in.close(); 1.106 + } catch (IOException e) { 1.107 + Log.e(LOGTAG, "error", e); 1.108 + } 1.109 + } 1.110 + } 1.111 + 1.112 + if (json != null) { 1.113 + /* 1.114 + * Sample result: 1.115 + * ["foo",["food network","foothill college","foot locker",...]] 1.116 + */ 1.117 + JSONArray results = new JSONArray(json); 1.118 + JSONArray jsonSuggestions = results.getJSONArray(1); 1.119 + 1.120 + int added = 0; 1.121 + for (int i = 0; (i < jsonSuggestions.length()) && (added < mMaxResults); i++) { 1.122 + String suggestion = jsonSuggestions.getString(i); 1.123 + if (!suggestion.equalsIgnoreCase(query)) { 1.124 + suggestions.add(suggestion); 1.125 + added++; 1.126 + } 1.127 + } 1.128 + } else { 1.129 + Log.e(LOGTAG, "Suggestion query failed"); 1.130 + } 1.131 + } catch (Exception e) { 1.132 + Log.e(LOGTAG, "Error", e); 1.133 + } 1.134 + 1.135 + mPrevQuery = query; 1.136 + mPrevResults = suggestions; 1.137 + return suggestions; 1.138 + } 1.139 + 1.140 + private boolean isNetworkConnected() { 1.141 + NetworkInfo networkInfo = getActiveNetworkInfo(); 1.142 + return networkInfo != null && networkInfo.isConnected(); 1.143 + } 1.144 + 1.145 + private NetworkInfo getActiveNetworkInfo() { 1.146 + ConnectivityManager connectivity = (ConnectivityManager) mContext 1.147 + .getSystemService(Context.CONNECTIVITY_SERVICE); 1.148 + if (connectivity == null) 1.149 + return null; 1.150 + return connectivity.getActiveNetworkInfo(); 1.151 + } 1.152 + 1.153 + private String convertStreamToString(java.io.InputStream is) { 1.154 + try { 1.155 + return new java.util.Scanner(is).useDelimiter("\\A").next(); 1.156 + } catch (java.util.NoSuchElementException e) { 1.157 + return ""; 1.158 + } 1.159 + } 1.160 +}