I'm trying to build an Android app that uses a broadcast receiver to detect when music playback starts, and then offer gesture control to trigger sending a skip track intent back out.
To begin, I just want to set the receiver up to trigger a notification when audio playback starts so that I can check this concept will work. I've declared a service and a receiver in my manifest file, and I've created a service class that (hopefully) creates a notification via onCreate().
I've crawled a tonne of documentation though and can't seem to find the correct intent to listen in for with my receiver. Surely something exists for this?
Regards.
It turns out there's a new security feature in Android 3.1 and above, where broadcast receivers don't register until the user manually opens the app at least once. Since I was trying to build a service-only app that had no UI to be opened, this was preventing all my intent listener attempts from working.
I've amended to have a splash-screen activity and now everything is working as I'd hoped. I'm now working to collate a list of player-specific intents to work from but for those trying to build something similar, com.android.music.playstatechanged seems to be the best start. This one is triggered by the default player (Google Play Music) when music either starts, pauses, or resumes and bundles itself with extra data including a boolean 'playing' property to differentiate between the play and pause states.
Essentially, this is the core receiver I'm now using. Have fun!
public class MainReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Start the service when music plays, stop the service when music ends.
if(intent.hasExtra("playing")) {
if(intent.getBooleanExtra("playing", false)) {
Intent service = new Intent(context, MainService.class);
context.startService(service);
} else {
Intent service = new Intent(context, MainService.class);
context.stopService(service);
}
}
}
}
Surely something exists for this?
There are thousands of music players. None are obligated to broadcast anything, let alone information about tracks. And none are obligated to allow you to "skip track" via any means.
You are welcome to search for specific music players that offer a documented and supported API for this sort of thing.
Related
I have one app that runs as a service and broadcast receiver with root and device administrator access. I need that app to be able to control the UI for any other app that may be running. For example, I might want to hide the system nav bar or override the home button while other apps are running in the foreground. It is to sandbox the user.
Can anyone suggest how I might do such a thing? Hiding the nav bar in your own app is easy, and of course overriding buttons is no big deal, but I need for one app to be able to do it for other apps.
I'm considering if the UI Automator could help.
My apps (the sandboxer and the other apps that will be running) are mine and they will all have root access. I will also be able to build my own custom version of the Android OS on each device if I need to.
-Thanks
Ok this needs to be done in a two step process,
Create a broadcast from your service
Register a broadcast receiver in your UI application to listen to the broadcasts
In your service do this
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
sendBroadcast(Intent);
In your mainActivity, use
registerReceiver(<receiver instance>, BROADCAST_ACTION)
in the onStart or onCreate method.
This will setup your mainActivity to listen to the broadcasts, next you need to define your broadcast receiver which is the in the above register call.
BroadcastReceiver receiver;
receiver = new BroadcastReceiver() {
public void onReceive(Context c, Intent i) {
//Modify the UI, in this case hide the dialog box.
}
}
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.
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
Is there a way to receive broadcasts(like sms notification) in stopped application?
Actually it works simply in lower than Android 3.1.
EDIT 1:
Thanks to #Squonk for comment.
So my questions is, is it REALLY impossible? you can check PlanB app in market which does this things.
EDIT 2:
this is my broadcast receiver. The onReceive function is never called(when application is stopped).
public class SmsReciever extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
Log.e("kpav", "kpav");
String url = "http://www.google.com";
Intent i = new Intent(Intent.ACTION_VIEW);
i.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(32);
i.setData(Uri.parse(url));
arg0.startActivity(i);
}
}
For Android v3.1 onwards, any app which has been manually started at least once by the user, will receive broadcasts that it has registered in the manifest even after a reboot.
BUT...the user must have manually started that app - it's not possible for an app to be installed and have it automatically receive broadcasts otherwise.
Also, if the user manually uses 'Force Stop' from the Settings on a device, it will no longer receive broadcasts until the user manually starts the app again.
So basically, in answer to your question...
Is there a way to receive broadcasts(like sms notification) in stopped application?
...the answer is no except under the circumstances I describe above.
You can inlcude Stopped Packages to receive broadcasts by simply adding the following flag to the broadcasting intent.
intent.addFlags(32);
Where as 32 refers to Intent.FLAG_INCLUDE_STOPPED_PACKAGES which is available from API level 12.
I would like to know if it is possible to launch my application whenever a new entry is written to phone call log (i.e. out-going, in-coming or missed call).
I wrote an application to manage the call log entries as per user preferences by listening to the publication of android.intent.action.PHONE_STATE events. My application is working fine as long as its process is running. However if the user has stopped my application with a task-killer application, then the log entries can not be managed as my app itself was not running. I need a way to make sure that my application is launched in the background if it is not already running when the android.intent.action.PHONE_STATE occurs.
Or is it possible to launch my application as a service that always runs?
Thanks in advance.
Bala
You can launch your application as Service:
http://developer.android.com/reference/android/app/Service.html
here is a basic service implementation:
public class MyService extends Service
{
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onCreate()
{
super.onCreate();
Log.i("Service", "Service is starting");
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.i("Service", "Service stopped");
}
}
AndroidManifest.xml
<application ....>
<service android:name=".App.MySyncService" />
</application>
However if the user has stopped my
application with a task-killer
application, then the log entries can
not be managed as my app itself was
not running.
There is nothing that can be done about this. The same thing will occur if the user terminates your service through the Settings > Applications page.
I need a way to make sure that my
application is launched in the
background if it is not already
running when the
android.intent.action.PHONE_STATE
occurs.
You can try setting up a BroadcastReceiver for this Intent in your manifest, and have it route control over to some IntentService for processing. It's the same pattern I use for AlarmManager (sample code here), just with a different trigger. I have not tried this specific Intent, though, so I cannot be certain the technique works. If it does, though, it has a huge benefit of keeping your service out of memory most of the time (IntentService shuts down when its work is complete), which will make your task-killing users happy.
Or is it possible to launch my
application as a service that always
runs?
No, because users are in control over their devices, not you or I.