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:
@@ -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) ────────────────────
|
||||
|
||||
+18
-6
@@ -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'overlay orologio dopo 5 min. Lo schermo resta sempre acceso.</string>
|
||||
|
||||
<!-- Summary -->
|
||||
<string name="summary_lang">Language</string>
|
||||
|
||||
Reference in New Issue
Block a user