当前位置: 首页 > article >正文

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的根布局文件,包裹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 可改可不改

 @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模块
  • 熟悉亮度范围定制

http://www.kler.cn/a/504398.html

相关文章:

  • 【论文阅读】SDA-FC: Bridging federated clustering and deep generative model
  • 《异步编程之美》— 全栈修仙《Java 8 CompletableFuture 对比 ES6 Promise 以及Spring @Async》
  • Linux(Centos 7.6)命令详解:split
  • 基于springboot+vue的 嗨玩-旅游网站
  • type 属性的用途和实现方式(图标,表单,数据可视化,自定义组件)
  • Hadoop•安装JDK
  • 一套UI精美、控件丰富、多主题的WinForm开源界面库
  • 【Uniapp-Vue3】pages设置页面路径及窗口表现
  • 寒假规划(服创比赛)
  • Nginx 访问状态统计功能配置与使用方法(status)
  • 【Docker】Docker与Docker compose离线安装
  • 宜自动化处理的五件事
  • PyTorch 时间序列与信号处理全解析:从预测到生成
  • 力扣 子集
  • uni-app h5修改浏览器导航栏的 title以及icon
  • 近红外数据预处理和简单分析matlab
  • 3、Go中的注释
  • 隐私计算,构建安全的未来数据空间
  • Docker Desktop 中安装 MySQL 并开启远程访问的详细教程
  • spring-mvc源码分析v3.3.0
  • C++并发编程之无锁数据结构及其优缺点
  • 基于springboot的幼儿园管理系统系统
  • 蓝桥杯 男女搭配
  • Golang学习笔记_25——协程
  • 服务器一次性部署One API + ChatGPT-Next-Web
  • Shell Integration Unavailable VSCode + Cline 报错解决