androidandroid-activitywebviewandroid-jetpack-composeforeground

Sharing WebView object between Activity and WindowManager in foreground


I am trying to show webview in foreground with floating view, i am taking webview from companion object of activity, and i added this to the floating view by removing webview' parent, and it worked and showing webview without losing current loaded page.

The problem is i wanna return this webview to the activity when user want to return to the app. And the same method (taking webview from foreground and removing parent of webview and giving this to compose AndroidView widget) not working and activity not showing webview, and it's not showing in foregroun too, if i switch to floating widget after that

The Floating View in foreground:

class OverlayWebViewScreen(
    private val context: Context, 
    private val webView: WebView, 
    val lifecycleService: ForegroundComposeLifeCycle
) {

    private lateinit var windowManager: WindowManager
    private lateinit var layoutParams: WindowManager.LayoutParams
    fun open() {
        PermissionManager.askForDisplayOverApps(context)
        context.run {
            windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
            layoutParams = WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT
            )

            val parentView = webView.parent as? ViewGroup
            parentView?.removeView(webView)
            val composableView = ComposeView(context)
            lifecycleService.attachToDecorView(composableView)
            lifecycleService.onResume()
            composableView.setViewTreeLifecycleOwner(lifecycleService)


            composableView.setContent {
                var offsetX by remember { mutableFloatStateOf(0f) }
                var offsetY by remember { mutableFloatStateOf(0f) }
                Column(modifier = Modifier.size(300.dp)) 
                {
                    Row {
                        Icon(
                            modifier = Modifier
                                .background(color = Color.Magenta)
                                .pointerInput(Unit) {
                                    detectDragGestures { change, dragAmount ->
                                        offsetX += dragAmount.x
                                        offsetY -= dragAmount.y
                                        layoutParams.x = offsetX.toInt()
                                        layoutParams.y = offsetY.toInt()
                                        windowManager.updateViewLayout(composableView, layoutParams)
                                    }
                                },
                            imageVector = Icons.Default.DragHandle, contentDescription = null
                        )
                        IconButton(onClick = {
                            windowManager.removeView(composableView)
                            ServiceManager.restartActivityWhenKilled(context)
                        }) {
                            Icon(
                                modifier = Modifier
                                    .background(color = Color.Magenta)
                                    ,
                                imageVector = Icons.Default.OpenInFull, contentDescription = null
                            )
                        }
                    }

                    AndroidView(
                        modifier = Modifier.size(200.dp),
                        factory = {
                            webView 
                        }
                    )
                    AdsManager.BannerAdView(modifier = Modifier)
                }
            }

            // Set the position of the WebView at the bottom of the screen
            layoutParams.gravity = Gravity.BOTTOM or Gravity.START

            windowManager.addView(composableView,layoutParams)
        }
    }

    fun close(){
        ServiceManager.restartActivityWhenKilled(context)
    }

}

Activity's onStart Method which is Compose and where i am getting webview from foreground service

override fun onStart() {
        val backPressedCallback = onBackPressedCallbackOverride()
        logger("onStart")
        if (ServiceManager.isServiceActive()){
            val parentView = webView.parent as? ViewGroup
            parentView?.removeView(webView)
            webView = AutoRefreshService.getWebView()
            webViewChanged.value = webViewChanged.value.not()
            logger(webView.toString())
        }
        setContent {
            val context = LocalContext.current
            val activity = context as? ComponentActivity
            activity?.onBackPressedDispatcher?.addCallback(this, backPressedCallback)
            InitVariables()
            AutoRefreshWebPageTheme {
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    Scaffold(
                        modifier = Modifier.fillMaxSize(),
                    ) { paddingValues ->
                        Column(modifier = Modifier.padding(paddingValues)) {

                            AndroidView(
                                modifier = Modifier.weight(1f),
                                update = {
                                    if (webViewChanged.value)
                                        webView.bringToFront()
                                },
                                factory = { webView },
                            )
                            AdsManager.BannerAdView(modifier = Modifier)
                        }
                    }
                    if (autoRefreshDialog.value) {
                        AutoRefreshDialog()
                    }

                }
            }
        }
        if (preferences.getAutoRefreshStatus()){
            if (ServiceManager.isServiceActive().not()) {
                startPageReloading(this)
            }
        }
        super.onStart()
    }

I tried compainion object in order to share webview across app, it taking just 200mb in ram in profiler. and I took webview from activity and applied to foreground and it showed webview with loaded screen even. But the reverse method (taking webview from foreground to the activity not working) video: here is situation

My expectation is returning to the activity by loaded screen of webview


Solution

  • I found the solution after couple of trying: Solution is i didn't attached webview to the androidView in jetpack compose because i had no idea how to do, but i found:

    Attaching to the AndroidView parent group will be like that:

    lateinit var webViewGroup: ViewGroup
    
    ...
    AndroidView(
    modifier = Modifier.weight(1f),
    update = { view ->
        val viewGroup = view.parent as? ViewGroup
        viewGroup?.let {
            // I used webViewGroup variable to keep view's parent in case it's 
            //changed unexpectedly
            if (::webViewGroup.isInitialized.not()){
                webViewGroup = viewGroup 
                // removing webview's current parent and attach to activity's 
                //parent
                val parentView = webView.parent as? ViewGroup
                parentView?.removeView(webView)
                webViewGroup.addView(webView)
            }
        }
    },
    factory = { webView },