import android.os.Bundle | |
import androidx.lifecycle.Lifecycle | |
import androidx.lifecycle.LifecycleRegistry | |
import androidx.savedstate.SavedStateRegistry | |
import androidx.savedstate.SavedStateRegistryController | |
import androidx.savedstate.SavedStateRegistryOwner | |
internal class MyLifecycleOwner : SavedStateRegistryOwner { | |
private var mLifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this) | |
private var mSavedStateRegistryController: SavedStateRegistryController = SavedStateRegistryController.create(this) | |
/** | |
* @return True if the Lifecycle has been initialized. | |
*/ | |
val isInitialized: Boolean | |
get() = true | |
override fun getLifecycle(): Lifecycle { | |
return mLifecycleRegistry | |
} | |
fun setCurrentState(state: Lifecycle.State) { | |
mLifecycleRegistry.currentState = state | |
} | |
fun handleLifecycleEvent(event: Lifecycle.Event) { | |
mLifecycleRegistry.handleLifecycleEvent(event) | |
} | |
override fun getSavedStateRegistry(): SavedStateRegistry { | |
return mSavedStateRegistryController.savedStateRegistry | |
} | |
fun performRestore(savedState: Bundle?) { | |
mSavedStateRegistryController.performRestore(savedState) | |
} | |
fun performSave(outBundle: Bundle) { | |
mSavedStateRegistryController.performSave(outBundle) | |
} | |
} |
import android.app.AlertDialog | |
import android.app.Service | |
import android.content.Intent | |
import android.graphics.PixelFormat | |
import android.os.Build | |
import android.os.IBinder | |
import android.util.TypedValue | |
import android.view.Window | |
import android.view.WindowManager | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.layout.wrapContentSize | |
import androidx.compose.material.Text | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.platform.ComposeView | |
import androidx.compose.ui.unit.sp | |
import androidx.lifecycle.Lifecycle | |
import androidx.lifecycle.ViewModelStore | |
import androidx.lifecycle.ViewTreeLifecycleOwner | |
import androidx.lifecycle.ViewTreeViewModelStoreOwner | |
import androidx.savedstate.ViewTreeSavedStateRegistryOwner | |
import com.viatek.fitnation.echelon_android.R | |
class OverlayService : Service() { | |
val windowManager get() = getSystemService(WINDOW_SERVICE) as WindowManager | |
override fun onCreate() { | |
super.onCreate() | |
setTheme(R.style.ThemeOverlay_AppCompat_Light) | |
showOverlay() | |
} | |
private fun showOverlay() { | |
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 | |
) | |
val composeView = ComposeView(this) | |
composeView.setContent { | |
Text( | |
text = "Hello", | |
color = Color.Black, | |
fontSize = 50.sp, | |
modifier = Modifier | |
.wrapContentSize() | |
.background(Color.Green) | |
) | |
} | |
// Trick The ComposeView into thinking we are tracking lifecycle | |
val viewModelStore = ViewModelStore() | |
val lifecycleOwner = MyLifecycleOwner() | |
lifecycleOwner.performRestore(null) | |
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) | |
ViewTreeLifecycleOwner.set(composeView, lifecycleOwner) | |
ViewTreeViewModelStoreOwner.set(composeView) { viewModelStore } | |
ViewTreeSavedStateRegistryOwner.set(composeView, lifecycleOwner) | |
windowManager.addView(composeView, params) | |
} | |
override fun onBind(intent: Intent): IBinder? { | |
return null | |
} | |
} |
Does anyone else get the error Class 'MyLifecycleOwner' is not abstract and does not implement abstract member public abstract val lifecycle: Lifecycle defined in androidx.savedstate.SavedStateRegistryOwner with lifecycle version 2.6.1?
I am facing the same problem with version 2.5.1. However, I have managed to resolve it by overriding the
lifecycle
as a variable instead of a function. Although the IDE is currently displaying an error ("lifecycle" overrides nothing), but the project can still be compiled and built without any issues.
override val lifecycle: Lifecycle get() = lifecycleRegistry
I also ran into this problem. Follow @AhmedMousa7 's method to solve this problem,
Android Studio prompts
Class 'LifecycleOwner' is not abstract and does not implement abstract member public abstract fun getLifecycle(): Lifecycle defined in androidx.savedstate.SavedStateRegistryOwner
'lifecycle' overrides nothing
but gradle compiles and runs without problems.
I found that the version of LifecycleOwner
inherited by SavedStateRegistryOwner
is wrong. The dependency it uses is androidx.lifecycle:lifecycle-common:2.0.0
, not the expected 2.6.1
. I suspect this is the reason.
Anyone else also using androidx.lifecycle:lifecycle-common:2.0.0
?
There is an open source library to create overlay view with jetpackcompose
https://github.com/KuhakuPixel/UberAlles/
(DISCLAIMER: I am the author and still in early stage of development, would appreciate your feedback and fix :D )
@wilinz @FreePhoenix888 I fixed the ComposeView not recomposing by, in addition to lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
, adding
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START)
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
Reached the same conclusions on some of the comments, specially the updated APIs and the requirement to trigger the START and RESUME lifecycle events so recomposition worked. I found the snippet here, that's why I was unable to find the updates suggested by commenters: https://www.jetpackcompose.app/snippets/OverlayService See my code here: https://github.com/xrubioj/JetpackComposeOverlayTest
I have found a fix to the problem. Removing
FLAG_NOT_TOUCHABLE
and settingalpha
ofparams
to1f
did the job. Now the button or any other views/composables are receiving click events and also the transparency is removed. Also, Thanks to @tberghuis for his excellent Floating Timer open-source code.