Search code examples
androidbatterye-ink

Android: How to control e-ink screen while off


My e-book reader (tolino shine 3) allows you to configure what the e-ink display should show when the screen is turned off. How can I do this programatically?

I wrote a little app, that turns on wifi every 10 minutes to fetch and display the latest weather report and then turns off wifi again. Since e-ink dipslays do not use power when nothing changes, I figured that the battery would last very long (my goal is 1 week) - but not so. Apparently Android keeps sucking the battery dry as long as the device is officially "on". After 2 days the show was over. If I could turn off the screen without clearing it I guess this would dramatically improve the run-time.

Any help would be appreciated. There's very little out there regarding e-ink APIs on Android.

The tolino shine 3 runs on Android 4.4.


Solution

  • In logcat I found the following lines:

    06-12 13:22:09.250 2484-2510/system_process I/Terry-FB: strSuspendImgFileName = /storage/sdcard1/suspend_others.jpg
    06-12 13:22:09.250 2484-2510/system_process I/Terry-FB: strEPubFolder + "/" + strDefaultImgFileName = /data/data/de.telekom.epub/files//suspend_others.jpg
    06-12 13:22:09.250 2484-2510/system_process I/Terry-FB: strLocaleImgFolder + "/" + strDefaultImgFileName = /system/usr/sleep/drawable-de-nodpi/suspend_others.jpg
    06-12 13:22:09.250 2484-2510/system_process I/Terry-FB: strEPubFolder + "/" + strChargeImgFileName = /data/data/de.telekom.epub/files//suspend_charging_others.jpg
    06-12 13:22:09.250 2484-2510/system_process I/Terry-FB: strLocaleImgFolder + "/" + strChargeImgFileName = /system/usr/sleep/drawable-de-nodpi/suspend_charging_others.jpg
    06-12 13:22:09.250 2484-2510/system_process I/Terry-FB: strLocaleImgFolder + "/" + strFullImgFileName = /system/usr/sleep/drawable-de-nodpi/suspend_batteryfull_others.jpg
    

    Apparently this is where it loads the image that is shown during sleep. Using grep I found the code in /system/framework/android.policy.jar. So I decompiled this file using JADX and found the lines where the screen is cleared and overwritten in ShowSleepScreenEx(). Since recompiling code that was decompiled with JADX is rather cumbersome I used apktool to decompile the jar into smali code, where I removed the call to ShowSleepScreenEx(). Using "apktool build" I recreated the jar file and pushed it back to the device. Voila: the screen is no longer cleared when the device goes to sleep.

    I did not find a way to turn the screen off programmatically, so I simply set the screen timeout to a low value using

    adb shell settings put system screen_off_timeout 1000
    

    (Well, it turns out the minimum is 10s, but stubborn as I am I still set it to 1s :-)) Using ALarmManager I wake up every minute to update the time. The usual methods for turning on the screen (SCREEN_DIM_WAKE_LOCK, WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) did not work on this device for some reason, so I found a different one: I cross-compiled libevdev and evemu and simulate pressing the power button:

    public class AlarmWorker extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/evemu-event",
                        "--sync", "/dev/input/event0", "--type", "EV_KEY", "--code", "KEY_POWER", "--value", "1"});
                proc.waitFor();
                SystemClock.sleep(50);
                proc = Runtime.getRuntime().exec(new String[]{ "/system/bin/evemu-event",
                        "--sync", "/dev/input/event0", "--type", "EV_KEY", "--code", "KEY_POWER", "--value", "0" });
                proc.waitFor();
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

    Instead of 2 days the battery now lasts 5 days on one charge.