如何在 Android / Google Glass 中管理语音和触摸输入的多个菜单

How to manage multiple menus for voice and touch input in Android / Google Glass

我正在开发一个 Google Glass 应用程序,可以向用户显示 n 张卡片,每张卡片都有其 自定义菜单 .

用户应该能够通过语音 ('Ok Glass') 和触摸 ('Tap').以下示例仅处理 两张 卡片(和两个菜单):

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;
}

上面的代码适用于几种情况:

但是,代码在以下情况下不起作用

解决方案在onPrepareOptionsMenu

public boolean onPrepareOptionsMenu (Menu menu){

    for (int i = 0; i < mJobMenu.size(); i++)
        menu.add(Menu.NONE, i, Menu.NONE, mJobMenu.getItem(i));

}

onPrepareOptionsMenu 由系统调用,菜单项被添加到传递给它的菜单中。每次调用菜单时都会发生这种情况(无论是通过点击还是玻璃)。因此,如果您覆盖此方法,您应该能够在菜单中插入值