Search code examples
androidandroid-intentandroid-music-player

How can I start the MusicPlaybackService from an external app?


I'm trying to extend the functionality of the Wired Mic Remote Button through a Service and Receiver that sits on top of the Google Play Music App and communicates with it through broadcasts. I'm on ICS with a Google Nexus S.

The issue I have is my code works great once the MusicPlaybackService is running, which is not always the case. How do I start this service without showing any UI (without the user knowing). My code has the following definitions:

public static final String SERVICECMD = "com.android.music.musicservicecommand";
public static final String CMDNAME = "command";
public static final String CMDTOGGLEPAUSE = "togglepause";
public static final String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause";

I have tried the following options:

1) Based off this SO question. I'm not sure whether about SERVICECMD, as the question states I should use "com.android.music.musicservicecommand" though for ICS I believe the package names have changed.

Intent i = new Intent(SERVICECMD); 
i.putExtra(CMDNAME, CMDTOGGLEPAUSE); 
sendBroadcast(i);

I have also tried replacing SERVICECMD with TOGGLEPAUSE_ACTION.

2) From this android project issue.

Intent musicIntent = new Intent();
musicIntent.setClassName("com.google.android.music", "com.google.android.music.MusicPlaybackService");
musicIntent.setAction(TOGGLEPAUSE_ACTION);
musicIntent.putExtra(CMDNAME, CMDTOGGLEPAUSE); // or "next" or "previous"
sendBroadcast(musicIntent);

3) This code crashes with the error below. I'm not sure how to go further with this option.

Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.google.android.music/com.google.android.music.MusicPlaybackService}; have you declared this activity in your AndroidManifest.xml?

Intent intent = new Intent();
intent.putExtra(CMDNAME, CMDTOGGLEPAUSE); 
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName("com.google.android.music", "com.google.android.music.MusicPlaybackService");
startActivity(intent);

4) I've noticed that when the headset is removed from my phone, the MusicPlaybackService is started because it is responding to the Intent.ACTION_HEADSET_PLUG broadcast that is picked up by WiredAccessoryObserver. I tried duplicating that broadcast in my code using the values shown in LogCat.

Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("state", 0);
intent.putExtra("name", "h2w");
intent.putExtra("microphone", 1);
sendBroadcast(intent);

I'm really looking for a method that works all the time that just starts up the Service. I'm open to anything. I still have to try binding to the service that uses IMediaPlaybackService.aidl which is supposed to break randomly, and is not ideal. Thanks in advance for helping out.

EDIT

I tried binding to the service using the code below which threw an error:

Caused by: java.lang.SecurityException: Not allowed to bind to service Intent { cmp=com.google.android.music/.MusicPlaybackService }

In my OnCreate function

if (mPlaybackService == null) { 
    Intent i = new Intent(); 
    i.setClassName("com.google.android.music","com.google.android.music.MusicPlaybackService" ); 
    bindService(i, connection, Context.BIND_AUTO_CREATE); 
}

In my class

IMediaPlaybackService mPlaybackService = null;
ServiceConnection connection = new ServiceConnection() {
    public void onServiceConnected(ComponentName name, IBinder service) {     
        mPlaybackService = IMediaPlaybackService.Stub.asInterface(service);
}

    public void onServiceDisconnected(ComponentName name) { 
         mPlaybackService = null; 
    } 
};

Solution

  • I don't think this is possible. My workaround is to let the apps own broadcastreceiver wake up the service when the button is pressed. I just request audiofocus for my app and wait til it gets lost.