Android: changing the ringer volume
Posted by Dimitri | May 27th, 2011 | Filed under Programming
Another Android tutorial, this time, explaining how to change the different sound volumes of the Android system, such as the ringer, music and notification loudness. The source code featured below is available for download at the end of the post.
Using a seek bar to control audio’s volume in Android is a lot like changing the screen brightness with a seek bar. However, instead of using a ContentResolver to obtain the service that controls the audio, Android has a class that makes everything easier, named AudioManager. So, the example here will basically obtain a reference to the AudioManager and will use it to get the current ringer volume and use it to set the progress of a seek bar. When changed, the seek bar progress will set the value of the sound volume. Here is the code:
package fortyonepost.com.sbvol; import android.app.Activity; import android.content.Context; import android.media.AudioManager; import android.os.Bundle; import android.view.KeyEvent; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; public class VolumeActivity extends Activity { //a variable to store the seek bar from the XML file private SeekBar volumeBar; //an AudioManager object, to change the volume settings private AudioManager amanager; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //get the seek bar from main.xml file volumeBar = (SeekBar) findViewById(R.id.sb_volumebar); //get the audio manager amanager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); //seek bar settings// //sets the range between 0 and the max volume volumeBar.setMax(amanager.getStreamMaxVolume(AudioManager.STREAM_RING)); //set the seek bar progress to 1 volumeBar.setKeyProgressIncrement(1); //sets the progress of the seek bar based on the system's volume volumeBar.setProgress(amanager.getStreamVolume(AudioManager.STREAM_RING)); //register OnSeekBarChangeListener, so that the seek bar can change the volume volumeBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { //change the volume, displaying a toast message containing the current volume and playing a feedback sound amanager.setStreamVolume(AudioManager.STREAM_RING, progress, AudioManager.FLAG_SHOW_UI + AudioManager.FLAG_PLAY_SOUND); } }); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //if one of the volume keys were pressed if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) { //change the seek bar progress indicator position volumeBar.setProgress(amanager.getStreamVolume(AudioManager.STREAM_RING)); } //propagate the key event return super.onKeyDown(keyCode, event); } }
The first object declared in the code (at line 15) is a seek bar, and it’s the only GUI element at this example (line 15). The other is an AudioManager object. These purpose of those two objects is to store a reference to the seek bar defined at the main.xml file and to access the system’s audio service that control the different volumes.
Inside the onCreate method, the aforementioned references are obtained (lines 28 and 31). Then, some seek bar settings are defined, such as the maximum value (which is set to be the same as the maximum ringer’s volume), and the increment (lines 35 and 37). Note that this example will change the ringer volume, and that’s why its maximum value was used, however it’s possible to use the music playback volume or the notification values simply by writing AudioManager.STREAM_MUSIC or AudioManager.STREAM_NOTIFICATION instead. It just a matter of using the correct AudioManager stream constant. Click here for a list of available streams.
Line 40 sets the seek bar progress to be the same as the current ringer volume. Now that the seek bar progress displays the current volume, its time to change it every time the progress indicator is dragged. That’s achieved by the onProgressChanged() method, inside the OnSeekBarChangeListener interface, which is called every time the seek bar indicator is repositioned. The only code inside it (line 59) calls the setStreamVolume() method, which takes three parameters: the first, is the stream we want to set the volume; the second is the volume’s intensity. In this case, it is set to be equal to the seek bar’s progress. The third parameter takes some constants, that define what should happen when the volume changes. In this example, if you hold the seek bar indicator, it will display a toast containing the Volume and will play a feedback sound, to indicate the ringer’s loudness.
Finally, the onKeyDown() method (line 65) runs every time a key has been pressed. Since the volume can be also changed through the volume keys, it’s wise to update the seek bar progress as they are pressed. First, the if statement inside this method will check if one of those keys were pressed (line 68). Case that’s true, the seek bar is updated to display the current volume (line 71). The last line of code propagates the key event to other key event listeners, so that they can handle the pressed keys (line 74).
That’s it! Just hold down the seek bar progress indicator and move it to set the ringer’s volume.
On my phone, there’s a setting to link the ringer to the notification volume. I had assumed it was just something the system setting app was doing internally, as an app, but no, if I programmatically adjust the ringer volume, it will drag my notification volume around with it, whether I like it or not.
Are you familiar with this?
Do you know of a way to programmatically enable or disable this? I can’t find anything in the SDK for this, but I could well be missing it.
I guess that’s the standard behavior.
You could try getting the notification volume at the beginning of the above code and storing it’s value at a variable. When the ringer volume is set (line 59), also set the notification volume to be the one you have previously stored.
It just I was looking for!helpful! thank you!