Android 如何實(shí)現(xiàn)亮度自動調(diào)節(jié)
下拉狀態(tài)欄有個亮度的進(jìn)度條,如果開啟了亮度自動調(diào)節(jié)開關(guān),會隨著周圍光線變化,這個進(jìn)度條也會隨著變化,接下來就是看看這個功能是如何實(shí)現(xiàn)的。
源碼版本
基于 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,
概述
狀態(tài)欄里亮度頁面是 BrightnessDialog,其中進(jìn)度條設(shè)置是 ToggleSliderView,亮度自動調(diào)節(jié)主要是 DisplayPowerController 和 AutomaticBrightnessController 兩個類,當(dāng)亮度發(fā)生變化時,如果關(guān)聯(lián)到 ToggleSliderView,用的是 ContentObserver,Uri 為 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ。
源碼梳理
1、BrightnessDialog#onCreate:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//省略部分代碼
mBrightnessController = new BrightnessController(this, icon, slider);
}
2、這里進(jìn)行了 BrightnessController 初始化,來看下:
public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
//省略部分代碼
mBrightnessObserver = new BrightnessObserver(mHandler);
//省略部分代碼
}
又進(jìn)行了 BrightnessObserver 初始化:
/** 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);
}
}
其實(shí)我目前下載的源碼,這塊功能是不全的,我已經(jīng)加上了,哪里進(jìn)行 BrightnessObserver 的 ContentObserver 注冊呢?
3、回到 BrightnessDialog#onStart:
@Override
protected void onStart() {
super.onStart();
mBrightnessController.registerCallbacks();
MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
}
4、調(diào)用mBrightnessController.registerCallbacks();最終走到 mStartListeningRunnable:
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);
}
};
當(dāng)亮度有變化時,會走 BrightnessObserver#onChange,最終走到:
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方法,到 :
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:
@Override
public void setValue(int value) {
//這里正是修改進(jìn)度條
mSlider.setProgress(value);
if (mMirror != null) {
mMirror.setValue(value);
}
}
接下來就是看看亮度自動調(diào)節(jié)主要的兩個類 DisplayPowerController 和 AutomaticBrightnessController。DisplayPowerController 屬于 Display 模塊,其控制設(shè)備屏幕亮滅、背光、與Power關(guān)系密切,這里主要看下屏幕亮度的控制這方面的邏輯。
6、首先,在 DisplayManagerService 中初始化 DisplayPowerController,如下:
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 構(gòu)造方法,如下:
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 中的核心函數(shù) updatePowerState():
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():
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);
}
繼續(xù)看下 clampAutoBrightnessAdjustment:
private static float clampAutoBrightnessAdjustment(float value) {
return MathUtils.constrain(value, -1.0f, 1.0f);
}
這里注意下 MathUtils.constrain() 表示百分比縮放函數(shù),比如 MathUtils.constrain(0.5, 0, 255) 表示 (255-0)*0.5。
這樣了解了 autoBrightnessAdjustment,接下來看 newAutoBrightnessAdjustment。
8、回到 DisplayPowerController#updatePowerState(),
看到 newAutoBrightnessAdjustment 調(diào)用了 AutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment(),最終是到了 BrightnessMapper#getAutoBrightnessAdjustment() 其中 mAutoBrightnessAdjustment 變量,賦值是在 BrightnessMapper#setAutoBrightnessAdjustment:
@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
這個方法調(diào)用又回到了 AutomaticBrightnessController#setAutoBrightnessAdjustment:
private boolean setAutoBrightnessAdjustment(float adjustment) {
return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
}
AutomaticBrightnessController#setAutoBrightnessAdjustment調(diào)用是來到 AutomaticBrightnessController#configure()方法:
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()調(diào)用來到了 DisplayPowerController #updatePowerState()。
這樣也知道了 newAutoBrightnessAdjustment,繼續(xù) putAutoBrightnessAdjustmentSetting:
private void putAutoBrightnessAdjustmentSetting(float adjustment) {
mAutoBrightnessAdjustment = adjustment;
Settings.System.putFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, UserHandle.USER_CURRENT);
}
就調(diào)到第 4 步 BrightnessObserver#onChange,進(jìn)度條隨之變化,Over!
以上就是Android 如何實(shí)現(xiàn)亮度自動調(diào)節(jié)的詳細(xì)內(nèi)容,更多關(guān)于Android 亮度自動調(diào)節(jié)的資料請關(guān)注腳本之家其它相關(guān)文章!
- Android開發(fā)實(shí)現(xiàn)調(diào)節(jié)屏幕亮度功能
- Android視頻播放器屏幕左側(cè)邊隨手指上下滑動亮度調(diào)節(jié)功能的原理實(shí)現(xiàn)
- Android亮度調(diào)節(jié)的幾種實(shí)現(xiàn)方法
- Android編程調(diào)節(jié)屏幕亮度(背景燈)及保持背景燈常亮的方法
- Android調(diào)節(jié)屏幕亮度實(shí)現(xiàn)代碼
- android 如何設(shè)置開機(jī)后屏幕亮度默認(rèn)值為自動調(diào)節(jié)
- 使用android隱藏api實(shí)現(xiàn)亮度調(diào)節(jié)的方法
- android 屏幕亮度調(diào)節(jié)方法詳解
相關(guān)文章
Android編程實(shí)現(xiàn)簡單的UDP Client實(shí)例
這篇文章主要介紹了Android編程實(shí)現(xiàn)簡單的UDP Client,結(jié)合實(shí)例形式分析了Android實(shí)現(xiàn)UDP Clinet客戶端的實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-04-04
Android實(shí)現(xiàn)APP歡迎頁面簡單制作思路
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)APP歡迎頁面簡單制作思路,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-08-08
Android?studio實(shí)現(xiàn)簡單計算器的編寫
這篇文章主要為大家詳細(xì)介紹了Android?studio實(shí)現(xiàn)簡單計算器的編寫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05
android okhttp的基礎(chǔ)使用【入門推薦】
本文主要總結(jié)了Android著名網(wǎng)絡(luò)框架-okhttp的基礎(chǔ)使用。具有一定的參考價值,下面跟著小編一起來看下吧2017-01-01
Android Studio配置國內(nèi)鏡像源(利用hosts)
這篇文章主要介紹了Android Studio配置國內(nèi)鏡像源(利用hosts),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
淺談onTouch先執(zhí)行,還是onClick執(zhí)行(詳解)
onTouch先執(zhí)行,還是onClick執(zhí)行?下面小編就為大家?guī)硪黄獪\談onTouch先執(zhí)行,還是onClick執(zhí)行(詳解)。希望對大家有所幫助。一起跟隨小編過來看看吧2017-03-03

