Android 工作室电视遥控器按钮
Android Studio TV remote buttons
我正在尝试为 android 电视制作一个应用程序,它将使用电视遥控器上的以下按钮:up
、down
、left
、right
, center/enter
, home
, back
.
我需要什么 classes/events 才能做到这一点?
我一直在尝试使用此处的 Dpad
代码:Link dev android.
但是当我尝试在带有方向键输入的电视上使用 android 模拟器对其进行测试时,它不起作用。有很多Log语句,我发现我的问题是以下代码行:
if (event instanceof MotionEvent) {
// Use the hat axis value to find the D-pad direction
MotionEvent motionEvent = (MotionEvent) event;
float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);
Log.d("test", "xaxis = " + String.valueOf(xaxis) +
" yaxis = " + String.valueOf(yaxis));
}
Log.d("test", "returning directionPressed as - " +
String.valueOf(directionPressed));
return directionPressed;
我得到的输出如下(打印 2 次,即使我只按一次按钮):
09-13 14:45:05.643 1489-1489/omgandroid D/test: is motion event = true
09-13 14:45:05.643 1489-1489/omgandroid D/test: is key event = false
09-13 14:45:05.643 1489-1489/omgandroid D/test: xaxis = 0.0 yaxis = 0.0
09-13 14:45:05.643 1489-1489/omgandroid D/test: returning directionPressed as -1
我看到 getAxisValue(MotionEvent.AXIS_HAT_X/Y)
总是返回 0.0,但我不知道为什么。
这是我在 MainActivity.java
中调用此函数的代码(在 OnCreate
中):
mContentView.setOnGenericMotionListener(new View.OnGenericMotionListener() {
@Override
public boolean onGenericMotion(View view, MotionEvent event) {
Log.d("test", "this works too");
// Check if this event if from a D-pad and process accordingly.
boolean check = Dpad.isDpadDevice(event);
String str_check = String.valueOf(check);
Log.d("test", "is dpad device? " + str_check);
if (check) {
int press = mDpad.getDirectionPressed(event);
Log.d("test", String.valueOf(press));
switch (press) {
case LEFT:
// Do something for LEFT direction press
Log.d("test", "LEFT");
String uri = source + image;
ImageView img = (ImageView) findViewById(R.id.fullscreen_content);
img.setImageResource(R.drawable.a00_d01_01);
return true;
case RIGHT:
// Do something for RIGHT direction press
Log.d("test", "RIGHT");
return true;
case UP:
// Do something for UP direction press
Log.d("test", "UP");
return true;
case DOWN:
// Do something for DOWN direction press
Log.d("test", "DOWN");
return true;
case CENTER:
// DO something for CENTER direction press
Log.d("test", "CENTER");
return true;
default:
return false;
}
}
return false;
}
});
如果您不使用 Leanback 并且想要 Activity
中的功能,那么您可以覆盖 Activity
方法 onKeyDown()
:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d("debug", "we are here");
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_ESCAPE:
Log.d("OnKey", "key pressed!");
Toast.makeText(MainActivity.this, "key pressed!", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
然后使用如下的 switch 语句(在 keyCode 上)触发您想要捕获的条件(case KeyEvent.KEYCODE_DPAD_UP
、case KeyEvent.KEYCODE_DPAD_DOWN
等)。
正如您在代码共享中所做的那样,您还可以在视图上设置 OnKeyListener
,但在这种情况下,您只需要覆盖 Activity
方法。
如果您使用的是 Leanback(擅长列表管理和媒体播放):
Leanback,Google 为简化编写 Android 电视应用程序而创建的库,本机处理此问题,因为它与内容列表和媒体播放有关。我建议查看我上面链接的示例项目。
如果您想自己实现点击处理,您可以查看他们的源代码并了解他们如何在 PlaybackControlGlue
和 PlaybackOverlayFragment
类 中解决它。
Here 他们处理 onKey(...)
方法中的事件:
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_ESCAPE:
在其正下方的 dispatchAction(...)
方法中还有一些其他事件:
boolean canPlay = keyEvent == null ||
keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY;
他们通过输入处理程序设置密钥处理程序:
private final PlaybackOverlayFragment.InputEventHandler mOnInputEventHandler =
new PlaybackOverlayFragment.InputEventHandler() {
@Override
public boolean handleInputEvent(InputEvent event) {
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
return onKey(null, keyEvent.getKeyCode(), keyEvent);
}
return false;
}
};
通过以下方式设置:mFragment.setInputEventHandler(mOnInputEventHandler);
另一个很好的例子是 PlaybackOverlayFragment
的 onInterceptInputEvent(...)
方法找到 here:
private boolean onInterceptInputEvent(InputEvent event) {
final boolean controlsHidden = areControlsHidden();
if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
boolean consumeEvent = false;
int keyCode = KeyEvent.KEYCODE_UNKNOWN;
if (mInputEventHandler != null) {
consumeEvent = mInputEventHandler.handleInputEvent(event);
}
if (event instanceof KeyEvent) {
keyCode = ((KeyEvent) event).getKeyCode();
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
他们通过以下方式附加拦截器:getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
如果这能解决您的问题,请告诉我。
我正在尝试为 android 电视制作一个应用程序,它将使用电视遥控器上的以下按钮:up
、down
、left
、right
, center/enter
, home
, back
.
我需要什么 classes/events 才能做到这一点?
我一直在尝试使用此处的 Dpad
代码:Link dev android.
但是当我尝试在带有方向键输入的电视上使用 android 模拟器对其进行测试时,它不起作用。有很多Log语句,我发现我的问题是以下代码行:
if (event instanceof MotionEvent) {
// Use the hat axis value to find the D-pad direction
MotionEvent motionEvent = (MotionEvent) event;
float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);
Log.d("test", "xaxis = " + String.valueOf(xaxis) +
" yaxis = " + String.valueOf(yaxis));
}
Log.d("test", "returning directionPressed as - " +
String.valueOf(directionPressed));
return directionPressed;
我得到的输出如下(打印 2 次,即使我只按一次按钮):
09-13 14:45:05.643 1489-1489/omgandroid D/test: is motion event = true
09-13 14:45:05.643 1489-1489/omgandroid D/test: is key event = false
09-13 14:45:05.643 1489-1489/omgandroid D/test: xaxis = 0.0 yaxis = 0.0
09-13 14:45:05.643 1489-1489/omgandroid D/test: returning directionPressed as -1
我看到 getAxisValue(MotionEvent.AXIS_HAT_X/Y)
总是返回 0.0,但我不知道为什么。
这是我在 MainActivity.java
中调用此函数的代码(在 OnCreate
中):
mContentView.setOnGenericMotionListener(new View.OnGenericMotionListener() {
@Override
public boolean onGenericMotion(View view, MotionEvent event) {
Log.d("test", "this works too");
// Check if this event if from a D-pad and process accordingly.
boolean check = Dpad.isDpadDevice(event);
String str_check = String.valueOf(check);
Log.d("test", "is dpad device? " + str_check);
if (check) {
int press = mDpad.getDirectionPressed(event);
Log.d("test", String.valueOf(press));
switch (press) {
case LEFT:
// Do something for LEFT direction press
Log.d("test", "LEFT");
String uri = source + image;
ImageView img = (ImageView) findViewById(R.id.fullscreen_content);
img.setImageResource(R.drawable.a00_d01_01);
return true;
case RIGHT:
// Do something for RIGHT direction press
Log.d("test", "RIGHT");
return true;
case UP:
// Do something for UP direction press
Log.d("test", "UP");
return true;
case DOWN:
// Do something for DOWN direction press
Log.d("test", "DOWN");
return true;
case CENTER:
// DO something for CENTER direction press
Log.d("test", "CENTER");
return true;
default:
return false;
}
}
return false;
}
});
如果您不使用 Leanback 并且想要 Activity
中的功能,那么您可以覆盖 Activity
方法 onKeyDown()
:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d("debug", "we are here");
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_ESCAPE:
Log.d("OnKey", "key pressed!");
Toast.makeText(MainActivity.this, "key pressed!", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
然后使用如下的 switch 语句(在 keyCode 上)触发您想要捕获的条件(case KeyEvent.KEYCODE_DPAD_UP
、case KeyEvent.KEYCODE_DPAD_DOWN
等)。
正如您在代码共享中所做的那样,您还可以在视图上设置 OnKeyListener
,但在这种情况下,您只需要覆盖 Activity
方法。
如果您使用的是 Leanback(擅长列表管理和媒体播放):
Leanback,Google 为简化编写 Android 电视应用程序而创建的库,本机处理此问题,因为它与内容列表和媒体播放有关。我建议查看我上面链接的示例项目。
如果您想自己实现点击处理,您可以查看他们的源代码并了解他们如何在 PlaybackControlGlue
和 PlaybackOverlayFragment
类 中解决它。
Here 他们处理 onKey(...)
方法中的事件:
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_ESCAPE:
在其正下方的 dispatchAction(...)
方法中还有一些其他事件:
boolean canPlay = keyEvent == null ||
keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY;
他们通过输入处理程序设置密钥处理程序:
private final PlaybackOverlayFragment.InputEventHandler mOnInputEventHandler =
new PlaybackOverlayFragment.InputEventHandler() {
@Override
public boolean handleInputEvent(InputEvent event) {
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
return onKey(null, keyEvent.getKeyCode(), keyEvent);
}
return false;
}
};
通过以下方式设置:mFragment.setInputEventHandler(mOnInputEventHandler);
另一个很好的例子是 PlaybackOverlayFragment
的 onInterceptInputEvent(...)
方法找到 here:
private boolean onInterceptInputEvent(InputEvent event) {
final boolean controlsHidden = areControlsHidden();
if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
boolean consumeEvent = false;
int keyCode = KeyEvent.KEYCODE_UNKNOWN;
if (mInputEventHandler != null) {
consumeEvent = mInputEventHandler.handleInputEvent(event);
}
if (event instanceof KeyEvent) {
keyCode = ((KeyEvent) event).getKeyCode();
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
他们通过以下方式附加拦截器:getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
如果这能解决您的问题,请告诉我。