MediaSession onMediaButtonEvent works for a few seconds then quits - Android - android

I've been trying to listen to media button intents on this Bluetooth button I bought off eBay for the past week and cannot figure out how to do it practically and reliably on my Oreo device. The first thing I tried was overriding onKeyDown in my main activity, which worked perfectly every time. However, I found it was impossible to listen to these calls once the application is minimized.
Next I tried a very hacky solution of reading the logcat line by line and checking if dispatched media key KeyEvent { action=ACTION_UP, keyCode=KEYCODE_MEDIA_NEXT was present in that line. It worked alright until I again exited the app, which then it would completely stop.
Finally I tried using a MediaSession and the onMediaButtonEvent method, which works perfectly for a few seconds to minutes after I start my activity then it just completely ceases to receive these intents.
Here's my code right now (I copied another answer on StackOverflow who included playing a dummy audio clip to try and get focus):
MediaSession ms = new MediaSession(getApplicationContext(), getPackageName());
ms.setActive(true);
ms.setCallback(new MediaSession.Callback() {
#Override
public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
KeyEvent keyEvent = (KeyEvent) mediaButtonIntent.getExtras().get(Intent.EXTRA_KEY_EVENT);
if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyEvent.getKeyCode()) {
//do button specific stuff here
}
}
return super.onMediaButtonEvent(mediaButtonIntent);
}
});
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
PendingIntent mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
ms.setMediaButtonReceiver(mediaButtonReceiverPendingIntent);
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.getMinBufferSize(48000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT), AudioTrack.MODE_STREAM);
at.play();
// a little sleep
at.stop();
at.release();
I'm just trying to figure out now, why it seems to work for a few seconds perfectly, then it just stops out of nowhere. I don't have any other media app like Spotify open or playing whatsoever, and if that was the issue, I've tried running the audio code every 5 seconds or so which still has no effect. The only thing that will reset it is fully restarting the app.
This code is in a service I have created. It only stops working if I am not in the app and simply press the home button to minimize it after a few seconds. I have a loop running to tell me that the service is still running, and it's seems it's running when it quits receiving the intents.
Any help would be appreciated.

I've tested this code, it seems the bluetooth button press is only listened to by your app if music (or silent sound) is currently playing. Otherwise the button press is not detected.

Related

How to control currently playing music player in android?

I use this code to send actions like play/pause for music player.
// play / pause
i.putExtra("command", "togglepause");
context.sendBroadcast(i);
But it works only for default music player (phone's own music player). Is there any way to control other music players while they're playing?
From API level 19, new API dispatchMediaKeyEvent() is introduced.
Sends a simulated key event for a media button. To simulate a key press, you must first send a KeyEvent built with a ACTION_DOWN action, then another event with the ACTION_UP action.
AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
am.dispatchMediaKeyEvent(downEvent);
upEvent = new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
am.dispatchMediaKeyEvent(upEvent);
This media event will be dispatched to the current running music player only, not to all players.
Thanks
Have you tried this -
i.putExtra("command", "pause");
EDIT:
Alternate Solution, List programmatically all music apps using PackageManager , Intent, ResolveInfo etc. and than send command to all apps in the list.

Weird blinking on the lock screen remote control client when stopping it from the client itself

I'm currently building a streaming Android app and I'm trying to integrate a remote control client (to have for example a control from the lock screen on ICS+).
To do so, I'm doing that at start up in my streaming service:
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
stopSelf();
}
mediaButtonReceiverComponent = new ComponentName(this, RemoteControlReceiver.class);
audioManager.registerMediaButtonEventReceiver(mediaButtonReceiverComponent);
if (remoteControlClientCompat == null) {
final Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(mediaButtonReceiverComponent);
remoteControlClientCompat = new RemoteControlClientCompat(
PendingIntent.getBroadcast(
getApplicationContext(),
0,
mediaButtonIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
);
RemoteControlHelper.registerRemoteControlClient(audioManager, remoteControlClientCompat);
}
final int flags = RemoteControlClient.FLAG_KEY_MEDIA_STOP;
remoteControlClientCompat.setTransportControlFlags(flags);
remoteControlClientCompat is simply an instance of RemoteControlClientCompat from the samples.
then during the streaming I'm updating the metadata. everything is working normally, even the controls get sent to my RemoteControlReceiver. The data and the image appear nicely on the lock screen.
Stopping the streaming from my app destroys the lock screen thing but when I'm trying to destroy it from the widget itself (by pressing the stop button), it's doing something weird. Pressing the stop button makes the broadcast receiver stop my streaming service. Then in the service's onDestroy() method, I'm doing that:
RemoteControlHelper.unregisterRemoteControlClient(audioManager, remoteControlClientCompat);
audioManager.unregisterMediaButtonEventReceiver(mediaButtonReceiverComponent);
audioManager.abandonAudioFocus(this);
The widget goes blinking as soon as audioManager.unregisterMediaButtonEventReceiver(mediaButtonReceiverComponent); is called. I've tried commenting the line and the blinking happens with audioManager.abandonAudioFocus(this);. Commenting that other line makes it blink as well when the service stops.
I've noticed this happens too when I'm stopping the streaming from my notification.
What am I doing wrong? I tried changing the order of this calls but I couldn't solve it.
I've notice Spotify had the exact same issue a couple of versions ago. I'm wondering how they solved it...
Ok I fixed it. It's simply because the RemoteControlClient cannot be playing when we abandon audio focus. So I just had to call that before destroying anything:
remoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);

Back to the drawing board: Volume Switch App Starter

Alright as I have been asking the last couple days and inching closer and closer to the final outcome of this question:
Is it possible to use the volume (up / down) buttons to start an app?
Here is the code I am working with:
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
Log.w("myApp", "LONG PRESS");
}
//my code here
return super.onKeyLongPress(keyCode, event);
}
I am wondering what I am doing wrong. Nothing in the code is giving me errors, its just not running when I tell it to.
Note:
I am testing this on a live android if that helps out at all.
Any advice would be wonderful.
Is it possible to use the volume (up / down) buttons to start an app?
No, sorry. You cannot use hardware buttons to start apps, with the exception of the CAMERA button (where it exists) or the MEDIA button (where it exists, typically on headsets). For those, you would register a BroadcastReceiver in the manifest for their respective broadcasts, and bear in mind that those broadcasts are only sent out if the foreground activity does not consume the key event (e.g., music player pausing when the MEDIA button is pressed).

How to check something at regular intervals?

Beginner here, I have a simple question.
In Android what would be the best what to check for something at regular intervals?
Please bear with me, I'll try to explain the best I can --
For example my audio app is very simple, a main activity and a service. The main activity has a UI with two buttons, start and stop audio. I press start and the audio service starts. Likewise when I click Stop the service stops and the audio ends. If isLooping() is hard-coded to true there is no issue because the audio never ends unless I hit stop button, which stops the audio service and also resets the button states.
This is an issue now because I set isLooping() to false so the audio doesn't loop. So the audio will stop playing but the service is still running.
I want to be able to detect when the audio stops so I can set the states of the UI buttons. So I need something that is always checking whether audio is playing (i.e. check player.isPlaying() so I can end the service and set the enable/disable state of the buttons.
I figured out binding to the service so I can access the MediaPlayer controls via my main activity so I know the code to check if it's playing, but WHERE do I put this code so it's checked all the time?
Am I making sense? I know this is probably very simple. Thanks for any help.
You can repeat it with the TimerTask and Timer. Code below:
public final void RepeatSoundFunction(){
t = new Timer();
tt = new TimerTask() {
#Override
public void run() {
mp.seekTo(0); //Reset sound to beginning position
mp.start(); //Start the sound
t.purge(); //Purge the sound
}
};
t.schedule(tt, 10*1000); //Schedule to run tt (TimerTask) again after 10 seconds
}
then you set a MediaPlayer onCompletionListener and in there you put this.
Inside the run-code you can check for other things than
music, I just show an example with the audio.

How to handle Alarm notification in Android?

I'm developing an media player application for Android, for which I need to handle any Alarm notification, and based on that I'll pause my playback. When the Alarm in snoozed or dismissed, I'll then resume the playback.
I googled a lot for the Alarm handling, but what I found was the way to enable Alarm notifications through code, set the intent and then handle it. However, no where could I locate just handling the Alarm notification part. I don't need to set the Alarm on, it could've been set by the user, and I don't need to programmatically. All I need is just handle that notification.
Any ideas on this would be extremely useful?
Thanks,
Asheesh
HI Asheesh Vashishtha,
Correct me on this, but AFAIK whenever any other application even if it is the alarm clock, is activated, your activity will surely go in background. So i guess u can override the OnPause and OnResume functions to put your bit of code. As far as snooze or other things are concerned, they all will result in the Alarm Activity getting destroyed(or paused, don know much about it) and your activity will get resumed. So that wont be a matter of concern for u!
Hope this helps...
AFAIK, there is no way for you to be notified of what the Alarm Clock application does, any more than you get notified about any other third-party alarm clock.
Note that AlarmManager -- what you were probably reading about -- is not the same as the Alarm Clock application.
Sorry!
I ran into a similar situation while developing a media player. My solution was to use the AudioManager's OnAudioFocusChangeListener.
You implement the listener in the class like so
public class VideoPlayerHelper implements AudioManager.OnAudioFocusChangeListener {
Then you override onAudioFocusChange
#Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
//Just fall through by omitting break
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
LogUtil.log(LogUtil.DEBUG, TAG, "AUDIOFOCUS_LOSS or AUDIOFOCUS_LOSS_TRANSIENT"); //Custom logging class
if (isPlaying()) {
pause();
mAudioManager.abandonAudioFocus(VideoPlayerHelper.this);
}
break;
case AudioManager.AUDIOFOCUS_GAIN:
LogUtil.log(LogUtil.DEBUG, TAG, "AUDIOFOCUS_GAIN"); //Custom logging class
break;
default:
break;
}
}
The key here is AudioManager.AUDIOFOCUS_LOSS_TRANSIENT. This was the code the listener kept receiving when the alarm clock would go off (on The Note 5). So I simply handled AudioManager.AUDIOFOCUS_LOSS_TRANSIENT the same as AudioManager.AUDIOFOCUS_LOSS by pausing the media player and letting go of the audio focus.
When we setup the media player, I added this line before adding the data source
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
Make sure your code for starting the media player also has this line in it (I have it in the start code and onResume code in case the alarm went off while the app was in the background).
mAudioManager.requestAudioFocus(VideoPlayerHelper.this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
That line helps you get back the audio focus when you hit the play button after dismissing the alarm clock.
You should also let go off audio focus when you're finished with the media player. I put this line of code in the onStop and onDetach methods.
mAudioManager.abandonAudioFocus(VideoPlayerHelper.this);
It's not as much setup as you may think and it allows you to adjust your media player whenever unexpected audio is introduced (such as an alarm clock or timer goes off).

Categories

Resources