Android Studio TV 遥控器按钮

Posted

技术标签:

【中文标题】Android Studio TV 遥控器按钮【英文标题】:Android Studio TV remote buttons 【发布时间】:2017-01-21 14:44:13 【问题描述】:

我正在尝试为 android 电视制作一个应用程序,它将使用电视遥控器中的以下按钮:updownleftrightcenter/enterhome、@ 987654328@.

我需要哪些课程/活动才能做到这一点? 我一直在尝试使用此处找到的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.javaOnCreate 内部)中调用此函数的代码:

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

【问题讨论】:

【参考方案1】:

如果您不使用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_UPcase KeyEvent.KEYCODE_DPAD_DOWN 等)。

正如您在代码共享中设置的那样,您还可以在视图上设置OnKeyListener,但在这种情况下,您只需覆盖Activity 方法。


如果您使用的是leanback(擅长列表管理和媒体播放):

Leanback 是 Google 创建的库,旨在让编写 Android TV 应用程序变得更容易,因为它与内容列表和媒体播放相关,所以可以本地处理这个问题。我建议查看我上面链接到的他们的示例项目。

如果您想自己实现点击处理,您可以查看他们的源代码,看看他们如何在PlaybackControlGluePlaybackOverlayFragment 类中解决它。

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


另一个很好的例子是在PlaybackOverlayFragmentonInterceptInputEvent(...) 方法中找到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);

如果这能解决您的问题,请告诉我。

【讨论】:

我对如何针对我的具体情况实现这一点有点困惑。我的电视应用程序只有一个全屏活动,只有一张图像,我想根据我按下的远程按钮更改图像。没有视频或其他任何东西 我针对活动的情况编辑了答案。如果您需要任何澄清,请告诉我。 This link 可能会提供更多见解。还有this link。 你离得太近了!因此,在您的示例中,您有两个关键侦听器,一个是您在视图上设置的 (mContentView),另一个是您在活动本身上设置的 (@Override onKey)。您可以删除添加到视图中的键侦听器,并将onKey 方法的实际主体移动到活动的 onKey 方法。那么这应该工作。我已经在我的帖子顶部附加了代码,因为你在那里 90%。我在电视上对其进行了测试,它可以正常工作。 我找到了另一个指南,它只是简单地为其他人提供参考:developer.android.com/training/game-controllers/… 哇,这条评论真的是救命稻草,谢谢先生。

以上是关于Android Studio TV 遥控器按钮的主要内容,如果未能解决你的问题,请参考以下文章

Android 遥控器如何与 Google TV 配合使用

安卓TV开发 Android模拟事件 遥控器变身成鼠标来操作TV

Jetpack Compose:在 Android TV 中使用遥控器触发 onClick 事件

Android TV开发中所有的遥控器按键监听及注意事项,新增home键监听

Android TV 选中高亮显示

Android TV开发焦点移动源码分析