我已经尝试了所有方法,但无法让蓝牙控件在我的媒体应用程序中做出响应。我已经阅读了一百遍文档,但仍然无法正常工作。我的蓝牙耳机响应我设备上的其他媒体应用程序,所以它在我的应用程序中。
根据文档,如果应用程序使用 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 正在发送正确的命令,但我的应用由于某种原因无法识别它。