Search code examples
androidandroid-fragmentsaudiovolumemediacontroller

Android app not recognising volume key presses when showing android.widget.MediaController


I cannot get an Android app (running on Android 6.0) to respond to volume key presses when the android.widget.MediaController is showing.

The media controller is shown by a fragment when a button in the fragment is tapped.

The activity that has loaded the fragment has the following code in onCreate:

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);        
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);

When the media controller is not showing, the volume key presses do adjust the volume and this volume adjustment does impact on the volume with which the sound is played by the media controller.

However, when the media controller is shown visible in the app, then the volume keys are ignored. I have overridden the onKeyDown method of the activity to detect when the key presses are recognised, and they are only recognised when the media controller is not visible.

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    switch (keyCode) {
    case KeyEvent.KEYCODE_VOLUME_UP:
        Log.i(TAG, "Increased volume");
        getAudioManager().adjustStreamVolume(AudioManager.STREAM_MUSIC,
                AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
        return true;
    case KeyEvent.KEYCODE_VOLUME_DOWN:
        Log.i(TAG, "Decreased volume");
        getAudioManager().adjustStreamVolume(AudioManager.STREAM_MUSIC,
                AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
        return true;
    default:
        return false;
    }
}

Users will tend to want to adjust volumes when the sound is being heard and this is exactly when they cannot adjust volumes, the way things are working. How can the media controller behaviour be changed so that it recognises the volume key presses?


Solution

  • Had this issue yesterday and stumbled upon your question. I know it's rather old and you've probably found a way around it but I thought I should post an answer in case someone else finds their way here.

    Your initial idea helped a lot but instead of overriding the handler for KeyEvents for my activity I did so for the MediaController.

    What I did was override public boolean dispatchKeyEvent(KeyEvent event) and initialise my MediaController object like this:

            mediaControls = new MediaController(this) {
    
                @Override
                public boolean dispatchKeyEvent(KeyEvent event) {
                    int action = event.getAction();
                    int keyCode = event.getKeyCode();
                    switch (keyCode) {
                        case KeyEvent.KEYCODE_VOLUME_UP:
                            if (action == KeyEvent.ACTION_DOWN) {
                                audioManager.adjustVolume(AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
                            }
                            break;
                        case KeyEvent.KEYCODE_VOLUME_DOWN:
                            if (action == KeyEvent.ACTION_DOWN) {
                                audioManager.adjustVolume(AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
                            }
                            break;
                        default:
                            return super.dispatchKeyEvent(event);
                    }
                    return true;
                }
            };
    

    audioManager is a private member in my Activity and is created the same way as in the question above.

    Hope this will help someone.

    Have a productive day!