Skip to content

Commit 75e7eaf

Browse files
authored
Add support for the Tolino Shine 4, and a proper light controller for the B300 Tolino devices (#570)
1 parent fba2aa2 commit 75e7eaf

File tree

5 files changed

+173
-0
lines changed

5 files changed

+173
-0
lines changed

app/src/main/java/org/koreader/launcher/TestActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import org.koreader.launcher.device.lights.OnyxWarmthController
2727
import org.koreader.launcher.device.lights.TolinoRootController
2828
import org.koreader.launcher.device.lights.TolinoNtxController
2929
import org.koreader.launcher.device.lights.TolinoNtxNoWarmthController
30+
import org.koreader.launcher.device.lights.TolinoB300Controller
3031
import org.koreader.launcher.device.lights.BoyueS62RootController
3132
import org.koreader.launcher.dialog.LightDialog
3233
import org.koreader.launcher.dialog.ToolTip
@@ -81,6 +82,7 @@ class TestActivity: AppCompatActivity() {
8182
lightsMap["Tolino Root"] = TolinoRootController()
8283
lightsMap["Tolino Ntx"] = TolinoNtxController()
8384
lightsMap["Tolino Ntx (no warmth)"] = TolinoNtxNoWarmthController()
85+
lightsMap["Tolino B300"] = TolinoB300Controller()
8486

8587
// Device ID
8688
binding.info.append("Manufacturer: ${DeviceInfo.MANUFACTURER}\n")

app/src/main/java/org/koreader/launcher/device/DeviceInfo.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ object DeviceInfo {
141141
TOLINO_EPOS3,
142142
TOLINO_PAGE2,
143143
TOLINO_SHINE3,
144+
TOLINO_SHINE4,
144145
TOLINO_VISION4,
145146
TOLINO_VISION5,
146147
TOLINO_VISION6,
@@ -614,6 +615,10 @@ object DeviceInfo {
614615
BRAND == STR_KOBO && MODEL == STR_TOLINO && DEVICE == STR_NTX && HARDWARE == "e60k00"
615616
-> Id.TOLINO_SHINE3
616617

618+
// Tolino Shine 4
619+
BRAND == STR_KOBO && MODEL == "tolino shine 4" && DEVICE == STR_TOLINO && HARDWARE == "sun8iw15p1"
620+
-> Id.TOLINO_SHINE4
621+
617622
// Tolino Vision 4 also has warmth lights, but with ntx_io file
618623
BRAND == STR_KOBO && MODEL == STR_TOLINO && DEVICE == STR_NTX && HARDWARE == "e60q50"
619624
-> Id.TOLINO_VISION4

app/src/main/java/org/koreader/launcher/device/EPDFactory.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ object EPDFactory {
6969
DeviceInfo.Id.NOOK_GL4,
7070
DeviceInfo.Id.TOLINO_EPOS3,
7171
DeviceInfo.Id.TOLINO_VISION6,
72+
DeviceInfo.Id.TOLINO_SHINE4,
7273
-> {
7374
logController("NOOK_GL4")
7475
NGL4EPDController()

app/src/main/java/org/koreader/launcher/device/LightsFactory.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ object LightsFactory {
106106
logController("TolinoRoot")
107107
TolinoRootController()
108108
}
109+
DeviceInfo.Id.TOLINO_EPOS3,
110+
DeviceInfo.Id.TOLINO_VISION6,
111+
DeviceInfo.Id.TOLINO_SHINE4,
112+
-> {
113+
logController("TolinoB300Controller")
114+
TolinoB300Controller()
115+
}
109116
else -> {
110117
logController("Generic")
111118
GenericController()
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package org.koreader.launcher.device.lights
2+
3+
import android.app.Activity
4+
import android.provider.Settings
5+
import android.util.Log
6+
import android.widget.Toast
7+
import android.os.Looper
8+
import android.os.Handler
9+
import org.koreader.launcher.device.Ioctl
10+
import org.koreader.launcher.device.LightsInterface
11+
import org.koreader.launcher.device.DeviceInfo
12+
13+
// Light and warmth controller for B300 Tolino devices (Epos 3, Vision 6, Shine 4)
14+
class TolinoB300Controller : Ioctl(), LightsInterface {
15+
16+
companion object {
17+
private const val TAG = "Lights"
18+
private const val BRIGHTNESS_MAX = 100
19+
private const val WARMTH_MAX = 10
20+
private const val MIN = 0
21+
private const val SCREEN_BRIGHTNESS = "screen_brightness"
22+
private const val SCREEN_BRIGHTNESS_COLOR = "screen_brightness_color"
23+
}
24+
25+
private fun needsInvertedWarmth(): Boolean {
26+
return DeviceInfo.ID == DeviceInfo.Id.TOLINO_VISION6 ||
27+
DeviceInfo.ID == DeviceInfo.Id.TOLINO_SHINE4
28+
}
29+
30+
private fun showToastOnUiThread(activity: Activity, message: String) {
31+
Handler(Looper.getMainLooper()).post {
32+
Toast.makeText(activity.applicationContext, message, Toast.LENGTH_LONG).show()
33+
}
34+
}
35+
36+
private fun ensureWriteSettingsPermission(activity: Activity): Boolean {
37+
if (!Settings.System.canWrite(activity.applicationContext)) {
38+
showToastOnUiThread(
39+
activity,
40+
"Please enable 'Modify system settings' for KOReader in Android settings."
41+
)
42+
Log.w(TAG, "WRITE_SETTINGS permission not granted.")
43+
return false
44+
}
45+
return true
46+
}
47+
48+
override fun getPlatform(): String {
49+
return "tolino"
50+
}
51+
52+
override fun hasFallback(): Boolean {
53+
return false
54+
}
55+
56+
override fun hasWarmth(): Boolean {
57+
return true
58+
}
59+
60+
override fun needsPermission(): Boolean {
61+
return true
62+
}
63+
64+
override fun enableFrontlightSwitch(activity: Activity): Int {
65+
return 1
66+
}
67+
68+
override fun getBrightness(activity: Activity): Int {
69+
return try {
70+
Settings.System.getInt(activity.applicationContext.contentResolver, SCREEN_BRIGHTNESS)
71+
} catch (e: Exception) {
72+
Log.w(TAG, e.toString())
73+
0
74+
}
75+
}
76+
77+
override fun getWarmth(activity: Activity): Int {
78+
return try {
79+
val raw = Settings.System.getInt(
80+
activity.applicationContext.contentResolver,
81+
SCREEN_BRIGHTNESS_COLOR
82+
)
83+
if (needsInvertedWarmth()) WARMTH_MAX - raw else raw
84+
} catch (e: Exception) {
85+
Log.w(TAG, e.toString())
86+
0
87+
}
88+
}
89+
90+
override fun setBrightness(activity: Activity, brightness: Int) {
91+
if (!ensureWriteSettingsPermission(activity)) return
92+
if (brightness < MIN || brightness > BRIGHTNESS_MAX) {
93+
Log.w(TAG, "brightness value of of range: $brightness")
94+
return
95+
}
96+
Log.v(TAG, "Setting brightness to $brightness")
97+
try {
98+
Settings.System.putInt(
99+
activity.applicationContext.contentResolver,
100+
SCREEN_BRIGHTNESS,
101+
brightness
102+
)
103+
} catch (e: Exception) {
104+
Log.w(TAG, "$e")
105+
}
106+
}
107+
108+
override fun setWarmth(activity: Activity, warmth: Int) {
109+
if (!ensureWriteSettingsPermission(activity)) return
110+
if (warmth < MIN || warmth > WARMTH_MAX) {
111+
Log.w(TAG, "warmth value of of range: $warmth")
112+
return
113+
}
114+
val warmthToSet = if (needsInvertedWarmth()) WARMTH_MAX - warmth else warmth
115+
Log.v(TAG, "Setting warmth to $warmth (actual: $warmthToSet)")
116+
try {
117+
Settings.System.putInt(
118+
activity.applicationContext.contentResolver,
119+
SCREEN_BRIGHTNESS_COLOR,
120+
warmthToSet
121+
)
122+
// workaround, toggle brightness to force warmth refresh
123+
val currentBrightness: Int = getBrightness(activity)
124+
Settings.System.putInt(
125+
activity.applicationContext.contentResolver,
126+
SCREEN_BRIGHTNESS,
127+
currentBrightness + 1
128+
)
129+
Settings.System.putInt(
130+
activity.applicationContext.contentResolver,
131+
SCREEN_BRIGHTNESS,
132+
currentBrightness
133+
)
134+
} catch (e: Exception) {
135+
Log.w(TAG, "$e")
136+
}
137+
}
138+
139+
override fun getMinWarmth(): Int {
140+
return MIN
141+
}
142+
143+
override fun getMaxWarmth(): Int {
144+
return WARMTH_MAX
145+
}
146+
147+
override fun getMinBrightness(): Int {
148+
return MIN
149+
}
150+
151+
override fun getMaxBrightness(): Int {
152+
return BRIGHTNESS_MAX
153+
}
154+
155+
override fun hasStandaloneWarmth(): Boolean {
156+
return false
157+
}
158+
}

0 commit comments

Comments
 (0)