How to create "lockscreen-like" music playback controls - android

I am trying to create widget that can control music playback. Basically the same as the widget that appears on lockscreen when music is playing. (Which as I read somewhere, is connected to the Remote Control Client - is that true?) My problem:
I was able to create Media Buttons using the following code
Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
synchronized (this) {
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
sendOrderedBroadcast(i, null);
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
sendOrderedBroadcast(i, null);
First, I thought this was the solution used also in the lockscreen widget. But then I noticed that this solution works only with some music players, but certainly not with all that can be controlled by default lockscreen widget(f.e. DoubleTwist responds to lockscreen widget, but not to my Media Buttons). So I spent last few days digging in the Android sources, Logcat outputs and various forums, but I was not able to find any difference between intents called by my buttons and by buttons on the lockscreen widget.
What exactly is lockscreen widget doing to control apps that are not listening to my Media Button intents?
Or, can somebody at least help me to find the source code of this widget? I tried default music app, audio service, remote control client, widgets, but I can't find it anywhere.

While working on my app I've actually found how to implement your own RemoteControlDisplay which can control music player the same way the lockscreen does.
Basically, you extend IRemoteControlDisplay$Stub, which sends messages to special handler, this handler updates metadata and thing. Then you register your own class extended from IRemoteControlDisplay$Stub by calling to AudioManager#registerRemoteControlDisplay().
And then you unregister it by calling AudioManager#unregisterRemoteControlDisplay().
It's fairly complex, but I've wrote an article on how to this.
I've published it on XDA, check it here:
http://forum.xda-developers.com/showthread.php?p=44513199

What exactly is lockscreen widget doing to control apps that are not listening to my Media Button intents?
Based on the docs, it is doing what those apps asked it to do -- execute the PendingIntent supplied to it by the RemoteControlClient. Notably:
it will not be an ordered broadcast, as PendingIntent does not support it
it may be one targeted at the specific media client, via setComponent()
it may or may not have the extras you are trying (incorrectly) to use
(The "incorrectly" part is because you are sending two ACTION_UP operations some of the time, as sendOrderedBroadcast() is asynchronous with respect to the calling thread, and therefore you may be replacing your ACTION_DOWN with ACTION_UP before the first ordered broadcast is sent. You are better off using a separate Intent object for each broadcast.)
However, while the docs claim that the PendingIntent needs to be set up for ACTION_MEDIA_BUTTON, I would not be surprised if this is a documentation error, and that no specific action is needed, as setComponent() is sufficient to deliver the broadcast to the right receiver.

Related

Detect when app is opened with a service

I want to be able to detect when an application is opened and notify the user of something at the moment related to that same application but I don't know how to do this.
The user opens my app
I intent the service (background / foreground) and it successfully starts
Whenever the user opens another application I want to "catch it" and present a notification to the user
How can this be made? Are there any event listeners i need to use? Thank you very much.
If you are trying to catch "open app" intents in general, then it depends on how the app defined the intent. If it specified a class (explicit intent) then it will generally not be visible to your app unless the device is rooted, for example.
Implicit intents are broadcast and you simply need to define an intent filter in order to receive them. These are intents that allow Android and/or the user to select the appropriate app target based on data sent with the intent.
There are both useful and malicious motivations to do the kind of thing you are asking about. Read this:
Android Intent Security
And also the posted comment on learning about intents overall.
This is really simple. Here I am trying to figure out the solution. When your app goes on onPause() state then broadcast a message using BroadcastReceiver. On the other hand in another app just register for that broadcast.

Detect when music starts playing (or related events) without polling

My goal is to detect when music starts playing on the device. In my case I want to launch volume controls on an Android Wear device but that's irrelevant for the question.
I know there is AudioManager.isMusicActive() but it requires polling. I would rather listen for a broadcast without keeping a service alive indefinitely.
The other alternative would be to listen for headphones being plugged in but apparently Intent.ACTION_HEADSET_PLUG is only delivered to dynamic receivers as this answer suggests.
I'm a bit clueless here. How can I listen for any audio related events without constant polling?

How does the android lockscreen get playing song?

Recently posted a question how to get the current song playing from the music app spotify, there seems by the response that there are no easy way of doing this.
The android lockscreen at least in 4.0+ will show the current song and works with almost any music player including spotify. So my question is how does the lockscreen get this information?
On Android 4.0 and 4.1, the portion of the lockscreen you are seeing is called the "remote controls". You can call registerRemoteControlClient() to supply information to it.
On Android 4.2+, you are welcome to create your own lockscreen-capable app widget instead.
Through a broadcast receiver, you can create a broadcast receiver and define filters for it in the manifest. Then all the music applications that send this broadcast will trigger your onReceive method, along with the information sent from the app.
EDIT:
Intent intent = new Intent("com.android.music.playstatechanged");
intent.putExtra("playing", (mState & FLAG_PLAYING) != 0);
if (song != null) {
intent.putExtra("track", song.title);
intent.putExtra("album", song.album);
intent.putExtra("artist", song.artist);
intent.putExtra("songid", song.id);
intent.putExtra("albumid", song.albumId);
}
sendBroadcast(intent);
This is the code in the stock player used to send broadcast, Look into broadcast receiver and you able be able to figure out how to get the data needed.
Also You will need to find the filter for spotify, AFIK This one works for soptify.
"com.android.music.metachanged" or look here http://pastebin.com/ukfPnZwg

Global control handler

I have an Android service that runs in background.
I need it to recieve feedback (and stop, for example) just when user did something, no matter if it's only touch event on homescreen of somewhere else or key press.
Is it possible to handle global touch and key events?
While I highly doubt that there is an easy way to do this, you can register intents and intercept the messages for your own purpose. Have a look at the intent library for specific intents that you might hijack for your application. You may find further information in the android documentation on intent filters.

Issue with system intents

I have a program that has a broadcast receiver that listens for Phone_State and then sends a user defined intent.
Well, my problem is that the system also sends out an intent (the one that I am trying to replace with my program) .
So I am trying to find a way to CANCEL the systems intent.
I have found that if i have a timer just wait for a little bit, then I can send mine after the systems, but that is not very good, and sometimes defeats the purpose of my program.
Also, i cannot set my program as a default because it is not a full dialer program. Just one action of it.
Someone please help me find how to listen for and cancel a system intent/activity....
Someone please help me find how to
listen for and cancel a system
intent/activity
You cannot "cancel" an activity, period.
You cannot replace the dialer.
If the system Intent was sent via sendOrderedBroadcast(), then you can call abortBroadcast() from your BroadcastReceiver, and any lower-priority receivers will not get the broadcast. However, I have no evidence that ACTION_PHONE_STATE_CHANGED is an ordered broadcast, and I sincerely hope it isn't.
Whatever you are trying to do probably should be accomplished via modifications to your own custom firmware.

Categories

Resources