Skip to content

Commit 757539a

Browse files
committed
Refactor OnyxSdkLightsController to improve handling of brightness types and streamline SDK bridging
Move ONYX_GO7 to use the SDK
1 parent 75edae7 commit 757539a

2 files changed

Lines changed: 234 additions & 92 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ object LightsFactory {
1717
DeviceInfo.Id.ONYX_GALILEO2,
1818
DeviceInfo.Id.ONYX_GO_COLOR7,
1919
DeviceInfo.Id.ONYX_GO6,
20-
DeviceInfo.Id.ONYX_GO7,
2120
DeviceInfo.Id.ONYX_GO7GEN2,
2221
DeviceInfo.Id.ONYX_NOTE_AIR_3C,
2322
DeviceInfo.Id.ONYX_NOTE_AIR_4C,
@@ -82,7 +81,8 @@ object LightsFactory {
8281
DeviceInfo.Id.ONYX_POKE4LITE,
8382
DeviceInfo.Id.ONYX_TAB_ULTRA,
8483
DeviceInfo.Id.STORYTEL_READER2,
85-
-> {
84+
DeviceInfo.Id.ONYX_GO7,
85+
-> {
8686
logController("Onyx/Sdk")
8787
OnyxSdkLightsController()
8888
}

app/src/main/java/org/koreader/launcher/device/lights/OnyxSdkLightsController.kt

Lines changed: 232 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -7,144 +7,286 @@ import android.content.Context
77
import java.lang.Class.forName
88
import java.lang.reflect.Method
99

10+
// ─── Constants mirroring FrontLightController / BaseBrightnessProvider ────────
11+
12+
private const val LIGHT_TYPE_FL = 1 // FLBrightnessProvider — single channel
13+
private const val LIGHT_TYPE_CTM_WARM = 2 // WarmBrightnessProvider — warm channel
14+
private const val LIGHT_TYPE_CTM_COLD = 3 // ColdBrightnessProvider — cold channel
15+
private const val LIGHT_TYPE_CTM_ALL = 4 // open/close the whole CTM unit
16+
private const val LIGHT_TYPE_TEMP = 6 // CTMTemperatureProvider — CTM warmth param
17+
private const val LIGHT_TYPE_CTM_BR = 7 // CTMBrightnessProvider — CTM brightness param
18+
19+
// Mirrors BrightnessType enum
20+
enum class OnyxBrightnessType { FL, WARM_AND_COLD, CTM, NONE }
21+
22+
// ─── Controller ───────────────────────────────────────────────────────────────
23+
1024
class OnyxSdkLightsController : LightsInterface {
25+
1126
companion object {
1227
private const val TAG = "Lights"
13-
private const val BRIGHTNESS_MAX = 255
14-
private const val WARMTH_MAX = 255
1528
private const val MIN = 0
29+
private const val FALLBACK_MAX = 255
1630
}
1731

18-
override fun getPlatform(): String {
19-
return "onyx-sdk-lights"
20-
}
21-
22-
override fun hasFallback(): Boolean {
23-
return false
24-
}
32+
override fun getPlatform(): String = "onyx-sdk-lights"
33+
override fun hasFallback(): Boolean = false
34+
override fun needsPermission(): Boolean = false
35+
override fun hasStandaloneWarmth(): Boolean = false
2536

2637
override fun hasWarmth(): Boolean {
27-
return true
38+
// We can't easily re-init here without Activity/Context,
39+
// but we can trust the previous detection if it found warmth.
40+
return when (OnyxDevice.brightnessType) {
41+
OnyxBrightnessType.WARM_AND_COLD,
42+
OnyxBrightnessType.CTM -> true
43+
else -> !OnyxDevice.isInitialized // optimistic before init
44+
}
2845
}
2946

30-
override fun needsPermission(): Boolean {
31-
return false
32-
}
47+
// ── Read ──────────────────────────────────────────────────────────────────
3348

3449
override fun getBrightness(activity: Activity): Int {
35-
return FrontLight.getCold(activity)
50+
OnyxDevice.init(activity)
51+
return when (OnyxDevice.brightnessType) {
52+
OnyxBrightnessType.FL -> OnyxDevice.getLightValue(activity, LIGHT_TYPE_FL) ?: 0
53+
OnyxBrightnessType.WARM_AND_COLD -> OnyxDevice.getLightValue(activity, LIGHT_TYPE_CTM_COLD) ?: 0
54+
OnyxBrightnessType.CTM -> OnyxDevice.getLightValue(activity, LIGHT_TYPE_CTM_BR) ?: 0
55+
OnyxBrightnessType.NONE -> 0
56+
}
3657
}
3758

3859
override fun getWarmth(activity: Activity): Int {
39-
return FrontLight.getWarm(activity)
60+
OnyxDevice.init(activity)
61+
return when (OnyxDevice.brightnessType) {
62+
OnyxBrightnessType.WARM_AND_COLD -> OnyxDevice.getLightValue(activity, LIGHT_TYPE_CTM_WARM) ?: 0
63+
OnyxBrightnessType.CTM -> OnyxDevice.getLightValue(activity, LIGHT_TYPE_TEMP) ?: 0
64+
else -> 0
65+
}
4066
}
4167

68+
// ── Write ─────────────────────────────────────────────────────────────────
69+
4270
override fun setBrightness(activity: Activity, brightness: Int) {
43-
if (brightness < MIN || brightness > BRIGHTNESS_MAX) {
44-
Log.w(TAG, "brightness value of of range: $brightness")
71+
OnyxDevice.init(activity)
72+
val max = getMaxBrightness()
73+
if (brightness < MIN || brightness > max) {
74+
Log.w(TAG, "brightness out of range: $brightness (max=$max)")
4575
return
4676
}
47-
Log.v(TAG, "Setting brightness to $brightness")
48-
FrontLight.setCold(brightness, activity)
77+
Log.v(TAG, "setBrightness=$brightness type=${OnyxDevice.brightnessType}")
78+
when (OnyxDevice.brightnessType) {
79+
OnyxBrightnessType.FL ->
80+
OnyxDevice.setLight(activity, LIGHT_TYPE_FL, brightness)
81+
OnyxBrightnessType.WARM_AND_COLD ->
82+
OnyxDevice.setLight(activity, LIGHT_TYPE_CTM_COLD, brightness)
83+
OnyxBrightnessType.CTM ->
84+
OnyxDevice.setLight(activity, LIGHT_TYPE_CTM_BR, brightness)
85+
OnyxBrightnessType.NONE -> Unit
86+
}
4987
}
5088

5189
override fun setWarmth(activity: Activity, warmth: Int) {
52-
if (warmth < MIN || warmth > WARMTH_MAX) {
53-
Log.w(TAG, "warmth value of of range: $warmth")
90+
OnyxDevice.init(activity)
91+
val max = getMaxWarmth()
92+
if (warmth < MIN || warmth > max) {
93+
Log.w(TAG, "warmth out of range: $warmth (max=$max)")
5494
return
5595
}
56-
Log.v(TAG, "Setting warmth to $warmth")
57-
FrontLight.setWarm(warmth, activity)
96+
Log.v(TAG, "setWarmth=$warmth type=${OnyxDevice.brightnessType}")
97+
when (OnyxDevice.brightnessType) {
98+
OnyxBrightnessType.WARM_AND_COLD ->
99+
OnyxDevice.setLight(activity, LIGHT_TYPE_CTM_WARM, warmth)
100+
OnyxBrightnessType.CTM ->
101+
OnyxDevice.setLight(activity, LIGHT_TYPE_TEMP, warmth)
102+
else -> Unit
103+
}
58104
}
59105

60-
override fun getMinWarmth(): Int {
61-
return MIN
62-
}
106+
// ── Range ─────────────────────────────────────────────────────────────────
63107

64-
override fun getMaxWarmth(): Int {
65-
return WARMTH_MAX
66-
}
108+
override fun getMinBrightness(): Int = MIN
109+
override fun getMinWarmth(): Int = MIN
67110

68-
override fun getMinBrightness(): Int {
69-
return MIN
111+
override fun getMaxBrightness(): Int = when (OnyxDevice.brightnessType) {
112+
OnyxBrightnessType.FL -> OnyxDevice.getMaxLightValue(LIGHT_TYPE_FL) ?: FALLBACK_MAX
113+
OnyxBrightnessType.WARM_AND_COLD -> OnyxDevice.getMaxLightValue(LIGHT_TYPE_CTM_COLD) ?: FALLBACK_MAX
114+
OnyxBrightnessType.CTM -> OnyxDevice.getMaxLightValue(LIGHT_TYPE_CTM_BR) ?: FALLBACK_MAX
115+
OnyxBrightnessType.NONE -> FALLBACK_MAX
70116
}
71117

72-
override fun getMaxBrightness(): Int {
73-
return BRIGHTNESS_MAX
118+
override fun getMaxWarmth(): Int = when (OnyxDevice.brightnessType) {
119+
OnyxBrightnessType.WARM_AND_COLD -> OnyxDevice.getMaxLightValue(LIGHT_TYPE_CTM_WARM) ?: FALLBACK_MAX
120+
OnyxBrightnessType.CTM -> OnyxDevice.getMaxLightValue(LIGHT_TYPE_TEMP) ?: FALLBACK_MAX
121+
else -> FALLBACK_MAX
74122
}
75123

76-
override fun enableFrontlightSwitch(activity: Activity): Int {
77-
return 1
78-
}
79-
80-
override fun hasStandaloneWarmth(): Boolean {
81-
return false
82-
}
124+
override fun enableFrontlightSwitch(activity: Activity): Int = 1
83125
}
84126

85-
object FrontLight {
86-
private const val TAG = "lights"
127+
// ─── Low-level SDK bridge ─────────────────────────────────────────────────────
87128

88-
private val flController: Class<*>? = try {
89-
forName("android.onyx.hardware.DeviceController")
90-
} catch (e: Exception) {
91-
Log.w(TAG, "$e")
92-
null
93-
}
129+
object OnyxDevice {
130+
private const val TAG = "OnyxDevice"
94131

95-
private val setWarmBrightness: Method? = try {
96-
flController!!.getMethod("setWarmLightDeviceValue", Context::class.java, Integer.TYPE)
132+
private val controller: Class<*>? = try {
133+
Class.forName("android.onyx.hardware.DeviceController")
97134
} catch (e: Exception) {
98-
Log.w(TAG, "$e")
99-
null
135+
Log.w(TAG, "DeviceController not found: $e"); null
100136
}
101-
private val setColdBrightness: Method? = try {
102-
flController!!.getMethod("setColdLightDeviceValue", Context::class.java, Integer.TYPE)
103-
} catch (e: Exception) {
104-
Log.w(TAG, "$e")
105-
null
137+
138+
// Integer getLightValue(int type)
139+
private val mGetLightValue: Method? = method("getLightValue", Integer.TYPE)
140+
?: method("getLightValues", Integer.TYPE)
141+
// Integer getMaxLightValue(int type)
142+
private val mGetMaxLightValue: Method? = method("getMaxLightValue", Integer.TYPE)
143+
?: method("getMaxLightValues", Integer.TYPE)
144+
// boolean setLightValue(int type, int value)
145+
private val mSetLightValue: Method? = method("setLightValue", Integer.TYPE, Integer.TYPE)
146+
?: method("setLightValues", Integer.TYPE, Integer.TYPE)
147+
// boolean openFrontLight(int type)
148+
private val mOpenFrontLight: Method? = method("openFrontLight", Integer.TYPE)
149+
// boolean closeFrontLight(int type)
150+
private val mCloseFrontLight: Method? = method("closeFrontLight", Integer.TYPE)
151+
// boolean isLightOn(int type)
152+
private val mIsLightOn: Method? = method("isLightOn", Context::class.java, Integer.TYPE)
153+
?: method("isLightOn", Integer.TYPE)
154+
// boolean hasFLBrightness(Context)
155+
private val mHasFLBrightness: Method? = method("hasFLBrightness", Context::class.java)
156+
// boolean hasCTMBrightness(Context)
157+
private val mHasCTMBrightness: Method? = method("hasCTMBrightness", Context::class.java)
158+
// boolean checkCTM()
159+
private val mCheckCTM: Method? = method("checkCTM")
160+
161+
var brightnessType: OnyxBrightnessType = OnyxBrightnessType.NONE
162+
private set
163+
164+
var isInitialized = false
165+
private set
166+
167+
/**
168+
* Call once from Activity.onCreate.
169+
* Mirrors BrightnessController.initProviderMap() priority order:
170+
* checkCTM() → CTM (open/close via type 4, read/write via types 6+7)
171+
* hasCTMBrightness → WARM_AND_COLD (types 2+3)
172+
* hasFLBrightness → FL (type 1)
173+
*/
174+
fun init(context: Context) {
175+
// Allow re-initialization if we are currently in a state without warmth,
176+
// to handle cases where detection might be state-dependent (like "OFF" vs "Custom" mode).
177+
if (isInitialized && brightnessType != OnyxBrightnessType.NONE && brightnessType != OnyxBrightnessType.FL) return
178+
179+
val checkCTM = mCheckCTM?.invoke(controller) as? Boolean ?: false
180+
val hasFL = mHasFLBrightness?.invoke(controller, context) as? Boolean ?: false
181+
val hasCTM = mHasCTMBrightness?.invoke(controller, context) as? Boolean ?: false
182+
183+
// Check actual hardware channel availability as fallback/confirmation
184+
val maxCTM = getMaxLightValue(LIGHT_TYPE_TEMP) ?: 0
185+
val maxWarm = getMaxLightValue(LIGHT_TYPE_CTM_WARM) ?: 0
186+
187+
val oldType = brightnessType
188+
brightnessType = when {
189+
checkCTM || maxCTM > 0 -> OnyxBrightnessType.CTM
190+
hasCTM || maxWarm > 0 -> OnyxBrightnessType.WARM_AND_COLD
191+
hasFL -> OnyxBrightnessType.FL
192+
else -> OnyxBrightnessType.NONE
193+
}
194+
195+
if (brightnessType != OnyxBrightnessType.NONE) {
196+
isInitialized = true
197+
}
198+
199+
if (oldType != brightnessType) {
200+
Log.d(TAG, "Detection: checkCTM=$checkCTM hasCTM=$hasCTM hasFL=$hasFL maxCTM=$maxCTM maxWarm=$maxWarm$brightnessType")
201+
}
106202
}
107203

108-
private val getCoolWarmBrightness: Method? = try {
109-
flController!!.getMethod("getBrightnessConfig", Context::class.java, Integer.TYPE)
110-
} catch (e: Exception) {
111-
Log.w(TAG, "$e")
112-
null
204+
// ── Reads ─────────────────────────────────────────────────────────────────
205+
206+
fun getLightValue(context: Context, type: Int): Int? = mGetLightValue?.invoke(controller, type) as? Int
207+
fun getMaxLightValue(type: Int): Int? {
208+
val max = mGetMaxLightValue?.invoke(controller, type) as? Number
209+
return if (max == null || max.toInt() == 0) null else max.toInt()
113210
}
114-
private const val BRIGHTNESS_CONFIG_WARM_IDX: Int = 2
115-
private const val BRIGHTNESS_CONFIG_COLD_IDX: Int = 3
116-
117-
fun getWarm(context: Context?): Int {
118-
return try {
119-
getCoolWarmBrightness!!.invoke(flController!!, context, BRIGHTNESS_CONFIG_WARM_IDX) as Int
120-
} catch (e: Exception) {
121-
e.printStackTrace()
122-
0
211+
212+
fun isLightOn(context: Context, type: Int): Boolean = mIsLightOn?.let { method ->
213+
if (method.parameterTypes.size == 2) {
214+
method.invoke(controller, context, type)
215+
} else {
216+
method.invoke(controller, type)
123217
}
124-
}
218+
} as? Boolean ?: false
219+
220+
// ── Write ─────────────────────────────────────────────────────────────────
221+
//
222+
// Two different axes — this is the source of both bugs:
223+
//
224+
// open/close → operates on the HARDWARE CHANNEL:
225+
// LIGHT_TYPE_CTM_ALL (4) for CTM mode (types 6 and 7 are logical params,
226+
// not hardware channels — opening
227+
// type 6 or 7 individually does nothing)
228+
// LIGHT_TYPE_CTM_WARM (2) / LIGHT_TYPE_CTM_COLD (3) for WARM_AND_COLD
229+
// LIGHT_TYPE_FL (1) for FL
230+
//
231+
// setLightValue → operates on the LOGICAL PARAMETER (type passed as-is):
232+
// type 6 = temperature, type 7 = brightness in CTM mode
233+
// type 2 = warm, type 3 = cold in WARM_AND_COLD mode
234+
// type 1 = brightness in FL mode
235+
//
236+
// Bug 1 — "Off mode": channel is powered down; setLightValue() alone is ignored.
237+
// Fix: call openFrontLight(channelType) before setLightValue().
238+
//
239+
// Bug 2 — "Custom mode warmth": setLight(LIGHT_TYPE_TEMP=6, ...) was calling
240+
// openFrontLight(6), but type 6 is not a hardware channel — only type 4 is.
241+
// Fix: map types 6 and 7 to channelType = LIGHT_TYPE_CTM_ALL (4) for open/close.
125242

126-
fun getCold(context: Context?): Int {
127-
return try {
128-
getCoolWarmBrightness!!.invoke(flController!!, context, BRIGHTNESS_CONFIG_COLD_IDX) as Int
129-
} catch (e: Exception) {
130-
e.printStackTrace()
131-
0
243+
fun setLight(context: Context, type: Int, value: Int): Boolean {
244+
// Map logical parameter type → physical channel type for open/close.
245+
// For CTM, type 4 (ALL) controls the master switch.
246+
// For WARM_AND_COLD, channels 2 and 3 are independent.
247+
val channelType = when (type) {
248+
LIGHT_TYPE_CTM_BR,
249+
LIGHT_TYPE_TEMP -> LIGHT_TYPE_CTM_ALL // CTM: always open/close the whole unit
250+
else -> type // FL / WARM / COLD: direct channel
132251
}
133-
}
134252

135-
fun setWarm(value: Int, context: Context?) {
136-
try {
137-
setWarmBrightness!!.invoke(flController!!, context, value)
138-
} catch (e: Exception) {
139-
e.printStackTrace()
253+
return if (value == 0) {
254+
// Only close the master switch if it's CTM brightness (7) or FL brightness (1).
255+
// Closing warmth channel (2 or 6) shouldn't turn off all lights.
256+
val shouldClose = when (type) {
257+
LIGHT_TYPE_FL,
258+
LIGHT_TYPE_CTM_BR,
259+
LIGHT_TYPE_CTM_COLD,
260+
LIGHT_TYPE_CTM_WARM -> true
261+
else -> false
262+
}
263+
264+
if (shouldClose) {
265+
val ok = mCloseFrontLight?.invoke(controller, channelType) as? Boolean ?: false
266+
Log.v(TAG, "closeFrontLight(channelType=$channelType) → $ok")
267+
ok
268+
} else {
269+
// For warmth, just set value to 0
270+
val ok = mSetLightValue?.invoke(controller, type, 0) as? Boolean ?: false
271+
Log.v(TAG, "setLightValue(type=$type, value=0) → $ok")
272+
ok
273+
}
274+
} else {
275+
if (!isLightOn(context, channelType)) {
276+
val opened = mOpenFrontLight?.invoke(controller, channelType) as? Boolean ?: false
277+
Log.v(TAG, "openFrontLight(channelType=$channelType) → $opened")
278+
}
279+
val ok = mSetLightValue?.invoke(controller, type, value) as? Boolean ?: false
280+
Log.v(TAG, "setLightValue(type=$type, value=$value) → $ok")
281+
ok
140282
}
141283
}
142284

143-
fun setCold(value: Int, context: Context?) {
144-
try {
145-
setColdBrightness!!.invoke(flController!!, context, value)
146-
} catch (e: Exception) {
147-
e.printStackTrace()
148-
}
285+
// ── Helpers ───────────────────────────────────────────────────────────────
286+
287+
private fun method(name: String, vararg params: Class<*>): Method? = try {
288+
controller?.getMethod(name, *params)
289+
} catch (e: Exception) {
290+
Log.w(TAG, "Method '$name' not found: $e"); null
149291
}
150292
}

0 commit comments

Comments
 (0)