Auto dark/bright follows the sun at the tablet's own location
Without a light sensor an app may read (the Redmi Pad SE has none), auto is dark while the sun is more than 4° below the horizon (lib/theme/sun.dart), at Android's coarse location, polled and kept across restarts. The tablet's own, not the Orin's GNSS: the tablet has its own GNSS and cellular. Android's dark theme is the last fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<!-- requestNetwork for the USB (NCM) Ethernet link to the Orin -->
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<!-- Where the tablet is, roughly: for the sun (auto dark/bright, lib/theme/sun.dart). -->
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<application
|
||||
android:label="Yukart"
|
||||
android:name="${applicationName}"
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
package dev.yukart.display
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import android.location.LocationManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
@@ -29,6 +33,7 @@ import io.flutter.plugin.common.MethodChannel
|
||||
*
|
||||
* 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).
|
||||
* And, for the sun instead, the tablet's own rough location on `yukart/location`.
|
||||
*
|
||||
* 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.
|
||||
@@ -39,6 +44,7 @@ class MainActivity : FlutterActivity() {
|
||||
private var ethernet: Network? = null
|
||||
private var wantBinding = false
|
||||
private var pendingLinkTest: String? = null
|
||||
private var askedLocation = false
|
||||
|
||||
private val callback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
@@ -90,10 +96,38 @@ class MainActivity : FlutterActivity() {
|
||||
.build()
|
||||
cm.requestNetwork(request, callback)
|
||||
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "yukart/location").setMethodCallHandler { call, result ->
|
||||
if (call.method == "last") result.success(lastLocation()) else result.notImplemented()
|
||||
}
|
||||
|
||||
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "yukart/light")
|
||||
.setStreamHandler(LightStream(getSystemService(Context.SENSOR_SERVICE) as SensorManager))
|
||||
}
|
||||
|
||||
/**
|
||||
* [lat, lon] of the newest location Android has (other apps' fixes included), or null.
|
||||
* Asks for coarse location the first time; with none known, asks for one, which the
|
||||
* next call sees.
|
||||
*/
|
||||
private fun lastLocation(): List<Double>? {
|
||||
if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
if (!askedLocation) {
|
||||
askedLocation = true
|
||||
requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 1)
|
||||
}
|
||||
return null
|
||||
}
|
||||
val lm = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
val enabled = lm.getProviders(true)
|
||||
val best = enabled.mapNotNull { runCatching { lm.getLastKnownLocation(it) }.getOrNull() }.maxByOrNull { it.time }
|
||||
if (best == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
listOf("fused", LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER)
|
||||
.firstOrNull { it in enabled }
|
||||
?.let { runCatching { lm.getCurrentLocation(it, null, mainExecutor) {} } }
|
||||
}
|
||||
return best?.let { listOf(it.latitude, it.longitude) }
|
||||
}
|
||||
|
||||
/** 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
|
||||
|
||||
Reference in New Issue
Block a user