mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 586885 - Add search suggestions to AwesomeBar. r=mfinkle,lucasr
This commit is contained in:
parent
469c975cb5
commit
4ab9b4aa7f
@ -11,6 +11,7 @@ import android.content.DialogInterface;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -42,6 +43,7 @@ import android.widget.TabWidget;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||||
@ -54,6 +56,9 @@ import org.json.JSONObject;
|
|||||||
public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
||||||
private static final String LOGTAG = "GeckoAwesomeBar";
|
private static final String LOGTAG = "GeckoAwesomeBar";
|
||||||
|
|
||||||
|
private static final int SUGGESTION_TIMEOUT = 2000;
|
||||||
|
private static final int SUGGESTION_MAX = 3;
|
||||||
|
|
||||||
static final String URL_KEY = "url";
|
static final String URL_KEY = "url";
|
||||||
static final String CURRENT_URL_KEY = "currenturl";
|
static final String CURRENT_URL_KEY = "currenturl";
|
||||||
static final String TYPE_KEY = "type";
|
static final String TYPE_KEY = "type";
|
||||||
@ -67,6 +72,11 @@ public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
|||||||
private ImageButton mGoButton;
|
private ImageButton mGoButton;
|
||||||
private ContentResolver mResolver;
|
private ContentResolver mResolver;
|
||||||
private ContextMenuSubject mContextMenuSubject;
|
private ContextMenuSubject mContextMenuSubject;
|
||||||
|
private SuggestClient mSuggestClient;
|
||||||
|
private AsyncTask<String, Void, ArrayList<String>> mSuggestTask;
|
||||||
|
|
||||||
|
private static String sSuggestEngine;
|
||||||
|
private static String sSuggestTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@ -91,8 +101,20 @@ public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
|||||||
openUrlAndFinish(url);
|
openUrlAndFinish(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSearch(String engine) {
|
public void onSearch(String engine, String text) {
|
||||||
openSearchAndFinish(mText.getText().toString(), engine);
|
openSearchAndFinish(text, engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEditSuggestion(final String text) {
|
||||||
|
GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
mText.setText(text);
|
||||||
|
mText.setSelection(mText.getText().length());
|
||||||
|
mText.requestFocus();
|
||||||
|
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.showSoftInput(mText, InputMethodManager.SHOW_IMPLICIT);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -159,6 +181,24 @@ public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
|||||||
|
|
||||||
// no composition string. It is safe to update IME flags.
|
// no composition string. It is safe to update IME flags.
|
||||||
updateGoButton(text);
|
updateGoButton(text);
|
||||||
|
|
||||||
|
// cancel previous query
|
||||||
|
if (mSuggestTask != null) {
|
||||||
|
mSuggestTask.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSuggestClient != null) {
|
||||||
|
mSuggestTask = new AsyncTask<String, Void, ArrayList<String>>() {
|
||||||
|
protected ArrayList<String> doInBackground(String... query) {
|
||||||
|
return mSuggestClient.query(query[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostExecute(ArrayList<String> suggestions) {
|
||||||
|
mAwesomeTabs.setSuggestions(suggestions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mSuggestTask.execute(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
public void beforeTextChanged(CharSequence s, int start, int count,
|
||||||
@ -190,14 +230,46 @@ public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
|||||||
registerForContextMenu(mAwesomeTabs.findViewById(R.id.bookmarks_list));
|
registerForContextMenu(mAwesomeTabs.findViewById(R.id.bookmarks_list));
|
||||||
registerForContextMenu(mAwesomeTabs.findViewById(R.id.history_list));
|
registerForContextMenu(mAwesomeTabs.findViewById(R.id.history_list));
|
||||||
|
|
||||||
|
if (sSuggestTemplate == null) {
|
||||||
|
loadSuggestClientFromPrefs();
|
||||||
|
} else {
|
||||||
|
loadSuggestClient();
|
||||||
|
}
|
||||||
|
|
||||||
GeckoAppShell.registerGeckoEventListener("SearchEngines:Data", this);
|
GeckoAppShell.registerGeckoEventListener("SearchEngines:Data", this);
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadSuggestClientFromPrefs() {
|
||||||
|
GeckoAppShell.getHandler().post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
SharedPreferences prefs = getSearchPreferences();
|
||||||
|
sSuggestEngine = prefs.getString("suggestEngine", null);
|
||||||
|
sSuggestTemplate = prefs.getString("suggestTemplate", null);
|
||||||
|
if (sSuggestTemplate != null) {
|
||||||
|
loadSuggestClient();
|
||||||
|
mAwesomeTabs.setSuggestEngine(sSuggestEngine, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSuggestClient() {
|
||||||
|
mSuggestClient = new SuggestClient(GeckoApp.mAppContext, sSuggestTemplate, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
public void handleMessage(String event, JSONObject message) {
|
public void handleMessage(String event, JSONObject message) {
|
||||||
try {
|
try {
|
||||||
if (event.equals("SearchEngines:Data")) {
|
if (event.equals("SearchEngines:Data")) {
|
||||||
mAwesomeTabs.setSearchEngines(message.getJSONArray("searchEngines"));
|
final String suggestEngine = message.optString("suggestEngine");
|
||||||
|
final String suggestTemplate = message.optString("suggestTemplate");
|
||||||
|
if (!TextUtils.equals(suggestTemplate, sSuggestTemplate)) {
|
||||||
|
saveSuggestEngineData(suggestEngine, suggestTemplate);
|
||||||
|
sSuggestEngine = suggestEngine;
|
||||||
|
sSuggestTemplate = suggestTemplate;
|
||||||
|
loadSuggestClient();
|
||||||
|
}
|
||||||
|
mAwesomeTabs.setSearchEngines(suggestEngine, message.getJSONArray("searchEngines"));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
@ -205,6 +277,18 @@ public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveSuggestEngineData(final String suggestEngine, final String suggestTemplate) {
|
||||||
|
GeckoAppShell.getHandler().post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
SharedPreferences prefs = getSearchPreferences();
|
||||||
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
editor.putString("suggestEngine", suggestEngine);
|
||||||
|
editor.putString("suggestTemplate", suggestTemplate);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfiguration) {
|
public void onConfigurationChanged(Configuration newConfiguration) {
|
||||||
super.onConfigurationChanged(newConfiguration);
|
super.onConfigurationChanged(newConfiguration);
|
||||||
@ -678,4 +762,8 @@ public class AwesomeBar extends GeckoActivity implements GeckoEventListener {
|
|||||||
mOnKeyPreImeListener = listener;
|
mOnKeyPreImeListener = listener;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SharedPreferences getSearchPreferences() {
|
||||||
|
return getSharedPreferences("search.prefs", MODE_PRIVATE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -67,9 +68,10 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
private boolean mInflated;
|
private boolean mInflated;
|
||||||
private LayoutInflater mInflater;
|
private LayoutInflater mInflater;
|
||||||
private OnUrlOpenListener mUrlOpenListener;
|
private OnUrlOpenListener mUrlOpenListener;
|
||||||
private JSONArray mSearchEngines;
|
|
||||||
private ContentResolver mContentResolver;
|
private ContentResolver mContentResolver;
|
||||||
private ContentObserver mContentObserver;
|
private ContentObserver mContentObserver;
|
||||||
|
private SearchEngine mSuggestEngine;
|
||||||
|
private ArrayList<SearchEngine> mSearchEngines;
|
||||||
|
|
||||||
private BookmarksQueryTask mBookmarksQueryTask;
|
private BookmarksQueryTask mBookmarksQueryTask;
|
||||||
private HistoryQueryTask mHistoryQueryTask;
|
private HistoryQueryTask mHistoryQueryTask;
|
||||||
@ -86,16 +88,24 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
|
|
||||||
public interface OnUrlOpenListener {
|
public interface OnUrlOpenListener {
|
||||||
public void onUrlOpen(String url);
|
public void onUrlOpen(String url);
|
||||||
public void onSearch(String engine);
|
public void onSearch(String engine, String text);
|
||||||
|
public void onEditSuggestion(String suggestion);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ViewHolder {
|
private class AwesomeEntryViewHolder {
|
||||||
public TextView titleView;
|
public TextView titleView;
|
||||||
public TextView urlView;
|
public TextView urlView;
|
||||||
public ImageView faviconView;
|
public ImageView faviconView;
|
||||||
public ImageView starView;
|
public ImageView starView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SearchEntryViewHolder {
|
||||||
|
public FlowLayout suggestionView;
|
||||||
|
public ImageView iconView;
|
||||||
|
public LinearLayout userEnteredView;
|
||||||
|
public TextView userEnteredTextView;
|
||||||
|
}
|
||||||
|
|
||||||
private class HistoryListAdapter extends SimpleExpandableListAdapter {
|
private class HistoryListAdapter extends SimpleExpandableListAdapter {
|
||||||
public HistoryListAdapter(Context context, List<? extends Map<String, ?>> groupData,
|
public HistoryListAdapter(Context context, List<? extends Map<String, ?>> groupData,
|
||||||
int groupLayout, String[] groupFrom, int[] groupTo,
|
int groupLayout, String[] groupFrom, int[] groupTo,
|
||||||
@ -108,12 +118,12 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
@Override
|
@Override
|
||||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
||||||
View convertView, ViewGroup parent) {
|
View convertView, ViewGroup parent) {
|
||||||
ViewHolder viewHolder = null;
|
AwesomeEntryViewHolder viewHolder = null;
|
||||||
|
|
||||||
if (convertView == null) {
|
if (convertView == null) {
|
||||||
convertView = mInflater.inflate(R.layout.awesomebar_row, null);
|
convertView = mInflater.inflate(R.layout.awesomebar_row, null);
|
||||||
|
|
||||||
viewHolder = new ViewHolder();
|
viewHolder = new AwesomeEntryViewHolder();
|
||||||
viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
|
viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
|
||||||
viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
|
viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
|
||||||
viewHolder.faviconView = (ImageView) convertView.findViewById(R.id.favicon);
|
viewHolder.faviconView = (ImageView) convertView.findViewById(R.id.favicon);
|
||||||
@ -121,7 +131,7 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
|
|
||||||
convertView.setTag(viewHolder);
|
convertView.setTag(viewHolder);
|
||||||
} else {
|
} else {
|
||||||
viewHolder = (ViewHolder) convertView.getTag();
|
viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -256,7 +266,7 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
int viewType = getItemViewType(position);
|
int viewType = getItemViewType(position);
|
||||||
ViewHolder viewHolder = null;
|
AwesomeEntryViewHolder viewHolder = null;
|
||||||
|
|
||||||
if (convertView == null) {
|
if (convertView == null) {
|
||||||
if (viewType == VIEW_TYPE_ITEM)
|
if (viewType == VIEW_TYPE_ITEM)
|
||||||
@ -264,7 +274,7 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
else
|
else
|
||||||
convertView = mInflater.inflate(R.layout.awesomebar_folder_row, null);
|
convertView = mInflater.inflate(R.layout.awesomebar_folder_row, null);
|
||||||
|
|
||||||
viewHolder = new ViewHolder();
|
viewHolder = new AwesomeEntryViewHolder();
|
||||||
viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
|
viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
|
||||||
viewHolder.faviconView = (ImageView) convertView.findViewById(R.id.favicon);
|
viewHolder.faviconView = (ImageView) convertView.findViewById(R.id.favicon);
|
||||||
|
|
||||||
@ -273,7 +283,7 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
|
|
||||||
convertView.setTag(viewHolder);
|
convertView.setTag(viewHolder);
|
||||||
} else {
|
} else {
|
||||||
viewHolder = (ViewHolder) convertView.getTag();
|
viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
Cursor cursor = getCursor();
|
Cursor cursor = getCursor();
|
||||||
@ -612,42 +622,45 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
public void onClick();
|
public void onClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AwesomeBarCursorItem implements AwesomeBarItem {
|
|
||||||
private Cursor mCursor;
|
|
||||||
|
|
||||||
public AwesomeBarCursorItem(Cursor cursor) {
|
|
||||||
mCursor = cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onClick() {
|
|
||||||
String url = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL));
|
|
||||||
if (mUrlOpenListener != null) {
|
|
||||||
int display = mCursor.getInt(cursor.getColumnIndexOrThrow(Combined.DISPLAY));
|
|
||||||
if (display == Combined.DISPLAY_READER) {
|
|
||||||
url = getReaderForUrl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
mUrlOpenListener.onUrlOpen(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AwesomeBarSearchEngineItem implements AwesomeBarItem {
|
|
||||||
private String mSearchEngine;
|
|
||||||
|
|
||||||
public AwesomeBarSearchEngineItem(String searchEngine) {
|
|
||||||
mSearchEngine = searchEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onClick() {
|
|
||||||
if (mUrlOpenListener != null)
|
|
||||||
mUrlOpenListener.onSearch(mSearchEngine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AwesomeBarCursorAdapter extends SimpleCursorAdapter {
|
private class AwesomeBarCursorAdapter extends SimpleCursorAdapter {
|
||||||
private String mSearchTerm;
|
private String mSearchTerm;
|
||||||
|
|
||||||
|
private static final int ROW_SEARCH = 0;
|
||||||
|
private static final int ROW_STANDARD = 1;
|
||||||
|
|
||||||
|
private class AwesomeBarCursorItem implements AwesomeBarItem {
|
||||||
|
private Cursor mCursor;
|
||||||
|
|
||||||
|
public AwesomeBarCursorItem(Cursor cursor) {
|
||||||
|
mCursor = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClick() {
|
||||||
|
String url = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL));
|
||||||
|
if (mUrlOpenListener != null) {
|
||||||
|
int display = mCursor.getInt(mCursor.getColumnIndexOrThrow(Combined.DISPLAY));
|
||||||
|
if (display == Combined.DISPLAY_READER) {
|
||||||
|
url = getReaderForUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
mUrlOpenListener.onUrlOpen(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AwesomeBarSearchEngineItem implements AwesomeBarItem {
|
||||||
|
private String mSearchEngine;
|
||||||
|
|
||||||
|
public AwesomeBarSearchEngineItem(String searchEngine) {
|
||||||
|
mSearchEngine = searchEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClick() {
|
||||||
|
if (mUrlOpenListener != null)
|
||||||
|
mUrlOpenListener.onSearch(mSearchEngine, mSearchTerm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AwesomeBarCursorAdapter(Context context) {
|
public AwesomeBarCursorAdapter(Context context) {
|
||||||
super(context, -1, null, new String[] {}, new int[] {});
|
super(context, -1, null, new String[] {}, new int[] {});
|
||||||
mSearchTerm = "";
|
mSearchTerm = "";
|
||||||
@ -658,58 +671,123 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
getFilter().filter(searchTerm);
|
getFilter().filter(searchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getSuggestEngineCount() {
|
||||||
|
return (mSearchTerm.length() == 0 || mSuggestEngine == null) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Add the search engines to the number of reported results.
|
// Add the search engines to the number of reported results.
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
final int resultCount = super.getCount();
|
final int resultCount = super.getCount();
|
||||||
|
|
||||||
// don't show additional search engines if search field is empty
|
// don't show search engines or suggestions if search field is empty
|
||||||
if (mSearchTerm.length() == 0)
|
if (mSearchTerm.length() == 0)
|
||||||
return resultCount;
|
return resultCount;
|
||||||
|
|
||||||
return resultCount + mSearchEngines.length();
|
return resultCount + mSearchEngines.size() + getSuggestEngineCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an item is part of the cursor result set, return that entry.
|
// If an item is part of the cursor result set, return that entry.
|
||||||
// Otherwise, return the search engine data.
|
// Otherwise, return the search engine data.
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(int position) {
|
||||||
final int resultCount = super.getCount();
|
int engineIndex = getEngineIndex(position);
|
||||||
if (position < resultCount)
|
|
||||||
return new AwesomeBarCursorItem((Cursor) super.getItem(position));
|
|
||||||
|
|
||||||
JSONObject engine;
|
if (engineIndex == -1) {
|
||||||
String engineName = null;
|
// return awesomebar result
|
||||||
try {
|
position -= getSuggestEngineCount();
|
||||||
engine = mSearchEngines.getJSONObject(position - resultCount);
|
return new AwesomeBarCursorItem((Cursor) super.getItem(position));
|
||||||
engineName = engine.getString("name");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.e(LOGTAG, "Error getting search engine JSON", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AwesomeBarSearchEngineItem(engineName);
|
// return search engine
|
||||||
|
return new AwesomeBarSearchEngineItem(getEngine(engineIndex).name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchEngine getEngine(int index) {
|
||||||
|
final int suggestEngineCount = getSuggestEngineCount();
|
||||||
|
if (index < suggestEngineCount)
|
||||||
|
return mSuggestEngine;
|
||||||
|
return mSearchEngines.get(index - suggestEngineCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getEngineIndex(int position) {
|
||||||
|
final int resultCount = super.getCount();
|
||||||
|
final int suggestEngineCount = getSuggestEngineCount();
|
||||||
|
|
||||||
|
// return suggest engine index
|
||||||
|
if (position < suggestEngineCount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// not an engine
|
||||||
|
if (position - suggestEngineCount < resultCount)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// return search engine index
|
||||||
|
return position - resultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return getEngineIndex(position) == -1 ? ROW_STANDARD : ROW_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
// view can be either a standard awesomebar row or a search engine row
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int position) {
|
||||||
|
// If the suggestion row only contains one item (the user-entered
|
||||||
|
// query), allow the entire row to be clickable; clicking the row
|
||||||
|
// has the same effect as clicking the single suggestion. If the
|
||||||
|
// row contains multiple items, clicking the row will do nothing.
|
||||||
|
int index = getEngineIndex(position);
|
||||||
|
if (index != -1) {
|
||||||
|
return getEngine(index).suggestions.isEmpty();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
ViewHolder viewHolder = null;
|
if (getItemViewType(position) == ROW_SEARCH) {
|
||||||
|
SearchEntryViewHolder viewHolder = null;
|
||||||
|
|
||||||
if (convertView == null) {
|
if (convertView == null) {
|
||||||
convertView = mInflater.inflate(R.layout.awesomebar_row, null);
|
convertView = mInflater.inflate(R.layout.awesomebar_suggestion_row, null);
|
||||||
|
|
||||||
viewHolder = new ViewHolder();
|
viewHolder = new SearchEntryViewHolder();
|
||||||
viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
|
viewHolder.suggestionView = (FlowLayout) convertView.findViewById(R.id.suggestion_layout);
|
||||||
viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
|
viewHolder.iconView = (ImageView) convertView.findViewById(R.id.suggestion_icon);
|
||||||
viewHolder.faviconView = (ImageView) convertView.findViewById(R.id.favicon);
|
viewHolder.userEnteredView = (LinearLayout) convertView.findViewById(R.id.suggestion_user_entered);
|
||||||
viewHolder.starView = (ImageView) convertView.findViewById(R.id.bookmark_star);
|
viewHolder.userEnteredTextView = (TextView) convertView.findViewById(R.id.suggestion_text);
|
||||||
|
|
||||||
convertView.setTag(viewHolder);
|
convertView.setTag(viewHolder);
|
||||||
|
} else {
|
||||||
|
viewHolder = (SearchEntryViewHolder) convertView.getTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindSearchEngineView(getEngine(getEngineIndex(position)), viewHolder);
|
||||||
} else {
|
} else {
|
||||||
viewHolder = (ViewHolder) convertView.getTag();
|
AwesomeEntryViewHolder viewHolder = null;
|
||||||
}
|
|
||||||
|
|
||||||
final int resultCount = super.getCount();
|
if (convertView == null) {
|
||||||
if (position < resultCount) {
|
convertView = mInflater.inflate(R.layout.awesomebar_row, null);
|
||||||
|
|
||||||
|
viewHolder = new AwesomeEntryViewHolder();
|
||||||
|
viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
|
||||||
|
viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
|
||||||
|
viewHolder.faviconView = (ImageView) convertView.findViewById(R.id.favicon);
|
||||||
|
viewHolder.starView = (ImageView) convertView.findViewById(R.id.bookmark_star);
|
||||||
|
|
||||||
|
convertView.setTag(viewHolder);
|
||||||
|
} else {
|
||||||
|
viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
position -= getSuggestEngineCount();
|
||||||
Cursor cursor = getCursor();
|
Cursor cursor = getCursor();
|
||||||
if (!cursor.moveToPosition(position))
|
if (!cursor.moveToPosition(position))
|
||||||
throw new IllegalStateException("Couldn't move cursor to position " + position);
|
throw new IllegalStateException("Couldn't move cursor to position " + position);
|
||||||
@ -718,45 +796,69 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
updateUrl(viewHolder.urlView, cursor);
|
updateUrl(viewHolder.urlView, cursor);
|
||||||
updateFavicon(viewHolder.faviconView, cursor);
|
updateFavicon(viewHolder.faviconView, cursor);
|
||||||
updateBookmarkStar(viewHolder.starView, cursor);
|
updateBookmarkStar(viewHolder.starView, cursor);
|
||||||
} else {
|
|
||||||
bindSearchEngineView(position - resultCount, viewHolder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertView;
|
return convertView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable getDrawableFromDataURI(String dataURI) {
|
private void bindSearchEngineView(final SearchEngine engine, SearchEntryViewHolder viewHolder) {
|
||||||
String base64 = dataURI.substring(dataURI.indexOf(',') + 1);
|
// when a suggestion is clicked, do a search
|
||||||
Drawable drawable = null;
|
OnClickListener clickListener = new OnClickListener() {
|
||||||
try {
|
public void onClick(View v) {
|
||||||
byte[] bytes = GeckoAppShell.decodeBase64(base64, GeckoAppShell.BASE64_DEFAULT);
|
if (mUrlOpenListener != null) {
|
||||||
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
|
String suggestion = ((TextView) v.findViewById(R.id.suggestion_text)).getText().toString();
|
||||||
drawable = Drawable.createFromStream(stream, "src");
|
mUrlOpenListener.onSearch(engine.name, suggestion);
|
||||||
stream.close();
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
}
|
||||||
Log.i(LOGTAG, "exception while decoding drawable: " + base64, e);
|
};
|
||||||
} catch (IOException e) { }
|
|
||||||
return drawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindSearchEngineView(int position, ViewHolder viewHolder) {
|
// when a suggestion is long-clicked, copy the suggestion into the URL EditText
|
||||||
String name;
|
OnLongClickListener longClickListener = new OnLongClickListener() {
|
||||||
String iconURI;
|
public boolean onLongClick(View v) {
|
||||||
String searchText = getResources().getString(R.string.awesomebar_search_engine, mSearchTerm);
|
if (mUrlOpenListener != null) {
|
||||||
try {
|
String suggestion = ((TextView) v.findViewById(R.id.suggestion_text)).getText().toString();
|
||||||
JSONObject searchEngine = mSearchEngines.getJSONObject(position);
|
mUrlOpenListener.onEditSuggestion(suggestion);
|
||||||
name = searchEngine.getString("name");
|
return true;
|
||||||
iconURI = searchEngine.getString("iconURI");
|
}
|
||||||
} catch (JSONException e) {
|
return false;
|
||||||
Log.e(LOGTAG, "Error getting search engine JSON", e);
|
}
|
||||||
return;
|
};
|
||||||
|
|
||||||
|
// set the search engine icon (e.g., Google) for the row
|
||||||
|
FlowLayout suggestionView = viewHolder.suggestionView;
|
||||||
|
viewHolder.iconView.setImageDrawable(engine.icon);
|
||||||
|
|
||||||
|
// user-entered search term is first suggestion
|
||||||
|
viewHolder.userEnteredTextView.setText(mSearchTerm);
|
||||||
|
viewHolder.userEnteredView.setOnClickListener(clickListener);
|
||||||
|
|
||||||
|
// add additional suggestions given by this engine
|
||||||
|
int recycledSuggestionCount = suggestionView.getChildCount();
|
||||||
|
int suggestionCount = engine.suggestions.size();
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < suggestionCount; i++) {
|
||||||
|
String suggestion = engine.suggestions.get(i);
|
||||||
|
View suggestionItem = null;
|
||||||
|
|
||||||
|
// reuse suggestion views from recycled view, if possible
|
||||||
|
if (i+1 < recycledSuggestionCount) {
|
||||||
|
suggestionItem = suggestionView.getChildAt(i+1);
|
||||||
|
suggestionItem.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
suggestionItem = mInflater.inflate(R.layout.awesomebar_suggestion_item, null);
|
||||||
|
((ImageView) suggestionItem.findViewById(R.id.suggestion_magnifier)).setVisibility(View.GONE);
|
||||||
|
suggestionView.addView(suggestionItem);
|
||||||
|
}
|
||||||
|
((TextView) suggestionItem.findViewById(R.id.suggestion_text)).setText(suggestion);
|
||||||
|
|
||||||
|
suggestionItem.setOnClickListener(clickListener);
|
||||||
|
suggestionItem.setOnLongClickListener(longClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide extra suggestions that have been recycled
|
||||||
|
for (++i; i < recycledSuggestionCount; i++) {
|
||||||
|
suggestionView.getChildAt(i).setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
viewHolder.titleView.setText(name);
|
|
||||||
viewHolder.urlView.setText(searchText);
|
|
||||||
Drawable drawable = getDrawableFromDataURI(iconURI);
|
|
||||||
viewHolder.faviconView.setImageDrawable(drawable);
|
|
||||||
viewHolder.starView.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -767,7 +869,7 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mInflated = false;
|
mInflated = false;
|
||||||
mSearchEngines = new JSONArray();
|
mSearchEngines = new ArrayList<SearchEngine>();
|
||||||
mContentResolver = context.getContentResolver();
|
mContentResolver = context.getContentResolver();
|
||||||
mContentObserver = null;
|
mContentObserver = null;
|
||||||
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
@ -1043,10 +1145,98 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
mAllPagesCursorAdapter.filter(searchTerm);
|
mAllPagesCursorAdapter.filter(searchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSearchEngines(final JSONArray engines) {
|
private Drawable getDrawableFromDataURI(String dataURI) {
|
||||||
|
String base64 = dataURI.substring(dataURI.indexOf(',') + 1);
|
||||||
|
Drawable drawable = null;
|
||||||
|
try {
|
||||||
|
byte[] bytes = GeckoAppShell.decodeBase64(base64, GeckoAppShell.BASE64_DEFAULT);
|
||||||
|
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
|
||||||
|
drawable = Drawable.createFromStream(stream, "src");
|
||||||
|
stream.close();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.i(LOGTAG, "exception while decoding drawable: " + base64, e);
|
||||||
|
} catch (IOException e) { }
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SearchEngine {
|
||||||
|
public String name;
|
||||||
|
public Drawable icon;
|
||||||
|
public ArrayList<String> suggestions;
|
||||||
|
|
||||||
|
public SearchEngine(String name) {
|
||||||
|
this(name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchEngine(String name, Drawable icon) {
|
||||||
|
this.name = name;
|
||||||
|
this.icon = icon;
|
||||||
|
this.suggestions = new ArrayList<String>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the suggest engine, which will show suggestions for user-entered queries.
|
||||||
|
* If the suggest engine has already been set, it will be replaced, and its
|
||||||
|
* suggestions will be copied to the new suggest engine.
|
||||||
|
*/
|
||||||
|
public void setSuggestEngine(String name, Drawable icon) {
|
||||||
|
// We currently save the suggest engine in shared preferences, so this
|
||||||
|
// method is called immediately when the AwesomeBar is created. It's
|
||||||
|
// called again in setSuggestions(), when the list of search engines is
|
||||||
|
// received from Gecko (in case the suggestion engine has changed).
|
||||||
|
final SearchEngine suggestEngine = new SearchEngine(name, icon);
|
||||||
|
if (mSuggestEngine != null)
|
||||||
|
suggestEngine.suggestions = mSuggestEngine.suggestions;
|
||||||
|
|
||||||
GeckoAppShell.getMainHandler().post(new Runnable() {
|
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
mSearchEngines = engines;
|
mSuggestEngine = suggestEngine;
|
||||||
|
mAllPagesCursorAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets suggestions associated with the current suggest engine.
|
||||||
|
* If there is no suggest engine, this does nothing.
|
||||||
|
*/
|
||||||
|
public void setSuggestions(final ArrayList<String> suggestions) {
|
||||||
|
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (mSuggestEngine != null) {
|
||||||
|
mSuggestEngine.suggestions = suggestions;
|
||||||
|
mAllPagesCursorAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets search engines to be shown for user-entered queries.
|
||||||
|
*/
|
||||||
|
public void setSearchEngines(String suggestEngine, JSONArray engines) {
|
||||||
|
final ArrayList<SearchEngine> searchEngines = new ArrayList<SearchEngine>();
|
||||||
|
for (int i = 0; i < engines.length(); i++) {
|
||||||
|
try {
|
||||||
|
JSONObject engineJSON = engines.getJSONObject(i);
|
||||||
|
String name = engineJSON.getString("name");
|
||||||
|
String iconURI = engineJSON.getString("iconURI");
|
||||||
|
Drawable icon = getDrawableFromDataURI(iconURI);
|
||||||
|
if (name.equals(suggestEngine)) {
|
||||||
|
setSuggestEngine(name, icon);
|
||||||
|
} else {
|
||||||
|
searchEngines.add(new SearchEngine(name, icon));
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOGTAG, "Error getting search engine JSON", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
mSearchEngines = searchEngines;
|
||||||
mAllPagesCursorAdapter.notifyDataSetChanged();
|
mAllPagesCursorAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1058,7 +1248,10 @@ public class AwesomeBarTabs extends TabHost {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
hideSoftInput(this);
|
// we should only have to hide the soft keyboard once - when the user
|
||||||
|
// initially touches the screen
|
||||||
|
if (ev.getAction() == MotionEvent.ACTION_DOWN)
|
||||||
|
hideSoftInput(this);
|
||||||
|
|
||||||
// the android docs make no sense, but returning false will cause this and other
|
// the android docs make no sense, but returning false will cause this and other
|
||||||
// motion events to be sent to the view the user tapped on
|
// motion events to be sent to the view the user tapped on
|
||||||
|
@ -98,6 +98,7 @@ FENNEC_JAVA_FILES = \
|
|||||||
RemoteTabs.java \
|
RemoteTabs.java \
|
||||||
SetupScreen.java \
|
SetupScreen.java \
|
||||||
SiteIdentityPopup.java \
|
SiteIdentityPopup.java \
|
||||||
|
SuggestClient.java \
|
||||||
SurfaceBits.java \
|
SurfaceBits.java \
|
||||||
Tab.java \
|
Tab.java \
|
||||||
Tabs.java \
|
Tabs.java \
|
||||||
@ -254,6 +255,8 @@ RES_LAYOUT = \
|
|||||||
res/layout/awesomebar_folder_row.xml \
|
res/layout/awesomebar_folder_row.xml \
|
||||||
res/layout/awesomebar_header_row.xml \
|
res/layout/awesomebar_header_row.xml \
|
||||||
res/layout/awesomebar_row.xml \
|
res/layout/awesomebar_row.xml \
|
||||||
|
res/layout/awesomebar_suggestion_item.xml \
|
||||||
|
res/layout/awesomebar_suggestion_row.xml \
|
||||||
res/layout/awesomebar_search.xml \
|
res/layout/awesomebar_search.xml \
|
||||||
res/layout/awesomebar_tab_indicator.xml \
|
res/layout/awesomebar_tab_indicator.xml \
|
||||||
res/layout/awesomebar_tabs.xml \
|
res/layout/awesomebar_tabs.xml \
|
||||||
@ -815,6 +818,7 @@ MOZ_ANDROID_DRAWABLES += \
|
|||||||
mobile/android/base/resources/drawable/remote_tabs_group_bg_repeat.xml \
|
mobile/android/base/resources/drawable/remote_tabs_group_bg_repeat.xml \
|
||||||
mobile/android/base/resources/drawable/start.png \
|
mobile/android/base/resources/drawable/start.png \
|
||||||
mobile/android/base/resources/drawable/site_security_level.xml \
|
mobile/android/base/resources/drawable/site_security_level.xml \
|
||||||
|
mobile/android/base/resources/drawable/suggestion_selector.xml \
|
||||||
mobile/android/base/resources/drawable/tabs_button.xml \
|
mobile/android/base/resources/drawable/tabs_button.xml \
|
||||||
mobile/android/base/resources/drawable/tabs_level.xml \
|
mobile/android/base/resources/drawable/tabs_level.xml \
|
||||||
mobile/android/base/resources/drawable/tabs_tray_bg_repeat.xml \
|
mobile/android/base/resources/drawable/tabs_tray_bg_repeat.xml \
|
||||||
|
127
mobile/android/base/SuggestClient.java
Normal file
127
mobile/android/base/SuggestClient.java
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use network-based search suggestions.
|
||||||
|
*/
|
||||||
|
public class SuggestClient {
|
||||||
|
private static final String LOGTAG = "GeckoSuggestClient";
|
||||||
|
private static final String USER_AGENT = GeckoApp.mAppContext.getDefaultUAString();
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final int mTimeout;
|
||||||
|
|
||||||
|
// should contain the string "__searchTerms__", which is replaced with the query
|
||||||
|
private final String mSuggestTemplate;
|
||||||
|
|
||||||
|
// the maximum number of suggestions to return
|
||||||
|
private final int mMaxResults;
|
||||||
|
|
||||||
|
public SuggestClient(Context context, String suggestTemplate, int timeout, int maxResults) {
|
||||||
|
mContext = context;
|
||||||
|
mMaxResults = maxResults;
|
||||||
|
mSuggestTemplate = suggestTemplate;
|
||||||
|
mTimeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SuggestClient(Context context, String suggestTemplate, int timeout) {
|
||||||
|
this(context, suggestTemplate, timeout, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries for a given search term and returns an ArrayList of suggestions.
|
||||||
|
*/
|
||||||
|
public ArrayList<String> query(String query) {
|
||||||
|
ArrayList<String> suggestions = new ArrayList<String>();
|
||||||
|
if (TextUtils.isEmpty(mSuggestTemplate) || TextUtils.isEmpty(query)) {
|
||||||
|
return suggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNetworkConnected()) {
|
||||||
|
Log.i(LOGTAG, "Not connected to network");
|
||||||
|
return suggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String encoded = URLEncoder.encode(query, "UTF-8");
|
||||||
|
String suggestUri = mSuggestTemplate.replace("__searchTerms__", encoded);
|
||||||
|
|
||||||
|
URL url = new URL(suggestUri);
|
||||||
|
String json = null;
|
||||||
|
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||||
|
try {
|
||||||
|
urlConnection.setConnectTimeout(mTimeout);
|
||||||
|
urlConnection.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
|
||||||
|
json = convertStreamToString(in);
|
||||||
|
} finally {
|
||||||
|
urlConnection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json != null) {
|
||||||
|
/*
|
||||||
|
* Sample result:
|
||||||
|
* ["foo",["food network","foothill college","foot locker",...]]
|
||||||
|
*/
|
||||||
|
JSONArray results = new JSONArray(json);
|
||||||
|
JSONArray jsonSuggestions = results.getJSONArray(1);
|
||||||
|
|
||||||
|
int added = 0;
|
||||||
|
for (int i = 0; (i < jsonSuggestions.length()) && (added < mMaxResults); i++) {
|
||||||
|
String suggestion = jsonSuggestions.getString(i);
|
||||||
|
if (!suggestion.equalsIgnoreCase(query)) {
|
||||||
|
suggestions.add(suggestion);
|
||||||
|
added++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(LOGTAG, "Suggestion query failed");
|
||||||
|
}
|
||||||
|
} catch (InterruptedIOException e) {
|
||||||
|
Log.d(LOGTAG, "Suggestion query interrupted");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(LOGTAG, "Error", e);
|
||||||
|
}
|
||||||
|
return suggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNetworkConnected() {
|
||||||
|
NetworkInfo networkInfo = getActiveNetworkInfo();
|
||||||
|
return networkInfo != null && networkInfo.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetworkInfo getActiveNetworkInfo() {
|
||||||
|
ConnectivityManager connectivity = (ConnectivityManager) mContext
|
||||||
|
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
if (connectivity == null)
|
||||||
|
return null;
|
||||||
|
return connectivity.getActiveNetworkInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertStreamToString(java.io.InputStream is) {
|
||||||
|
try {
|
||||||
|
return new java.util.Scanner(is).useDelimiter("\\A").next();
|
||||||
|
} catch (java.util.NoSuchElementException e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/suggestion_pressed" />
|
||||||
|
|
||||||
|
<padding android:left="7dp"
|
||||||
|
android:top="7dp"
|
||||||
|
android:right="7dp"
|
||||||
|
android:bottom="7dp" />
|
||||||
|
|
||||||
|
<corners android:bottomRightRadius="4dp"
|
||||||
|
android:bottomLeftRadius="4dp"
|
||||||
|
android:topLeftRadius="4dp"
|
||||||
|
android:topRightRadius="4dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:state_enabled="true">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/suggestion_primary" />
|
||||||
|
|
||||||
|
<padding android:left="7dp"
|
||||||
|
android:top="7dp"
|
||||||
|
android:right="7dp"
|
||||||
|
android:bottom="7dp" />
|
||||||
|
|
||||||
|
<corners android:bottomRightRadius="4dp"
|
||||||
|
android:bottomLeftRadius="4dp"
|
||||||
|
android:topLeftRadius="4dp"
|
||||||
|
android:topRightRadius="4dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</selector>
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/suggestion_selector"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/suggestion_magnifier"
|
||||||
|
android:src="@drawable/ic_awesomebar_search"
|
||||||
|
android:layout_marginRight="3dip"
|
||||||
|
android:layout_width="16dip"
|
||||||
|
android:layout_height="16dip" />
|
||||||
|
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/suggestion_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="6dip">
|
||||||
|
|
||||||
|
<ImageView android:id="@+id/suggestion_icon"
|
||||||
|
android:layout_width="32dip"
|
||||||
|
android:layout_height="32dip"
|
||||||
|
android:layout_marginRight="10dip"
|
||||||
|
android:minWidth="32dip"
|
||||||
|
android:minHeight="32dip"
|
||||||
|
android:scaleType="fitCenter"/>
|
||||||
|
|
||||||
|
<org.mozilla.gecko.FlowLayout android:id="@+id/suggestion_layout"
|
||||||
|
android:layout_toRightOf="@id/suggestion_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<include layout="@layout/awesomebar_suggestion_item"
|
||||||
|
android:id="@+id/suggestion_user_entered"/>
|
||||||
|
|
||||||
|
</org.mozilla.gecko.FlowLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -14,5 +14,7 @@
|
|||||||
<color name="identity_identified">#B7D46A</color>
|
<color name="identity_identified">#B7D46A</color>
|
||||||
<color name="tabs_counter_color">#C7D1DB</color>
|
<color name="tabs_counter_color">#C7D1DB</color>
|
||||||
<color name="url_bar_text_highlight">#FF9500</color>
|
<color name="url_bar_text_highlight">#FF9500</color>
|
||||||
|
<color name="suggestion_primary">#dddddd</color>
|
||||||
|
<color name="suggestion_pressed">#bbbbbb</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
@ -4999,15 +4999,41 @@ var SearchEngines = {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let suggestTemplate = null;
|
||||||
|
let suggestEngine = null;
|
||||||
|
if (Services.prefs.getBoolPref("browser.search.suggest.enabled")) {
|
||||||
|
let engine = this.getSuggestionEngine();
|
||||||
|
if (engine != null) {
|
||||||
|
suggestEngine = engine.name;
|
||||||
|
suggestTemplate = engine.getSubmission("__searchTerms__", "application/x-suggestions+json").uri.spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sendMessageToJava({
|
sendMessageToJava({
|
||||||
gecko: {
|
gecko: {
|
||||||
type: "SearchEngines:Data",
|
type: "SearchEngines:Data",
|
||||||
searchEngines: searchEngines
|
searchEngines: searchEngines,
|
||||||
|
suggestEngine: suggestEngine,
|
||||||
|
suggestTemplate: suggestTemplate
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSuggestionEngine: function () {
|
||||||
|
let engines = [ Services.search.currentEngine,
|
||||||
|
Services.search.defaultEngine,
|
||||||
|
Services.search.originalDefaultEngine ];
|
||||||
|
|
||||||
|
for (let i = 0; i < engines.length; i++) {
|
||||||
|
let engine = engines[i];
|
||||||
|
if (engine && engine.supportsResponseType("application/x-suggestions+json"))
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
addEngine: function addEngine(aElement) {
|
addEngine: function addEngine(aElement) {
|
||||||
let form = aElement.form;
|
let form = aElement.form;
|
||||||
let charset = aElement.ownerDocument.characterSet;
|
let charset = aElement.ownerDocument.characterSet;
|
||||||
|
Loading…
Reference in New Issue
Block a user