Bug 876765 - Part 3: Enable navigating to search suggestions with gamepad. r=lucasr

This commit is contained in:
Brian Nicholson 2013-07-15 14:36:13 -07:00
parent 29f9c4f4cb
commit 19bfc66f26
5 changed files with 132 additions and 2 deletions

View File

@ -6,12 +6,14 @@
package org.mozilla.gecko;
import org.mozilla.gecko.AwesomeBarTabs.OnUrlOpenListener;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.widget.FaviconView;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@ -37,6 +39,9 @@ class SearchEngineRow extends AnimatedHeightLayout {
// Search engine associated with this view
private SearchEngine mSearchEngine;
// Selected suggestion view
private int mSelectedView = 0;
// Event listeners for suggestion views
private final OnClickListener mClickListener;
private final OnLongClickListener mLongClickListener;
@ -163,5 +168,64 @@ class SearchEngineRow extends AnimatedHeightLayout {
for (int i = suggestionCount + 1; i < recycledSuggestionCount; i++) {
mSuggestionView.getChildAt(i).setVisibility(View.GONE);
}
// Make sure mSelectedView is still valid
if (mSelectedView >= mSuggestionView.getChildCount()) {
mSelectedView = mSuggestionView.getChildCount() - 1;
}
}
@Override
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
final View suggestion = mSuggestionView.getChildAt(mSelectedView);
if (event.getAction() != android.view.KeyEvent.ACTION_DOWN) {
return false;
}
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_RIGHT:
final View nextSuggestion = mSuggestionView.getChildAt(mSelectedView + 1);
if (nextSuggestion != null) {
changeSelectedSuggestion(suggestion, nextSuggestion);
mSelectedView++;
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
final View prevSuggestion = mSuggestionView.getChildAt(mSelectedView - 1);
if (prevSuggestion != null) {
changeSelectedSuggestion(suggestion, prevSuggestion);
mSelectedView--;
return true;
}
break;
case KeyEvent.KEYCODE_BUTTON_A:
// TODO: handle long pressing for editing suggestions
return suggestion.performClick();
}
return false;
}
private void changeSelectedSuggestion(View oldSuggestion, View newSuggestion) {
oldSuggestion.setDuplicateParentStateEnabled(false);
newSuggestion.setDuplicateParentStateEnabled(true);
oldSuggestion.refreshDrawableState();
newSuggestion.refreshDrawableState();
}
public void onSelected() {
mSelectedView = 0;
mUserEnteredView.setDuplicateParentStateEnabled(true);
mUserEnteredView.refreshDrawableState();
}
public void onDeselected() {
final View suggestion = mSuggestionView.getChildAt(mSelectedView);
suggestion.setDuplicateParentStateEnabled(false);
suggestion.refreshDrawableState();
}
}

View File

@ -123,7 +123,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
mView = (LinearLayout) (LayoutInflater.from(mContext).inflate(R.layout.awesomebar_allpages_list, null));
mView.setTag(TAG);
ListView list = getListView();
final ListView list = getListView();
list.setTag(TAG);
((Activity)mContext).registerForContextMenu(list);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@ -136,6 +136,23 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
AwesomeBarCursorAdapter adapter = getCursorAdapter();
list.setAdapter(adapter);
list.setOnTouchListener(mListListener);
final ListSelectionListener listener = new ListSelectionListener();
list.setOnItemSelectedListener(listener);
list.setOnFocusChangeListener(listener);
list.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
View selected = list.getSelectedView();
if (selected instanceof SearchEngineRow) {
return ((SearchEngineRow) selected).onKeyDown(keyCode, event);
}
return false;
}
});
}
return mView;
@ -461,6 +478,12 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
@Override
public boolean isEnabled(int position) {
// If we're using a gamepad or keyboard, allow the row to be
// focused so it can pass the focus to its child suggestion views.
if (!getListView().isInTouchMode()) {
return true;
}
// 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
@ -879,4 +902,46 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
}
}
}
private static class ListSelectionListener implements View.OnFocusChangeListener,
AdapterView.OnItemSelectedListener {
private SearchEngineRow mSelectedEngineRow;
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
View selectedRow = ((ListView) v).getSelectedView();
if (selectedRow != null) {
selectRow(selectedRow);
}
} else {
deselectRow();
}
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
deselectRow();
selectRow(view);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
deselectRow();
}
private void selectRow(View row) {
if (row instanceof SearchEngineRow) {
mSelectedEngineRow = (SearchEngineRow) row;
mSelectedEngineRow.onSelected();
}
}
private void deselectRow() {
if (mSelectedEngineRow != null) {
mSelectedEngineRow.onDeselected();
mSelectedEngineRow = null;
}
}
}
}

View File

@ -7,4 +7,5 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/awesomebar_row_height"
android:duplicateParentState="true"
android:padding="7dp"/>

View File

@ -17,6 +17,7 @@
<org.mozilla.gecko.FlowLayout android:id="@+id/suggestion_layout"
android:layout_toRightOf="@id/suggestion_icon"
android:layout_width="wrap_content"
android:duplicateParentState="true"
android:layout_height="wrap_content">
<include layout="@layout/suggestion_item"

View File

@ -10,7 +10,6 @@
android:background="@drawable/suggestion_selector"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:padding="7dp">
<ImageView android:id="@+id/suggestion_magnifier"