20

What I'm basically trying to achieve is custom global hot keys or in other words 'things will happen when I push certain buttons no matter which program is currently on top'.
I assume a service is needed.

I have a quick and dirty test that just tells me what has been pressed that will work if it is the active window.

public boolean onKeyDown(int keyCode, KeyEvent event) {
    char pop;
    pop = (char)event.getUnicodeChar();
    Toast.makeText(this, Character.toString(pop) , Toast.LENGTH_SHORT).show();
    return super.onKeyDown(keyCode, event);
  }

But obviously if I change window or go into a text box it doesn't work. If I stick it directly into a service (or an imputmethodservice) and launch said service nothing happens. (Some permissions required maybe?) Any suggestions where I'm going wrong? Or a better way of capturing which button is pressed?

Thanks!

Fizz
  • 201
  • 1
  • 2
  • 3
  • hiii if u hv a workaround for this then plz let me knw. – Its not blank Feb 13 '12 at 08:08
  • 1
    @Vincent Romain Guy works in Android team, he said this is [impossible](http://stackoverflow.com/a/3455094/942821). And Fizz, could you please accept Romain's answer? –  Jul 09 '12 at 14:51
  • possible duplicate of [Is it possible to create an Android Service that listens for hardware key presses?](http://stackoverflow.com/questions/2986337/is-it-possible-to-create-an-android-service-that-listens-for-hardware-key-presse) – isalgueiro Feb 20 '15 at 12:20

2 Answers2

19

You cannot do this :)

Romain Guy
  • 97,993
  • 18
  • 219
  • 200
7

This requires Lollipop (v5.0/API 21) or higher

My goal was to adjust system volume from a Service, so this will only listen for the rocker. Any action can be taken on press though.

It will override volume key action, so using it globally may not be desired.

public class VolumeKeyController {

    private MediaSessionCompat mMediaSession;
    private final Context mContext;

    public VolumeKeyController(Context context) {
        mContext = context;
    }

    private void createMediaSession() {
        mMediaSession = new MediaSessionCompat(mContext, KeyUtil.log);

        mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mMediaSession.setPlaybackState(new Builder()
                .setState(PlaybackStateCompat.STATE_PLAYING, 0, 0)
                .build());
        mMediaSession.setPlaybackToRemote(getVolumeProvider());
        mMediaSession.setActive(true);
    }

    private VolumeProviderCompat getVolumeProvider() {
        final AudioManager audio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);

        int STREAM_TYPE = AudioManager.STREAM_MUSIC;
        int currentVolume = audio.getStreamVolume(STREAM_TYPE);
        int maxVolume = audio.getStreamMaxVolume(STREAM_TYPE);

        return new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, maxVolume, currentVolume) {
            @Override
            public void onAdjustVolume(int direction) {
                // Volume Up = AudioManager.ADJUST_LOWER, Volume Down = AudioManager.ADJUST_LOWER, Release = AudioManager.ADJUST_SAME
                // Replace with your action, if you don't want to adjust system volume
                if (direction == AudioManager.ADJUST_RAISE) {
                    audio.adjustStreamVolume(STREAM_TYPE,
                            AudioManager.ADJUST_RAISE, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
                }
                else if (direction == AudioManager.ADJUST_LOWER) {
                    audio.adjustStreamVolume(STREAM_TYPE,
                            AudioManager.ADJUST_LOWER, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
                }
                setCurrentVolume(audio.getStreamVolume(STREAM_TYPE));
            }
        };
    }

    // Call when control needed, add a call to constructor if needed immediately
    public void setActive(boolean active) {
        if (mMediaSession != null) {
            mMediaSession.setActive(active);
            return;
        }
        createMediaSession();
    }

    // Call from Service's onDestroy method
    public void destroy() {
        if (mMediaSession != null) {
            mMediaSession.release();
        }
    }
}
Community
  • 1
  • 1
Gibolt
  • 42,564
  • 15
  • 187
  • 127