如何在 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;
}
上面的代码适用于几种情况:
如果我说'Ok Glass'和'Go to the next card'。说 'Ok Glass',现在在第二张卡片中,调出 正确的 菜单。
如果我点击和select'Go to the next card'。 再次点击,现在在第二张卡片中,调出正确的菜单。
如果我向右滑动。说 'Ok Glass',现在在第二张卡片中,调出 正确的 菜单。
但是,代码在以下情况下不起作用:
如果我说'Ok Glass'和'Go to the next card'。如果我 点击,现在在第二张卡片中,它会弹出 不正确的 菜单(来自第一张卡片的菜单)。
如果我向右滑动。如果我 点击,现在在第二张卡片中,它会弹出 不正确的 菜单(来自第一张卡片的菜单)。
如果我点击和select'Go to the next card'。说 'Ok Glass',现在在第二张卡片中,调出 不正确的 菜单(来自第一张卡片的菜单)。
解决方案在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
由系统调用,菜单项被添加到传递给它的菜单中。每次调用菜单时都会发生这种情况(无论是通过点击还是玻璃)。因此,如果您覆盖此方法,您应该能够在菜单中插入值
我正在开发一个 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;
}
上面的代码适用于几种情况:
如果我说'Ok Glass'和'Go to the next card'。说 'Ok Glass',现在在第二张卡片中,调出 正确的 菜单。
如果我点击和select'Go to the next card'。 再次点击,现在在第二张卡片中,调出正确的菜单。
如果我向右滑动。说 'Ok Glass',现在在第二张卡片中,调出 正确的 菜单。
但是,代码在以下情况下不起作用:
如果我说'Ok Glass'和'Go to the next card'。如果我 点击,现在在第二张卡片中,它会弹出 不正确的 菜单(来自第一张卡片的菜单)。
如果我向右滑动。如果我 点击,现在在第二张卡片中,它会弹出 不正确的 菜单(来自第一张卡片的菜单)。
如果我点击和select'Go to the next card'。说 'Ok Glass',现在在第二张卡片中,调出 不正确的 菜单(来自第一张卡片的菜单)。
解决方案在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
由系统调用,菜单项被添加到传递给它的菜单中。每次调用菜单时都会发生这种情况(无论是通过点击还是玻璃)。因此,如果您覆盖此方法,您应该能够在菜单中插入值