MTK6768 Android13 亮度条均匀调节实现
文章目录
- 需求:
- 问题现象:
- 需求实现疑难问题点:
- 相关资源
- 修改的文件
- 调试技巧
- 具体需求实现
- 去除亮度弹框
- 设置去掉跳转逻辑
- 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 ToggleSlider
ToggleSlider.java : 定义进度条控制器的接口,如:进度条变化回调 onChanged、setMax、getMax、getValue、setValue
BrightnessDialog.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 可改可不改
@Override
public 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
@Override
public 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 on
int 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 end
return 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 控制后肯定设置了亮度的呀,我们找到对应的方法,看看源码。
@Override
public 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.0017
if(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 call
public 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);
}
总结
- 亮度条均匀调节实现 只是一个需求而已,通过此需求 需要掌握的基本知识技能如下:
- 熟悉物理按键触发流程,进一步了解 PhoneWindowManager
- 熟悉亮度控制逻辑和业务
- 熟悉亮度brightness模块
- 熟悉亮度范围定制