Mr.Smile填坑记——安卓P、安卓10 Google原生设置中音量条调节的3个bug

先来看看问题

  1. 先调节一次通话音量,之后铃声音量和闹钟音量会发生联动现象
  2. 调节任一音量,有音量条的回弹现象
  3. 打开音量的高级,快速上下滑动页面,音量条会跳到上次调节的位置,然后再回到正常位置(前提是要调节过音量,并且要快速滑动页面)

再来看看方案

     第一个问题最后再说,先从第二个问题说起。一些问题,通过重复的复现问题,可以发现一些规律,从规律当中可以大胆的推测定位问题或者绕过某些bug.

     问题二:

     音量回弹这个,通过反复的测试发现,每次回弹的位置都是上次调节的位置,并且音量大小是弹回位置的大小,这说明,数据库的值没有设置过来,那么我们大胆的推测为什么会是上次的数值,有没有可能是赋值的时候出问题,先去看看逻辑所在位置,验证下猜测。alps/frameworks/base/core/java/android/preference/SeekBarVolumizer.java 代码在此,打开看看吧。

     postSetVolume(int progress) 调试发现问题果然还是在这个progress,设置的是mLastAudibleStreamVolume 这个东西,但是事实是这个东西变化并不是很及时,逻辑是拖动音量滑块后再调用此方法更新数据库。因此,问题的解决法案是onProgressChanged的时候,搞一个成员变量记录当前的位置,然后在手指离开的时候去改变数据库onStopTrackingTouch。

    问题三:

    根据上面问题二的思路,我们先来分析一下问题三的现象,从设置首页第一次进入音量的时候不会出现此问题,进入之后需要先调节一次音量,然后再快速滑动页面,这里需要注意下,把音量最下面那个高级的部分取消折叠才能复现问题,并且多次测试发现,滑块闪动的位置,也是上次调节的位置,到这里我们得到3个信息:

  • 初始化进入页面的时候无此现象
  • 进来没有条调节过的时候无此现象,调节过后的位置,就是闪动的位置
  • 音量条一直在视野范围的时候无此现象

    好,从信息中得出,问题肯定是进度条的progress有问题,并且有问题的地方是在音量条重新加载的时候,那么带着问题我们再去看代码alps/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/widget/SeekBarPreference.java果然,在快速滑动音量又出现的时候重新走了 onBindViewHolder(PreferenceViewHolder view) 的方法

 @Override
    public void onBindViewHolder(PreferenceViewHolder view) {
        super.onBindViewHolder(view);
        view.itemView.setOnKeyListener(this);
        mSeekBar = (SeekBar) view.findViewById(
                com.android.internal.R.id.seekbar);
        mSeekBar.setOnSeekBarChangeListener(this);
        mSeekBar.setMax(mMax);
        mSeekBar.setMin(mMin);
        // 添加
        Log.d("HZH", "onBindViewHolder: " + mCount);
        boolean useSeekProgress = mCount > 0 && this instanceof VolumeSeekBarPreference;
        mSeekBar.setProgress(useSeekProgress ? mSeekBar.getProgress() : mProgress);
        mCount++;
        // 添加结束
        final CharSequence title = getTitle();
        mSeekBar.setEnabled(isEnabled());
        .......
}

mSeekBar.setProgress的时候,mProgress就是上次条结果的progress,所以断定就是这里的问题了,至于为什么要用mCount >0的判断呢,那是因为从新看到音量条的时候,走了两次onBindViewHolder的方法,我们要在第二次的时候去改变才可以,另外用,instanceof VolumeSeekBarPreference是为了避免影响设置中其他位置的seekbar,比如无障碍中的语音转文字的seekbar也用的这个,不做判断的话会导致,这个音量条无法重置。以上问题三解决。

      问题一:

      再看最后一个问题,这个bug确实很奇怪,真的,代码确实是玄学,Google的大佬也是有不少bug的,并且隐藏的很深很深。表面上看确实没什么头绪,只有 “卧槽,这特么什么情况?!” 浮现在我的脑海,但是后面仔细想想,还是有了点方向,我调节铃声的时候并没有触摸到闹钟的seekbar啊,能不能区分出那个是用手触摸过的呢?

      带着唯一的线索去看代码,SeekBarVolumizer.java和问题一用的是同一个东西,果然发现了有可以区分的地方,onProgressChanged的时候可以区分,于是按照下面注释的改法试了一把,果然搞定了。

扫描二维码关注公众号,回复: 8724575 查看本文章
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();
        mSeekBar.setEnabled(!zenMuted);
        // 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);
            }
        }
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_SET_STREAM_VOLUME:
                // 删除
                //if (mMuted && mLastProgress > 0) {
                //    mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_UNMUTE, 0);
                //} else if (!mMuted && mLastProgress == 0) {
                //    mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_MUTE, 0);
                //}
                // 删除结束
                mAudioManager.setStreamVolume(mStreamType, mLastProgress,
                        AudioManager.FLAG_SHOW_UI_WARNINGS);
                break;
           .......
    }

   

    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
        // 添加
        mProgress = progress;
        mFromTouch = fromTouch;
        //添加
    }

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

   ............

    public void onStopTrackingTouch(SeekBar seekBar) {
        // 添加
        startChangeProgress(seekBar);
        // 添加结束
        postStartSample();
    }

    ...........
}

到此,3个问题都得以解决,我发现有篇文章这个代码居然要 5个C币在我这里完全免费,但是,如果有幸帮到你,希望能留个赞,如果有问题或更好的解决办法,请不吝赐教。

发布了22 篇原创文章 · 获赞 29 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Keep_Holding_On/article/details/104038099