那些我们解过的bug之蓝牙耳机不能播放上一首歌

这里写图片描述

问题描述:

手机连接蓝牙耳机(SAMSUNG耳机),无法用耳机切换上一首(只能切换下一首)

重现问题:

这个问题因为重现概率是100%,所以我借了一只蓝牙耳机,从设置的蓝牙进入,点击连接蓝牙耳机,切换下一首,手机能正常插入下一首。点击上一首,问题来了,确实是不能播放上一首,具体的表现是重新播放此首音乐。

初步分析:

根据问题描述,初步分析:

  1. 可能是蓝牙耳机切换下一首按键命令有问题,可能按下切换下一首按键,发出的是重播的命令。
  2. 也有可能是按键命令本身正确,但是处理切换下一首按键的代码逻辑本身的问题

问题解决:

首先,确认蓝牙耳机按键是否正常。

我用自己的小米手机测试了此蓝牙耳机,发现在小米手机上蓝牙耳机的切换上一首和切换下一首功能是正常的,那么基本上排除了第一个蓝牙耳机切换下一首按键命令问题。

下面就只有第二个原因,

我首先查看了log,但是没有发现有效的log信息。
再在网上查了一资料,找到了一个感觉有用的东西:
Android 接收蓝牙耳机按键操作
http://blog.csdn.net/lihongyu65085/article/details/39853669

我选择关键字蓝牙耳机下一首按键来搜索:

KeyEvent.KEYCODE_MEDIA_NEXT

查找到代码:

……/app/Music/src/com/android/music/MediaButtonIntentReceiver.java:91:                case KeyEvent.KEYCODE_MEDIA_NEXT:

好家伙,确实有线索。我们打开此文件:


public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) {
            Intent i = new Intent(context, MediaPlaybackService.class);
            i.setAction(MediaPlaybackService.SERVICECMD);
            i.putExtra(MediaPlaybackService.CMDNAME, MediaPlaybackService.CMDPAUSE);
            context.startService(i);
        } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
            KeyEvent event = (KeyEvent)
                    intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);

            if (event == null) {
                return;
            }

            int keycode = event.getKeyCode();
            int action = event.getAction();
            long eventtime = event.getEventTime();

            // single quick press: pause/resume. 
            // double press: next track
            // long press: start auto-shuffle mode.

            String command = null;
            switch (keycode) {
                case KeyEvent.KEYCODE_MEDIA_STOP:
                    command = MediaPlaybackService.CMDSTOP;
                    break;
                case KeyEvent.KEYCODE_HEADSETHOOK:
                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                    command = MediaPlaybackService.CMDTOGGLEPAUSE;
                    break;
                case KeyEvent.KEYCODE_MEDIA_NEXT:
                    command = MediaPlaybackService.CMDNEXT;
                    break;
                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
                    command = MediaPlaybackService.CMDPREVIOUS;
                    break;
                case KeyEvent.KEYCODE_MEDIA_PAUSE:
                    command = MediaPlaybackService.CMDPAUSE;
                    break;
                case KeyEvent.KEYCODE_MEDIA_PLAY:
                    command = MediaPlaybackService.CMDPLAY;
                    break;
            }

此代码,我们可以知道,MediaButtonIntentReceiver主要接受广播AudioManager.ACTION_AUDIO_BECOMING_NOISY和Intent.ACTION_MEDIA_BUTTON。而我们的蓝牙按键就是发送广播Intent.ACTION_MEDIA_BUTTON。并且,我们可以看到我们的按键事件:
KeyEvent.KEYCODE_MEDIA_STOP —停止
KeyEvent.KEYCODE_MEDIA_PAUSE —暂停
KeyEvent.KEYCODE_MEDIA_NEXT —下一首
MediaPlaybackService.CMDPREVIOUS —上一首
KeyEvent.KEYCODE_MEDIA_PLAY —播放

再往下看:

// only consider the first event in a sequence, not the repeat events,
// so that we don't trigger in cases where the first event went to
// a different app (e.g. when the user ends a phone call by
// long pressing the headset button)
// The service may or may not be running, but we need to send it
// a command.
Intent i = new Intent(context, MediaPlaybackService.class);
i.setAction(MediaPlaybackService.SERVICECMD);
if (keycode == KeyEvent.KEYCODE_HEADSETHOOK &&eventtime - mLastClickTime < 300) {
   i.putExtra(MediaPlaybackService.CMDNAME,      MediaPlaybackService.CMDNEXT);
   context.startService(i);
   mLastClickTime = 0;
} else {
   i.putExtra(MediaPlaybackService.CMDNAME, command);
   context.startService(i);
   mLastClickTime = eventtime;
}

从代码,我们可以看出,启动一个服务:MediaPlaybackService,并将按键命令发送过去。

我们再打开MediaPlaybackService:


public int onStartCommand(Intent intent, int flags, int startId) {

         ………..
            String action = intent.getAction();
            String cmd = intent.getStringExtra("command");

            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
                gotoNext(true);
            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
                if (position() < 2000) {
                    prev();
                } else {
                    seek(0);
                    play();
                }

从代码,我们可以看出:当按键命令是上一首时,

                seek(0);
                play();

这段代码,非常明显,就是导致不能播放上一首的原因所在。

问题找到了,解决就比较简单了:

//JABALCOA-139 prev music by bluetooth headset 20151208 start
                    //seek(0);
                    //play();
                    prev();
//JABALCOA-139 prev music by bluetooth headset 20151208 end

总结:

我们再来看MediaButtonIntentReceiver广播监听器:
其主要监听如下二个广播:

    <receiver android:name="com.android.music.MediaButtonIntentReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
            <action android:name="android.media.AUDIO_BECOMING_NOISY" />
        </intent-filter>
    </receiver>

监听按键事件有:

KeyEvent.KEYCODE_MEDIA_STOP:
KeyEvent.KEYCODE_HEADSETHOOK:
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
KeyEvent.KEYCODE_MEDIA_NEXT:
KeyEvent.KEYCODE_MEDIA_PREVIOUS:
KeyEvent.KEYCODE_MEDIA_PAUSE:
KeyEvent.KEYCODE_MEDIA_PLAY:

当监听到按键事件后,再启动服务:MediaPlaybackService

    <service android:name="com.android.music.MediaPlaybackService"
        android:exported="false" />

在onStartCommand方法中判断按键事件,再进行相应的操作。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hfreeman2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值