我将我的服务注册为Intent接收者,但它不接受它们。
我想接受android.intent.action.MEDIA_BUTTON事件,但是当它们发生时,我在LogCat中看到该事件未发送到我的应用程序(如果以前已打开任何媒体播放器),或者未发送给所有人。
我都是根据Google的官方文档编写了代码,然后反编译以确保可以正常工作的应用程序,并复制了其服务的代码,在两种情况下代码均无法正常工作。
我考虑了所有有关此的Google建议。 我在Google的推荐下编写的代码与我从正在运行的应用程序中复制的代码略有不同,因为它有些陈旧并且使用了旧的API方法。因此,为了清楚起见,我将给出两个版本的代码。
在从工作应用程序复制的版本中:
清单中
<manifest>
<application>
<service
android:name="ru.exsoft.mediaretranslator.PlaybackService"
android:exported="true"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
<receiver
android:name="ru.exsoft.mediaretranslator.PlaybackService$MusicIntentReceiver"
android:enabled="true">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
</application>
</manifest>
代码:
private void initRemoteControlClient() {
Intent intent = new Intent("android.intent.action.MEDIA_BUTTON");
intent.setComponent(this.mMediaButtonReceiverComponent);
this.mRemoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this, 0, intent, 0));
RemoteControlHelper.registerRemoteControlClient(this.mAudioManager, this.mRemoteControlClientCompat);
}
private void registerMediaButtonEventReceiver() {
this.mAudioManager.registerMediaButtonEventReceiver(this.mMediaButtonReceiverComponent);
}
public void giveUpAudioFocus() {
try {
if (this.mAudioFocusHelper != null && this.mAudioFocusHelper.abandonFocus()) {
this.mAudioFocus = AudioFocus.NoFocusNoDuck;
}
if (VERSION.SDK_INT >= 14) {
unregisterMediaButtonEventReceiver();
}
} catch (Throwable th) {
th.printStackTrace();
}
}
public void onCreate() {
Log.i("100", "onCreate");
super.onCreate();
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
this.phoneListener = new TestPhoneStateListener();
telephonyManager.listen(this.phoneListener, 32);
this.myNoisyAudioStreamReceiver = new NoisyAudioStreamReceiver();
registerMyNoisyAudioStreamReceiver();
if (VERSION.SDK_INT >= 14) {
this.mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
this.mMediaButtonReceiverComponent = new ComponentName(this, MusicIntentReceiver.class);
}
this.mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this.musicFocusable);
}
public static class MusicIntentReceiver extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent) {
try {
if (intent.getAction().equals("android.intent.action.MEDIA_BUTTON")) {
KeyEvent keyEvent = (KeyEvent) intent.getExtras().get("android.intent.extra.KEY_EVENT");
StringBuilder sb = new StringBuilder();
sb.append("ACTION_MEDIA_BUTTON ");
sb.append(keyEvent.getKeyCode());
Log.i("xxx", sb.toString());
} catch (Throwable th) {
th.printStackTrace();
}
}
}
public void play() {
Log.d("100", "PLAY");
saveState();
displayNotification(true);
tryToGetAudioFocus();
if (VERSION.SDK_INT >= 14) {
updateRemoteControlClientData();
}
}
private void displayNotification(boolean z) {
Notification notification;
try {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("com.audioanywhere.from_notification", true);
if (VERSION.SDK_INT > 10) {
Intent intent2 = new Intent(this, PlaybackService.class);
boolean z2 = (state == 0 || state == 3 || state == 5);
if (z2) {
intent2.setAction("pause");
} else {
intent2.setAction("resume");
}
PendingIntent service = PendingIntent.getService(this, 1, intent2, 0);
Intent intent3 = new Intent(this, PlaybackService.class);
intent3.setAction("previous");
PendingIntent service2 = PendingIntent.getService(this, 1, intent3, 0);
Intent intent4 = new Intent(this, PlaybackService.class);
intent4.setAction("next");
PendingIntent service3 = PendingIntent.getService(this, 1, intent4, 0);
Intent intent5 = new Intent(this, PlaybackService.class);
intent5.setAction("hide_notification");
PendingIntent service4 = PendingIntent.getService(this, 1, intent5, 0);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.audio_notifications_layout);
remoteViews.setTextViewText(R.id.notif_audio_artist, "Artist");
remoteViews.setTextViewText(R.id.notif_audio_title, "Title");
if (VERSION.SDK_INT < 21) {
remoteViews.setImageViewResource(R.id.notif_audio_play_button, z2 ? R.drawable.player_pause_button_grey : R.drawable.player_play_button_grey);
} else {
remoteViews.setImageViewResource(R.id.notif_audio_play_button, z2 ? R.drawable.player_pause_button_grey : R.drawable.player_play_button_grey);
remoteViews.setImageViewResource(R.id.notif_audio_previous_button, R.drawable.player_previous_button_grey);
remoteViews.setImageViewResource(R.id.notif_audio_next_button, R.drawable.player_next_button_grey);
remoteViews.setImageViewResource(R.id.close, R.drawable.close_mini_player);
}
remoteViews.setOnClickPendingIntent(R.id.notif_audio_previous_button, service2);
remoteViews.setOnClickPendingIntent(R.id.notif_audio_play_button, service);
remoteViews.setOnClickPendingIntent(R.id.notif_audio_next_button, service3);
remoteViews.setOnClickPendingIntent(R.id.close, service4);
if (this.notification_builder == null) {
String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel(
"my_service",
"My Background Service"
) : "";
notification_builder = new NotificationCompat.Builder(this, channelId);
}
this.notification_builder.setSmallIcon(R.drawable.player_next_button_grey).setContent(remoteViews);
this.notification_builder.setContentIntent(PendingIntent.getActivity(this, 1, intent, 0));
this.notification_builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
notification = this.notification_builder.build();
} else {
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.drawable.player_next_button_grey).setContentTitle(getText(R.string.app_name)).setContentText("Title").setContentIntent(PendingIntent.getActivity(this, 0, intent, 0));
notification = builder.getNotification();
}
notification.flags |= 2;
if (z) {
startForeground(10, notification);
Log.i("100", "start foreground state");
return;
}
simpleDisplayNotification(notification);
} catch (Throwable th) {
th.printStackTrace();
}
}
private void simpleDisplayNotification(Notification notification) {
((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(10, notification);
}
以及新的Google文档编写的版本:
清单:
<manifest>
<application>
<service
android:name="ru.exsoft.mediaretranslator.RetranslatorService"
android:exported="true"
android:enabled="true"
tools:ignore="ExportedService" >
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
<receiver
android:name="androidx.media.session.MediaButtonReceiver"
android:enabled="true">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<application>
<manifest>
代码:
class RetranslatorService : Service() {
private var audioManager: AudioManager? = null
private val serviceBinder = ServiceBinder()
private val metadataBuilder = MediaMetadataCompat.Builder()
private val stateBuilder = PlaybackStateCompat.Builder().setActions(
PlaybackStateCompat.ACTION_PLAY
or PlaybackStateCompat.ACTION_STOP
or PlaybackStateCompat.ACTION_PAUSE
or PlaybackStateCompat.ACTION_PLAY_PAUSE
or PlaybackStateCompat.ACTION_SKIP_TO_NEXT
or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
)
private var mediaSession: MediaSessionCompat? = null
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.d("100", "onStartCommand")
Log.d("100", "action = " + intent.action)
Log.d("100", "extra = " + intent.getStringExtra("extra"))
MediaButtonReceiver.handleIntent(mediaSession, intent)
return super.onStartCommand(intent, flags, startId)
}
override fun onCreate() {
super.onCreate()
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
loadPrefs()
startFrg()
createMediaSession()
Log.d("100", "onCreate")
}
private fun startFrg() {
val notIntent = Intent(this, MainActivity::class.java)
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendInt =
PendingIntent.getActivity(this, 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createNotificationChannel(
"my_service",
"My Background Service"
)
else ""
val builder = NotificationCompat.Builder(this, channelId)
builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Content title")
.setContentText("Content text")
val not = builder.build()
startForeground(1, not)
}
private fun createMediaSession() {
mediaSession = MediaSessionCompat(applicationContext, packageName)
val componentName =
ComponentName(applicationContext, RetranslatorService::class.java)
val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON)
mediaButtonIntent.component = componentName
val mediaButtonReceiverPendingIntent =
PendingIntent.getBroadcast(applicationContext, 0, mediaButtonIntent, 0)
mediaSession!!.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
mediaSession!!.setCallback(mediaSessionCallback)
val appContext = applicationContext
val serviceIntent = Intent(appContext, RetranslatorService::class.java)
mediaSession!!.setSessionActivity(
PendingIntent.getActivity(
appContext,
0,
serviceIntent,
0
)
)
mediaSession!!.setMediaButtonReceiver(
mediaButtonReceiverPendingIntent
)
val metadata = metadataBuilder
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Windows controller")
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, "ExSoft")
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "ExSoft")
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 10)
.build()
mediaSession?.setMetadata(metadata)
val state = PlaybackStateCompat.Builder().setActions(
PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PLAY_PAUSE or
PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID or PlaybackStateCompat.ACTION_PAUSE or
PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
).setState(PlaybackStateCompat.STATE_PLAYING, 1, 1.0f, SystemClock.elapsedRealtime())
.build()
mediaSession?.setPlaybackState(state)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val audioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(audioAttributes)
.setOnAudioFocusChangeListener(audioFocusChangeListener)
.build()
audioManager!!.requestAudioFocus(audioFocusRequest)
} else {
audioManager!!.requestAudioFocus(
audioFocusChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN
)
}
mediaSession!!.isActive = true
}
inner class ServiceBinder : Binder() {
internal val service: RetranslatorService
get() = this@RetranslatorService
fun getMediaSessionToken(): MediaSessionCompat.Token {
return mediaSession!!.getSessionToken()
}
}
private var mediaSessionCallback: MediaSessionCompat.Callback =
object : MediaSessionCompat.Callback() {
override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
Log.d("100", "onMediaButtonEvent")
return super.onMediaButtonEvent(mediaButtonEvent)
}
}
}
我重复一遍,如果在加载系统后没有启动任何媒体应用程序,那么我在LogCat中看不到任何消息。否则,我会看到以下内容:
2019-09-04 18:37:21.817 1671-4413/? D/MediaSessionService: Sending KeyEvent { action=ACTION_UP, keyCode=KEYCODE_MEDIA_PAUSE, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=508419172, downTime=508419172, deviceId=-1, source=0x0 } to the last known PendingIntent PendingIntent{e2b4330: PendingIntentRecord{7ce4b98 com.perm.kate broadcastIntent}}
2019-09-04 18:37:21.819 1671-4116/? D/MediaSessionService: Sending KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_MEDIA_PAUSE, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=508419172, downTime=508419172, deviceId=-1, source=0x0 } to the last known PendingIntent PendingIntent{e2b4330: PendingIntentRecord{7ce4b98 com.perm.kate broadcastIntent}}
2019-09-04 18:37:21.819 2478-2478/? V/Avrcp_ext: recordKeyDispatched: KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_MEDIA_PAUSE, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=52644639, downTime=52644639, deviceId=-1, source=0x0 } dispatched to com.perm.kate
2019-09-04 18:37:21.819 2478-2478/? V/Avrcp_ext: Player 9 package: com.perm.kate
2019-09-04 18:37:21.819 2478-2478/? W/Avrcp_ext: recordKeyDispatch: can't find matching log!
顺便说一句,以防万一我使用从中复制输出代码的应用程序,如下所示:
2019-09-04 18:31:41.817 1671-4413/? D/MediaSessionService: Sending KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_MEDIA_PAUSE, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=52644639, downTime=52644639, deviceId=-1, source=0x0 } to com.perm.kate/MediaSessionHelper-com.perm.kate (userId=0)
2019-09-04 18:31:41.819 1671-4116/? D/MediaSessionService: Sending KeyEvent { action=ACTION_UP, keyCode=KEYCODE_MEDIA_PAUSE, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=52644639, downTime=52644639, deviceId=-1, source=0x0 } to com.perm.kate/MediaSessionHelper-com.perm.kate (userId=0)
2019-09-04 18:31:41.819 2478-2478/? V/Avrcp_ext: recordKeyDispatched: KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_MEDIA_PAUSE, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=52644639, downTime=52644639, deviceId=-1, source=0x0 } dispatched to com.perm.kate
2019-09-04 18:31:41.819 2478-2478/? V/Avrcp_ext: Player 9 package: com.perm.kate
2019-09-04 18:31:41.819 2478-2478/? W/Avrcp_ext: recordKeyDispatch: can't find matching log!