Mr.Smile: three bug s of volume bar adjustment in Android P and Android 10 Google native settings

Let's look at the problem first

  1. First adjust the volume of a call, and then the volume of the ring tone and the volume of the alarm clock will be linked
  2. Adjust any volume, with rebound of volume bar
  3. Turn on the advanced level of the volume, quickly slide the page up and down, the volume bar will jump to the last adjusted position, and then return to the normal position (provided that the volume is adjusted and the page is quickly slid)

Let's look at the plan

At the end of the first question, let's start with the second one. Some problems can be found through repeated recurrence problems, from which we can boldly speculate and locate problems or bypass some bug s

Question 2:

Volume rebound. Through repeated tests, it is found that the rebound position is the last adjusted position, and the volume is the size of the rebound position. This shows that the database value has not been set, so we boldly speculate why it is the last value, and whether it is possible that there is a problem in the assignment. First, go to the location of the logic and verify it Guess it. alps/frameworks/base/core/java/android/preference/ Here is the code. Open it.

postSetVolume(int progress) debugging found that the problem is really in this progress. The setting is mlastauditauditablestreamvolume, but the fact is that the change is not very timely. The logic is to drag the volume slider and then call this method to update the database. Therefore, the solution to the problem is to make a member variable to record the current position when onProgressChanged, and then change the database onStopTrackingTouch when the finger leaves.

Question 3:

According to the idea of question 2 above, let's first analyze the phenomenon of question 3. This problem will not occur when the volume is first set on the home page. After entering, you need to adjust the volume first, and then quickly slide the page. Here, you need to pay attention to the problem that the most advanced part at the bottom of the volume can only be refolded, and it is found through many tests, The flashing position of the slider is also the last adjusted position. Here we get three information:

  • No such phenomenon when entering the page for initialization
  • There is no such phenomenon when there is no regulation. The adjusted position is the flashing position
  • No such phenomenon when the volume bar is always in the field of view

OK, from the information, the problem must be the progress of the progress bar. And the problem is when the volume bar is reloaded, so let's take a look at the code with the problem alps/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/widget/ As expected, the method of onBindViewHolder(PreferenceViewHolder view) was re used when the fast sliding volume reappeared

    public void onBindViewHolder(PreferenceViewHolder view) {
        mSeekBar = (SeekBar) view.findViewById(
        // Add to
        Log.d("HZH", "onBindViewHolder: " + mCount);
        boolean useSeekProgress = mCount > 0 && this instanceof VolumeSeekBarPreference;
        mSeekBar.setProgress(useSeekProgress ? mSeekBar.getProgress() : mProgress);
        // Add end
        final CharSequence title = getTitle();

At mSeekBar.setProgress, mProgress is the progress of the last result, so it's decided to be the problem here. As for why to use the judgment of mcount > 0, that's because when we see the volume bar, we walk the method of onBindViewHolder twice. We need to change it at the second time. In addition, instanceof volumeseekbar preference is used to To avoid affecting the seekbar at other positions in the setting, for example, the seekbar in barrier free voice to text also uses this. If no judgment is made, the volume bar cannot be reset. Solve the above three problems.

Question 1:

Look at the last question. This bug is really strange. Really, the code is really metaphysical. Google's big guys also have many bugs, and they hide them deeply. On the surface, I don't have any clue, just "lying trough, what's the special situation?" It came to my mind, but after careful consideration, there was still a little direction. I didn't touch the seekbar of the alarm clock when I adjusted the ring tone. Can I distinguish that which was touched by hand?

Look at the code with the only clue, It's the same thing as the problem. It's found that there is something that can be distinguished. When onProgressChanged, it can be distinguished. So I tried to change it according to the following notes, and it's done.

public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
    private static final String TAG = "SeekBarVolumizer";


    private boolean mFromTouch;
    private int mProgress;


    protected void updateSeekBar() {
        final boolean zenMuted = isZenMuted();
        // Modify 
        if((mLastProgress == -1) || (mLastAudibleStreamVolume == mLastProgress)){
        //Modify end
            if (zenMuted) {
                mSeekBar.setProgress(mLastAudibleStreamVolume, true);
            } else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
                mSeekBar.setProgress(0, true);
            } else if (mMuted) {
                mSeekBar.setProgress(0, true);
            } else {
                mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume, true);

    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_SET_STREAM_VOLUME:
                // delete
                //if (mMuted && mLastProgress > 0) {
                //    mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_UNMUTE, 0);
                //} else if (!mMuted && mLastProgress == 0) {
                //    mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_MUTE, 0);
                // Delete end
                mAudioManager.setStreamVolume(mStreamType, mLastProgress,


    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
        // Add to
        mProgress = progress;
        mFromTouch = fromTouch;
        //Add to

    //Add to
    private void startChangeProgress(SeekBar seekBar){
        Log.d(TAG,"mProgress: "+mProgress);
        if (mFromTouch) {
        if (mCallback != null) {
            mCallback.onProgressChanged(seekBar, mProgress, mFromTouch);
    //Add to


    public void onStopTrackingTouch(SeekBar seekBar) {
        // Add to
        // Add end


So far, all three problems have been solved. I found that there was an article that asked for five C coins in this code. It's totally free here. However, if you are lucky enough to help you, I hope you can leave a comment. If there is a problem or a better solution, please don't hesitate to comment.

21 original articles published, 28 praised, 60000 visitors+
Private letter follow

Tags: Java Database Android Google

Posted on Sun, 19 Jan 2020 03:53:31 -0500 by direction