feat(kiosk): true kiosk mode, gateway bg launch, update checks, wizard fix v1.2.0
- Screen pinning (startLockTask) blocks home/recent buttons - Gateway launches in background, kiosk returns to front after 1.5s - Injected thin green bar at top of WebView for triple-tap exit - JavaScript bridge for kiosk exit from WebView context - Update check via GitHub releases API (every 6h) - Shows banner in WebView when kiosk/gateway updates available - Setup wizard no longer re-appears after completion/skip (evershelf_setup_done flag) - REORDER_TASKS permission for moveTaskToFront - singleTask launch mode for proper kiosk behavior - Version bumped to 1.2.0 (versionCode 3)
This commit is contained in:
+9
-5
@@ -9810,15 +9810,19 @@ function _getMissingSetupSteps(serverSettings) {
|
|||||||
const missing = [];
|
const missing = [];
|
||||||
const s = getSettings();
|
const s = getSettings();
|
||||||
const srv = serverSettings || {};
|
const srv = serverSettings || {};
|
||||||
|
const setupDone = localStorage.getItem('evershelf_setup_done');
|
||||||
|
|
||||||
// Step 0 — language: missing only if never set at all (fresh install)
|
// Step 0 — language: missing only if never set at all (fresh install)
|
||||||
if (!localStorage.getItem('evershelf_lang') && !localStorage.getItem('evershelf_setup_done')) {
|
if (!localStorage.getItem('evershelf_lang') && !setupDone) {
|
||||||
missing.push(0);
|
missing.push(0);
|
||||||
}
|
}
|
||||||
// Step 1 — Gemini API key (check both localStorage and server .env)
|
// Steps 1 & 2 only show on first run (before setup is completed/skipped)
|
||||||
if (!s.gemini_key && !srv.gemini_key && !srv.gemini_key_set) missing.push(1);
|
if (!setupDone) {
|
||||||
// Step 2 — Bring! credentials (check both localStorage and server .env)
|
// Step 1 — Gemini API key (check both localStorage and server .env)
|
||||||
if ((!s.bring_email && !srv.bring_email) || (!s.bring_password && !srv.bring_password_set)) missing.push(2);
|
if (!s.gemini_key && !srv.gemini_key && !srv.gemini_key_set) missing.push(1);
|
||||||
|
// Step 2 — Bring! credentials (check both localStorage and server .env)
|
||||||
|
if ((!s.bring_email && !srv.bring_email) || (!s.bring_password && !srv.bring_password_set)) missing.push(2);
|
||||||
|
}
|
||||||
// Note: step 3 (done screen) gets appended automatically when there are missing steps
|
// Note: step 3 (done screen) gets appended automatically when there are missing steps
|
||||||
|
|
||||||
return missing;
|
return missing;
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ android {
|
|||||||
applicationId = "it.dadaloop.evershelf.kiosk"
|
applicationId = "it.dadaloop.evershelf.kiosk"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 2
|
versionCode = 3
|
||||||
versionName = "1.1.0"
|
versionName = "1.2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
<!-- Keep screen on -->
|
<!-- Keep screen on -->
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
|
||||||
|
<!-- Move task to front (bring kiosk back after gateway launch) -->
|
||||||
|
<uses-permission android:name="android.permission.REORDER_TASKS" />
|
||||||
|
|
||||||
<!-- Query gateway app visibility (required Android 11+) -->
|
<!-- Query gateway app visibility (required Android 11+) -->
|
||||||
<queries>
|
<queries>
|
||||||
<package android:name="it.dadaloop.evershelf.scalegate" />
|
<package android:name="it.dadaloop.evershelf.scalegate" />
|
||||||
@@ -26,6 +29,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".KioskActivity"
|
android:name=".KioskActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
android:launchMode="singleTask"
|
||||||
android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
|
android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package it.dadaloop.evershelf.kiosk
|
package it.dadaloop.evershelf.kiosk
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.ActivityManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
@@ -33,6 +34,7 @@ import android.widget.TextView
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import org.json.JSONObject
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import javax.net.ssl.HttpsURLConnection
|
import javax.net.ssl.HttpsURLConnection
|
||||||
import javax.net.ssl.SSLContext
|
import javax.net.ssl.SSLContext
|
||||||
@@ -74,7 +76,9 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
private const val KEY_SETUP_COMPLETE = "setup_complete"
|
private const val KEY_SETUP_COMPLETE = "setup_complete"
|
||||||
private const val GATEWAY_PACKAGE = "it.dadaloop.evershelf.scalegate"
|
private const val GATEWAY_PACKAGE = "it.dadaloop.evershelf.scalegate"
|
||||||
private const val GATEWAY_DOWNLOAD_URL = "https://github.com/dadaloop82/EverShelf/releases/latest/download/evershelf-scale-gateway.apk"
|
private const val GATEWAY_DOWNLOAD_URL = "https://github.com/dadaloop82/EverShelf/releases/latest/download/evershelf-scale-gateway.apk"
|
||||||
|
private const val KIOSK_DOWNLOAD_URL = "https://github.com/dadaloop82/EverShelf/releases/latest/download/evershelf-kiosk.apk"
|
||||||
private const val SPLASH_DURATION = 1500L
|
private const val SPLASH_DURATION = 1500L
|
||||||
|
private const val GITHUB_RELEASES_API = "https://api.github.com/repos/dadaloop82/EverShelf/releases/latest"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -84,6 +88,7 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
bindViews()
|
bindViews()
|
||||||
enterImmersiveMode()
|
enterImmersiveMode()
|
||||||
|
enableKioskLock()
|
||||||
|
|
||||||
// Show splash then proceed
|
// Show splash then proceed
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
@@ -143,21 +148,19 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
goToStep(2)
|
goToStep(2)
|
||||||
}
|
}
|
||||||
findViewById<MaterialButton>(R.id.btnFinish).setOnClickListener {
|
findViewById<MaterialButton>(R.id.btnFinish).setOnClickListener {
|
||||||
launchGatewayIfInstalled()
|
launchGatewayInBackground()
|
||||||
finishWizard()
|
finishWizard()
|
||||||
}
|
}
|
||||||
findViewById<MaterialButton>(R.id.btnSkipScale).setOnClickListener {
|
findViewById<MaterialButton>(R.id.btnSkipScale).setOnClickListener {
|
||||||
finishWizard()
|
finishWizard()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings — triple-tap to exit
|
||||||
btnSettings.setOnClickListener {
|
btnSettings.setOnClickListener {
|
||||||
startActivity(Intent(this, SettingsActivity::class.java))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triple-tap on settings gear to exit
|
|
||||||
btnSettings.setOnLongClickListener {
|
|
||||||
handleTripleTap()
|
handleTripleTap()
|
||||||
|
}
|
||||||
|
btnSettings.setOnLongClickListener {
|
||||||
|
startActivity(Intent(this, SettingsActivity::class.java))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,10 +178,32 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
tapHandler.removeCallbacks(tapResetRunnable)
|
tapHandler.removeCallbacks(tapResetRunnable)
|
||||||
tapHandler.postDelayed(tapResetRunnable, 800)
|
tapHandler.postDelayed(tapResetRunnable, 800)
|
||||||
|
|
||||||
if (tapCount >= 3) {
|
when (tapCount) {
|
||||||
tapCount = 0
|
1 -> {} // silent
|
||||||
Toast.makeText(this, "Exiting kiosk mode...", Toast.LENGTH_SHORT).show()
|
2 -> Toast.makeText(this, "Tap once more to exit kiosk", Toast.LENGTH_SHORT).show()
|
||||||
finishAffinity()
|
3 -> {
|
||||||
|
tapCount = 0
|
||||||
|
disableKioskLock()
|
||||||
|
Toast.makeText(this, "Exiting kiosk mode...", Toast.LENGTH_SHORT).show()
|
||||||
|
finishAffinity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Kiosk Lock (pin app) ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
private fun enableKioskLock() {
|
||||||
|
// Screen pinning (task lock) — prevents home/recent buttons
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
startLockTask()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disableKioskLock() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
try {
|
||||||
|
stopLockTask()
|
||||||
|
} catch (_: Exception) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,28 +276,30 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun launchGatewayIfInstalled() {
|
private fun launchGatewayInBackground() {
|
||||||
if (isGatewayInstalled()) {
|
if (!isGatewayInstalled()) return
|
||||||
val launchIntent = packageManager.getLaunchIntentForPackage(GATEWAY_PACKAGE)
|
val launchIntent = packageManager.getLaunchIntentForPackage(GATEWAY_PACKAGE) ?: return
|
||||||
if (launchIntent != null) {
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
|
||||||
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
startActivity(launchIntent)
|
||||||
startActivity(launchIntent)
|
// Bring kiosk back to foreground after gateway launches
|
||||||
}
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
}
|
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||||
|
am.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME)
|
||||||
|
}, 1500)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkGatewayStatus() {
|
private fun checkGatewayStatus() {
|
||||||
if (isGatewayInstalled()) {
|
if (isGatewayInstalled()) {
|
||||||
scaleStatusIcon.text = "✅"
|
scaleStatusIcon.text = "✅"
|
||||||
scaleStatusText.text = "Scale Gateway is installed"
|
scaleStatusText.text = "Scale Gateway is installed"
|
||||||
scaleStatusDetail.text = "It will be launched automatically when you finish setup"
|
scaleStatusDetail.text = "It will be launched in the background when you proceed"
|
||||||
scaleStatusDetail.setTextColor(0xFF34d399.toInt())
|
scaleStatusDetail.setTextColor(0xFF34d399.toInt())
|
||||||
findViewById<MaterialButton>(R.id.btnSkipScale).visibility = View.GONE
|
findViewById<MaterialButton>(R.id.btnSkipScale).visibility = View.GONE
|
||||||
findViewById<MaterialButton>(R.id.btnFinish).text = "🚀 Launch EverShelf"
|
findViewById<MaterialButton>(R.id.btnFinish).text = "🚀 Launch EverShelf"
|
||||||
} else {
|
} else {
|
||||||
scaleStatusIcon.text = "📥"
|
scaleStatusIcon.text = "📥"
|
||||||
scaleStatusText.text = "Scale Gateway not installed"
|
scaleStatusText.text = "Scale Gateway not installed"
|
||||||
scaleStatusDetail.text = "You need the EverShelf Scale Gateway app to use a Bluetooth scale"
|
scaleStatusDetail.text = "Install the Scale Gateway app to use a Bluetooth scale"
|
||||||
scaleStatusDetail.setTextColor(0xFFfbbf24.toInt())
|
scaleStatusDetail.setTextColor(0xFFfbbf24.toInt())
|
||||||
|
|
||||||
findViewById<MaterialButton>(R.id.btnFinish).text = "🚀 Launch without scale"
|
findViewById<MaterialButton>(R.id.btnFinish).text = "🚀 Launch without scale"
|
||||||
@@ -301,7 +328,6 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
Thread {
|
Thread {
|
||||||
try {
|
try {
|
||||||
// Test the base URL directly (not /api/)
|
|
||||||
val conn = URL(url).openConnection()
|
val conn = URL(url).openConnection()
|
||||||
|
|
||||||
if (conn is HttpsURLConnection) {
|
if (conn is HttpsURLConnection) {
|
||||||
@@ -362,6 +388,7 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
settings.domStorageEnabled = true
|
settings.domStorageEnabled = true
|
||||||
settings.mediaPlaybackRequiresUserGesture = false
|
settings.mediaPlaybackRequiresUserGesture = false
|
||||||
settings.allowFileAccess = true
|
settings.allowFileAccess = true
|
||||||
|
settings.mixedContentMode = android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
||||||
|
|
||||||
webView.webViewClient = object : WebViewClient() {
|
webView.webViewClient = object : WebViewClient() {
|
||||||
override fun onReceivedSslError(
|
override fun onReceivedSslError(
|
||||||
@@ -378,6 +405,14 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
view?.loadData(errorPageHtml(), "text/html", "UTF-8")
|
view?.loadData(errorPageHtml(), "text/html", "UTF-8")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPageFinished(view: WebView?, url: String?) {
|
||||||
|
super.onPageFinished(view, url)
|
||||||
|
// Inject triple-tap exit on the header bar
|
||||||
|
injectKioskOverlay()
|
||||||
|
// Check for updates periodically
|
||||||
|
checkForUpdates()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webView.webChromeClient = object : WebChromeClient() {
|
webView.webChromeClient = object : WebChromeClient() {
|
||||||
@@ -403,13 +438,132 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
val url = prefs.getString(KEY_URL, "http://evershelf.local") ?: "http://evershelf.local"
|
val url = prefs.getString(KEY_URL, "http://evershelf.local") ?: "http://evershelf.local"
|
||||||
webView.loadUrl(url)
|
webView.loadUrl(url)
|
||||||
|
|
||||||
// Launch gateway if installed
|
// Launch gateway in background
|
||||||
launchGatewayIfInstalled()
|
launchGatewayInBackground()
|
||||||
|
|
||||||
// Keep screen on
|
// Keep screen on
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Inject kiosk overlay (triple-tap exit zone) ───────────────────────
|
||||||
|
|
||||||
|
private fun injectKioskOverlay() {
|
||||||
|
val js = """
|
||||||
|
(function() {
|
||||||
|
if (document.getElementById('_kiosk_exit_zone')) return;
|
||||||
|
var zone = document.createElement('div');
|
||||||
|
zone.id = '_kiosk_exit_zone';
|
||||||
|
zone.style.cssText = 'position:fixed;top:0;left:0;right:0;height:6px;z-index:999999;background:linear-gradient(90deg,#059669,#10B981);cursor:pointer;';
|
||||||
|
var count = 0, timer = null;
|
||||||
|
zone.addEventListener('click', function() {
|
||||||
|
count++;
|
||||||
|
clearTimeout(timer);
|
||||||
|
timer = setTimeout(function(){ count=0; }, 800);
|
||||||
|
if (count === 2) {
|
||||||
|
var toast = document.createElement('div');
|
||||||
|
toast.style.cssText = 'position:fixed;top:12px;left:50%;transform:translateX(-50%);background:#1e293b;color:#f1f5f9;padding:8px 20px;border-radius:8px;font-size:13px;z-index:9999999;box-shadow:0 4px 12px rgba(0,0,0,0.3);';
|
||||||
|
toast.textContent = 'Tap once more to exit kiosk';
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
setTimeout(function(){ toast.remove(); }, 2000);
|
||||||
|
}
|
||||||
|
if (count >= 3) {
|
||||||
|
count = 0;
|
||||||
|
window._kioskExit && window._kioskExit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.body.appendChild(zone);
|
||||||
|
})();
|
||||||
|
""".trimIndent()
|
||||||
|
webView.evaluateJavascript(js, null)
|
||||||
|
|
||||||
|
// Add JS interface for exit
|
||||||
|
webView.addJavascriptInterface(object {
|
||||||
|
@android.webkit.JavascriptInterface
|
||||||
|
fun exit() {
|
||||||
|
runOnUiThread {
|
||||||
|
disableKioskLock()
|
||||||
|
Toast.makeText(this@KioskActivity, "Exiting kiosk mode...", Toast.LENGTH_SHORT).show()
|
||||||
|
finishAffinity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "_kioskBridge")
|
||||||
|
|
||||||
|
// Connect the overlay to the bridge
|
||||||
|
webView.evaluateJavascript("window._kioskExit = function() { _kioskBridge.exit(); };", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Update Check ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private fun checkForUpdates() {
|
||||||
|
val lastCheck = prefs.getLong("last_update_check", 0)
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
// Check at most once every 6 hours
|
||||||
|
if (now - lastCheck < 6 * 60 * 60 * 1000) return
|
||||||
|
prefs.edit().putLong("last_update_check", now).apply()
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
try {
|
||||||
|
val conn = URL(GITHUB_RELEASES_API).openConnection() as java.net.HttpURLConnection
|
||||||
|
conn.setRequestProperty("Accept", "application/vnd.github+json")
|
||||||
|
conn.connectTimeout = 5000
|
||||||
|
conn.readTimeout = 5000
|
||||||
|
val body = conn.inputStream.bufferedReader().readText()
|
||||||
|
conn.disconnect()
|
||||||
|
val json = JSONObject(body)
|
||||||
|
val latestTag = json.optString("tag_name", "")
|
||||||
|
|
||||||
|
// Check kiosk APK version
|
||||||
|
val currentKiosk = try {
|
||||||
|
packageManager.getPackageInfo(packageName, 0).versionName ?: ""
|
||||||
|
} catch (_: Exception) { "" }
|
||||||
|
|
||||||
|
// Check gateway APK version
|
||||||
|
val currentGateway = try {
|
||||||
|
packageManager.getPackageInfo(GATEWAY_PACKAGE, 0).versionName ?: ""
|
||||||
|
} catch (_: Exception) { null }
|
||||||
|
|
||||||
|
var updateMsg = ""
|
||||||
|
// If the release has kiosk or gateway assets with newer versions
|
||||||
|
val assets = json.optJSONArray("assets")
|
||||||
|
if (assets != null) {
|
||||||
|
for (i in 0 until assets.length()) {
|
||||||
|
val asset = assets.getJSONObject(i)
|
||||||
|
val name = asset.optString("name", "")
|
||||||
|
if (name.contains("kiosk") && latestTag.isNotEmpty() &&
|
||||||
|
latestTag != currentKiosk && latestTag != "v$currentKiosk") {
|
||||||
|
updateMsg += "• Kiosk update available: $latestTag\n"
|
||||||
|
}
|
||||||
|
if (name.contains("gateway") && currentGateway != null &&
|
||||||
|
latestTag.isNotEmpty() && latestTag != currentGateway &&
|
||||||
|
latestTag != "v$currentGateway") {
|
||||||
|
updateMsg += "• Gateway update available: $latestTag\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateMsg.isNotEmpty()) {
|
||||||
|
runOnUiThread { showUpdateBanner(updateMsg.trim()) }
|
||||||
|
}
|
||||||
|
} catch (_: Exception) { }
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showUpdateBanner(message: String) {
|
||||||
|
val js = """
|
||||||
|
(function() {
|
||||||
|
if (document.getElementById('_kiosk_update_banner')) return;
|
||||||
|
var banner = document.createElement('div');
|
||||||
|
banner.id = '_kiosk_update_banner';
|
||||||
|
banner.style.cssText = 'position:fixed;bottom:0;left:0;right:0;background:#1e293b;color:#fbbf24;padding:10px 16px;font-size:13px;z-index:999998;display:flex;align-items:center;justify-content:space-between;border-top:2px solid #fbbf24;';
|
||||||
|
banner.innerHTML = '<span>⬆️ ${message.replace("\n", "<br>")}</span><button onclick="this.parentElement.remove()" style="background:none;border:none;color:#64748b;font-size:18px;cursor:pointer;">✕</button>';
|
||||||
|
document.body.appendChild(banner);
|
||||||
|
})();
|
||||||
|
""".trimIndent()
|
||||||
|
webView.evaluateJavascript(js, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Error Page ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private fun errorPageHtml(): String {
|
private fun errorPageHtml(): String {
|
||||||
val url = prefs.getString(KEY_URL, "") ?: ""
|
val url = prefs.getString(KEY_URL, "") ?: ""
|
||||||
return """
|
return """
|
||||||
@@ -492,5 +646,6 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
if (webView.visibility == View.VISIBLE && webView.canGoBack()) {
|
if (webView.visibility == View.VISIBLE && webView.canGoBack()) {
|
||||||
webView.goBack()
|
webView.goBack()
|
||||||
}
|
}
|
||||||
|
// Block back button in kiosk mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user