pandulapeter / beagle

A smart, reliable, and highly customizable debug menu library for Android apps that supports screen recording, network activity logging, and many other useful features.
Apache License 2.0
491 stars 27 forks source link

Drawer doesn't appear when using content.viewTreeObserver.addOnPreDrawListener on the Acitivty #107

Open rahulsainani opened 2 years ago

rahulsainani commented 2 years ago

On adding the SplashScreenApi and keeping it visible while some background tasks are happening as shared in the docs, the drawer doesn't appear. Is there a way we can work around this?

pandulapeter commented 2 years ago

Hi!

The splash screen itself is not an Activity as far as I know, so there is no way to add the debug menu on top of it. In that state the Application class already exists, but the first frame of the first Activity is not yet drawn (the layout is not yet inflated). Delaying that state using a PreDrawListener simply keeps the Splash UI visible: you won't see Beagle until the Activity actually becomes visible. However, once your first Activity is drawn, Beagle should be there.

Sorry, let me think about this a bit more, but adding custom UI like a debug menu to the splash screen should be impossible, the way I understand it (rightfully so: the splash is there to be a lightweight placeholder that can be shown while the more heavy stuff is getting loaded into memory).

One option (that I personally dislike) is to add a SplashActivity that looks just like your splash screen. But that way at least you could do error handling in case your background tasks fail.

rahulsainani commented 2 years ago

Sorry, my message wasn't framed correctly, I should have added that: We have a single activity and we initialise the debug drawer in the application, but since adding the PreDrawListener, the debug drawer doesn't appear on that activity. We still want to debug drawer on the activity, not the splash screen. When using just the splash screen api without the PreDrawListener, the debug drawer works fine.

pandulapeter commented 2 years ago

Thanks for clarifying. Let me look into it more, now I get it that it's a bug that should be fixed.

pandulapeter commented 2 years ago

Hey @rahulsainani !

Sorry for taking this long. Unfortunately I'm having trouble reproducing the issue.

I'm using the latest version of the splashscreen dependency, 1.0.0.

I modified the demo app in this repository. It has a single Activity, which does the following in onCreate():

var shouldShowSplashScreen = true
lifecycleScope.launch {
    delay(3000)
    shouldShowSplashScreen = false
}
val content: View = findViewById(android.R.id.content)
content.viewTreeObserver.addOnPreDrawListener(
    object : ViewTreeObserver.OnPreDrawListener {
        override fun onPreDraw() = if (shouldShowSplashScreen) false else {
            content.viewTreeObserver.removeOnPreDrawListener(this)
            true
        }
    }
)

With these changes, the splash screen is kept visible for an extra 3 seconds, as expected. Also, when it disappears, the DrawerLayout of the debug menu works as expected. Am I missing something? Can you please double-check?

rahulsainani commented 2 years ago

Hi @pandulapeter Sorry for the delay on my side. Switched project.

I tried to use the same code and realised that the error happens because we call SetContent inside onPreDraw. Here's the code snippet:

private fun setupPreDrawListener(onAuthCheckComplete: (Intent?) -> Unit) {
        Logger.d { "setupPreDrawListener" }
        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                Logger.d { "onPreDraw" }
                val value = viewModel.startDestinationState.value
                return if (value != null) {
                    Logger.d { "Will remove pre draw listener" }
                    content.viewTreeObserver.removeOnPreDrawListener(this)
                    onAuthCheckComplete(mapToIntent(value))
                    true
                } else {
                    Logger.d { "Continue checking" }
                    false
                }
            }
        })
    }

And onCreate after splash setup looks like:

setupPreDrawListener(onAuthCheckComplete = { intent ->
            Logger.d { "onAuthCheckComplete: $intent" }
            setContent {
                App(deepLinkIntent = intent)
            }
        })

on moving SetContent outside of onAuthCheckComplete callback, to onCreate, the debug drawer works fine. I guess the issue is how we are hacking this.

If you think this isn't a bug, please feel free to close this. If you have any ideas around why this is happening, it would be awesome if you could share it.