Search code examples
androidbroadcastreceiver

Screen lock, but still perform work and listen to ACTION_MEDIA_BUTTON


I have a mainActivity that can detect clicks from my headset via a BroadcastReciever class, but only when my app is in foreground. I want to be able to the same thing when my app is in background, or to be more specific when my screen is locked. Clicking button on headset now when the screen is locked opens spotify.

In my onCreate and equivalent onDestroy i tried using:

    powerMngr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    wakeLock = powerMngr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
    wakeLock.acquire();

However, this does not do what i want. What steps do i need to take in order to accomplish this? What classes is needed? And how can work be performed when the screen is locked?

Edit: After further research i atleast know why Spotify is being started when i click the headsetbutton. It is the last run MediaSession. If i interpreted it correctly, it seems like my app needs to have the latest MediaSession and a mediaButtonReciever. Still not sure how to implement this tho: https://developer.android.com/guide/topics/media-apps/mediabuttons.html

This is the service im currently using for capturing headset clicks:

public class HeadsetActionButtonReceiver extends BroadcastReceiver {

public static Delegate delegate;

private static AudioManager mAudioManager;
private static ComponentName mRemoteControlResponder;

private static int doublePressSpeed = 300; // double keypressed in ms
private static Timer doublePressTimer;
private static int counter;

public interface Delegate {
    void onMediaButtonSingleClick();
    void onMediaButtonDoubleClick();
}

@Override
public void onReceive(Context context, Intent intent) {
    if (intent == null || delegate == null || !Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction()))
        return;

    KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
    if (keyEvent == null || keyEvent.getAction() != KeyEvent.ACTION_DOWN) return;

    counter++;
    if (doublePressTimer != null) {
        doublePressTimer.cancel();
    }
    doublePressTimer = new Timer();
    doublePressTimer.schedule(new TimerTask() {

        @Override
        public void run() {
            if (counter == 1) {
                delegate.onMediaButtonSingleClick();
            } else {
                delegate.onMediaButtonDoubleClick();
            }
            counter = 0;
        }
    }, doublePressSpeed);
}

public static void register(final Context context) {
    mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    mRemoteControlResponder = new ComponentName(context, HeadsetActionButtonReceiver.class);
    mAudioManager.registerMediaButtonEventReceiver(mRemoteControlResponder);
}

public static void unregister(final Context context) {
    mAudioManager.unregisterMediaButtonEventReceiver(mRemoteControlResponder);
    if (doublePressTimer != null) {
        doublePressTimer.cancel();
        doublePressTimer = null;
    }
}

}


Solution

  • I managed to get this working. In order to capture headset button clicks and even bluetooth button clicks you will need a MediaSession. You will also need to define a MediaSessionCompat. Where you set MediaSession.setActive(true), which is a must in order to capture clicks in background. Furthermore create a MediaSessionCompat.Callback() where your override onMediaButtonEvent.

    Follow googles developer guides on all the things i have written here to get further information and you should be able to accomplish this. Also services generally do run in background and are able to perform work as long as they are not destroyed.