Closed huronhorn closed 3 months ago
In theory you could reverse engineer it, but if it fails all the tests the simple answer is probably that it can't be done easily.
How to turn on ADB for those interested (basically regular Android) https://github.com/epodegrid/epd106-ADB
It probably can be done, but it's a huge PITA and none of the developers have this device so unlikely. I did it for onyx, this can hopefully give someone idea where to start.
Well im not too familiar with coding/reverse engineering myself but im willing to help since no other devs have this device. Thank you anyway, overall still really a great app
@huronhorn basically you need to decompile the apk and search the metods to find an epd update using reflection. There are plenty of tickets with info about the tools and the kind of info we need.
I'm afraid you need to do that yourself. Once you get a routine that refreshes the screen you can paste it here and we can integrate it
@pazos You mean the default reader apk? Or full firmware? I already extract default reader apk and out of curiosity try to installed it on my phone (but couldn't be installed). What tool can i be used to decompile an apk? I will try to figure it out. Thanks!
@huronhorn: see past tickets https://github.com/koreader/koreader/issues/3517 and https://github.com/koreader/koreader/issues/4595 for some inspiration.
I'm afraid you need to do that yourself. Once you get a routine that refreshes the screen you can paste it here and we can integrate it
I have a Xiaomi/Moaan inkPalm 5 which is almost identical to huronhorn's MiReader (only the screen resolution + DPI and storage space differs; the processor is the same):
Manufacturer: Allwinner Brand: Allwinner Model: EPD105 Product: virgo_perf1 Hardware: sun8iw15p1 Platform: virgo run test koreader/koreader#1 -> rk30xx: fail run test koreader/koreader#2 -> rk33xx: fail run test koreader/koreader#3 -> tolino: fail run test koreader/koreader#4 -> qualcomm: fail
getContext().sendBroadcast(new Intent("android.eink.force.refresh"));
is enough to trigger a full-screen refresh on this device. Looking at results on GitHub for android.eink.force.refresh
, it may be generic to all Allwinner devices rather than being Xiaomi-specific.
getContext().sendBroadcast(new Intent("android.eink.force.refresh")); is enough to trigger a full-screen refresh on this device.
That's cool. We can integrate that if there's no other way to trigger a refresh. I still like reflection more because reasons:
run test koreader/koreader#5 -> allwinner
will always be true.I'm assuming there's some service running on the device that registers the Intent android.eink.force.refresh
. The proper solution would be find all services that declare that intent (it should be just one) and decompile it to see what it does under the hood. Given that the broadcast event is exported and any app can issue a refresh without being a system app or sharing the same signature there's no reason to think that reflection won't work.
Yeah, that's understandable. I found the receiver in the boot-framework:
// android.app.activity:
private Window mWindow;
public void onReceive(Context context, Intent intent) {
if ("android.eink.force.refresh".equals(intent.getAction())) {
int intExtra = intent.getIntExtra("rightnow", 1);
if (Activity.this.mWindow != null) {
if (intExtra > 0) {
Activity.this.mWindow.forceGlobalRefresh(true);
} else {
Activity.this.mWindow.forceGlobalRefresh(false);
}
}
}
}
You're right: using that info to Reflect with Window's forceGlobalRefresh
in my unprivileged test application works without a problem.
EDIT: Apologies, but the only reason I'm not writing a PR myself is because I probably wouldn't be able to write something robust enough, even for this. I couldn't find any sort of specific EPD control methods in the framework (although I wasn't looking too hard) - I'm pretty sure forceGlobalRefresh
is implemented in libgui.so
EDIT: Apologies, but the only reason I'm not writing a PR myself is because I probably wouldn't be able to write something robust enough, even for this.
No apologies needed :).
I couldn't find any sort of specific EPD control methods in the framework (although I wasn't looking too hard) - I'm pretty sure forceGlobalRefresh is implemented in libgui.so
That's the beauty of reflection. It works for native methods too. Everything low level on android is expected to be coded in c/c++ and packaged as a shared library with some JNI wrapper. One of the classes of the framework loads the shared library and declares that native method.
We just need to know the name of the class that implements the method and the kind of arguments the method accepts. In most frameworks epd routines are part of "android.view.View" class. That makes sense as it makes possible to update view hierarchies without any specific call, so any Android app would drive the EPD screen without any specific coding needed.
You're right: using that info to Reflect with Window's forceGlobalRefresh in my unprivileged test application works without a problem.
Could you please share the snippet?
Oh, duh, sorry. I created a Hello World app in Android Studio, dragged a button and then put this in:
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Window win = ((Activity) v.getContext()).getWindow();
try {
Method forceGlobalRefresh = win.getClass().getMethod("forceGlobalRefresh", boolean.class);
forceGlobalRefresh.invoke(win, true /* "rightnow" */);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
This snippet and the one before showing the intent reciever calling forceGlobalRefresh
is the best I can do. I ran ripgrep on the inkPalm 5 with the following results (lots of "Permission denied (os error 13)" in /vendor and /system/bin):
virgo-perf1:/ $ /data/local/tmp/rg -uuu -i 'forceGlobalRefresh' -g '!/proc/*' -g '!/dev/*' -g '!/sys/*' 2>/dev/null
Binary file system/priv-app/SystemUI/oat/arm/SystemUI.vdex matches (found "\u{0}" byte around offset 7)
Binary file system/lib/libgui.so matches (found "\u{0}" byte around offset 7)
Binary file system/lib/libandroid_runtime.so matches (found "\u{0}" byte around offset 7)
Binary file system/framework/oat/arm/services.vdex matches (found "\u{0}" byte around offset 7)
Binary file system/framework/arm/boot-framework.vdex matches (found "\u{0}" byte around offset 7)
Binary file system/app/MgSettings/oat/arm/MgSettings.vdex matches (found "\u{0}" byte around offset 7)
Binary file system/app/FactoryTest/oat/arm/FactoryTest.vdex matches (found "\u{0}" byte around offset 7)
Binary file system/app/MasLauncher/oat/arm/MasLauncher.vdex matches (found "\u{0}" byte around offset 7)
Binary file system/app/BootLoading/oat/arm/BootLoading.vdex matches (found "\u{0}" byte around offset 7)
Binary file system/app/DkReader105/oat/arm/DkReader105.vdex matches (found "\u{0}" byte around offset 7)
Both SystemUI and forceGlobalRefresh just call the method, I discounted the files in /system/app because they probably do the same. In services.vdex, there's a chain that ultimately leads nowhere:
The actual content of the methods are pretty bare - they're just a chain of calls to forceGlobalRefresh
in other classes until we reach SurfaceControlWithBackground
, where it becomes:
public void forceGlobalRefresh(boolean z) {
super.forceGlobalRefresh(z);
}
and JADX cannot navigate any further.
If needed, I can upload any folder this non-rooted device allows me access to.
Is there still interest to add support for this? I have a Xiaomi Reader Pro and would really love to have a fully working reader app, I can provide any files I can pull without root, I will eventually root also but that'll be in like another year or so, when I'm sure there won't be another OTA.
The ticket already covers how to call system methods. Only thing left to do is to write a driver using those methods. We are going to rely on device owners for all those things: document behaviour, write drivers, test drivers.
All we can do is to provide help and/or help refactoring.
I am not familiar with android so not quite sure how to start. I found Refresh
in
virgo-perf1:/ $ grep -r Refresh /system/app/
Binary file /system/app/AbupdateEpd106/oat/arm/AbupdateEpd106.vdex matches
Binary file /system/app/Bluetooth/lib/arm/libbluetooth_jni.so matches
Binary file /system/app/Bluetooth/oat/arm/Bluetooth.vdex matches
Binary file /system/app/DkReader106/DkReader106.apk matches
Binary file /system/app/DkReader106/oat/arm/DkReader106.vdex matches
Binary file /system/app/DkWps/oat/arm/DkWps.vdex matches
Binary file /system/app/FactoryTest/oat/arm/FactoryTest.vdex matches
Binary file /system/app/FileExplore/oat/arm/FileExplore.vdex matches
Binary file /system/app/MgSettings/MgSettings.apk matches
Binary file /system/app/MgSettings/oat/arm/MgSettings.vdex matches
Binary file /system/app/NfcNci/oat/arm/NfcNci.vdex matches
Binary file /system/app/PrintSpooler/oat/arm/PrintSpooler.vdex matches
Binary file /system/app/webview/oat/arm/webview.vdex matches
Binary file /system/app/webview/webview.apk matches
I tried decompiling the DkReader106 apk (since that is the default reader app with refresh) with jadx, vdexExtractor, apktool. The output does not seemed useful to me, at least it doesn't seemed to work well with vdex and odex files. In case anyone is interested, here is the full directory for DkReader106 and separated file upload (files too big).
> exa -T DkReader106/
DkReader106
├── DkReader106.apk
└── oat
└── arm
├── DkReader106.odex
└── DkReader106.vdex
DkReader106.zip
DkReader106.z02.zip (remove the .zip
before extract)
DkReader106.z01.zip (remove the .zip
before extract)
Not sure if the logs are useful since I do see something about refresh when I turn off and on the screen, it shows a panda and do a refresh
Out of date, please repeat the EinkTest
Hi I wonder if there is a way to implement full refresh for Xiaomi MiReader 6" (non pro), sadly, MiReader fail all eink/gpd test from koreader
i have already installed latest development version of koreader. And if not can black page shown to "trick" the device to refresh instead of real full refresh, thank you, really appreciate all the effort to make this awesome app
MiReader spec: PROCESSOR: Allwinner B300 (quad-core, 1.8 GHz) Storageb16 GB Android 8.1 Oreo 1GB RAM and 16GB ROM SCREEN: 6", 1024 x 768 212 DPI, PROCESSOR: Allwinner B300 (quad-core, 1.8 GHz)