diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9a40236..4387fae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,3 +1,33 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/cz/c3c/webviewkiosk/MainActivity.kt b/app/src/main/java/cz/c3c/webviewkiosk/MainActivity.kt new file mode 100644 index 0000000..f9a141f --- /dev/null +++ b/app/src/main/java/cz/c3c/webviewkiosk/MainActivity.kt @@ -0,0 +1,87 @@ +package cz.c3c.webviewkiosk + +import android.annotation.SuppressLint +import android.app.Activity +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.View +import android.view.WindowManager +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest +import android.webkit.WebSettings +import android.webkit.WebView +import android.webkit.WebViewClient + +class MainActivity : Activity() { + + companion object { + const val DASHBOARD_URL = + "https://grafana.c3c.cz/public-dashboards/381fe3e71e164eb99dd0b10e246a36e2" + } + + private lateinit var webView: WebView + private val handler = Handler(Looper.getMainLooper()) + private val backoff = BackoffPolicy(initialDelayMs = 2_000, maxDelayMs = 60_000) + private var lastLoadFailed = false + + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + + webView = WebView(this) + webView.settings.apply { + javaScriptEnabled = true + domStorageEnabled = true + cacheMode = WebSettings.LOAD_DEFAULT + mediaPlaybackRequiresUserGesture = false + } + webView.webViewClient = object : WebViewClient() { + override fun onPageFinished(view: WebView, url: String) { + // onPageFinished also fires after a failed load (error page), + // so only treat a clean finish as recovery. + if (!lastLoadFailed) backoff.reset() + lastLoadFailed = false + } + + override fun onReceivedError( + view: WebView, + request: WebResourceRequest, + error: WebResourceError, + ) { + // Subresource failures (one panel's query, a font) must not + // tear down the whole page; only main-frame failures retry. + if (!request.isForMainFrame) return + lastLoadFailed = true + handler.postDelayed( + { view.loadUrl(DASHBOARD_URL) }, + backoff.nextDelayMs(), + ) + } + } + + setContentView(webView) + hideSystemUi() + webView.loadUrl(DASHBOARD_URL) + } + + override fun onResume() { + super.onResume() + hideSystemUi() + } + + private fun hideSystemUi() { + @Suppress("DEPRECATION") // WindowInsetsController needs API 30; minSdk is 26 + window.decorView.systemUiVisibility = + View.SYSTEM_UI_FLAG_FULLSCREEN or + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + + override fun onDestroy() { + handler.removeCallbacksAndMessages(null) + webView.destroy() + super.onDestroy() + } +} diff --git a/app/src/main/res/drawable/banner.png b/app/src/main/res/drawable/banner.png new file mode 100644 index 0000000..1660719 Binary files /dev/null and b/app/src/main/res/drawable/banner.png differ diff --git a/app/src/main/res/drawable/icon.png b/app/src/main/res/drawable/icon.png new file mode 100644 index 0000000..079ba00 Binary files /dev/null and b/app/src/main/res/drawable/icon.png differ