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:
parent
ba057f0092
commit
99e5d766e9
3 changed files with 71 additions and 6 deletions
|
|
@ -8,6 +8,8 @@
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<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.CHANGE_WIFI_MULTICAST_STATE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<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.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
|
|
@ -50,7 +52,8 @@
|
||||||
android:name="net.laenre.oasis.MainActivity"
|
android:name="net.laenre.oasis.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|keyboardHidden|keyboard|navigation|uiMode|fontScale|layoutDirection"
|
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|keyboardHidden|keyboard|navigation|uiMode|fontScale|layoutDirection"
|
||||||
android:launchMode="singleTask">
|
android:launchMode="singleTask"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,33 @@
|
||||||
package net.laenre.oasis
|
package net.laenre.oasis
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.app.DownloadManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.webkit.PermissionRequest
|
import android.webkit.PermissionRequest
|
||||||
|
import android.webkit.URLUtil
|
||||||
import android.webkit.ValueCallback
|
import android.webkit.ValueCallback
|
||||||
import android.webkit.WebChromeClient
|
import android.webkit.WebChromeClient
|
||||||
import android.webkit.WebResourceError
|
import android.webkit.WebResourceError
|
||||||
import android.webkit.WebResourceRequest
|
import android.webkit.WebResourceRequest
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
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
|
import com.solarnethub.oasis.BuildConfig
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
@ -57,7 +66,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
startService(Intent(this, NodeService::class.java))
|
startService(Intent(this, NodeService::class.java))
|
||||||
|
|
||||||
web = WebView(this)
|
web = WebView(this)
|
||||||
setContentView(web)
|
setContentView(edgeToEdge(web))
|
||||||
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
|
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
|
||||||
|
|
||||||
web.settings.apply {
|
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()
|
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) =
|
private fun has(p: String) =
|
||||||
ContextCompat.checkSelfPermission(this, p) == PackageManager.PERMISSION_GRANTED
|
ContextCompat.checkSelfPermission(this, p) == PackageManager.PERMISSION_GRANTED
|
||||||
|
|
||||||
|
|
@ -158,9 +218,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
val s = attempt / 2
|
val s = attempt / 2
|
||||||
web.loadDataWithBaseURL(null, """
|
web.loadDataWithBaseURL(null, """
|
||||||
<html><head><meta name='viewport' content='width=device-width,initial-scale=1'>
|
<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}
|
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>
|
<body><div><h2>Oasis</h2>
|
||||||
<p>Preparando la aplicación…<br>El primer arranque descomprime el
|
<p>Preparando la aplicación…<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>
|
servidor y puede tardar un minuto. No hace falta hacer nada.</p><p>${s}s</p></div></body></html>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<style name="Theme.Oasis" parent="Theme.AppCompat.NoActionBar">
|
<style name="Theme.Oasis" parent="Theme.AppCompat.NoActionBar">
|
||||||
<item name="android:windowBackground">#121212</item>
|
<item name="android:windowBackground">#FFFFFF</item>
|
||||||
<item name="android:statusBarColor">#121212</item>
|
<item name="android:statusBarColor">#FFFFFF</item>
|
||||||
|
<item name="android:windowLightStatusBar">true</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue