From ace577140d793dab12d91654d3278881104f9f84 Mon Sep 17 00:00:00 2001 From: Natalie Date: Sun, 31 Aug 2025 15:14:56 +0200 Subject: [PATCH 1/6] Adding (hopefully) proper Shine 4 support, adding proper light controls for the B300 Tolinos based off of koreader/android-luajit-launcher/pull/520 --- .../org/koreader/launcher/TestActivity.kt | 2 + .../koreader/launcher/device/DeviceInfo.kt | 4 + .../koreader/launcher/device/EPDFactory.kt | 1 + .../koreader/launcher/device/LightsFactory.kt | 7 + .../device/lights/TolinoB300Controller.kt | 131 ++++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt diff --git a/app/src/main/java/org/koreader/launcher/TestActivity.kt b/app/src/main/java/org/koreader/launcher/TestActivity.kt index b93b25d9d..fea9cfeb9 100644 --- a/app/src/main/java/org/koreader/launcher/TestActivity.kt +++ b/app/src/main/java/org/koreader/launcher/TestActivity.kt @@ -27,6 +27,7 @@ import org.koreader.launcher.device.lights.OnyxWarmthController import org.koreader.launcher.device.lights.TolinoRootController import org.koreader.launcher.device.lights.TolinoNtxController import org.koreader.launcher.device.lights.TolinoNtxNoWarmthController +import org.koreader.launcher.device.lights.TolinoB300Controller import org.koreader.launcher.device.lights.BoyueS62RootController import org.koreader.launcher.dialog.LightDialog import org.koreader.launcher.dialog.ToolTip @@ -81,6 +82,7 @@ class TestActivity: AppCompatActivity() { lightsMap["Tolino Root"] = TolinoRootController() lightsMap["Tolino Ntx"] = TolinoNtxController() lightsMap["Tolino Ntx (no warmth)"] = TolinoNtxNoWarmthController() + lightsMap["Tolino B300"] = TolinoB300Controller() // Device ID binding.info.append("Manufacturer: ${DeviceInfo.MANUFACTURER}\n") diff --git a/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt b/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt index 3e0a3dc88..0f6ab18ce 100644 --- a/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt +++ b/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt @@ -614,6 +614,10 @@ object DeviceInfo { BRAND == STR_KOBO && MODEL == STR_TOLINO && DEVICE == STR_NTX && HARDWARE == "e60k00" -> Id.TOLINO_SHINE3 + // Tolino Shine 4 + BRAND == STR_KOBO && MODEL == "tolino shine 4" && DEVICE == STR_TOLINO && HARDWARE == "sun8iw15p1" + -> Id.TOLINO_SHINE4 + // Tolino Vision 4 also has warmth lights, but with ntx_io file BRAND == STR_KOBO && MODEL == STR_TOLINO && DEVICE == STR_NTX && HARDWARE == "e60q50" -> Id.TOLINO_VISION4 diff --git a/app/src/main/java/org/koreader/launcher/device/EPDFactory.kt b/app/src/main/java/org/koreader/launcher/device/EPDFactory.kt index 673a80211..0b74405c8 100644 --- a/app/src/main/java/org/koreader/launcher/device/EPDFactory.kt +++ b/app/src/main/java/org/koreader/launcher/device/EPDFactory.kt @@ -69,6 +69,7 @@ object EPDFactory { DeviceInfo.Id.NOOK_GL4, DeviceInfo.Id.TOLINO_EPOS3, DeviceInfo.Id.TOLINO_VISION6, + DeviceInfo.Id.TOLINO_SHINE4, -> { logController("NOOK_GL4") NGL4EPDController() diff --git a/app/src/main/java/org/koreader/launcher/device/LightsFactory.kt b/app/src/main/java/org/koreader/launcher/device/LightsFactory.kt index 8614bd339..eda2e6314 100644 --- a/app/src/main/java/org/koreader/launcher/device/LightsFactory.kt +++ b/app/src/main/java/org/koreader/launcher/device/LightsFactory.kt @@ -106,6 +106,13 @@ object LightsFactory { logController("TolinoRoot") TolinoRootController() } + DeviceInfo.Id.TOLINO_EPOS3, + DeviceInfo.Id.TOLINO_VISION6, + DeviceInfo.Id.TOLINO_SHINE4, + -> { + logController("TolinoB300Controller") + TolinoB300Controller() + } else -> { logController("Generic") GenericController() diff --git a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt new file mode 100644 index 000000000..e4d9ea1b9 --- /dev/null +++ b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt @@ -0,0 +1,131 @@ +package org.koreader.launcher.device.lights + +import android.app.Activity +import android.provider.Settings +import android.util.Log +import org.koreader.launcher.device.Ioctl +import org.koreader.launcher.device.LightsInterface + +// Light and warmth controller for B300 Tolino devices (Epos 3, Vision 6, Shine 4) +// Need testers for Shine 4, I'm operating under the assumption that this works. +// Vision 6 has inverted warmth from personal testing. +class TolinoB300Controller : Ioctl(), LightsInterface { + + companion object { + private const val TAG = "Lights" + private const val BRIGHTNESS_MAX = 100 + private const val WARMTH_MAX = 10 + private const val MIN = 0 + } + + override fun getPlatform(): String { + return "tolino" + } + + override fun hasFallback(): Boolean { + return false + } + + override fun hasWarmth(): Boolean { + return true + } + + override fun needsPermission(): Boolean { + return true + } + + override fun enableFrontlightSwitch(activity: Activity): Int { + return 1 + } + + override fun getBrightness(activity: Activity): Int { + return try { + Settings.System.getInt(activity.applicationContext.contentResolver, "screen_brightness") + } catch (e: Exception) { + Log.w(TAG, e.toString()) + 0 + } + } + + override fun getWarmth(activity: Activity): Int { + return try { + Settings.System.getInt( + activity.applicationContext.contentResolver, + "screen_brightness_color" + ) + } catch (e: Exception) { + Log.w(TAG, e.toString()) + } + } + + override fun setBrightness(activity: Activity, brightness: Int) { + if (brightness < MIN || brightness > BRIGHTNESS_MAX) { + Log.w(TAG, "brightness value of of range: $brightness") + return + } + Log.v(TAG, "Setting brightness to $brightness") + try { + Settings.System.putInt( + activity.applicationContext.contentResolver, + "screen_brightness", + brightness + ) + } catch (e: Exception) { + Log.w(TAG, "$e") + } + } + + override fun setWarmth(activity: Activity, warmth: Int) { + if (warmth < MIN || warmth > WARMTH_MAX) { + Log.w(TAG, "warmth value of of range: $warmth") + return + } + Log.v(TAG, "Setting warmth to $warmth") + try { + Settings.System.putInt( + activity.applicationContext.contentResolver, + "screen_brightness_color", + warmth + ) + + // crappy toggle brightness to force warmth refresh + val currentBrightness: Int = + Settings.System.getInt( + activity.applicationContext.contentResolver, + "screen_brightness" + ) + Settings.System.putInt( + activity.applicationContext.contentResolver, + "screen_brightness", + currentBrightness + 1 + ) + Settings.System.putInt( + activity.applicationContext.contentResolver, + "screen_brightness", + currentBrightness + ) + } catch (e: Exception) { + Log.w(TAG, "$e") + } + } + + override fun getMinWarmth(): Int { + return MIN + } + + override fun getMaxWarmth(): Int { + return WARMTH_MAX + } + + override fun getMinBrightness(): Int { + return MIN + } + + override fun getMaxBrightness(): Int { + return BRIGHTNESS_MAX + } + + override fun hasStandaloneWarmth(): Boolean { + return false + } +} From 807657d79877a8da6d010616ca399c91cf243bef Mon Sep 17 00:00:00 2001 From: Natalie Date: Sat, 6 Sep 2025 22:33:05 +0200 Subject: [PATCH 2/6] Update DeviceInfo.kt Forgot to add the Shine 4 in the enum id. --- app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt b/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt index 0f6ab18ce..b299c193d 100644 --- a/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt +++ b/app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt @@ -141,6 +141,7 @@ object DeviceInfo { TOLINO_EPOS3, TOLINO_PAGE2, TOLINO_SHINE3, + TOLINO_SHINE4, TOLINO_VISION4, TOLINO_VISION5, TOLINO_VISION6, From 8f6195399eedbf95c832c5511db4ee2b8ee91194 Mon Sep 17 00:00:00 2001 From: Natalie Date: Sun, 7 Sep 2025 13:14:13 +0200 Subject: [PATCH 3/6] Fixing string literals, replaced with constants. --- .../device/lights/TolinoB300Controller.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt index e4d9ea1b9..7230bcfe9 100644 --- a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt +++ b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt @@ -8,7 +8,7 @@ import org.koreader.launcher.device.LightsInterface // Light and warmth controller for B300 Tolino devices (Epos 3, Vision 6, Shine 4) // Need testers for Shine 4, I'm operating under the assumption that this works. -// Vision 6 has inverted warmth from personal testing. +// Vision 6 has inverted warmth from personal testing. class TolinoB300Controller : Ioctl(), LightsInterface { companion object { @@ -16,6 +16,8 @@ class TolinoB300Controller : Ioctl(), LightsInterface { private const val BRIGHTNESS_MAX = 100 private const val WARMTH_MAX = 10 private const val MIN = 0 + private const val SCREEN_BRIGHTNESS = "screen_brightness" + private const val SCREEN_BRIGHTNESS_COLOR = "screen_brightness_color" } override fun getPlatform(): String { @@ -40,7 +42,7 @@ class TolinoB300Controller : Ioctl(), LightsInterface { override fun getBrightness(activity: Activity): Int { return try { - Settings.System.getInt(activity.applicationContext.contentResolver, "screen_brightness") + Settings.System.getInt(activity.applicationContext.contentResolver, SCREEN_BRIGHTNESS) } catch (e: Exception) { Log.w(TAG, e.toString()) 0 @@ -51,7 +53,7 @@ class TolinoB300Controller : Ioctl(), LightsInterface { return try { Settings.System.getInt( activity.applicationContext.contentResolver, - "screen_brightness_color" + SCREEN_BRIGHTNESS_COLOR ) } catch (e: Exception) { Log.w(TAG, e.toString()) @@ -67,7 +69,7 @@ class TolinoB300Controller : Ioctl(), LightsInterface { try { Settings.System.putInt( activity.applicationContext.contentResolver, - "screen_brightness", + SCREEN_BRIGHTNESS, brightness ) } catch (e: Exception) { @@ -84,7 +86,7 @@ class TolinoB300Controller : Ioctl(), LightsInterface { try { Settings.System.putInt( activity.applicationContext.contentResolver, - "screen_brightness_color", + SCREEN_BRIGHTNESS_COLOR, warmth ) @@ -92,16 +94,16 @@ class TolinoB300Controller : Ioctl(), LightsInterface { val currentBrightness: Int = Settings.System.getInt( activity.applicationContext.contentResolver, - "screen_brightness" + SCREEN_BRIGHTNESS ) Settings.System.putInt( activity.applicationContext.contentResolver, - "screen_brightness", + SCREEN_BRIGHTNESS, currentBrightness + 1 ) Settings.System.putInt( activity.applicationContext.contentResolver, - "screen_brightness", + SCREEN_BRIGHTNESS, currentBrightness ) } catch (e: Exception) { From 3aa73c907583e36154e7fbc993cca4910ebdff59 Mon Sep 17 00:00:00 2001 From: Natalie Date: Sun, 7 Sep 2025 13:36:54 +0200 Subject: [PATCH 4/6] Removed the duplication in the toggle brightness workaround. --- .../koreader/launcher/device/lights/TolinoB300Controller.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt index 7230bcfe9..2a2d56f22 100644 --- a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt +++ b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt @@ -91,11 +91,7 @@ class TolinoB300Controller : Ioctl(), LightsInterface { ) // crappy toggle brightness to force warmth refresh - val currentBrightness: Int = - Settings.System.getInt( - activity.applicationContext.contentResolver, - SCREEN_BRIGHTNESS - ) + val currentBrightness: Int = getBrightness(activity) Settings.System.putInt( activity.applicationContext.contentResolver, SCREEN_BRIGHTNESS, From ed2cab28e65b8b0f597d52e366dec8f29e9ab5cc Mon Sep 17 00:00:00 2001 From: Natalie Date: Sun, 14 Sep 2025 22:11:49 +0200 Subject: [PATCH 5/6] Fixed inverted warmth slider for Vis6/Shine4, Added toast for permission requirement --- .../device/lights/TolinoB300Controller.kt | 63 ++++++++++++++----- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt index 2a2d56f22..c634c7a33 100644 --- a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt +++ b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt @@ -3,12 +3,14 @@ package org.koreader.launcher.device.lights import android.app.Activity import android.provider.Settings import android.util.Log +import android.widget.Toast +import android.os.Looper +import android.os.Handler import org.koreader.launcher.device.Ioctl import org.koreader.launcher.device.LightsInterface +import org.koreader.launcher.device.DeviceInfo // Light and warmth controller for B300 Tolino devices (Epos 3, Vision 6, Shine 4) -// Need testers for Shine 4, I'm operating under the assumption that this works. -// Vision 6 has inverted warmth from personal testing. class TolinoB300Controller : Ioctl(), LightsInterface { companion object { @@ -20,6 +22,29 @@ class TolinoB300Controller : Ioctl(), LightsInterface { private const val SCREEN_BRIGHTNESS_COLOR = "screen_brightness_color" } + private fun needsInvertedWarmth(): Boolean { + return DeviceInfo.ID == DeviceInfo.Id.TOLINO_VISION6 || + DeviceInfo.ID == DeviceInfo.Id.TOLINO_SHINE4 + } + + private fun showToastOnUiThread(activity: Activity, message: String) { + Handler(Looper.getMainLooper()).post { + Toast.makeText(activity.applicationContext, message, Toast.LENGTH_LONG).show() + } + } + + private fun ensureWriteSettingsPermission(activity: Activity): Boolean { + if (!Settings.System.canWrite(activity.applicationContext)) { + showToastOnUiThread( + activity, + "Please enable 'Modify system settings' for KOReader in Android settings." + ) + Log.w(TAG, "WRITE_SETTINGS permission not granted.") + return false + } + return true + } + override fun getPlatform(): String { return "tolino" } @@ -51,16 +76,19 @@ class TolinoB300Controller : Ioctl(), LightsInterface { override fun getWarmth(activity: Activity): Int { return try { - Settings.System.getInt( - activity.applicationContext.contentResolver, - SCREEN_BRIGHTNESS_COLOR + val raw = Settings.System.getInt( + activity.applicationContext.contentResolver, + SCREEN_BRIGHTNESS_COLOR ) + if (needsInvertedWarmth()) WARMTH_MAX - raw else raw } catch (e: Exception) { Log.w(TAG, e.toString()) + 0 } } override fun setBrightness(activity: Activity, brightness: Int) { + if (!ensureWriteSettingsPermission(activity)) return if (brightness < MIN || brightness > BRIGHTNESS_MAX) { Log.w(TAG, "brightness value of of range: $brightness") return @@ -78,29 +106,30 @@ class TolinoB300Controller : Ioctl(), LightsInterface { } override fun setWarmth(activity: Activity, warmth: Int) { + if (!ensureWriteSettingsPermission(activity)) return if (warmth < MIN || warmth > WARMTH_MAX) { Log.w(TAG, "warmth value of of range: $warmth") return } - Log.v(TAG, "Setting warmth to $warmth") + val warmthToSet = if (needsInvertedWarmth()) WARMTH_MAX - warmth else warmth + Log.v(TAG, "Setting warmth to $warmth (actual: $warmthToSet)") try { Settings.System.putInt( - activity.applicationContext.contentResolver, - SCREEN_BRIGHTNESS_COLOR, - warmth + activity.applicationContext.contentResolver, + SCREEN_BRIGHTNESS_COLOR, + warmthToSet ) - - // crappy toggle brightness to force warmth refresh + // workaround, toggle brightness to force warmth refresh val currentBrightness: Int = getBrightness(activity) Settings.System.putInt( - activity.applicationContext.contentResolver, - SCREEN_BRIGHTNESS, - currentBrightness + 1 + activity.applicationContext.contentResolver, + SCREEN_BRIGHTNESS, + currentBrightness + 1 ) Settings.System.putInt( - activity.applicationContext.contentResolver, - SCREEN_BRIGHTNESS, - currentBrightness + activity.applicationContext.contentResolver, + SCREEN_BRIGHTNESS, + currentBrightness ) } catch (e: Exception) { Log.w(TAG, "$e") From 374535d5657ee9eeab316679f893f28e309f7cab Mon Sep 17 00:00:00 2001 From: Natalie Date: Sun, 14 Sep 2025 23:10:27 +0200 Subject: [PATCH 6/6] I loathe trailing spaces. --- .../org/koreader/launcher/device/lights/TolinoB300Controller.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt index c634c7a33..3c32767a8 100644 --- a/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt +++ b/app/src/main/java/org/koreader/launcher/device/lights/TolinoB300Controller.kt @@ -83,7 +83,7 @@ class TolinoB300Controller : Ioctl(), LightsInterface { if (needsInvertedWarmth()) WARMTH_MAX - raw else raw } catch (e: Exception) { Log.w(TAG, e.toString()) - 0 + 0 } }