Android 如何實(shí)現(xiàn)亮度自動(dòng)調(diào)節(jié)
下拉狀態(tài)欄有個(gè)亮度的進(jìn)度條,如果開啟了亮度自動(dòng)調(diào)節(jié)開關(guān),會(huì)隨著周圍光線變化,這個(gè)進(jìn)度條也會(huì)隨著變化,接下來就是看看這個(gè)功能是如何實(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,亮度自動(dòng)調(diào)節(jié)主要是 DisplayPowerController 和 AutomaticBrightnessController 兩個(gè)類,當(dāng)亮度發(fā)生變化時(shí),如果關(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 注冊(cè)呢?
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 注冊(cè) 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)亮度有變化時(shí),會(huì)走 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); } }
接下來就是看看亮度自動(dòng)調(diào)節(jié)主要的兩個(gè)類 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; //省略部分代碼 }
由于亮屏之后屏幕自動(dòng)亮度才會(huì)生效,所以在亮屏的時(shí)候,流程會(huì)走到 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
這個(gè)方法調(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)亮度自動(dòng)調(diào)節(jié)的詳細(xì)內(nèi)容,更多關(guān)于Android 亮度自動(dòng)調(diào)節(jié)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android開發(fā)實(shí)現(xiàn)調(diào)節(jié)屏幕亮度功能
- Android視頻播放器屏幕左側(cè)邊隨手指上下滑動(dòng)亮度調(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)值為自動(dòng)調(diào)節(jié)
- 使用android隱藏api實(shí)現(xiàn)亮度調(diào)節(jié)的方法
- android 屏幕亮度調(diào)節(jié)方法詳解
相關(guān)文章
Android ViewPager實(shí)現(xiàn)圖片輪翻效果
這篇文章主要為大家詳細(xì)介紹了Android ViewPager實(shí)現(xiàn)圖片輪翻效果的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01Android利用代碼控制設(shè)備上其他音樂播放器的方法
這篇文章主要給大家介紹了關(guān)于Android利用代碼如何控制設(shè)備上其他音樂播放器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06Kotlin遍歷集合導(dǎo)致并發(fā)修改異常的原因和解決方法
這篇文章主要介紹了Kotlin遍歷集合導(dǎo)致并發(fā)修改異常的原因和解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Android游戲開發(fā)之碰撞檢測(cè)(矩形碰撞、圓形碰撞、像素碰撞)
這篇文章主要介紹了Android游戲開發(fā)之碰撞檢測(cè),主要內(nèi)容包含矩形碰撞、圓形碰撞、像素碰撞、多矩形碰撞的代碼,感興趣的小伙伴們可以參考一下2016-07-07android onTouchEvent處理機(jī)制總結(jié)(必看)
下面小編就為大家?guī)硪黄猘ndroid onTouchEvent處理機(jī)制總結(jié)(必看)小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Android 實(shí)現(xiàn)定時(shí)器的四種方式總結(jié)及實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Android 實(shí)現(xiàn)定時(shí)器的四種方式總結(jié)及實(shí)現(xiàn)實(shí)例的相關(guān)資料,這里對(duì)定時(shí)器進(jìn)行詳解,并附實(shí)例代碼,需要的朋友可以參考下2016-12-12Android?nonTransitiveRClass資源沖突問題淺析
這篇文章主要介紹了Android?nonTransitiveRClass資源沖突問題,別搞錯(cuò)了,nonTransitiveRClass不能解決資源沖突,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-12-12Android入門教程之RecyclerView的具體使用詳解
RecyclerView是Android一個(gè)更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實(shí)現(xiàn)數(shù)據(jù)縱向滾動(dòng),也可以實(shí)現(xiàn)橫向滾動(dòng)(ListView做不到橫向滾動(dòng))。接下來講解RecyclerView的用法2021-10-10Android編程實(shí)現(xiàn)XML解析與保存的三種方法詳解
這篇文章主要介紹了Android編程實(shí)現(xiàn)XML解析與保存的三種方法,結(jié)合實(shí)例形式詳細(xì)分析了Android實(shí)現(xiàn)xml解析的SAX、DOM、PULL三種方法的相關(guān)操作技巧,需要的朋友可以參考下2017-08-08