Mr.Smile填坑记——安卓P、安卓10 Google原生设置中音量条调节的3个bug
先来看看问题
- 先调节一次通话音量,之后铃声音量和闹钟音量会发生联动现象
- 调节任一音量,有音量条的回弹现象
- 打开音量的高级,快速上下滑动页面,音量条会跳到上次调节的位置,然后再回到正常位置(前提是要调节过音量,并且要快速滑动页面)
再来看看方案
第一个问题最后再说,先从第二个问题说起。一些问题,通过重复的复现问题,可以发现一些规律,从规律当中可以大胆的推测定位问题或者绕过某些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的时候可以区分,于是按照下面注释的改法试了一把,果然搞定了。
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币,在我这里完全免费,但是,如果有幸帮到你,希望能留个赞,如果有问题或更好的解决办法,请不吝赐教。