2015年4月11日 星期六

Android Brightness

Brightness有兩種模式, 一種是App根據使用者或Window Manager Service(WMS)的要求去設定, 另一種則是透過Ambient Light Sensor(ALS)測得環境的亮度算出適當的Brightness值, 前者稱為手動模式, 後者又稱為自動模式. 在自動模式下, WMS/APP提供的Brightness不會被採用, PMS會根據ALS讀出的值, 算出要設定的Brightness, 最後再經由Light HAL設定到硬體裡.



上圖顯示的是WMS與APP如何通知PMS新的Brightness值. PMS提供兩個API給WMS與APP使用. 之所有用兩個API是因為優先權的問題. 如果WMS與APP同時要求改變Brightness, WMS的要求被會採用. 對APP而言, 除了setTemporaryScreenBrightnessSettingOverride之外, 其實還有一個方法是透過SettingProvider. 為何要提供兩個途徑供APP使用呢? 原因是setTemporaryScreenBrightnessSettingOverride是希望提供APP一個暫時改變Brightness的方式(像是提供Slider暫時改變Brightness讓user知道效果), 最後的設定是將值寫入SettingProvider裡的screen_brightness裡. PMS有設定Setting Observer, 所以當screen_brightness改變時, 它會收到通知, 並將screen_brightness的值反應到硬體裡. 我個人看不大出為何要提供APP兩個方式去設定Brightness, 感覺似乎只要是使用SettingProvider就好, 不過或許透過這兩種方式Brightness反應的時間有所不同吧.

不管WMS或APP所要求的Brightness是什麼, 在自動模式底下, PMS會根據ALS的值算出適當的Brightness, 並忽略WMS/APP的要求. 這種做法是否比較好, 見人見智. 或許應該要考慮將自動模式改成以user的選擇為基準, 再根據ALS的值做調整.

Code Flow
PMS會將WMS/APP的要求, 用一個DisplayPowerRequest的結構描述, 並交由DisplayManagerService (DMS)的DisplayPowerController來處置. DisplayPowerController的updatePowerState就是主要處理的function. 我們可以將updatePowerState分成兩個部份來看, 一個是screen的state update, 另一個則是brightness update. 這兩個state的update是同時進行的, 並以Animation的形態進行, 這樣user才不會覺得畫面的改變太突兀. 在updatePowerState裡, 會決定display state與brightness值, 並啟動這兩個animation, user就會慢慢看到screen state與brightness改變.

Screen State Animation
Screen state有以下四種, 分別代表不同的意義
  • STATE_ON
  • STATE_OFF
  • STATE_DOZE
  • STATE_SOZE_SUSPEND
monitor的狀態不是ON就是OFF, 突然由ON->OFF或OFF->ON會讓user覺得不夠smooth, 因此, CodeFade是一個Software的方式, 藉由改變畫面讓user覺得monitor漸漸關掉或漸漸打開. 所謂的screen state animation其實是利用另一個View (ColorFade)蓋住其它的Window, 然後一直改變Fade Level (0.0 -> 1.0或1.0 -> 0.0), 最後將monitor的打開或關掉. 這種漸漸改變的方式很適合利用Android Animation架構. animateScreenStateChange()就是用來啟動這個Animation.

Brightness Animation
一般來講, Brightness的值是介於0~255之間, 如果一個一個Level改變, user會覺得畫面亮度的改變不會太突兀, 但是user可能從80直接調到200, 因此, 當一個新的brightness值要改變時, AOSP也是利用animation的方式慢慢改變. animateScreenBrightness會觸發brightness animation.

DisplayPowerController算出screen state與brightness後, 就會啟動這兩個animation. 這兩個animation的執行沒有dependency, 但由於都利用Animation的架構, 所以當一個Animation進行一個frame時, 另一個Animation也會在很接近的時間處理下一個frame. 但這兩個animation也是有需要才會使用, 比方說, 如果只是brightness改變, 只要使用brightness animation即可, 不需要啟動screen state animation. 但 是當monitor變成OFF時, brightness會被設成0, 因此在screen off時, 這兩個animation同時會啟動.


Settings
Brightness有一些default值的設定, OEM可以利用這些設定預設的brightness值

config_screenBrightnessSettingMinimum
config_screenBrightnessDoze
config_screenBrightnessDim
config_screenBrightnessDark
config_animateScreenLights


APP可以將brightness的值或相關的設定寫入SettingProvider的database裡, 這個database位於
/data/data/com.android.providers.settings/databases/settings.db裡, 下面這3個跟brightness有關
  • screen_brightness - APP所設定的brightness值
  • screen_off_timeout - Monitor自動關掉的時間, 單位是milliseconds
  • screen_brightness_mode - 自動模式或手動模式
在Debug時, 我們可以利用adb讀取這些值, 下面可以讀取APP所設定的brightness值
adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "select value from system where name='screen_brightness';"

下面則可以寫入monitor timeout時間
adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "update system set value='600000' where name='screen_off_timeout';"

有時候Debug時, 我們也可以用下面的command來調整brightness的值, 而不用真的去操作系統.
    adb shell input keyevent KEYCODE_BRIGHTNESS_DOWN
    adb shell input keyevent KEYCODE_BRIGHTNESS_UP

要注意一點, 當我們使用上面兩個command時, SystemUI會將brightness模式改成手動模式.

FYI. 可以用下面的command打開monitor, 並將系統lock或unlock
    adb shell input keyevent 26 --> power key
    adb shell input keyevent 82 --> unlock
    adb shell input keyevent 82 --> lock

沒有留言:

張貼留言