遥控器快捷按键实现

源码修改之遥控器快捷通道添加

  • 获取遥控快捷通道按键的keycode

    logcat下遥控器按键值和源码keycode值,对应如下:

    public static final int KEYCODE_PROG_RED        = 183;
    public static final int KEYCODE_PROG_GREEN      = 184;
    public static final int KEYCODE_PROG_YELLOW     = 185;
    public static final int KEYCODE_PROG_BLUE       = 186;
    
  • 需求如下:

    KEYCODE_PROG_RED                AV[1,2]
    KEYCODE_PROG_GREEN              HDMI[1,2,3]
    KEYCODE_PROG_YELLOW             DTV
    KEYCODE_PROG_BLUE               ATV
    
  • 查找电视通道切换代码位置及方式

    设备切换到电视界面,不断地切换通道,记录当前activity情况(dumpsys activity)
    得到信息归纳集中如下:

  1. 所有电视通道下的主界面activity均为RootActivity.java

    路径如下::device/mstar/common/apps/MTvPlayer/src/com/mstar/tv/tvplayer/ui/RootActivity.java

  2. 各通道信息代码使用int值表示,具体信息如下:

    INPUT_SOURCE_ATV = 1;
    
    INPUT_SOURCE_CVBS = 2;
    INPUT_SOURCE_CVBS2 = 3;
    
    INPUT_SOURCE_HDMI = 23;
    INPUT_SOURCE_HDMI2 = 24;
    INPUT_SOURCE_HDMI3 = 25;
    
    INPUT_SOURCE_DTV = 28;
    
  3. 切换电视通道后,直接启动电视的apk软件,即可进入相应的通道

    //初始化intent
    Intent shortcutIntent = new Intent();
    shortcutIntent.setComponent(new ComponentName("com.mstar.tv.tvplayer.ui",
        "com.mstar.tv.tvplayer.ui.RootActivity"));
    
    // 此处设置电视通道即可
    // ...
    
    shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    mContext.startActivity(shortcutIntent);
    
  4. 获取及设置电视通道

    // 获取通道信息
    int currentTvInputSource = TvCommonManager.getInstance().getCurrentTvInputSource();
    
    // 设置通道信息
    TvCommonManager.getInstance().setInputSource(1);
    
  • 添加代码
  1. 我们知道系统按键的分发过程中肯定会走PhoneWindowManager中的interceptKeyBeforeDispatching方法,如果按键没有下层处理,这里会收到两次事件,我们这里添加我们的遥控按键处理流程

    // new code by allies begin
    else if (keyCode == KeyEvent.KEYCODE_PROG_RED || keyCode == KeyEvent.KEYCODE_PROG_GREEN ||
              keyCode == KeyEvent.KEYCODE_PROG_YELLOW || keyCode == KeyEvent.KEYCODE_PROG_BLUE) {
        if (down) {
            launchShortcut(keyCode);
            // do interceptKeyEvent
            return -1;
          }
    }
    // new code by allies end
    
    // new code by allies begin
    private static int av = 2;
    private static int hdmi = 23;
    private static int mAntennaType = 0;
    
    private void launchShortcut(int keycode) {
    
        final int currentTvInputSource = TvCommonManager.getInstance().getCurrentTvInputSource();
        final boolean withinTV = getTopActivity();
    
        if (TvCommonManager.getInstance().getCurrentTvSystem() == TvCommonManager.TV_SYSTEM_ISDB) {
            mAntennaType = (keycode == 185 ? 2 : 1);
        }
    
        Intent shortcutIntent1 = new Intent("com.mstar.android.intent.action.START_TV_PLAYER");
        shortcutIntent1.putExtra("inputAntennaType", mAntennaType);
        shortcutIntent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        shortcutIntent1.addFlags(8192);
    
        Intent shortcutIntent2 = new Intent("mstar.tvsetting.ui.intent.action.RootActivity");
    
        switch (keycode) {
            case KeyEvent.KEYCODE_PROG_RED:
                //keycode(183) AV[CVBS1-8] inputsource(2-9)
                if (withinTV && currentTvInputSource == 2 || currentTvInputSource ==3) {
                    av++;
                    if (av >= 4) {
                        av = 2;
                    }
                }
                TvCommonManager.getInstance().setInputSource(av);
                shortcutIntent1.putExtra("inputSrc", av);
                break;
            case KeyEvent.KEYCODE_PROG_GREEN:
                //(184) HDMI(23) HDMI1(24) HDMI2(25) HDMI3(26)
                if (withinTV  && currentTvInputSource == 23 || currentTvInputSource == 24 ||
                    currentTvInputSource == 25) {
                    hdmi++;
                    if (hdmi >= 26) {
                        hdmi = 23;
                    }
                }
                TvCommonManager.getInstance().setInputSource(hdmi);
                shortcutIntent1.putExtra("inputSrc", hdmi);
                break;
            case KeyEvent.KEYCODE_PROG_YELLOW:
                //(185) ATV(1) inputAntennaType 2
                if (withinTV && currentTvInputSource == 1) {
                    return;
                }
                TvCommonManager.getInstance().setInputSource(1);
                shortcutIntent1.putExtra("inputSrc", 1);
                break;
            case KeyEvent.KEYCODE_PROG_BLUE:
                //(186) DTV(28) inputAntennaType 1
                if (withinTV && currentTvInputSource == 28) {
                    return;
                }
                TvCommonManager.getInstance().setInputSource(28);
                shortcutIntent1.putExtra("inputSrc", 28);
              break;
          }
    
            mContext.startActivity(shortcutIntent1);
    
            if (withinTV) {
                shortcutIntent2.putExtra("task_tag", "input_source_changed");
            }else{
                shortcutIntent2.putExtra("no_change_source", true);
            }
    
            shortcutIntent2.putExtra("inputAntennaType", mAntennaType);
            mContext.startActivity(shortcutIntent2);
    }
    // new code by allies end
    
  1. 为了提高用户体验,例如在hdmi通道下,连续点按HDMI快捷键,是在各个HDMI通道下进行切换,如果当前界面不是在电视apk下,用户点击HDMI快捷键,直接进入上次的通道(HDMI通道不做切换)

    处于tv应用内,且当前通道位于HDMI下,HDMI通道自动切换
    if (withinTV && currentTvInputSource == 2 || currentTvInputSource ==3){
      // ...
    }
    
  2. 实现这个功能,需要获取当前resume的activity进行判断,无奈在安卓6.0中相应获取正在运行的api已经不能正常使用,这里测试一下通过如下代码可以获取到最近的进程名

    private boolean getTopActivity() {
         ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = manager.getRunningAppProcesses();
         Iterator<ActivityManager.RunningAppProcessInfo> iterator = runningAppProcesses.iterator();
    
         //get top-activity
         ActivityManager.RunningAppProcessInfo processInfo = iterator.next();
         String processName = processInfo.processName;
    
         //within tv-apk
         if (processName.equals("com.mstar.tv.tvplayer.ui") ||
                 // processName.equals("com.jrm.localmm") ||
                 processName.equals("com.mstar.tvsetting")) {
             return true;
         }else {
             return false;
         }
     }
    

    经测试发现,在PhoneWindowManager下调用可以准确获取运行的进程名

  • 编译生成测试

    1. mm -B 编译当前代码路径

    2. cd .. 后 cproj 跳到当前文件mk路径 mm -B 编译当前文件

    3. 同步步骤2,编译发现生成service.jar,替换系统中相应文件测试即可

坚持原创技术分享,您的支持将鼓励我继续创作!