0

我已经尝试了所有方法,但无法让蓝牙控件在我的媒体应用程序中做出响应。我已经阅读了一百遍文档,但仍然无法正常工作。我的蓝牙耳机响应我设备上的其他媒体应用程序,所以它在我的应用程序中。

根据文档,如果应用程序使用 MediaBrowserService,则在 Android 8 及更高版本上运行的应用程序应自动响应蓝牙控件。这是我写的:

媒体浏览器服务:

public class MediaPlayerService extends MediaBrowserServiceCompat {

    private static MediaPlayer mMediaPlayer;
    private MediaSessionCompat mMediaSessionCompat;
    private Context mContext;
    private PlaybackStateCompat.Builder mPlaybackBuilder;

    public MediaPlayerService() {
        super();
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mContext = this;

        mMediaSessionCompat = new MediaSessionCompat(this, MediaPlayerService.class.getSimpleName());
        mMediaSessionCompat.setCallback(mMediaSessionCallback);
        setSessionToken(mMediaSessionCompat.getSessionToken());

        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        mMediaPlayer.setAudioAttributes(
                new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_MEDIA)
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        .build());

        mPlaybackBuilder = new PlaybackStateCompat.Builder();
        mPlaybackBuilder.setActions(
                PlaybackStateCompat.ACTION_PLAY_PAUSE
        );
    }
    
    public int onStartCommand(Intent intent, int flags, int startId) {
        MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent);

        return super.onStartCommand(intent, flags, startId);
    }


    private final MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {

        @Override
        public void onPlay() {
            super.onPlay();
            setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING,  0);

            mMediaPlayer.start();
        }

        @Override
        public void onPause() {
            super.onPause();
            setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED,  0);
            mMediaPlayer.pause();
        }

        @Override
        public void onPlayFromUri(final Uri uri, final Bundle extras) {
            super.onPlayFromUri(uri, extras);

            try {
                mMediaSessionCompat.setActive(true);

                mMediaPlayer.setDataSource(uri.toString());
                mMediaPlayer.prepareAsync();

                mMediaPlayer.setOnPreparedListener(mp -> {
                    mMediaPlayer.start();
                    setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING,  0);

                    final String channelID = getPackageName().concat(".playback");
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        final NotificationManager notificationManager = getSystemService(NotificationManager.class);
                        final NotificationChannel channel = new NotificationChannel(channelID, "Test", NotificationManager.IMPORTANCE_DEFAULT);
                        notificationManager.createNotificationChannel(channel);
                    }

                    final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, channelID)
                            .setSmallIcon(R.mipmap.ic_launcher)
                            .setLocalOnly(true)
                            .setContentTitle("Test")
                            .setOngoing(true);

                    builder.addAction(new NotificationCompat.Action(
                            android.R.drawable.ic_media_pause, "Pause",
                            MediaButtonReceiver.buildMediaButtonPendingIntent(mContext,
                                    PlaybackStateCompat.ACTION_PLAY_PAUSE)));


                    builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle().setShowActionsInCompactView(0).setMediaSession(mMediaSessionCompat.getSessionToken()));

                    final NotificationManagerCompat manager = NotificationManagerCompat.from(getApplicationContext());
                    manager.notify(1, builder.build());

                    mMediaSessionCompat.setPlaybackState(mPlaybackBuilder.build());

                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        private void setMediaPlaybackState(final int state, final int position) {

                mPlaybackBuilder.setState(state, position, 1.0f);

            mMediaSessionCompat.setPlaybackState(mPlaybackBuilder.build());
        }
    };

    @Nullable
    @Override
    public BrowserRoot onGetRoot(@NonNull String clientPackageName, final int clientUid, @Nullable Bundle rootHints) {
        if (clientPackageName.equalsIgnoreCase(getPackageName())) {
            final Bundle extras = new Bundle();
            extras.putBoolean("android.media.browse.CONTENT_STYLE_SUPPORTED", true);
            extras.putInt("android.media.browse.CONTENT_STYLE_PLAYABLE_HINT", 1);
            extras.putInt("android.media.browse.CONTENT_STYLE_BROWSABLE_HINT", 2);

            return new BrowserRoot(getString(R.string.app_name), extras);
        }

        return null;
    }

    @Override
    public void onLoadChildren(@NonNull String parentId, @NonNull MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>> result) {

    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.bug.audiofocusbug">

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.DeviceDefault">

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name="androidx.media.session.MediaButtonReceiver">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
        </receiver>

        <service
            android:name=".MediaPlayerService"
            android:foregroundServiceType="mediaPlayback"
            android:exported="true">
            <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
                <action android:name="android.media.browse.MediaBrowserService" />
            </intent-filter>
        </service>

    </application>

</manifest>

更新:

为了测试,我receiver在我的 AndroidManifest 中添加了一个:

<receiver android:name=".MediaButtonReceiver" >
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON"/>
    </intent-filter>
</receiver>

public class MediaButtonReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        Toast.makeText(context, "debug media button test", Toast.LENGTH_SHORT).show();
    }
}

并且receiver在按下通知中的操作时会被击中,但在按下蓝牙控件时不会被击中

更新 2

我在 Logcat 中看到这样的条目:

Sending KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_MEDIA_PLAY, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=0, downTime=0, deviceId=-1, source=0x0, displayId=0 } to com.bug.audiofocusbug/MediaPlayerService (userId=0)

Sending KeyEvent { action=ACTION_UP, keyCode=KEYCODE_MEDIA_PAUSE, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=0, downTime=0, deviceId=-1, source=0x0, displayId=0 } to com.bug.audiofocusbug/MediaPlayerService (userId=0)

看起来 Android 正在发送正确的命令,但我的应用由于某种原因无法识别它。

4

1 回答 1

0

希望这对将来的某人有所帮助,但问题是我需要像这样将两者都添加PlaybackStateCompat.ACTION_PLAYPlaybackStateCompat.ACTION_PAUSE对象中PlaybackStateCompat.Builder

 mPlaybackBuilder.setActions(
            PlaybackStateCompat.ACTION_PLAY_PAUSE |
                    PlaybackStateCompat.ACTION_PLAY |
                    PlaybackStateCompat.ACTION_PAUSE
    );
于 2021-07-06T16:28:00.693 回答