前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 亮度自动调节

Android 亮度自动调节

作者头像
吴小龙同學
发布2019-12-11 15:53:47
2.4K0
发布2019-12-11 15:53:47
举报
文章被收录于专栏:吴小龙同學吴小龙同學

下拉状态栏有个亮度的进度条,如果开启了亮度自动调节开关,会随着周围光线变化,这个进度条也会随着变化,接下来就是看看这个功能是如何实现的。

源码版本

基于 Android 9.0 分析。

BrightnessDialog,位于: frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java ToggleSliderView,位于: frameworks/base/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java

DisplayPowerController,位于: frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

AutomaticBrightnessController,位于: frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java

BrightnessMappingStrategy,

概述

状态栏里亮度页面是 BrightnessDialog,其中进度条设置是 ToggleSliderView,亮度自动调节主要是 DisplayPowerController 和 AutomaticBrightnessController 两个类,当亮度发生变化时,如果关联到 ToggleSliderView,用的是 ContentObserver,Uri 为 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ。

源码梳理

1、BrightnessDialog#onCreate:

代码语言:javascript
复制
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //省略部分代码
    mBrightnessController = new BrightnessController(this, icon, slider);
}

2、这里进行了 BrightnessController 初始化,来看下:

代码语言:javascript
复制
public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
    //省略部分代码
    mBrightnessObserver = new BrightnessObserver(mHandler);
    //省略部分代码
}

又进行了 BrightnessObserver 初始化:

代码语言:javascript
复制
/** ContentObserver to watch brightness **/
private class BrightnessObserver extends ContentObserver {
    //省略部分代码
    private final Uri BRIGHTNESS_FOR_VR_URI =
            Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR);
    //Add By WuXiaolong for AutomaticBrightness
    private final Uri BRIGHTNESS_ADJ_URI =
            Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
    public BrightnessObserver(Handler handler) {
        super(handler);
    }
    @Override
    public void onChange(boolean selfChange) {
        onChange(selfChange, null);
    }
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        if (selfChange) return;
        if (BRIGHTNESS_MODE_URI.equals(uri)) {
            mBackgroundHandler.post(mUpdateModeRunnable);
            mBackgroundHandler.post(mUpdateSliderRunnable);
        } 
        //省略部分代码
        //Add By WuXiaolong for AutomaticBrightness
        else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
            mBackgroundHandler.post(mUpdateSliderRunnable);
        } else {
            mBackgroundHandler.post(mUpdateModeRunnable);
            mBackgroundHandler.post(mUpdateSliderRunnable);
        }
        for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
            cb.onBrightnessLevelChanged();
        }
    }
    public void startObserving() {
        final ContentResolver cr = mContext.getContentResolver();
        cr.unregisterContentObserver(this);
        //省略部分代码
        cr.registerContentObserver(
                BRIGHTNESS_FOR_VR_URI,
                false, this, UserHandle.USER_ALL);
        //Add By WuXiaolong for AutomaticBrightness
        cr.registerContentObserver(
                BRIGHTNESS_ADJ_URI,
                false, this, UserHandle.USER_ALL);
    }
    public void stopObserving() {
        final ContentResolver cr = mContext.getContentResolver();
        cr.unregisterContentObserver(this);
    }
}

其实我目前下载的源码,这块功能是不全的,我已经加上了,哪里进行 BrightnessObserver 的 ContentObserver 注册呢?

3、回到 BrightnessDialog#onStart:

代码语言:javascript
复制
@Override
protected void onStart() {
    super.onStart();
    mBrightnessController.registerCallbacks();
    MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
}

4、调用mBrightnessController.registerCallbacks();最终走到 mStartListeningRunnable:

代码语言:javascript
复制
private final Runnable mStartListeningRunnable = new Runnable() {
    @Override
    public void run() {
        //BrightnessObserver 注册
        mBrightnessObserver.startObserving();
        mUserTracker.startTracking();
        // Update the slider and mode before attaching the listener so we don't
        // receive the onChanged notifications for the initial values.
        mUpdateModeRunnable.run();
        mUpdateSliderRunnable.run();
        mHandler.sendEmptyMessage(MSG_ATTACH_LISTENER);
    }
};

当亮度有变化时,会走 BrightnessObserver#onChange,最终走到:

代码语言:javascript
复制
private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        mExternalChange = true;
        try {
            switch (msg.what) {
                //省略部分代码
                case MSG_UPDATE_SLIDER:
                    updateSlider(msg.arg1, msg.arg2 != 0);
                    break;
                //省略部分代码
                default:
                    super.handleMessage(msg);
            }
        } finally {
            mExternalChange = false;
        }
    }
};

走 updateSlider方法,到 :

代码语言:javascript
复制
private void animateSliderTo(int target) {
    if (!mControlValueInitialized) {
        // Don't animate the first value since it's default state isn't mea
        mControl.setValue(target);
        mControlValueInitialized = true;
    }
    //省略部分代码
}

5、跳到 ToggleSliderView#setValue:

代码语言:javascript
复制
@Override
public void setValue(int value) {
    //这里正是修改进度条
    mSlider.setProgress(value);
    if (mMirror != null) {
        mMirror.setValue(value);
    }
}

接下来就是看看亮度自动调节主要的两个类 DisplayPowerController 和 AutomaticBrightnessController。DisplayPowerController 属于 Display 模块,其控制设备屏幕亮灭、背光、与Power关系密切,这里主要看下屏幕亮度的控制这方面的逻辑。

6、首先,在 DisplayManagerService 中初始化 DisplayPowerController,如下:

代码语言:javascript
复制
private final class LocalService extends DisplayManagerInternal {
    @Override
    public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
            SensorManager sensorManager) {
        synchronized (mSyncRoot) {
            //省略部分代码
            mDisplayPowerController = new DisplayPowerController(
                    mContext, callbacks, handler, sensorManager, blanker);
        }
        mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
    }

7、接着看下 DisplayPowerController 构造方法,如下:

代码语言:javascript
复制
public DisplayPowerController(Context context,
        DisplayPowerCallbacks callbacks, Handler handler,
        SensorManager sensorManager, DisplayBlanker blanker) {
    //省略部分代码
    mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
            com.android.internal.R.bool.config_automatic_brightness_available);
    //省略部分代码
    if (mUseSoftwareAutoBrightnessConfig) {
        //省略部分代码
        mBrightnessMapper = BrightnessMappingStrategy.create(resources);
        if (mBrightnessMapper != null) {
            mAutomaticBrightnessController = new AutomaticBrightnessController(this,
                    handler.getLooper(), sensorManager, mBrightnessMapper,
                    lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
                    mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                    initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
                    autoBrightnessResetAmbientLuxAfterWarmUp, hysteresisLevels);
        } else {
            mUseSoftwareAutoBrightnessConfig = false;
        }
    }
    //省略部分代码
    mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
    mTemporaryAutoBrightnessAdjustment = Float.NaN;
    //省略部分代码
}

由于亮屏之后屏幕自动亮度才会生效,所以在亮屏的时候,流程会走到 DisplayPowerController 中的核心函数 updatePowerState():

代码语言:javascript
复制
private void updatePowerState() {
    // Update the power state request.
    //省略部分代码
    
    final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
    if (autoBrightnessAdjustmentChanged) {
        mTemporaryAutoBrightnessAdjustment = Float.NaN;
    }
    // Use the autobrightness adjustment override if set.
    final float autoBrightnessAdjustment;
    if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) {
        autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment;
        mAppliedTemporaryAutoBrightnessAdjustment = true;
    } else {
        autoBrightnessAdjustment = mAutoBrightnessAdjustment;
        mAppliedTemporaryAutoBrightnessAdjustment = false;
    }
    
    boolean hadUserBrightnessPoint = false;
    // Configure auto-brightness.
    if (mAutomaticBrightnessController != null) {
        hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
        mAutomaticBrightnessController.configure(autoBrightnessEnabled,
                mBrightnessConfiguration,
                mLastUserSetScreenBrightness / (float) PowerManager.BRIGHTNESS_ON,
                userSetBrightnessChanged, autoBrightnessAdjustment,
                autoBrightnessAdjustmentChanged, mPowerRequest.policy);
    }
    
    // Apply auto-brightness.
    boolean slowChange = false;
    if (brightness < 0) {
        float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
        if (autoBrightnessEnabled) {
            brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
            newAutoBrightnessAdjustment =
                    mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
        }
        if (brightness >= 0) {
            // Use current auto-brightness value and slowly adjust to changes.
            brightness = clampScreenBrightness(brightness);
            if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
                slowChange = true; // slowly adapt to auto-brightness
            }
            // Tell the rest of the system about the new brightness. Note that we do this
            // before applying the low power or dim transformations so that the slider
            // accurately represents the full possible range, even if they range changes what
            // it means in absolute terms.
            putScreenBrightnessSetting(brightness);
            mAppliedAutoBrightness = true;
        } else {
            mAppliedAutoBrightness = false;
        }
        if (autoBrightnessAdjustment != newAutoBrightnessAdjustment) {
            // If the autobrightness controller has decided to change the adjustment value
            // used, make sure that's reflected in settings.
            putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment);
        }
    } else {
        mAppliedAutoBrightness = false;
    }
    //省略部分代码
}

接下来分别看看 autoBrightnessAdjustment 和 newAutoBrightnessAdjustment 怎么来的?

autoBrightnessAdjustment 是来自 mTemporaryAutoBrightnessAdjustment 或 mAutoBrightnessAdjustment 赋值,mAutoBrightnessAdjustment 在第 7 步mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();有初始化,看下 getAutoBrightnessAdjustmentSetting():

代码语言:javascript
复制
private float getAutoBrightnessAdjustmentSetting() {
    final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(),
            Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT);
    return Float.isNaN(adj) ? 0.0f : clampAutoBrightnessAdjustment(adj);
}

继续看下 clampAutoBrightnessAdjustment:

代码语言:javascript
复制
private static float clampAutoBrightnessAdjustment(float value) {
    return MathUtils.constrain(value, -1.0f, 1.0f);
}

这里注意下 MathUtils.constrain() 表示百分比缩放函数,比如 MathUtils.constrain(0.5, 0, 255) 表示 (255-0)*0.5。

这样了解了 autoBrightnessAdjustment,接下来看 newAutoBrightnessAdjustment。

8、回到 DisplayPowerController#updatePowerState(),看到 newAutoBrightnessAdjustment 调用了 AutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment(),最终是到了 BrightnessMapper#getAutoBrightnessAdjustment() 其中 mAutoBrightnessAdjustment 变量,赋值是在 BrightnessMapper#setAutoBrightnessAdjustment

代码语言:javascript
复制
@Override
public boolean setAutoBrightnessAdjustment(float adjustment) {
    adjustment = MathUtils.constrain(adjustment, -1, 1);
    if (adjustment == mAutoBrightnessAdjustment) {
        return false;
    }
    if (DEBUG) {
        Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
                adjustment);
        PLOG.start("auto-brightness adjustment");
    }
    mAutoBrightnessAdjustment = adjustment;
    computeSpline();
    return true;
}

9、BrightnessMapper#setAutoBrightnessAdjustment 这个方法调用又回到了 AutomaticBrightnessController#setAutoBrightnessAdjustment:

代码语言:javascript
复制
private boolean setAutoBrightnessAdjustment(float adjustment) {
    return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
}

AutomaticBrightnessController#setAutoBrightnessAdjustment调用是来到 AutomaticBrightnessController#configure()方法:

代码语言:javascript
复制
public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
        float brightness, boolean userChangedBrightness, float adjustment,
        boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
    // While dozing, the application processor may be suspended which will prevent us from
    // receiving new information from the light sensor. On some devices, we may be able to
    // switch to a wake-up light sensor instead but for now we will simply disable the sensor
    // and hold onto the last computed screen auto brightness.  We save the dozing flag for
    // debugging purposes.
    boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
    boolean changed = setBrightnessConfiguration(configuration);
    changed |= setDisplayPolicy(displayPolicy);
    if (userChangedAutoBrightnessAdjustment) {
        changed |= setAutoBrightnessAdjustment(adjustment);
    }
    if (userChangedBrightness && enable) {
        // Update the brightness curve with the new user control point. It's critical this
        // happens after we update the autobrightness adjustment since it may reset it.
        changed |= setScreenBrightnessByUser(brightness);
    }
    final boolean userInitiatedChange =
            userChangedBrightness || userChangedAutoBrightnessAdjustment;
    if (userInitiatedChange && enable && !dozing) {
        prepareBrightnessAdjustmentSample();
    }
    changed |= setLightSensorEnabled(enable && !dozing);
    if (changed) {
        updateAutoBrightness(false /*sendUpdate*/);
    }
}

AutomaticBrightnessController#configure()调用来到了 DisplayPowerController #updatePowerState()

这样也知道了 newAutoBrightnessAdjustment,继续 putAutoBrightnessAdjustmentSetting:

代码语言:javascript
复制
private void putAutoBrightnessAdjustmentSetting(float adjustment) {
    mAutoBrightnessAdjustment = adjustment;
    Settings.System.putFloatForUser(mContext.getContentResolver(),
            Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, UserHandle.USER_CURRENT);
}

就调到第 4 步 BrightnessObserver#onChange,进度条随之变化,Over!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 源码版本
  • 概述
  • 源码梳理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档