文章目录
- 需求:
- 问题现象:
- 需求实现疑难问题点:
- 相关资源
- 修改的文件
- 调试技巧
- 具体需求实现
- 去除亮度弹框
- 设置去掉跳转逻辑
- SystemUI亮度条长按跳转屏蔽
- 实现亮度均匀调节
- PhoneWindowManager.java
- BrightnessUtils convertLinearToGammaFloat
- BrightnessSynchronizer brightnessIntToFloat brightnessFloatToIntRange
- ToggleSlider
- BrightnessController onChanged
- setBrightness(valFloat);
- 延伸内容
- DisplayManager setBrightness
- DisplayManagerGlobal setBrightness
- DisplayManagerService setBrightness
- 总结
需求:
问题现象:
- 当前亮度调节到最低:点击亮度+ 物理按键,SystemUI的下拉框的亮度条和亮度显示值 或者 在设置界面的亮度条
亮度显示值和亮度进度条一下子变成了50%; 反之也是一样。 - 基于问题1的现象,在亮度调节到50% 以上的时候,点击加或者减按钮时候,实际调节值不一样,非线性调节。
需求实现疑难问题点:
-
亮度条弹框是有两个地方: 都需要屏蔽
下拉框亮度条长按进入亮度条控制镜像
设置界面,设置->显示->亮度 点击会弹出亮度控制界面,和上面的亮度控制镜像是两个内容 -
亮度设置分为两个部分:UI上面的亮度条是一个SeekBar,调节设置;物理按键控制设置;
-
MTK6768产品,或者其它产品,因为恒压电路板电量功率原因、屏幕原因、显示底层原因 等多种原因
本身是一个复杂的体系,方方面面会造成亮度不均匀调节。 -
分析到最后发现,亮度本身就是线性调节的,那如何规避或者解决,达到实际用户体验上感觉亮度是线性的。
-
调试中,亮度调节到最低后,始终调节不下去了。比如 调节亮度到13%、5% ,亮度值或者亮度条再也调节不下去了。
-
调节亮度调节到最后,调节到亮度值为0 的时候,亮度却变成了最亮。
相关资源
实现本需求,结合自己以前写过的相关内容的笔记,结合起来了解相关最基本的基础内容:
实现本需求,结合自己以前写过的相关内容的笔记,结合起来了解相关最基本的基础内容:
Android12_SystemUI下拉框新增音量控制条-熟悉brightness
包下面的几个关键类:
熟悉几个关键类 并 熟悉 每个类的具体作用,方便对亮度条操控和新增功能BrightnessController.java :对外的控制器 BrightnessController implements ToggleSlider.Listener BrightnessSlider.java : 本质上也是一个View,带了ViewController控制器,extends ViewController<BrightnessSliderView> implements ToggleSliderToggleSlider.java : 定义进度条控制器的接口,如:进度条变化回调 onChanged、setMax、getMax、getValue、setValueBrightnessDialog.java :显示亮度的Activity,里面加载的是Dialog,源码暂未使用 BrightnessSliderView.java :SeekBar的根布局文件,包裹ToggleSeekBar 的View,本质是一个FrameLayout 布局ToggleSeekBar.java :SeekBar
Android13_SystemUI下拉新增音量控制条
查看跟亮度模块相关的部分
android 修改最低亮度值,不要太暗
Android亮度范围定制
DisplayManagerService 亮度调节
PowerManagerService
Android framework配置默认屏幕亮度值源码分析
Android10 安卓修改屏幕背光默认亮度
模拟Power长按事件实现应用调用 熟悉按键分发机制
基础的基本内容的核心要求就是熟悉亮度模块的基本类和工具类:通过下拉框进度条和范围作为入口来关联相关的类 来进一步熟悉。
修改的文件
frameworks/base/core/java/com/android/internal/display/BrightnessSynchronizer.java
frameworks/base/packages/SettingsLib/src/com/android/settingslib/display/BrightnessUtils.java
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
vendor/mediatek/proprietary/packages/apps/SystemUI/AndroidManifest.xml
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/settings/volume/VolumeSliderController.java
/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/display/BrightnessLevelPreferenceController.java
调试技巧
降低屏幕亮度: input keyevent 220
提高屏幕亮度: input keyevent 221
具体需求实现
去除亮度弹框
设置去掉跳转逻辑
系统设置找到对应的Activity,在跳转的地方屏蔽掉 跳转逻辑。AndroidManifest 可改可不改
@Overridepublic boolean handlePreferenceTreeClick(Preference preference) {if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {return false;}final Intent intent = new Intent(ACTION_SHOW_BRIGHTNESS_DIALOG);intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,SettingsTransitionHelper.TransitionType.TRANSITION_NONE);// Start activity in the same task and pass fade animations//wangfangchen add /*final ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext,android.R.anim.fade_in, android.R.anim.fade_out);mContext.startActivityForResult(preference.getKey(), intent, 0, options.toBundle());*///wangfangchen end return true;}
SystemUI亮度条长按跳转屏蔽
BrightnessSliderController.java@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {mTracking = true;if (mListener != null) {mListener.onChanged(mTracking, getValue(), false);}/*if (mMirrorController != null) {mMirrorController.showMirror();mMirrorController.setLocationAndSize(mView);}*/}
实现亮度均匀调节
PhoneWindowManager.java
为什么要看这个,或者说一定要看,从根本的角度来看物理按键触发后到底做了什么
case KeyEvent.KEYCODE_BRIGHTNESS_UP:case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:if (down) {int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;// Disable autobrightness if it's onint auto = Settings.System.getIntForUser(mContext.getContentResolver(),Settings.System.SCREEN_BRIGHTNESS_MODE,Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,UserHandle.USER_CURRENT_OR_SELF);if (auto != 0) {Settings.System.putIntForUser(mContext.getContentResolver(),Settings.System.SCREEN_BRIGHTNESS_MODE,Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,UserHandle.USER_CURRENT_OR_SELF);}float min = mPowerManager.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);float max = mPowerManager.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);float step = (max - min) / BRIGHTNESS_STEPS * direction;int screenDisplayId = displayId < 0 ? DEFAULT_DISPLAY : displayId;float brightness = mDisplayManager.getBrightness(screenDisplayId);//wangfangchen add Log.d(TAG, "brightness brightness:=" + brightness+" step:"+step+"========"); //wangfangchen end brightness += step;// Make sure we don't go beyond the limits.brightness = Math.min(max, brightness);brightness = Math.max(min, brightness);//wangfangchen add Log.d(TAG, "brightness brightness:=" + brightness+" max:"+max+" min:"+min); if(brightness>1||brightness<0.1){brightness=0.02f;Log.d(TAG, "brightness to large,let brightness ==0.02");}//wangfangchen end mDisplayManager.setBrightness(screenDisplayId, brightness);startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),UserHandle.CURRENT_OR_SELF);}
可以看出,最终亮度加减按钮调节亮度 通过调用方法:
mDisplayManager.setBrightness(screenDisplayId, brightness);
所以遇到异常的时候,如上面疑难点中的 亮度调节到0变成最亮、亮度调到小的时候不可调节 在这里check 问题原因。
BrightnessUtils convertLinearToGammaFloat
关注方法:
/*** Version of {@link #convertLinearToGamma} that takes float values.* TODO: brightnessfloat merge with above method(?)* @param val The brightness setting value.* @param min The minimum acceptable value for the setting.* @param max The maximum acceptable value for the setting.* @return The corresponding slider value*///wangfangchen add //public static final int convertLinearToGammaFloat(float val, float min, float max) {public static final int convertLinearToGammaFloat(float originalFloat, float min, float max) {BigDecimal bd = BigDecimal.valueOf(originalFloat);bd = bd.setScale(1, RoundingMode.HALF_UP); // 保留一位小数,四舍五入float val = bd.floatValue();// For some reason, HLG normalizes to the range [0, 12] rather than [0, 1]final float normalizedVal = MathUtils.norm(min, max, val) * 12;final float ret;Log.d(TAG,"convertLinearToGammaFloat originalFloat:"+originalFloat +" min:"+min+" max:"+max+" val:"+val+" normalizedVal:"+normalizedVal+" normalizedVal:"+normalizedVal);if (normalizedVal <= 1f) {ret = MathUtils.sqrt(normalizedVal) * R;} else {ret = A * MathUtils.log(normalizedVal - B) + C;}Log.d(TAG," ret:"+ret+" return value:"+Math.round(MathUtils.lerp(GAMMA_SPACE_MIN, GAMMA_SPACE_MAX, ret)));//return Math.round(MathUtils.lerp(GAMMA_SPACE_MIN, GAMMA_SPACE_MAX, ret));float ratio = (float)(val - min)/ (max - min);Log.d(TAG," shiji val:"+val+" min:"+min+" max:"+max+" return value:"+(int)(ratio * GAMMA_SPACE_MAX));Log.d(TAG," GAMMA_SPACE_MAX*val:"+(int)GAMMA_SPACE_MAX*val);int valueData= (int) (GAMMA_SPACE_MAX*val);Log.d(TAG," valueData:"+valueData);return valueData;}
这个方法,就是用convertLinearToGammaFloat 将线性值转换为伽马校正后的浮点值的过程,这个地方就是造成非线性的根本原因。
如果我们改成线性 ,显示上面就是线性显示了,实际的亮度值 可能就不是线性显示了。 为了 解决实际亮度值线性显示,那么就需要控制档位了,只显示60%-100%.
如 上述的笔记参考:Android亮度范围定制
BrightnessSynchronizer brightnessIntToFloat brightnessFloatToIntRange
/*** Converts between the int brightness system and the float brightness system.*/public static float brightnessIntToFloat(int brightnessInt) {if (brightnessInt == PowerManager.BRIGHTNESS_OFF) {return PowerManager.BRIGHTNESS_OFF_FLOAT;} else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) {return PowerManager.BRIGHTNESS_INVALID_FLOAT;} else {final float minFloat = PowerManager.BRIGHTNESS_MIN;final float maxFloat = PowerManager.BRIGHTNESS_MAX;//wangfangchen add //final float minInt = PowerManager.BRIGHTNESS_OFF + 1;Log.d(TAG," brightnessIntToFloat: minInt:"+PowerManager.BRIGHTNESS_OFF + 1);float minInt =0f;final float maxInt = PowerManager.BRIGHTNESS_ON;Log.d(TAG," brightnessIntToFloat: maxInt:"+PowerManager.BRIGHTNESS_ON);Log.d(TAG," brightnessIntToFloat: brightnessInt:"+brightnessInt);//wangfangchen endreturn MathUtils.constrainedMap(minFloat, maxFloat, minInt, maxInt, brightnessInt);}}/*** Translates specified value from the float brightness system to the int brightness system,* given the min/max of each range. Accounts for special values such as OFF and invalid values.* Value returned as a float primitive (to preserve precision), but is a value within the* int-system range.*/public static float brightnessFloatToIntRange(float brightnessFloat) {if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) {return PowerManager.BRIGHTNESS_OFF;} else if (Float.isNaN(brightnessFloat)) {return PowerManager.BRIGHTNESS_INVALID;} else {final float minFloat = PowerManager.BRIGHTNESS_MIN;final float maxFloat = PowerManager.BRIGHTNESS_MAX;//wangfangchen add //final float minInt = PowerManager.BRIGHTNESS_OFF + 1;float minInt =0f;//wangfangchen end final float maxInt = PowerManager.BRIGHTNESS_ON;return MathUtils.constrainedMap(minInt, maxInt, minFloat, maxFloat, brightnessFloat);}}在转换亮度范围的地方法,设置亮度范围值,这里可能涉及到亮度范围定制需求,如上笔记分析。 float minInt =0f; 表示最低亮度设置为0
ToggleSlider
顶层接口,添加接口方法:
public interface ToggleSlider {interface Listener {void onChanged(boolean tracking, int value, boolean stopTracking);}void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin);void setMirrorControllerAndMirror(BrightnessMirrorController c);boolean mirrorTouchEvent(MotionEvent ev);void setOnChangedListener(Listener l);void setMax(int max);int getMax();//wangfangchen add void setMin(int max);int getMin();//wangfangchen end void setValue(int value);int getValue();void showView();void hideView();boolean isVisible();
}
为什么添加这两个方法?
- void setMin(int max);
- int getMin();
给View 用,因为下拉框的亮度条,是需要新增最新亮度值的,默认是有最大亮度值的65535。 因为可能涉及到定制亮度在60%-100 之间调节,所以需要有最小亮度的控制。
BrightnessController onChanged
在下拉框,控制亮度条的时候,亮度为什么会变化? SeekBar 控制后肯定设置了亮度的呀,我们找到对应的方法,看看源码。
@Overridepublic void onChanged(boolean tracking, int value, boolean stopTracking) {if (mExternalChange) return;if (mSliderAnimator != null) {mSliderAnimator.cancel();}final float minBacklight;final float maxBacklight;final int metric;if (mIsVrModeEnabled) {metric = MetricsEvent.ACTION_BRIGHTNESS_FOR_VR;minBacklight = mMinimumBacklightForVr;maxBacklight = mMaximumBacklightForVr;} else {metric = mAutomatic? MetricsEvent.ACTION_BRIGHTNESS_AUTO: MetricsEvent.ACTION_BRIGHTNESS;minBacklight = mBrightnessMin;maxBacklight = mBrightnessMax;}final float valFloat = MathUtils.min(convertGammaToLinearFloat(value, minBacklight, maxBacklight),maxBacklight);if (stopTracking) {// TODO(brightnessfloat): change to use float value instead.MetricsLogger.action(mContext, metric,BrightnessSynchronizer.brightnessFloatToInt(valFloat));}Log.d(TAG," onChanged setBrightness valFloat:"+valFloat);//wangfangchen add // setBrightness(valFloat);// if (!tracking) {//wangfangchen end AsyncTask.execute(new Runnable() {public void run() {//wangfangchen add Log.d(TAG,"onChanged valFloat:"+valFloat);//0.0017if(valFloat>1||valFloat<0.002){// brightness=0.002f;float brightness=0.002f;Log.d(TAG, "onChanged brightness to large,let brightness ==0.002f");mDisplayManager.setBrightness(mDisplayId, brightness);}else{Log.d(TAG, "brightness setBrightness:"+valFloat);mDisplayManager.setBrightness(mDisplayId, valFloat);}//wangfangchen end }});//wangfangchen add //}//wangfangchen end }
这里我们找到了我们熟悉的方法:在PhoneWindowManager 里面我们看到过 setBrightness
mDisplayManager.setBrightness(mDisplayId, valFloat);
和在PhoneWindowManager 里面的 setBrightness 一样,调试具体哪里问题,适配来解决可能出现的:亮度无法调节、最小亮度可能实际变成最亮。
setBrightness(valFloat);
我们看看这个方法做什么的
private void setBrightness(float brightness) {//wangfangchen add Log.d(TAG," setBrightness brightness:"+brightness);Log.d(TAG,"setTemporaryBrightness brightness :"+brightness);//wangfangchen end mDisplayManager.setTemporaryBrightness(mDisplayId, brightness);}setTemporaryBrightness 其实也是设置一次亮度。 暂不关心,我们直接屏蔽掉。
其它修改类,我们暂不分析,通过上面源码分析,核心本质内容:
- 亮度适配:按键和下拉框进度条
- 新增接口方法,实现后续可能定制的亮度范围区间控制
延伸内容
结合上面控制亮度的方法作为入口:
mDisplayManager.setBrightness
DisplayManager setBrightness
/*** Sets the brightness of the specified display.* <p>* Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS}* permission.* </p>** @param displayId the logical display id* @param brightness The brightness value from 0.0f to 1.0f.** @hide*/@RequiresPermission(Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)public void setBrightness(int displayId, @FloatRange(from = 0f, to = 1f) float brightness) {mGlobal.setBrightness(displayId, brightness);}
DisplayManagerGlobal setBrightness
/*** Sets the brightness of the display.** @param brightness The brightness value from 0.0f to 1.0f.** @hide*/public void setBrightness(int displayId, float brightness) {try {mDm.setBrightness(displayId, brightness);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}}
DisplayManagerService setBrightness
@Override // Binder callpublic void setBrightness(int displayId, float brightness) {mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,"Permission required to set the display's brightness");Log.d(TAG,"setBrightness brightness:"+brightness);if (!isValidBrightness(brightness)) {Slog.w(TAG, "Attempted to set invalid brightness" + brightness);return;}final long token = Binder.clearCallingIdentity();try {synchronized (mSyncRoot) {DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);if (dpc != null) {dpc.setBrightness(brightness);}mPersistentDataStore.saveIfNeeded();}} finally {Binder.restoreCallingIdentity(token);}}private static boolean isValidBrightness(float brightness) {return !Float.isNaN(brightness)&& (brightness >= PowerManager.BRIGHTNESS_MIN)&& (brightness <= PowerManager.BRIGHTNESS_MAX);}