Search code examples
androidandroid-audiomanager

android - detecting stream volume change


in my app I have a VerticalSeekBar (some custom implementation of SeekBar) whos progress should change when the user changes media volume using the hardware buttons. Below is a half-working solution using a ContentObserver:

      public class SettingsContentObserver extends ContentObserver {

     private VerticalSeekBar sb;
     private AudioManager am;

public SettingsContentObserver(Handler handler, VerticalSeekBar sb, AudioManager am) {
    super(handler);
    this.sb = sb;
    this.am = am;

}

@Override
public boolean deliverSelfNotifications() {
    return super.deliverSelfNotifications();
}

@Override
public void onChange(boolean selfChange) {
    super.onChange(selfChange);
    sb.setProgress(am.getStreamVolume(AudioManager.STREAM_MUSIC));

}
    }

Activity:

        @Override
protected void onResume() {
    super.onResume();
    mSettingsContentObserver = new SettingsContentObserver( new Handler(), vBar, audioMan ); 
    this.getApplicationContext().getContentResolver().registerContentObserver( 
        android.provider.Settings.System.CONTENT_URI, true, 
        mSettingsContentObserver );

}

The issue: volume changes are detected BUT there's a few seconds delay until they get detected and SeekBar's progress changes.

The question: is there a more reliable way to listen for volume changes on a particular volume stream? Please share you solution in case you have some


Solution

  • I already made a solution that monitors volume level while in a phone call, so this should be similar.

    You can either listen for the key presses in your activity (onKey) and check for the corresponding keyCode (VOLUME_UP or VOLUME_DOWN).

    Or, if you can't listen for the key events for some reason (some remote view), just poll the volume level at a fast enough frequency:

    1. Use am.getStreamVolume(AudioManager.STREAM_MUSIC) to poll the volume level.

    2. Run this at your desired frequency. For example:

          private Runnable mVolumeUpdateRunnable = new Runnable() {
          public void run() {
              if (shouldUpdate)
              {
                      updateCurrentVolume();
                      new Handler().postDelayed(mVolumeUpdateRunnable, VOLUME_SAMPLING_DELAY);
              }
          }
      };
      

    The calls are not expensive so it shouldn't be a big problem to update at a high frequency.