chore: auto-merge develop → main

Triggered by: 8ee6fe8 kiosk: gateway auto-launch, update auto-download, gateway setup UX
This commit is contained in:
github-actions[bot]
2026-05-05 16:50:23 +00:00
4 changed files with 76 additions and 8 deletions
+2 -2
View File
@@ -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)