Auto dark/bright takes a light sensor where the device allows one
/ crosscheck (push) Successful in 1s
CI / Analyze & Test (push) Successful in 21s
CI / Debug APK (push) Successful in 41s

lib/theme/light.dart: dark at 15 lux or less, bright from 60, held 5 s; Settings shows the
reading. The Redmi Pad SE refuses apps its only light sensor (Xiaomi's, from the front
camera), so there Auto keeps following Android's dark theme. DASH-NEXT.md records the
other lux sources.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 22:24:36 +09:00
parent dcafc04cbc
commit 3398da3823
8 changed files with 215 additions and 13 deletions
@@ -2,6 +2,10 @@ package dev.yukart.display
import android.content.Context
import android.content.Intent
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
@@ -10,6 +14,7 @@ import android.os.Bundle
import android.view.WindowManager
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodChannel
/**
@@ -22,6 +27,9 @@ import io.flutter.plugin.common.MethodChannel
* When asked, the whole process is bound to the Ethernet (NCM) network while it
* exists, and unbound when it goes.
*
* Also the light sensor, for auto dark/bright (lib/theme/light.dart): lux on `yukart/light`
* while Dart listens, where the device lets apps read one (the Redmi Pad SE does not).
*
* Also a development hook: `am start -n dev.yukart.display/.MainActivity --es linktest [dl:|bi:]<label>[@<host>]`
* runs the link test (lib/linktest.dart) without touching the screen.
*/
@@ -81,6 +89,34 @@ class MainActivity : FlutterActivity() {
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
cm.requestNetwork(request, callback)
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "yukart/light")
.setStreamHandler(LightStream(getSystemService(Context.SENSOR_SERVICE) as SensorManager))
}
/** Lux from the default light sensor while listened to; an error at once without one, or when refused. */
private class LightStream(private val sm: SensorManager) : EventChannel.StreamHandler {
private var listener: SensorEventListener? = null
override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
val sensor = sm.getDefaultSensor(Sensor.TYPE_LIGHT)
?: return events.error("no_sensor", "no light sensor", null)
listener = object : SensorEventListener {
override fun onSensorChanged(e: SensorEvent) = events.success(e.values[0].toDouble())
override fun onAccuracyChanged(s: Sensor, accuracy: Int) {}
}
// The Redmi Pad SE lists one (derived from the front camera) but refuses apps:
// only the system's auto-brightness may read it.
if (!sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL)) {
listener = null
events.error("refused", "light sensor refused", null)
}
}
override fun onCancel(arguments: Any?) {
listener?.let { sm.unregisterListener(it) }
listener = null
}
}
private fun apply() {