Question

I spent hours to get this simple use case working: when I press the volume hardware buttons, I want to open a DialogFragment. The dialog contains a SeekBar, which should set according the button pressed.

I have several problems here.

First, I don't know how to pass the KeyEvents to the fragment. I created a BroadcastReceiver and registered it via AudioManager.registerMediaButtonEventReceiver. Additionally, I put the Receiver in the AndroidManifest.xml:

    <receiver android:name=".fragment.ActionbarFragment$MediaButtonEventReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON"/>
        </intent-filter>
    </receiver>

But this receiver does only work if I use the following intent filter:

        <intent-filter>
            <action android:name="android.media.VOLUME_CHANGED_ACTION"/>
        </intent-filter>

When I look into the AudioManager.VOLUME_CHANGED_ACTION, you'll find the following comment:

 * @hide Broadcast intent when the volume for a particular stream type changes.
 * Includes the stream, the new volume and previous volumes.
 * Notes:
 *  - for internal platform use only, do not make public,
 *  - never used for "remote" volume changes

So, it's likely to brake some day and I'd like to avoid this intent. What's the alternative? How do I pass the key events from the hardware buttons to the fragment correctly?

Second, when the DialogFragment is open, the default Android VolumePanel is shown though I have overridden onKeyDown:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    return true;
}

As far as I know, fragments don't have their own onKeyDown, so I was wondering why the VolumePanel is shown, when I press the hardware buttons.

Was it helpful?

Solution

I finally solved both issues. First of all, MEDIA_BUTTON seems not to respond to volume changes. It's obviously responds only to PLAY, PAUSE, STOP, etc. which is not what I want.

The simplest solution is still to handle the key events in OnKeyDown() of every Activity:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

    if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
       keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
       keyCode == KeyEvent.KEYCODE_MENU) {
        showSoundSettingsDialog();
    }

    return true;
}

To write the code once, I moved this part into a BaseActivity from which the Activities inherit.

The second issue was solved by adding a simple OnKeyListener to the Dialog, as they have their own KeyEvents, what I didn't know so far.

    builder.setOnKeyListener(new Dialog.OnKeyListener() {

        @Override
        public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                volumeUp();
            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                volumeDown();
            } else if (keyCode == KeyEvent.KEYCODE_BACK) {
                dialog.dismiss();
            }

            return true;
        }
    });

And that's it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top