kiosk: gateway auto-launch, update auto-download, gateway setup UX
- KioskActivity: move launchGatewayInBackground() BEFORE enableKioskLock() so Android's lock-task restriction does not block starting the gateway Activity - KioskActivity: webView.clearCache(true) before loadUrl — no caching - KioskActivity: checkForUpdates() uses proper semver > comparison (not !=) to avoid false-positive 'update available' when already up-to-date - KioskActivity: showNativeUpdateBanner() removed 30s auto-hide, now auto- triggers download immediately when update detected - SetupActivity: onResume() re-checks gateway status when returning from gateway config (user opens gateway, configures it, presses back → wizard refreshes) - SetupActivity: checkGatewayStatus() probes TCP 127.0.0.1:8765 to show whether gateway is actually running, with clear 'not running' warning to configure first - SettingsActivity: same TCP probe for live gateway status in settings screen - build.gradle.kts: versionCode 9, versionName 1.5.3
This commit is contained in:
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "it.dadaloop.evershelf.kiosk"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
versionCode = 8
|
||||
versionName = "1.5.2"
|
||||
versionCode = 9
|
||||
versionName = "1.5.3"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
||||
@@ -312,6 +312,10 @@ class KioskActivity : AppCompatActivity() {
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
private fun launchWebView() {
|
||||
// Start gateway BEFORE entering kiosk lock — in lock task mode Android blocks
|
||||
// startActivity() for other packages, so the gateway would never launch.
|
||||
launchGatewayInBackground()
|
||||
|
||||
// Ensure kiosk lock and permissions are active
|
||||
enableKioskLock()
|
||||
requestAllPermissions()
|
||||
@@ -432,9 +436,9 @@ class KioskActivity : AppCompatActivity() {
|
||||
}, "_kioskBridge")
|
||||
|
||||
val url = prefs.getString(KEY_URL, "http://evershelf.local") ?: "http://evershelf.local"
|
||||
webView.clearCache(true)
|
||||
webView.loadUrl(url)
|
||||
|
||||
launchGatewayInBackground()
|
||||
applyScreensaverFlag()
|
||||
}
|
||||
|
||||
@@ -513,6 +517,19 @@ class KioskActivity : AppCompatActivity() {
|
||||
val norm = { v: String -> v.trimStart('v') }
|
||||
val isSemver = latestTag.trimStart('v').matches(Regex("\\d+\\.\\d+.*"))
|
||||
|
||||
// Compare semver: returns true if `remote` is strictly greater than `local`
|
||||
fun semverNewer(remote: String, local: String): Boolean {
|
||||
val r = remote.split(".").map { it.filter(Char::isDigit).toIntOrNull() ?: 0 }
|
||||
val l = local.split(".").map { it.filter(Char::isDigit).toIntOrNull() ?: 0 }
|
||||
val len = maxOf(r.size, l.size)
|
||||
for (i in 0 until len) {
|
||||
val rv = r.getOrElse(i) { 0 }
|
||||
val lv = l.getOrElse(i) { 0 }
|
||||
if (rv != lv) return rv > lv
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
val assets = json.optJSONArray("assets")
|
||||
var kioskApkUrl = ""
|
||||
var gatewayApkUrl = ""
|
||||
@@ -527,9 +544,9 @@ class KioskActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
val kioskNeedsUpdate = kioskApkUrl.isNotEmpty() && currentKiosk.isNotEmpty() &&
|
||||
(!isSemver || norm(latestTag) != norm(currentKiosk))
|
||||
(!isSemver || semverNewer(norm(latestTag), norm(currentKiosk)))
|
||||
val gatewayNeedsUpdate = currentGateway != null && gatewayApkUrl.isNotEmpty() &&
|
||||
(!isSemver || norm(latestTag) != norm(currentGateway))
|
||||
(!isSemver || semverNewer(norm(latestTag), norm(currentGateway)))
|
||||
|
||||
if (!kioskNeedsUpdate && !gatewayNeedsUpdate) return@Thread
|
||||
|
||||
@@ -555,7 +572,9 @@ class KioskActivity : AppCompatActivity() {
|
||||
pendingApkDownloadUrl = apkDownloadUrl
|
||||
tvUpdateMessage.text = "⬆️ Aggiornamento disponibile: $message"
|
||||
updateBanner.visibility = View.VISIBLE
|
||||
updateBanner.postDelayed({ updateBanner.visibility = View.GONE }, 30_000)
|
||||
// Auto-start download immediately — no timer hide, stays until done or dismissed
|
||||
activeInstallBtn = btnInstallUpdate
|
||||
triggerApkDownload(apkDownloadUrl)
|
||||
}
|
||||
|
||||
// ── APK Download + Install ─────────────────────────────────────────────
|
||||
|
||||
@@ -77,6 +77,25 @@ class SettingsActivity : AppCompatActivity() {
|
||||
val intent = packageManager.getLaunchIntentForPackage(GATEWAY_PACKAGE)
|
||||
if (intent != null) startActivity(intent)
|
||||
}
|
||||
// Probe WebSocket port in background to show live status
|
||||
Thread {
|
||||
val running = try {
|
||||
java.net.Socket().use { s ->
|
||||
s.connect(java.net.InetSocketAddress("127.0.0.1", 8765), 1200); true
|
||||
}
|
||||
} catch (_: Exception) { false }
|
||||
runOnUiThread {
|
||||
if (running) {
|
||||
statusView.text = "Attivo ✅"
|
||||
statusView.setTextColor(0xFF34d399.toInt())
|
||||
deviceView.text = "Gateway in ascolto su ws://127.0.0.1:8765"
|
||||
} else {
|
||||
statusView.text = "Installato, non avviato ⚠️"
|
||||
statusView.setTextColor(0xFFfbbf24.toInt())
|
||||
deviceView.text = "Premi \"Apri Gateway\" per avviarlo e configurarlo"
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
} else {
|
||||
btnConfigureGateway.visibility = android.view.View.GONE
|
||||
}
|
||||
|
||||
@@ -189,6 +189,14 @@ class SetupActivity : AppCompatActivity() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// When returning from the gateway app (after pressing "Configura"), refresh status
|
||||
if (currentStep == 4 && gatewayInstallCard.visibility == View.VISIBLE) {
|
||||
checkGatewayStatus()
|
||||
}
|
||||
}
|
||||
|
||||
// ── Binding ────────────────────────────────────────────────────────────
|
||||
|
||||
private fun bindViews() {
|
||||
@@ -701,12 +709,34 @@ class SetupActivity : AppCompatActivity() {
|
||||
if (isGatewayInstalled()) {
|
||||
gatewayStatusIcon.text = "✅"
|
||||
gatewayStatusText.text = getString(R.string.wizard_gateway_installed)
|
||||
gatewayStatusDetail.text = getString(R.string.wizard_gateway_installed_detail)
|
||||
gatewayStatusDetail.setTextColor(0xFF34d399.toInt())
|
||||
gatewayStatusDetail.text = "⏳ Verifica connessione in corso..."
|
||||
gatewayStatusDetail.setTextColor(0xFF94a3b8.toInt())
|
||||
btnInstallGateway.visibility = View.GONE
|
||||
btnConfigureGateway.visibility = View.VISIBLE
|
||||
gatewayProgressBar.visibility = View.GONE
|
||||
gatewayProgressText.visibility = View.GONE
|
||||
// Probe WebSocket port to tell user if gateway is actually running
|
||||
Thread {
|
||||
val running = try {
|
||||
java.net.Socket().use { s ->
|
||||
s.connect(java.net.InetSocketAddress("127.0.0.1", 8765), 1200)
|
||||
true
|
||||
}
|
||||
} catch (_: Exception) { false }
|
||||
runOnUiThread {
|
||||
if (running) {
|
||||
gatewayStatusDetail.text = "✅ Gateway attivo su ws://127.0.0.1:8765"
|
||||
gatewayStatusDetail.setTextColor(0xFF34d399.toInt())
|
||||
btnConfigureGateway.text = "⚙️ Riapri Gateway per configurarlo"
|
||||
} else {
|
||||
gatewayStatusDetail.text =
|
||||
"⚠️ Gateway installato ma non ancora avviato.\n" +
|
||||
"Premi il pulsante qui sotto per aprirlo e configurarlo, poi torna a questa schermata."
|
||||
gatewayStatusDetail.setTextColor(0xFFfbbf24.toInt())
|
||||
btnConfigureGateway.text = "▶️ Apri e configura Gateway"
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
} else {
|
||||
gatewayStatusIcon.text = "📲"
|
||||
gatewayStatusText.text = getString(R.string.wizard_gateway_not_installed)
|
||||
|
||||
Reference in New Issue
Block a user