Android 9.0 自动背光机制分析

在android 9.0中,相比android 8.1而言,背光部分逻辑有较大的调整,这里就对android P背光机制进行完整的分析。

1.手动调节亮度

1.1.在SystemUI、Settings中手动调节

在界面(SystemUI)和Settings中拖动进度条调节亮度时,调节入口在BrightnessController中:

@Override
public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
        int value, boolean stopTracking) {
   
    final String setting;

    if (mIsVrModeEnabled) {
   
        setting = Settings.System.SCREEN_BRIGHTNESS_FOR_VR;
    } else {
   
        setting = Settings.System.SCREEN_BRIGHTNESS;
    }
    //获取亮度值
    final int val = convertGammaToLinear(value, min, max);
    //设置亮度值
    setBrightness(val);
    if (!tracking) {
   
    //在异步任务中将新的亮度值保存在SettingsProvider中
        AsyncTask.execute(new Runnable() {
   
                public void run() {
   
                    Settings.System.putIntForUser(mContext.getContentResolver(),
                            setting, val, UserHandle.USER_CURRENT);
                }
            });
    }
}

在BrightnessController中,首先根据亮度条的拖动,计算出新的亮度值,然后将调用本类中的setBrightneess()设置亮度,设置完成后,通过异步任务将新的亮度值保存在SettingsProvider中,我们看下一个方法:

private void setBrightness(int brightness) {
   
    mDisplayManager.setTemporaryBrightness(brightness);
}

在以上方法中,调用了DisplayManager对象的方法开始设置亮度,这和android8.1的一个不同点,在android 8.1中,设置亮度是由PMS开始,而在9.0中,直接从DisplayManagerService开始了。
当调用mDisplayManager的setTemporaryBrightness()后,经过一系列调用,最终进入了DisplayPowerController·中,这些调用过程代码如下:


//frameworks/base/core/java/android/hardware/display/DisplayManager.java
public void setTemporaryBrightness(int brightness) {
   
    mGlobal.setTemporaryBrightness(brightness);
}
//frameworks/base/core/java/android/hardware/display/DisplayManagerGlobal.java
public void setTemporaryBrightness(int brightness) {
   
    try {
   
        mDm.setTemporaryBrightness(brightness);
    } catch (RemoteException ex) {
   
        throw ex.rethrowFromSystemServer();
    }
}

//frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
@Override // Binder call
public void setTemporaryBrightness(int brightness) {
   
    mContext.enforceCallingOrSelfPermission(
            Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
            "Permission required to set the display's brightness");
    final long token = Binder.clearCallingIdentity();
    try {
   
        synchronized (mSyncRoot) {
   
            mDisplayPowerController.setTemporaryBrightness(brightness);
        }
    } finally {
   
        Binder.restoreCallingIdentity(token);
    }
}

我们直接进入DisplayPowerController中的setTemporaryBrightness()方法:

public void setTemporaryBrightness(int brightness) {
   
    Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS,
            brightness, 0 /*unused*/);
    msg.sendToTarget();
}

在这个方法中,通过Handler发送一个消息进行处理,这样做的目的是,将最终的亮度调节放在PowerManagerService线程中进行,因为这个Handler对象正是来自于PMS中。
继续下一步流程,来看看Handler中如何处理:

@Override
    public void handleMessage(Message msg) {
   
        switch (msg.what) {
   
            case MSG_SET_TEMPORARY_BRIGHTNESS:
                // TODO: Should we have a a timeout for the temporary brightness?
                //将brightness赋值给了mTemporaryScreenBrightness 
                mTemporaryScreenBrightness = msg.arg1;
                updatePowerState();
                break;
        }
    }
}

在handleMessage()中,将亮度值赋给了全局变量mTemporaryScreenBrightness ,然后开始调用updatePowerState()方法。
关于updatePowerState()方法,不做全部分析,这里只看亮度调节相关逻辑:

private void updatePowerState() {
   
// ......
    //手动设置亮度是否改变
    final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
    if (userSetBrightnessChanged) {
   
        mTemporaryScreenBrightness = -1;
    }
    // Use the temporary screen brightness if there isn't an override, either from
    // WindowManager or based on the display state.
    if (mTemporaryScreenBrightness > 0) {
   
    //使用手动设置的亮度
        brightness = mTemporaryScreenBrightness;
        mAppliedTemporaryBrightness = true;
    } else {
   
        mAppliedTemporaryBrightness = false;
    }
    //........
    if (!mPendingScreenOff) {
   
        final boolean isDisplayContentVisible = mColorFadeEnabled ?
                (mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f) :
                (state == Display.STATE_ON && mSkipRampState == RAMP_STATE_SKIP_NONE);
        if (initialRampSkip || hasBrightnessBuckets
                || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
   
            animateScreenBrightness(brightness, 0);
        } else {
   
            animateScreenBrightness(brightness,
                    slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
        }
    //......
}

updatePowerState()方法中,如果此时mTemporaryScreenBrightness大于0,则设备将使用它作为最终的亮度,而它大于0取决与updateUserSetScreenBrightness()方法的返回值,该方法如下:

private boolean updateUserSetScreenBrightness() {
   
    if (mPendingScreenBrightnessSetting < 0) {
   
        return false;
    }
    //add for bug BEG
    if (mPendingScreenBrightnessSetting > 0 && (mCurrentScreenBrightnessSetting == mTemporaryScreenBrightness)){
   
        return true;
    }
    //add for bug END
    if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) {
   
        mPendingScreenBrightnessSetting = -1;
        return false;
    }
    mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting;
    mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting;
    mPendingScreenBrightnessSetting = -1;
    return true;
}

这个方法中,实际是根据mPendingScreenBrightnessSetting的值做不同的处理。总结来说,如果mPendingScreenBrightnessSetting大于0,则返回true,并将当前亮度设置为它的值,否则返回false,再进一步概括,就是如果mPendingScreenBrightnessSettingmTemporaryScreenBrightness的值都大于0,那么系统将使用mTemporaryScreenBrightness的值作为亮度值。

mPendingScreenBrightnessSetting则是通过SettingsObserver监测Settings数据库中的值,它获取如下:

private void handleSettingsChange(boolean userSwitch) {
   
    mPendingScreenBrightnessSetting = getScreenBrightnessSetting();
    sendUpdatePowerState();
}


private int getScreenBrightnessSetting() {
   
    final int brightness = Settings.System.getIntForUser(mContext.getContentResolver(),
            Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessDefault,
            UserHandle.USER_CURRENT);
    return clampAbsoluteBrightness(brightness);
}

而对SettingsProvider中的亮度值的保存正是在BrightnessController中setBrightness()之后。

因此,对于手动背光调节,首先调用setBrightnessVal()进入DPC后,将调节亮度设置给全局变量mTemporaryScreenBrightness,然后等待SettingsProvider中保存的亮度值发生改变,当改变完成后,mPendingScreenBrightnessSetting将从SettingsProvider中读取到新的值,然后将使用mTemporaryScreenBrightness作为系统亮度值,并将mTemporaryScreenBrightness重置为-1.

之后的流程和8.1相比差别不大,最终会调用animateScreenBrightness()方法去设置亮度。
通过以上的分析可以发现,将用户调节亮度值表示为"Temporary"也是有原因的,因为在设置完成后,他将又变为-1。

手动调节亮度的时序图如下图所示:
在这里插入图片描述

1.2.在视频播放界面手动调节

这块流程还是保留在PMS中,和android 8.1保持一致,因此就不再进行分析。

2.自适应背光调节

android P背光设置流程中最大的差异,是自动背光调节流程。在Google IO上提出,Android P的新特性之一就是自适应背光。Google和DeepMind合作,利用机器学习,创建了自适应背光,通过了解用户在环境中设定亮度滑块的方式,学习你的习惯,从而自动完成亮度调节。下面我们就来看看,androidP中新的自适应背光。
首先我们看自适应背光的架构,了解一些类的功能后,再分析其流程。

2.1.类架构

自动背光相关类结构如下:

其中AutomaticBrightnessController中的功能进一步紧收,只进行环境光强的监听后的一些处理,将背光曲线的创建等工作,交给了BrightnessMappingStrategy,它将负责曲线的创建,自动背光值的计算等,当获取自动背光值时,AutomaticBrightnessController将调用BrightnessMappingStrategy的接口获取。

BrightnessMappingStrategy在创建曲线时,则需要从BrightnessConfigure类中读取两个数组源:config_autoBrightnessLevelsconfig_autoBrightnessDisplayValuesNits

现在我们进入流程的分析。

2.2.创建背光样条曲线

在9.0中,自动背光曲线的创建放在了BrightnessMappingStrategy中,当系统启动后,进入DisplayPowerController构造方法后,就会开始创建背光曲线。

public DisplayPowerController(Context context,
        DisplayPowerCallbacks callbacks, Handler handler,SensorManager sensorManager, DisplayBlanker blanker) {
   
        //获取映射Lux-Nits-Backlight值的对象
      mBrightnessMapper = BrightnessMappingStrategy.create(resources);
}

我们从BrightnessMappingStrategy.create(resources)进入,来查看曲线的绘制,create()方法如下,相关代码已进行注释:

@Nullable
public static BrightnessMappingStrategy create(Resources resources) {
   
    //Lux值的数组,getLuxLevels()中会将Lux[0] = 0.
    float[] luxLevels = getLuxLevels(resources.getIntAr
  • 13
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值