koreader / android-luajit-launcher

Android NativeActivity based launcher for LuaJIT, implementing the main loop within Lua land via FFI
MIT License
131 stars 84 forks source link

Brightness and Warmth support for Xiaomi Duokan Pro II #477

Closed cheehongw closed 3 months ago

cheehongw commented 5 months ago

Brightness/warmth controls currently don't work at all for this e-reader.

Commercial Product Name: Xiaomi Duokan Pro II / Xiaomi Ereader Pro II Model: miduokanreaderproii Product: moaan Device: rk3566_eink Hardware: rk30board Platform: rk356x Android Version: 11

I have tried my hands at making a driver for it, but have encountered a roadblock, so this is me sharing my findings.

The brightness/warmth can be controlled through the adb shell, but it appears that these values are located under Settings.Global, which means only system apps can set these values. If anyone has any tricks to set Settings.Global, please let me know!

rk3566_eink:/ $ settings list global | grep mogu                                                                                                                                                           
mogu_audio_status=1                       
mogu_audio_value=2        
mogu_cold_led_status=1                  //only applicable when backlight is on. From testing, this follows mogu_warm_led_status
mogu_cold_led_value=10                 //determines the warmth level
mogu_contrast_value=8
mogu_init_app_config=2
mogu_notification_status=1
mogu_notification_value=3
mogu_warm_led_status=1               //determines whether the backlight is on or off
mogu_warm_led_value=13              //determines the brightness level
mogu_wifi_status=0

I also investigated /sys/class/backlight but the files there are rather inconclusive and dont contain any real values.

rk3566_eink:/sys/class/backlight/aw99703 $ ls
actual_brightness  bl_power  brightness  device  max_brightness  power  subsystem  type  uevent
rk3566_eink:/sys/class/backlight/aw99703 $ cat actual_brightness                                                                                                                                           
0
rk3566_eink:/sys/class/backlight/aw99703 $ cat brightness                                                                                                                                                  
0
rk3566_eink:/sys/class/backlight/aw99703 $ cat bl_power                                                                                                                                                    
0
rk3566_eink:/sys/class/backlight/aw99703 $ cat max_brightness                                                                                                                                              
2047
pazos commented 5 months ago

ADB is not a reliable method to figure out what unprivilegied apps can do.

You'll need to RE the binaries to find which methods are called by the stock app. If you look in open/closed tickets and previous implemented drivers you'll find a lot of info on how it can be done. See https://github.com/koreader/android-luajit-launcher/issues/344, for instance

jkl16 commented 5 months ago

I continued the investigation from here and from https://github.com/koreader/android-luajit-launcher/issues/344 using a device:

Manufacturer: xiaomi Brand: xiaomi Model: xiaomi_reader Device: rk3566_eink Hardware: rk30board Android Version: 11

After decompiling SystemUI.apk & MoaanSettings.apk (preloaded settings app) it turns out that method forceGlobalRefresh() is in fact a call to a system service "eink". There is a class android.os.EinkManager which declares sendOneFullFrame() trigerring a refresh. The same class also declares setMode(String) method allowing to set one of EPD modes:

EPD_A2 = "12"
EPD_A2_DITHER = "13"
EPD_A2_ENTER = "16"
EPD_AUTO_DU = "22"
EPD_AUTO_DU4 = "23"
EPD_DU4 = "15"
EPD_DU = "14" // Balanced mode & Quick mode
EPD_FULL_GC16 = "2"
EPD_FULL_GCC16 = "6"
EPD_FULL_GL16 = "3"
EPD_FULL_GLD16 = "5"
EPD_FULL_GLR16 = "4"
EPD_OVERLAY = "1"
EPD_PART_GCC16 = "11"
EPD_PART_GL16 = "8"
EPD_PART_GLD16 = "10"
EPD_PART_GLR16 = "9"
EPD_PART_GC16 = "7" // Clear mode
EPD_RESET = "17"
EPD_AUTO = "0"
EPD_NULL = "-1"

I have implemented "full-only" driver in https://github.com/koreader/android-luajit-launcher/pull/478 Can you point me to details describing methods from interface EPDInterface? I would like to get a better understanding if "all" driver is possible.

Decompiling SystemUI.apk also allowed me to understand how lights & warmth is handled. There is a class android.os.MoanLedControl with several methods allowing to set and get light & warmth levels. Getting values using reflection works fine, however setting values is trying to write to /proc/aw99703/led_brightness & /proc/aw99703/led_current and it fails with "Permission denied". I assume it requires admin rights. Lights driver is also included in the PR mentioned above.

pazos commented 5 months ago

Can you point me to details describing methods from interface EPDInterface? I would like to get a better understanding if "all" driver is possible.

The "all" driver requires a system that doesn't refresh at all or a way to inhibit the refreshes of the system. Otherwise we end up with a bunch of partial refreshes done twice, and that's quite a mess :/

jkl16 commented 5 months ago

Thanks for clarification. In that case I assume all Xiaomi-based devices triggering android.eink.force.refresh intent will remain "full-only".

pazos commented 3 months ago

Out of date, please repeat the EinkTest