[Android Framework] 8.1 DisplayPowerController(三) 亮度调节

时间:2024-04-06 16:16:45

背光调节,即亮度调节,根据调节方式可以分为手动调节和自动调节。而手动调节有根据调节UI不同,有式有如下几种:

  • 1.在设置->显示中手动调节;
  • 2.在SystemUI中手动调节;
  • 3.在播放视频时上下滑动界面调节亮度.

本篇文章对手动调节亮度流程做一个总结。

1.设置-显示、SystemUI中调节亮度

Settings和SystemUI中的中亮度调节进度框都是来自于SystemUI中的BrightnessDialog,这里我们主要分析其设置亮度的功能,对于该进度框如何自定义实现不做分析。
当点击或者拖动进度框时,会回调SystemUI.BrightnessController中的onChange()方法,在这个方法中,会对根据是否自动亮度开启、是否VR模式等分别进行处理,每个分支中,首先会通过Binder调用PMS中的setTemporyScreenBrightnessSettingOverride(),改变临时亮度值,然后开启一个异步任务,将SettingsProvider中的对应值改变,该方法如下:

@Override
public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
        int value, boolean stopTracking) {
    updateIcon(mAutomatic);
    if (mExternalChange) return;

    if (mIsVrModeEnabled) {
         //VR模式相关亮度,略去
    } else if (!mAutomatic) {//未开启自动调节亮度时
        final int val = value + mMinimumBacklight;
        //设置背光
        setBrightness(val);
        if (!tracking ) {
            //将亮度值保存在SettingsProvider数据库中
            AsyncTask.execute(new Runnable() {
                    public void run() {
                        Settings.System.putIntForUser(mContext.getContentResolver(),
                                Settings.System.SCREEN_BRIGHTNESS, val,
                                UserHandle.USER_CURRENT);
                    }
                });
        }
    } else {//开启自动调节亮度时
        //计算得到自动背光亮度调整值,并设置
        final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
        setBrightnessAdj(adj);
        if (!tracking) {
            //保存在数据库中
            AsyncTask.execute(new Runnable() {
                public void run() {
                    Settings.System.putFloatForUser(mContext.getContentResolver(),
                            Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
                            UserHandle.USER_CURRENT);
                }
            });
        }
    }

继续看setBrightness():

    private void setBrightness(int brightness) {
        try {
            mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
        } catch (RemoteException ex) {
        }
    }

从以上方法中看出,最终,通过调用PowerManagerService的setTemporaryScreenBrightnessSettingOverride()方法,将亮度值传给PMS去进行处理。
进入到PMS中,该方法如下:

@Override // Binder call
public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
    //权限检查
    mContext.enforceCallingOrSelfPermission(
            android.Manifest.permission.DEVICE_POWER, null);

    final long ident = Binder.clearCallingIdentity();
    try {
        //调用Interal方法
        setTemporaryScreenBrightnessSettingOverrideInternal(brightness);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

接着分析:

private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) {
    synchronized (mLock) {
        //将亮度值设置给了mTemporaryScreenBrightnessSettingOverride变量
        if (mTemporaryScreenBrightnessSettingOverride != brightness) {
            mTemporaryScreenBrightnessSettingOverride = brightness;
            mDirty |= DIRTY_SETTINGS;
            updatePowerStateLocked();
        }
    }
}

经过一系列调用之后,将亮度值设置给了mTemporaryScreenBrightnessSettingOverride变量,然后开始调用updatePowerStateLocked()

在下一步分析前,我们先暂停此处,来看看播放视频时如何设置亮度的。

2.播放视频时设置亮度

在播放视频时,可以通过上下滑动界面来设置亮度,当退出播放界面时,又会恢复到原亮度,其调用接口正是PMS中的setScreenBrightnessOverrideFromWindowManager()方法,在Window模块中的RootWindowContainner.java中:

public void handleMessage(Message msg) {
        switch (msg.what) {
            case SET_SCREEN_BRIGHTNESS_OVERRIDE:
                //调用PMS相关接口
                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
                        msg.arg1);
                break;
            ......
        }
    }
}

在PMS中,将上面方法中设置的亮度值作如下设置:

private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
    synchronized (mLock) {
        //将亮度值设置给了mScreenBrightnessOverrideFromWindowManager变量
        if (mScreenBrightnessOverrideFromWindowManager != brightness) {
            mScreenBrightnessOverrideFromWindowManager = brightness;
            mDirty |= DIRTY_SETTINGS;
            updatePowerStateLocked();
        }
    }
}

可以看到,和Settings或SystemUI中调节亮度不同的时,通过播放视频设置的亮度值,最后是赋值给了mScreenBrightnessOverrideFromWindowManager,但这两种情况下,最终都调用了updatePowerStateLocked()方法,所以,此处将这两种情况合二为一进行分析。

共用流程

关于updatePowerStateLocked()方法,已经在PowerManagerService分析中进行了分析,它是PMS的核心方法,其中调用的updateDisplayPowerStateLocked()方法用于更新Display,背光调节也和这个方法有关系,这个方法在sdf也已经分析了,这里我们再来分析下此方法中仅和亮度调节相关的逻辑:

private boolean updateDisplayPowerStateLocked(int dirty) {
    final boolean oldDisplayReady = mDisplayReady;
    if (){
        // Determine appropriate screen brightness and auto-brightness adjustments.
        //是否由用户设置标记值,用来决定使用自动亮度还是手动设置亮度
        boolean brightnessSetByUser = true;
        //需要设置的亮度值,默认为config.xml中config_screenBrightnessSettingDefault的值
        int screenBrightness = mScreenBrightnessSettingDefault;
        //自动背光调节比例值
        float screenAutoBrightnessAdjustment = 0.0f;
        //根据Settings Provider中的值Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC判断是否开启了自动亮度调节
        //Settings中如果开启该开关,则将会设置如下值
        boolean autoBrightness = (mScreenBrightnessModeSetting ==
                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
        if (!mBootCompleted) {
            // Keep the brightness steady during boot. This requires the
            // bootloader brightness and the default brightness to be identical.
            autoBrightness = false;
            brightnessSetByUser = false;
        } else if (mIsVrModeEnabled) {//VR模式下
            screenBrightness = mScreenBrightnessForVrSetting;
            autoBrightness = false;
        //由setScreenBrightnessOverrideFromWindowManager()方法设置的亮度值
        } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
            screenBrightness = mScreenBrightnessOverrideFromWindowManager;
            autoBrightness = false;
            brightnessSetByUser = false;
        //由setTemporaryScreenBrightnessSettingOverride()方法设置的亮度值
        } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
            screenBrightness = mTemporaryScreenBrightnessSettingOverride;
        //Settings.System.SCREEN_BRIGHTNESS的值,即保存在数据库中的亮度值,亮度值设置完成后,都会进行保存
        } else if (isValidBrightness(mScreenBrightnessSetting)) {
            screenBrightness = mScreenBrightnessSetting;
        }
        //如果自动调节亮度开启,则只需要获得自动调节亮度比例值即可
        if (autoBrightness) {
            //将亮度值设置为默认亮度,即亮度的调节和手动设置的无关(开启自动调节亮度,手动调节时打印screenBrightness log可验证)
            screenBrightness = mScreenBrightnessSettingDefault;
            if (isValidAutoBrightnessAdjustment(
                    mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
                screenAutoBrightnessAdjustment =
                        mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
            } else if (isValidAutoBrightnessAdjustment(
                    mScreenAutoBrightnessAdjustmentSetting)) {
                screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
            }
        }
        // Update display power request.
        //封装到mDisplayPowerRequest中,去请求Display
        mDisplayPowerRequest.screenBrightness = screenBrightness;
        mDisplayPowerRequest.screenAutoBrightnessAdjustment =
                screenAutoBrightnessAdjustment;
        mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
        mDisplayPowerRequest.useAutoBrightness = autoBrightness;
        mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
   
        mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                mRequestWaitForNegativeProximity);
        mRequestWaitForNegativeProximity = false;
    }
    return mDisplayReady && !oldDisplayReady;
}

结合以上的分析,我们可以得出以下4个结论:

  • 1.通过Settings/SystemUI设置亮度值时,亮度值设置给了mTemporaryScreenBrightnessSettingOverride变量;
  • 2.播放视频界面设置亮度值时,设置给了mScreenBrightnessOverrideFromWindowManager变量;
  • 3.如果开启了自动调节亮度开关,虽然拖动亮度调节进度条可以活动,但是实际上跟手动设置的这两个变量值无关,而只和亮度调节比例值相关(至于其中的细节,在下面分析)。
  • 4.以上亮度设置值,优先级为:自动调节亮度 > 视频播放时设置亮度 > Settings、SystemUI中设置亮度(因为autoBrightness时将screenBrightness重置了)。

接下来的流程,在DisplayPowerController分析中分析过了,请求Display时,最终会到DisplayPowerController的updatePowerState()方法中,这里再看看此方法中亮度值相关的流程(有删减):

private void updatePowerState() {

    synchronized (mLock) {
    //表示要设置的亮度值,并初始化为默认值-1
    int brightness = PowerManager.BRIGHTNESS_DEFAULT;
    switch (mPowerRequest.policy) {
        case DisplayPowerRequest.POLICY_DOZE:
            if (!mAllowAutoBrightnessWhileDozingConfig) {
                //亮度值设置为mPowerRequest.dozeScreenBrightness
                brightness = mPowerRequest.dozeScreenBrightness;
            }
    }

    // 如果灭屏,设置为0
    if (state == Display.STATE_OFF) {
        brightness = PowerManager.BRIGHTNESS_OFF;
    }
    //如果开启了亮度增强,将亮度值设置为255
    if (mPowerRequest.boostScreenBrightness
            && brightness != PowerManager.BRIGHTNESS_OFF) {
        brightness = PowerManager.BRIGHTNESS_ON;
    }
    // Apply auto-brightness.
    //如果不满足以上条件,说明此时亮度值还未设置
    if (brightness < 0) {
    //自动调节亮度值是否可用
        if (autoBrightnessEnabled) {
                //如果可用,则从负责自动调节亮度的mAutomaticBrightnessController中获取亮度值
                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
        }
        if (brightness >= 0) {
            // 说明此时使用了自动亮度调节中的亮度值,对该值再次进行筛选
            brightness = clampScreenBrightness(brightness);
            //如果AUTOBrightness可用,且自动亮度调节比例值未发生变化,则说明是由LightSensor自动调节亮度,缓慢变化
            if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
                slowChange = true; // slowly adapt to auto-brightness
            }
            mAppliedAutoBrightness = true;
        } else {
            mAppliedAutoBrightness = false;
        }
    } else {
        mAppliedAutoBrightness = false;
    }
    // 如果当前亮度值还未设置且当前为Doze状态,则将亮度值设置为配置文件中配置的config_screenBrightnessDoze值
    if (brightness < 0 && (state == Display.STATE_DOZE
            || state == Display.STATE_DOZE_SUSPEND)) {
        brightness = mScreenBrightnessDozeConfig;
    }
    //如果到这里还未设置亮度值,则直接使用从PowerMangerService中传过来的、手动设置的值
    if (brightness < 0) {
        brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
    }
    //如果进入DIM状态,则亮度值为当前获取的亮度值和其他配置值限制
    if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
        if (brightness > mScreenBrightnessRangeMinimum) {
            brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
                    mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
        }
        if (!mAppliedDimming) {
            slowChange = false;
        }
        mAppliedDimming = true;
    } else if (mAppliedDimming) {
        slowChange = false;//如果是Dim状态而调整亮度,就不需要缓慢变化
        mAppliedDimming = false;
    }
    //如果当前处于低电量模式,需要亮度进行减半
    if (mPowerRequest.lowPowerMode) {
        if (brightness > mScreenBrightnessRangeMinimum) {
            final float brightnessFactor =
                    Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
            final int lowPowerBrightness = (int) (brightness * brightnessFactor);
            brightness = Math.max(lowPowerBrightness, mScreenBrightnessRangeMinimum);
        }
    } 
        boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
        if ((state == Display.STATE_ON //亮屏
                && mSkipRampState == RAMP_STATE_SKIP_NONE
                || state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig)
                && !wasOrWillBeInVr) {
            //设置亮度值,根据slowChange设置快速或慢速动画
            animateScreenBrightness(brightness,
                    slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
        } else {
            //直接设置亮度值,不需要亮度动画
            animateScreenBrightness(brightness, 0);
        }
    }
}

在以上方法中,我们可以看到,PowerManagerService中仅仅将手动调节亮度值进行了赋值,在DisplayPowerController中还需要进行多种决策,以确定最终的亮度值。这里我先用图的形式对以上方法中的决策亮度流程进行描述:
[Android Framework] 8.1 DisplayPowerController(三) 亮度调节结合图和代码,对最终亮度的决策如下:

  • 第1步.当要请求进入Doze状态时,如果配置了Doze下LightSensor不可用,则将亮度设置为dozeScreenBrightness,这个值从PMS中而来;
  • 第2步.当要灭屏时,直接将亮度设置为0;
  • 第3步.当设置了亮度增强时,直接将亮度值设置为255(最大值);
  • 第4步.如果不满足以上三步,且自动调节亮度开启,则获取自动调节的亮度;
  • 第5步.如果不满足以上四步,且当前为DOZE状态,则将亮度设置为mScreenBrightnessDozeConfig
  • 第6步.如果不满足以上五步,则使用手动设置的亮度值,即从PMS中得到的亮度值;
  • 第7步.如果要请求进入DIM状态时,则需要将当前得到的亮度值-10,并和mScreenBrightnessDimConfig比较取最小,和mScreenBrightnessRangeMinimum比较取最大。
  • 第8步.如果当前处于低电量模式,则需要将当前得到的亮度值* 低电量模式下亮度缩放比例,然后和mScreenBrightnessRangeMinimum取最大(一般缩放值为0.5,即减半);

经过以上8步后,才会得到最终的亮度值。

当亮度值确定了以后,接下来调用animateScreenBrightness()开始设置背光的亮度了,关于该方法在DisplayPOwerController分析中也已经分析过了,因此接下来的流程,就不再进行了。

结合整个亮度设置过程来看,手动调节亮度并不复杂。下一篇文章中,将会对自动调节亮度进行分析。