I'm developing a Google Glass app that displays n cards to the user, each with its custom menu.
The user should be able to access the menu through Voice ('Ok Glass') and Touch ('Tap'). The following example deals only with two cards (and two menus):
public class JobActivity extends Activity {
// Manages CardScrollView and CardScrollAdapter
private CardHolder mCardHolder;
private Menu mCustomMenu;
private GestureDetector mGestureDetector;
@Override
protected void onCreate(Bundle bundle)
{
super.onCreate(bundle);
mCardHolder = new CardHolder(this);
getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(mCardHolder.getView());
}
mGestureDetector = createGestureDetector(this);
}
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
gestureDetector.setBaseListener(new GestureDetector.BaseListener() {
@Override
public boolean onGesture(Gesture gesture) {
if (gesture == Gesture.TAP) {
openOptionsMenu();
return true;
} else if (gesture == Gesture.SWIPE_RIGHT) {
if (mCardHolder.getCurrentCardPos() == 0) {
// Moves to the next card automatically
updateOptionsMenu(getCardTwoMenuItems());
}
return true;
} else if (gesture == Gesture.SWIPE_LEFT) {
if (mCardHolder.getCurrentCardPos() == 1) {
// Moves to the previous card automatically
updateOptionsMenu(getCardOneMenuItems());
}
return true;
}
return false;
}
});
return gestureDetector;
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mGestureDetector != null) return mGestureDetector.onMotionEvent(event);
return false;
}
@Override
protected void onResume() {
super.onResume();
mCardHolder.activate();
}
@Override
protected void onPause() {
mCardHolder.deactivate(); }
super.onPause();
}
@Override
public boolean onCreatePanelMenu(int featId, Menu menu) {
if (featId == WindowUtils.FEATURE_VOICE_COMMANDS || featId == Window.FEATURE_OPTIONS_PANEL) {
List<String> itemList = getCardOneMenuItems();
mCustomMenu = menu;
for (int i = 0; i < itemList.size(); i++)
mCustomMenu.add(Menu.NONE, i, Menu.NONE, itemList.get(i));
super.onCreatePanelMenu(featId, mCustomMenu);
return true;
}
return false;
}
private void updateOptionsMenu(List<String> itemList) {
if (mCustomMenu != null) mCustomMenu.clear();
for (int i = 0; i < itemList.size(); i++)
mCustomMenu.add(Menu.NONE, i, Menu.NONE, itemList.get(i));
if (mCustomMenu != null) onPrepareOptionsMenu(mCustomMenu);
}
@Override
public boolean onMenuItemSelected(int featId, MenuItem menuItem) {
if (featId == WindowUtils.FEATURE_VOICE_COMMANDS || featId == Window.FEATURE_OPTIONS_PANEL) {
if (mCardHolder.getCurrentCardPos() == 0) {
// An item was selected from the menu in the first card
if (menuItem.getItemId() == 0) {
// User selected 'Goto the next card'
updateOptionsMenu(getCardTwoMenuItems());
mCardHolder.next(); // Moves to the next card
} else if (menuItem.getItemId() == 1) doSomething();
else if (menuItem.getItemId() == 2) doSomethingElse();
} else if (mCardHolder.getCurrentCardPos() == 1) {
// An item was selected from the menu in the second card
if (menuItem.getItemId() == 0) {
updateOptionsMenu(getCardOneMenuItems());
mCardHolder.previous(); // Moves to the previous card
} else if (menuItem.getItemId() == 1) doSomethingMore();
}
return true;
}
return super.onMenuItemSelected(featId, menuItem);
}
private List<String> getCardTwoMenuItems() {
List<String> cardTwoMenuItems = new ArrayList<>();
cardTwoMenuItems.add(getResources().getString(R.string.card_previous));
cardTwoMenuItems.add(getResources().getString(R.string.something_more));
return cardTwoMenuItems;
}
private List<String> getCardOneMenuItems() {
List<String> cardOneMenuItems = new ArrayList<>();
cardOneMenuItems.add(getResources().getString(R.string.card_next));
cardOneMenuItems.add(getResources().getString(R.string.something));
cardOneMenuItems.add(getResources().getString(R.string.something_else));
return cardOneMenuItems;
}
The code above works in several situations:
If I say 'Ok Glass' and 'Go to the next card'. Saying 'Ok Glass', now in the second card, brings up the correct menu.
If I tap and select 'Go to the next card'. Tapping again, now in the second card, brings up the correct menu.
If I swipe right. Saying 'Ok Glass', now in the second card, brings up the correct menu.
However, the code does not work in the following situations:
If I say 'Ok Glass' and 'Go to the next card'. If I tap, now in the second card, it brings up the incorrect menu (the one from the first card).
If I swipe right. If I tap, now in the second card, it brings up the incorrect menu (the one from the first card).
If I tap and select 'Go to the next card'. Saying 'Ok Glass', now in the second card, brings up the incorrect menu (the one from the first card).
The solution is in the
onPrepareOptionsMenu
The
onPrepareOptionsMenu
is called by the system and the menu items are added to the menu that is passed to it. This happens every time the menu is called (whether by tap or glass). Hence, if you override this method you should be able to insert values in the menu