-
Notifications
You must be signed in to change notification settings - Fork 188
System Host
SystemHost, from floatingx-system: a real WindowManager window that can be shown outside your
app. This page covers the three permission strategies and downgrading, LayoutParams customisation,
keyboard and back key, and installing from a Service.
SystemHost attaches the container to the WindowManager as a standalone system window, so it can
sit on top of other apps. It only needs an application context and does not depend on an
Activity, which means it can be installed from a Service (#192).
The module's manifest already declares the SYSTEM_ALERT_WINDOW permission and the transparent
permission-request Activity — you don't have to configure anything.
FloatingX.install("sys") {
layout(R.layout.fx_input)
anchor(FxGravity.TOP_START, dx = 24f, dy = 200f)
adsorb(FxAdsorb.Edges(setOf(FxEdge.START, FxEdge.END)))
systemHost(app) {
permission(FxPermissionStrategy.auto()) // default: request automatically
// fall back to an app-level window when permission is denied (2.x's SYSTEM_AUTO)
fallback(AppHost.builder(app).build())
layoutParams { it.alpha = 0.9f } // runs after the defaults, may override any field
keyboard(R.id.etInput) // touching these EditTexts makes the window focusable
onBackPressed { true } // only delivered while the keyboard is up
}
}.show()| Strategy | Behaviour |
|---|---|
FxPermissionStrategy.auto() |
Default. Requests via a transparent Activity; on denial falls back to fallback (stays INSTALLED if none) |
FxPermissionStrategy.manual { request -> … } |
You decide: request.proceed() to request / useFallback() to downgrade / deny() to give up |
FxPermissionStrategy.skip() |
Attach the window without checking (you requested it yourself, or the type needs no permission) |
Of the three methods on the FxPermissionRequest handed to manual, call exactly one:
systemHost(app) {
permission(
FxPermissionStrategy.manual { request ->
when {
userAgreed -> request.proceed() // open the system settings page
canDowngrade -> request.useFallback() // downgrade straight to the fallback host
else -> request.deny() // give up: no downgrade, stays INSTALLED
}
},
)
fallback(AppHost.builder(app).build())
}Once permission is granted after a denial, call retryPermission() to recover:
(control.host as? SystemHost)?.retryPermission()With fallback(...) configured, a denial triggers a requestSwap to that host (usually an
AppHost): the container is swapped, but the config, listeners, features and current position are
all kept — this is 2.x's SYSTEM_AUTO. Without a fallback it stays INSTALLED; call
retryPermission() once you have the permission.
systemHost(app) {
layoutParams { lp ->
lp.alpha = 0.9f
lp.flags = lp.flags or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
}
}The customizer runs after the default LayoutParams, so it may override any field (type /
flags / alpha …). SystemLayoutParamsCustomizer is a fun interface, so Java can pass a lambda.
System windows carry FLAG_NOT_FOCUSABLE by default (they must not steal focus, or they would block
input in the app below). Register the EditText ids inside your content with keyboard(...), and the
window becomes temporarily focusable when one of them is touched, bringing up the soft keyboard:
systemHost(app) {
keyboard(R.id.etInput) // vararg: register as many EditText ids as you need
onBackPressed { // only delivered while the window is focusable (keyboard up)
true // return true to consume it
}
}The back press that dismisses the keyboard is swallowed by the system and never reaches
onBackPressed.
Just like the app-level window, the content is created with an application context, and Material components need a Material theme:
systemHost(app) { theme(R.style.Theme_App) }SystemHost only needs an application context, so installing from a foreground Service is a fully
supported use case (#192):
class DemoService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startAsForeground() // on API 34+ a foreground Service must declare a foregroundServiceType matching the manifest
FloatingX.install("sys") { /* … */ systemHost(application) { } }.show()
return START_NOT_STICKY
}
}Two system restrictions to keep in mind:
-
Since Android 10 (Q) the background cannot start Activities: while the app is in the
background, the request page of the
auto()strategy may show nothing at all. For genuine background scenarios usemanual {}/skip()to defer the request and callretryPermission()once you are back in the foreground. -
Since Android 13 (T) notifications need user consent: without it
startForegroundstill succeeds, the notification just isn't displayed.
The window's lifetime belongs to the FloatingX registry (by tag) and does not follow the
Service — it stays alive when the Service is destroyed. Call control.cancel() or
FloatingX.uninstall(tag) yourself when you want it gone.
SystemHost host = SystemHost.builder(app)
.layoutParams(lp -> lp.alpha = 0.9f)
.permission(FxPermissionStrategy.auto())
.fallback(AppHost.builder(app).build())
.build();
FxControl control = FloatingX.install("java-system", config, host);
control.show();WindowManager.getCurrentWindowMetrics(), the only public entry point for screen-level insets, was
added in API 30 (R). Below R, SystemHost cannot obtain a safe area, so safeArea has no effect
(the usable area is the whole screen). Reserve the space yourself with margin(top = …) if you need
to avoid the status bar or cutout on older versions. More on FAQ.
Back to Home · Related: App Host · Configuration · FAQ