I want to open my app and see something from it (for example a widget) that will be available everywhere, not only when the app is opened
Example:
Note that I am on the desktop page, and app is not opened, but in is active in background and shows this "widget" with Hello
text everywhere
How to show a view when an android app is not active/focused?
Asked Answered
Add android.permission.SYSTEM_ALERT_WINDOW
permission to AndroidManifest.xml
// AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.freephoenix888.savemylife">
// Something else
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
// Something else
</manifest>
Note: Do not forget to request this permission from a user Documentation
Create a class that is implementing SavedStateRegistryOwner
internal class MyLifecycleOwner : SavedStateRegistryOwner {
private var mLifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
private var mSavedStateRegistryController: SavedStateRegistryController = SavedStateRegistryController.create(this)
val isInitialized: Boolean
get() = true
override val savedStateRegistry: SavedStateRegistry
get() = mSavedStateRegistryController.savedStateRegistry
override fun getLifecycle(): Lifecycle {
return mLifecycleRegistry
}
fun setCurrentState(state: Lifecycle.State) {
mLifecycleRegistry.currentState = state
}
fun handleLifecycleEvent(event: Lifecycle.Event) {
mLifecycleRegistry.handleLifecycleEvent(event)
}
fun performRestore(savedState: Bundle?) {
mSavedStateRegistryController.performRestore(savedState)
}
fun performSave(outBundle: Bundle) {
mSavedStateRegistryController.performSave(outBundle)
}
}
Note: Possibly it is better to inherit this class in the service if you are showing an overlay from a service. Write me in comments if you think it is better
Add your view in an activity or a service
val layoutFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
WindowManager.LayoutParams.TYPE_PHONE
}
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
layoutFlag,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
/* For views (not compose views)
val floatView = (getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater).inflate(R.layout.view_service_float, null)
*/
val composeView = ComposeView(this)
composeView.setContent {
Text(
text = "Hello",
color = Color.Black,
fontSize = 50.sp,
modifier = Modifier
.wrapContentSize()
.background(Color.Green)
)
}
val lifecycleOwner = MyLifecycleOwner()
lifecycleOwner.performRestore(null)
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
ViewTreeLifecycleOwner.set(composeView, lifecycleOwner)
composeView.setViewTreeSavedStateRegistryOwner(lifecycleOwner)
val viewModelStore = ViewModelStore()
ViewTreeViewModelStoreOwner.set(composeView) { viewModelStore }
val coroutineContext = AndroidUiDispatcher.CurrentThread
val runRecomposeScope = CoroutineScope(coroutineContext)
val recomposer = Recomposer(coroutineContext)
composeView.compositionContext = recomposer
runRecomposeScope.launch {
recomposer.runRecomposeAndApplyChanges()
}
windowManager.addView(composeView, params)
very nice finding, thanks for sharing the answer –
Tseng
© 2022 - 2024 — McMap. All rights reserved.