MTK6768 Android13 亮度条均匀调节实现

devtools/2025/1/15 7:01:33/

文章目录

  • 需求:
  • 问题现象:
  • 需求实现疑难问题点:
  • 相关资源
  • 修改的文件
  • 调试技巧
  • 具体需求实现
    • 去除亮度弹框
      • 设置去掉跳转逻辑
      • 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的根布局文件,包裹ToggleSeekBarView,本质是一个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);}

总结

  • 亮度条均匀调节实现 只是一个需求而已,通过此需求 需要掌握的基本知识技能如下:
  • 熟悉物理按键触发流程,进一步了解 PhoneWindowManager
  • 熟悉亮度控制逻辑和业务
  • 熟悉亮度brightness模块
  • 熟悉亮度范围定制

http://www.ppmy.cn/devtools/150608.html

相关文章

Flink类加载机制详解

1. 总览 在运行Flink应用时,它会加载各种类,另外我们用户代码也会引入依赖,由于他们依赖版本以及加载顺序等不同,就可能会导致冲突,所以很要必要了解Flink是如何加载类的。 根据加载的来源的不同,我们可以将类分为三种: Java Classpath:Java类路径下,这是Java通用的…

LabVIEW智能水肥一体灌溉控制系统

本文详细介绍了一种基于LabVIEW的智能水肥一体灌溉控制系统的设计与实现。该系统采用模糊控制策略&#xff0c;能够自动调节土壤湿度和肥液浓度&#xff0c;满足不同作物在不同生长阶段的需求&#xff0c;有效提高水肥利用效率&#xff0c;对现代精准农业具有重要的实践和推广价…

MATLAB中rescale函数用法

目录 语法 说明 示例 缩放到单位区间 缩放到指定范围 缩放矩阵列和行 rescale函数的功能是数组元素的缩放范围。 语法 R rescale(X) R rescale(X,a,b) R rescale(___,Name,Value) 说明 R rescale(X) 将 X 的条目缩放到区间 [0,1]。输出数组 R 的大小与 X 相同。 R…

ElectronSharp,.Net跨平台的多一种选择

文章目录 背景解决方案小结 背景 最近有个项目是基于Blazor的跨平台项目&#xff0c;要求在Windows、安卓平板和Mac上能跑&#xff0c;而且要求实现视频通话功能&#xff0c;而Web里的视频通话无非就是基于WebRTC技术。经过前期调研&#xff0c;通过套壳MAUI&#xff0c;Windo…

PyCharm 引用其他路径下的文件报错 ModuleNotFound 或报红

PyCharm 中引用其他路径下的文件提示 ModuleNotFound&#xff0c;将被引用目录添加到系统路径&#xff1a; # # 获取当前目录 dir_path os.path.dirname(os.path.realpath(__file__)) # # 获取上级目录 parent_dir_path os.path.abspath(os.path.join(dir_path, os.pardir))…

【进程与线程】程序和进程在内存中的表现

在计算机系统中&#xff0c;程序和进程是两个密切相关但又有本质区别的概念&#xff0c;尤其在内存中的表现上有显著不同&#xff1a; 在这张图中可以直观地看出程序和进程在内存中的结构区别。 基本定义 程序 程序 是一个 静态实体&#xff0c;表示一组写好的指令和数据的…

matlab GUI 打包成exe可执行文件

1、在命令行窗口输入deploytool回车&#xff0c;选择第一个。 2.选择刚刚gui的.mlapp程序&#xff08;Mortgage.mlapp&#xff09; 3、右上角Settings&#xff08;1&#xff09;中可以更改生成的路径&#xff0c; (2)可以替换exe的图标缩量图&#xff0c;默认就是下图 (3)是指示…

python检测gitlab中某个标签在一个月内添加和移除了多少次

可以通过 Python 脚本和 GitLab API 检测一个标签在一个月内被添加和移除的次数。以下是实现的步骤和示例代码&#xff1a; 步骤 获取 GitLab API 访问令牌&#xff1a;在 GitLab 中生成一个 Personal Access Token。设置时间范围&#xff1a;确定一个月的时间范围。调用 Git…