Bug 701376 - show search engine(s) when there are no/few awesomebar results [r=mfinkle]

This commit is contained in:
Brian Nicholson 2011-12-07 17:52:07 -08:00
parent fd4a33f486
commit 40cf92be54
6 changed files with 234 additions and 27 deletions

View File

@ -56,13 +56,17 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
public class AwesomeBar extends Activity {
import org.json.JSONArray;
import org.json.JSONObject;
public class AwesomeBar extends Activity implements GeckoEventListener {
private static final String LOGTAG = "GeckoAwesomeBar";
static final String URL_KEY = "url";
static final String TITLE_KEY = "title";
static final String CURRENT_URL_KEY = "currenturl";
static final String TYPE_KEY = "type";
static final String SEARCH_KEY = "search";
static enum Type { ADD, EDIT };
private String mType;
@ -83,6 +87,10 @@ public class AwesomeBar extends Activity {
public void onUrlOpen(String url) {
openUrlAndFinish(url);
}
public void onSearch(String engine) {
openSearchAndFinish(mText.getText().toString(), engine);
}
});
mGoButton = (ImageButton) findViewById(R.id.awesomebar_button);
@ -175,6 +183,20 @@ public class AwesomeBar extends Activity {
}
}
});
GeckoAppShell.registerGeckoEventListener("SearchEngines:Data", this);
GeckoAppShell.sendEventToGecko(new GeckoEvent("SearchEngines:Get", null));
}
public void handleMessage(String event, JSONObject message) {
try {
if (event.equals("SearchEngines:Data")) {
mAwesomeTabs.setSearchEngines(message.getJSONArray("searchEngines"));
}
} catch (Exception e) {
// do nothing
Log.i(LOGTAG, "handleMessage throws " + e + " for message: " + event);
}
}
@Override
@ -209,14 +231,25 @@ public class AwesomeBar extends Activity {
finish();
}
private void finishWithResult(Intent intent) {
setResult(Activity.RESULT_OK, intent);
finish();
overridePendingTransition(0, 0);
}
private void openUrlAndFinish(String url) {
Intent resultIntent = new Intent();
resultIntent.putExtra(URL_KEY, url);
resultIntent.putExtra(TYPE_KEY, mType);
finishWithResult(resultIntent);
}
setResult(Activity.RESULT_OK, resultIntent);
finish();
overridePendingTransition(0, 0);
private void openSearchAndFinish(String url, String engine) {
Intent resultIntent = new Intent();
resultIntent.putExtra(URL_KEY, url);
resultIntent.putExtra(TYPE_KEY, mType);
resultIntent.putExtra(SEARCH_KEY, engine);
finishWithResult(resultIntent);
}
@Override
@ -258,6 +291,7 @@ public class AwesomeBar extends Activity {
public void onDestroy() {
super.onDestroy();
mAwesomeTabs.destroy();
GeckoAppShell.unregisterGeckoEventListener("SearchEngines:Data", this);
}
public static class AwesomeBarEditText extends EditText {

View File

@ -49,6 +49,7 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.provider.Browser;
import android.util.AttributeSet;
import android.util.Base64;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
@ -66,12 +67,18 @@ import android.widget.SimpleExpandableListAdapter;
import android.widget.TabHost;
import android.widget.TextView;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class AwesomeBarTabs extends TabHost {
private static final String LOGTAG = "GeckoAwesomeBarTabs";
@ -84,8 +91,9 @@ public class AwesomeBarTabs extends TabHost {
private Context mContext;
private OnUrlOpenListener mUrlOpenListener;
private View.OnTouchListener mListTouchListener;
private JSONArray mSearchEngines;
private SimpleCursorAdapter mAllPagesAdapter;
private AwesomeBarCursorAdapter mAllPagesCursorAdapter;
private SimpleCursorAdapter mBookmarksAdapter;
private SimpleExpandableListAdapter mHistoryAdapter;
@ -94,7 +102,8 @@ public class AwesomeBarTabs extends TabHost {
private static final int MAX_RESULTS = 100;
public interface OnUrlOpenListener {
public abstract void onUrlOpen(String url);
public void onUrlOpen(String url);
public void onSearch(String engine);
}
private class HistoryListAdapter extends SimpleExpandableListAdapter {
@ -410,12 +419,114 @@ public class AwesomeBarTabs extends TabHost {
}
}
private class AwesomeBarCursorAdapter extends SimpleCursorAdapter {
private int mLayout;
private String[] mFrom;
private int[] mTo;
private String mSearchTerm;
public AwesomeBarCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
mLayout = layout;
mTo = to;
mFrom = from;
mSearchTerm = "";
}
public void filter(String searchTerm) {
mSearchTerm = searchTerm;
getFilter().filter(searchTerm);
}
// Add the search engines to the number of reported results.
@Override
public int getCount() {
final int resultCount = super.getCount();
// don't show additional search engines if search field is empty
if (mSearchTerm.length() == 0)
return resultCount;
return resultCount + mSearchEngines.length();
}
// If an item is part of the cursor result set, return that entry.
// Otherwise, return the search engine data.
@Override
public Object getItem(int position) {
final int resultCount = super.getCount();
if (position < resultCount)
return super.getItem(position);
JSONObject engine;
String engineName = null;
try {
engine = mSearchEngines.getJSONObject(position - resultCount);
engineName = engine.getString("name");
} catch (JSONException e) {
Log.e(LOGTAG, "error getting json arguments");
}
return engineName;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int resultCount = super.getCount();
if (position < resultCount)
return super.getView(position, convertView, parent);
View v;
if (convertView == null)
v = newView(mContext, null, parent);
else
v = convertView;
bindSearchEngineView(position - resultCount, v);
return v;
}
private Drawable getDrawableFromDataURI(String dataURI) {
String base64 = dataURI.substring(dataURI.indexOf(',') + 1);
byte[] bytes = Base64.decode(base64, Base64.DEFAULT);
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
Drawable drawable = (Drawable) Drawable.createFromStream(stream, "src");
try {
stream.close();
} catch (IOException e) { }
return drawable;
}
private void bindSearchEngineView(int position, View view) {
String name;
String iconURI;
String searchText = getResources().getString(R.string.awesomebar_search_engine, mSearchTerm);
try {
JSONObject searchEngine = mSearchEngines.getJSONObject(position);
name = searchEngine.getString("name");
iconURI = searchEngine.getString("iconURI");
} catch (JSONException e) {
Log.e(LOGTAG, "error getting json arguments");
return;
}
TextView titleView = (TextView) view.findViewById(R.id.title);
TextView urlView = (TextView) view.findViewById(R.id.url);
ImageView faviconView = (ImageView) view.findViewById(R.id.favicon);
titleView.setText(name);
urlView.setText(searchText);
faviconView.setImageDrawable(getDrawableFromDataURI(iconURI));
}
};
public AwesomeBarTabs(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(LOGTAG, "Creating AwesomeBarTabs");
mContext = context;
mSearchEngines = new JSONArray();
// Load layout into the custom view
LayoutInflater inflater =
@ -496,7 +607,7 @@ public class AwesomeBarTabs extends TabHost {
R.id.all_pages_list);
// Load the list using a custom adapter so we can create the bitmaps
mAllPagesAdapter = new SimpleCursorAdapter(
mAllPagesCursorAdapter = new AwesomeBarCursorAdapter(
mContext,
R.layout.awesomebar_row,
null,
@ -506,9 +617,9 @@ public class AwesomeBarTabs extends TabHost {
new int[] { R.id.title, R.id.url, R.id.favicon }
);
mAllPagesAdapter.setViewBinder(new AwesomeCursorViewBinder());
mAllPagesCursorAdapter.setViewBinder(new AwesomeCursorViewBinder());
mAllPagesAdapter.setFilterQueryProvider(new FilterQueryProvider() {
mAllPagesCursorAdapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
ContentResolver resolver = mContext.getContentResolver();
@ -535,7 +646,7 @@ public class AwesomeBarTabs extends TabHost {
}
});
allPagesList.setAdapter(mAllPagesAdapter);
allPagesList.setAdapter(mAllPagesCursorAdapter);
allPagesList.setOnTouchListener(mListTouchListener);
}
@ -586,11 +697,19 @@ public class AwesomeBarTabs extends TabHost {
}
private void handleItemClick(ListView list, int position) {
Cursor cursor = (Cursor) list.getItemAtPosition(position);
String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
if (mUrlOpenListener != null)
mUrlOpenListener.onUrlOpen(url);
Object item = list.getItemAtPosition(position);
// If an AwesomeBar entry is clicked, item will be a Cursor containing
// the entry's data. Otherwise, a search engine entry was clicked, and
// item will be a String containing the name of the search engine.
if (item instanceof Cursor) {
Cursor cursor = (Cursor) item;
String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
if (mUrlOpenListener != null)
mUrlOpenListener.onUrlOpen(url);
} else {
if (mUrlOpenListener != null)
mUrlOpenListener.onSearch((String)item);
}
}
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
@ -598,7 +717,7 @@ public class AwesomeBarTabs extends TabHost {
}
public void destroy() {
Cursor allPagesCursor = mAllPagesAdapter.getCursor();
Cursor allPagesCursor = mAllPagesCursorAdapter.getCursor();
if (allPagesCursor != null)
allPagesCursor.close();
@ -624,6 +743,15 @@ public class AwesomeBarTabs extends TabHost {
getTabWidget().setVisibility(tabsVisibility);
// Perform the actual search
mAllPagesAdapter.getFilter().filter(searchTerm);
mAllPagesCursorAdapter.filter(searchTerm);
}
public void setSearchEngines(JSONArray engines) {
mSearchEngines = engines;
GeckoAppShell.getMainHandler().post(new Runnable() {
public void run() {
mAllPagesCursorAdapter.notifyDataSetChanged();
}
});
}
}

View File

@ -1893,9 +1893,10 @@ abstract public class GeckoApp
if (data != null) {
String url = data.getStringExtra(AwesomeBar.URL_KEY);
AwesomeBar.Type type = AwesomeBar.Type.valueOf(data.getStringExtra(AwesomeBar.TYPE_KEY));
String searchEngine = data.getStringExtra(AwesomeBar.SEARCH_KEY);
if (url != null && url.length() > 0) {
mBrowserToolbar.setProgressVisibility(true);
loadUrl(url, type);
loadRequest(url, type, searchEngine);
}
}
break;
@ -1920,14 +1921,27 @@ abstract public class GeckoApp
startActivityForResult(intent, CAMERA_CAPTURE_REQUEST);
}
public void loadUrl(String url, AwesomeBar.Type type) {
// If searchEngine is provided, url will be used as the search query.
// Otherwise, the url is loaded.
private void loadRequest(String url, AwesomeBar.Type type, String searchEngine) {
mBrowserToolbar.setTitle(url);
Log.d(LOGTAG, type.name());
if (type == AwesomeBar.Type.ADD) {
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Add", url));
} else {
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Load", url));
JSONObject args = new JSONObject();
try {
args.put("url", url);
args.put("engine", searchEngine);
} catch (Exception e) {
Log.e(LOGTAG, "error building JSON arguments");
}
if (type == AwesomeBar.Type.ADD) {
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Add", args.toString()));
} else {
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Load", args.toString()));
}
}
public void loadUrl(String url, AwesomeBar.Type type) {
loadRequest(url, type, null);
}
public GeckoSoftwareLayerClient getSoftwareLayerClient() { return mSoftwareLayerClient; }

View File

@ -7,6 +7,7 @@
<!ENTITY awesomebar_all_pages_title "Top Sites">
<!ENTITY awesomebar_bookmarks_title "Bookmarks">
<!ENTITY awesomebar_history_title "History">
<!ENTITY awesomebar_search_engine "Search for \&quot;&#037;s\&quot;">
<!ENTITY crash_reporter_title "&brandShortName; Crash Reporter">
<!ENTITY crash_message "&brandShortName; has crashed. Your tabs should be listed on the &brandShortName; Start page when you restart.">

View File

@ -12,6 +12,7 @@
<string name="awesomebar_all_pages_title">&awesomebar_all_pages_title;</string>
<string name="awesomebar_bookmarks_title">&awesomebar_bookmarks_title;</string>
<string name="awesomebar_history_title">&awesomebar_history_title;</string>
<string name="awesomebar_search_engine">&awesomebar_search_engine;</string>
<string name="crash_reporter_title">&crash_reporter_title;</string>
<string name="crash_message">&crash_message;</string>

View File

@ -173,6 +173,7 @@ var BrowserApp = {
Services.obs.addObserver(this, "FullScreen:Exit", false);
Services.obs.addObserver(this, "Viewport:Change", false);
Services.obs.addObserver(this, "AgentMode:Change", false);
Services.obs.addObserver(this, "SearchEngines:Get", false);
function showFullScreenWarning() {
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertFullScreenToast"), "short");
@ -513,6 +514,34 @@ var BrowserApp = {
}
},
getSearchEngines: function() {
let engineData = Services.search.getEngines({});
let searchEngines = engineData.map(function (engine) {
return {
name: engine.name,
iconURI: engine.iconURI.spec
};
});
sendMessageToJava({
gecko: {
type: "SearchEngines:Data",
searchEngines: searchEngines
}
});
},
getSearchOrFixupURI: function(aData) {
let args = JSON.parse(aData);
let uri;
if (args.engine) {
let engine = Services.search.getEngineByName(args.engine);
uri = engine.getSubmission(args.url).uri;
} else
uri = URIFixup.createFixupURI(args.url, Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP);
return uri ? uri.spec : args.url;
},
scrollToFocusedInput: function(aBrowser) {
let doc = aBrowser.contentDocument;
if (!doc)
@ -542,11 +571,9 @@ var BrowserApp = {
} else if (aTopic == "Session:Stop") {
browser.stop();
} else if (aTopic == "Tab:Add") {
let uri = URIFixup.createFixupURI(aData, Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP);
let newTab = this.addTab(uri ? uri.spec : aData);
let newTab = this.addTab(this.getSearchOrFixupURI(aData));
} else if (aTopic == "Tab:Load") {
let uri = URIFixup.createFixupURI(aData, Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP);
browser.loadURI(uri ? uri.spec : aData);
browser.loadURI(this.getSearchOrFixupURI(aData));
} else if (aTopic == "Tab:Select") {
this.selectTab(this.getTabForId(parseInt(aData)));
} else if (aTopic == "Tab:Close") {
@ -573,6 +600,8 @@ var BrowserApp = {
} else if (aTopic == "Viewport:Change") {
this.selectedTab.viewport = JSON.parse(aData);
ViewportHandler.onResize();
} else if (aTopic == "SearchEngines:Get") {
this.getSearchEngines();
}
},