kiosk: fix install dialog + screensaver always-on

Fallback install (Intent.ACTION_VIEW):
- Remove FLAG_ACTIVITY_NEW_TASK: it caused startActivityForResult to return
  RESULT_CANCELED immediately, making the system installer dialog disappear in ~1s
- After fallback returns with app not installed: show '🔄 Riprova installazione'
  button that calls tryFallbackInstall() directly (skips PackageInstaller which
  is known to give STATUS=1 on this device)

Screensaver:
- KioskActivity.applyScreensaverFlag(): always add FLAG_KEEP_SCREEN_ON, never
  clear it — screen must ALWAYS stay on in kiosk mode
- The 'salvaschermo' toggle controls the in-app JS clock overlay (webapp setting),
  NOT the Android screen timeout
- finishSetup(): always push screensaver_enabled to webapp API (not just when scale
  is configured)
- SettingsActivity save: remove FLAG_KEEP_SCREEN_ON conditional; push
  screensaver_enabled to server API on save
- Update setup wizard description + strings to clarify in-app overlay vs screen off

Bump version to 1.5.2 (versionCode 8)
This commit is contained in:
dadaloop82
2026-05-05 16:01:47 +00:00
parent 84d2ff0264
commit 6500d22242
6 changed files with 86 additions and 43 deletions
+2 -2
View File
@@ -11,8 +11,8 @@ android {
applicationId = "it.dadaloop.evershelf.kiosk"
minSdk = 24
targetSdk = 34
versionCode = 7
versionName = "1.5.1"
versionCode = 8
versionName = "1.5.2"
}
signingConfigs {
@@ -439,11 +439,10 @@ class KioskActivity : AppCompatActivity() {
}
private fun applyScreensaverFlag() {
if (prefs.getBoolean(KEY_SCREENSAVER, false)) {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
// The kiosk screen must ALWAYS stay on — the in-app screensaver is a JS overlay
// (clock + info) shown by the webapp after inactivity, not an Android screen timeout.
// Never clear FLAG_KEEP_SCREEN_ON regardless of the screensaver preference.
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
// ── Inject kiosk overlay (exit + refresh buttons) ────────────────────
@@ -106,12 +106,24 @@ class SettingsActivity : AppCompatActivity() {
.putString(KEY_URL, url)
.putBoolean(KEY_SCREENSAVER, screensaverOn)
.apply()
// Apply FLAG_KEEP_SCREEN_ON immediately based on new setting
if (screensaverOn) {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
// Screen always stays on in kiosk mode — no FLAG_KEEP_SCREEN_ON change needed here.
// Push screensaver preference to the webapp so the in-app clock overlay is toggled.
Thread {
try {
val apiUrl = "$url/api/index.php?action=save_settings"
val body = "{\"screensaver_enabled\":$screensaverOn}"
val conn = (java.net.URL(apiUrl).openConnection() as java.net.HttpURLConnection).apply {
requestMethod = "POST"
setRequestProperty("Content-Type", "application/json")
connectTimeout = 5000
readTimeout = 5000
doOutput = true
}
conn.outputStream.use { it.write(body.toByteArray()) }
conn.inputStream.close()
conn.disconnect()
} catch (_: Exception) {}
}.start()
Toast.makeText(this, "Impostazioni salvate", Toast.LENGTH_SHORT).show()
finish()
}
@@ -1068,31 +1068,35 @@ class SetupActivity : AppCompatActivity() {
private fun finishSetup() {
prefs.edit().putBoolean(KEY_SETUP_COMPLETE, true).apply()
// ── Pre-configure Scale Gateway URL in webapp settings ──────────────────
// If the user has a scale and the gateway is installed, write the WebSocket
// URL and enable the scale in the webapp's server settings (.env via API)
// so the webapp works out-of-the-box without manual settings configuration.
if (prefs.getBoolean(KEY_HAS_SCALE, false) && isGatewayInstalled()) {
val baseUrl = (prefs.getString(KEY_URL, "") ?: "").trimEnd('/')
if (baseUrl.isNotEmpty()) {
val gwUrl = "ws://127.0.0.1:8765"
Thread {
try {
val url = "$baseUrl/api/index.php?action=save_settings"
val body = """{"scale_enabled":true,"scale_gateway_url":"$gwUrl"}"""
val conn = (java.net.URL(url).openConnection() as java.net.HttpURLConnection).apply {
requestMethod = "POST"
setRequestProperty("Content-Type", "application/json")
connectTimeout = 5000
readTimeout = 5000
doOutput = true
// ── Sync settings to webapp API ─────────────────────────────────────────
// Always push: screensaver_enabled (in-app clock overlay preference).
// Conditionally add: scale settings when gateway is installed.
val baseUrl = (prefs.getString(KEY_URL, "") ?: "").trimEnd('/')
if (baseUrl.isNotEmpty()) {
val hasScale = prefs.getBoolean(KEY_HAS_SCALE, false) && isGatewayInstalled()
val screensaver = prefs.getBoolean(KEY_SCREENSAVER, false)
Thread {
try {
val url = "$baseUrl/api/index.php?action=save_settings"
val body = buildString {
append("{\"screensaver_enabled\":$screensaver")
if (hasScale) {
append(",\"scale_enabled\":true,\"scale_gateway_url\":\"ws://127.0.0.1:8765\"")
}
conn.outputStream.use { it.write(body.toByteArray()) }
conn.inputStream.close()
conn.disconnect()
} catch (_: Exception) {}
}.start()
}
append("}")
}
val conn = (java.net.URL(url).openConnection() as java.net.HttpURLConnection).apply {
requestMethod = "POST"
setRequestProperty("Content-Type", "application/json")
connectTimeout = 5000
readTimeout = 5000
doOutput = true
}
conn.outputStream.use { it.write(body.toByteArray()) }
conn.inputStream.close()
conn.disconnect()
} catch (_: Exception) {}
}.start()
}
setResult(RESULT_OK)
finish()
@@ -1148,7 +1152,33 @@ class SetupActivity : AppCompatActivity() {
getString(R.string.install_success_detail), 0xFF34d399.toInt(), btnEnabled = false)
Handler(Looper.getMainLooper()).postDelayed({ checkGatewayStatus() }, 1500)
} else {
checkGatewayStatus()
// Install failed or user cancelled. Show an explicit retry button
// that re-launches the system installer directly (skipping PackageInstaller,
// which is known to give STATUS=1 on this device).
val retryFile = pendingInstallFile
val retryPkg = pendingInstallPkg
setGatewayUI(
"⚠️",
"Installazione non completata",
"L'app non risulta installata. Premi il pulsante sotto per riprovare.",
0xFFfbbf24.toInt()
)
btnInstallGateway.visibility = View.VISIBLE
btnInstallGateway.text = "🔄 Riprova installazione"
btnInstallGateway.setOnClickListener {
// Reset button back to default before retrying
btnInstallGateway.text = "📥 Installa Scale Gateway"
btnInstallGateway.setOnClickListener {
pendingApkDownloadUrl = GATEWAY_DOWNLOAD_URL
triggerApkDownload(GATEWAY_DOWNLOAD_URL)
}
if (retryFile != null && retryFile.exists()) {
tryFallbackInstall(retryFile, retryPkg)
} else {
pendingApkDownloadUrl = GATEWAY_DOWNLOAD_URL
triggerApkDownload(GATEWAY_DOWNLOAD_URL)
}
}
}
}, 800)
}
@@ -1162,7 +1192,9 @@ class SetupActivity : AppCompatActivity() {
)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/vnd.android.package-archive")
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK
// Note: do NOT add FLAG_ACTIVITY_NEW_TASK — it breaks startActivityForResult:
// Android would return RESULT_CANCELED immediately without waiting for the user.
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
pendingInstallFile = file
pendingInstallPkg = targetPkg
@@ -985,7 +985,7 @@
android:id="@+id/tvScreensaverDesc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Mostra un orologio con fatti utili dopo 5 minuti di inattività. Di default è disattivato (lo schermo resta sempre acceso)."
android:text="Dopo 5 minuti di inattività mostra un overlay con l'orologio e informazioni utili (statistiche, piano pasti). Lo schermo rimane SEMPRE acceso — questa opzione riguarda solo l'overlay visivo in-app."
android:textColor="#94a3b8"
android:textSize="15sp"
android:gravity="center"
@@ -59,10 +59,10 @@
<string name="wizard_server_error">Server not reachable ⚠️</string>
<string name="wizard_server_error_detail">Install errors won\'t reach GitHub Issues. Check the URL entered in step 2.</string>
<!-- Screensaver step -->
<string name="setup_screensaver_title">Screensaver</string>
<string name="setup_screensaver_title">Salvaschermo in-app</string>
<string name="setup_screensaver_desc">Shows a clock with useful facts after 5 minutes of inactivity. Off by default (screen stays always on).</string>
<string name="setup_screensaver_toggle_label">Enable screensaver</string>
<string name="setup_screensaver_toggle_hint">If disabled, the screen stays always on.</string>
<string name="setup_screensaver_toggle_label">Abilita salvaschermo orologio</string>
<string name="setup_screensaver_toggle_hint">Mostra l&#39;overlay orologio dopo 5 min. Lo schermo resta sempre acceso.</string>
<!-- Summary -->
<string name="summary_lang">Language</string>