android: pantalla completa con margenes, teclado y descargas

El contenedor deja sitio a las barras del sistema y al teclado (Android 15
obliga con targetSdk 35). Las descargas van al gestor de Android. Fondo
blanco e iconos oscuros, como el tema Acampada.
This commit is contained in:
hacklab 2026-10-10 00:10:59 +02:00 • committed by oasis-bot
parent ba057f0092
commit 99e5d766e9
3 changed files with 71 additions and 6 deletions

View file

@ -8,6 +8,8 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- solo para guardar descargas en Android 9 o anterior; desde el 10 no hace falta -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
@ -50,7 +52,8 @@
android:name="net.laenre.oasis.MainActivity"
android:exported="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|keyboardHidden|keyboard|navigation|uiMode|fontScale|layoutDirection"
android:launchMode="singleTask">
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View file

@ -1,24 +1,33 @@
package net.laenre.oasis
import android.Manifest
import android.app.DownloadManager
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.webkit.PermissionRequest
import android.webkit.URLUtil
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import com.solarnethub.oasis.BuildConfig
class MainActivity : AppCompatActivity() {
@ -57,7 +66,7 @@ class MainActivity : AppCompatActivity() {
startService(Intent(this, NodeService::class.java))
web = WebView(this)
setContentView(web)
setContentView(edgeToEdge(web))
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
web.settings.apply {
@ -143,9 +152,60 @@ class MainActivity : AppCompatActivity() {
}
}
// Lo que la pagina manda descargar (un PDF, un fichero adjunto) va al gestor de
// descargas de Android; sin esto el WebView no hace nada al tocar el enlace.
web.setDownloadListener { url, userAgent, disposition, mime, _ -> download(url, userAgent, disposition, mime) }
waitAndLoad()
}
/**
* La pantalla entera, por debajo de las barras del sistema (Android 15 lo impone
* con targetSdk 35, y en versiones anteriores se pide igual para que se vea lo
* mismo). El contenedor deja de margen lo que ocupan la barra de estado, la de
* navegacion, el recorte de la camara y el teclado cuando esta abierto, asi la
* barra de abajo de Oasis sube con el teclado en vez de quedar tapada.
* El fondo blanco y los iconos oscuros son los del tema Acampada.
*/
private fun edgeToEdge(content: WebView): FrameLayout {
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = Color.TRANSPARENT
window.navigationBarColor = Color.TRANSPARENT
val root = FrameLayout(this)
root.setBackgroundColor(Color.WHITE)
root.addView(content, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT))
WindowCompat.getInsetsController(window, root).apply {
isAppearanceLightStatusBars = true
isAppearanceLightNavigationBars = true
}
ViewCompat.setOnApplyWindowInsetsListener(root) { v, insets ->
val bars = insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
v.setPadding(bars.left, bars.top, bars.right, maxOf(bars.bottom, ime.bottom))
WindowInsetsCompat.CONSUMED
}
return root
}
/** Descarga por el gestor de Android, a la carpeta Descargas, con aviso al terminar. */
private fun download(url: String, userAgent: String?, disposition: String?, mime: String?) {
try {
val name = URLUtil.guessFileName(url, disposition, mime)
val req = DownloadManager.Request(Uri.parse(url))
.setTitle(name)
.setMimeType(mime)
.addRequestHeader("User-Agent", userAgent ?: "")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, name)
(getSystemService(DOWNLOAD_SERVICE) as DownloadManager).enqueue(req)
Toast.makeText(this, name, Toast.LENGTH_SHORT).show()
} catch (e: Exception) {
Log.w("OasisNode", "no se pudo descargar ${'$'}url: ${'$'}e")
// si el gestor no puede, que lo abra otra aplicacion
try { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) } catch (_: Exception) {}
}
}
private fun has(p: String) =
ContextCompat.checkSelfPermission(this, p) == PackageManager.PERMISSION_GRANTED
@ -158,9 +218,10 @@ class MainActivity : AppCompatActivity() {
val s = attempt / 2
web.loadDataWithBaseURL(null, """
<html><head><meta name='viewport' content='width=device-width,initial-scale=1'>
<style>body{background:#121212;color:#FFB400;font-family:sans-serif;display:flex;
<style>body{background:#fff;color:#000;font-family:sans-serif;display:flex;
height:100vh;margin:0;align-items:center;justify-content:center;text-align:center}
div{padding:24px}p{opacity:.7;font-size:14px;line-height:1.5}</style></head>
div{padding:24px}h2{text-transform:uppercase;border-bottom:3px solid #000;padding-bottom:6px}
p{font-size:15px;line-height:1.5}</style></head>
<body><div><h2>Oasis</h2>
<p>Preparando la aplicaci&oacute;n&hellip;<br>El primer arranque descomprime el
servidor y puede tardar un minuto. No hace falta hacer nada.</p><p>${s}s</p></div></body></html>

View file

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Oasis" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">#121212</item>
<item name="android:statusBarColor">#121212</item>
<item name="android:windowBackground">#FFFFFF</item>
<item name="android:statusBarColor">#FFFFFF</item>
<item name="android:windowLightStatusBar">true</item>
</style>
</resources>