在 Android 可组合项中删除按后退按钮时的叠加层

问题描述 投票:0回答:1

我在 Android 中使用 Jetpack Compose 编写的 Overlay 服务遇到问题。我试图在按下后退按钮时删除覆盖层,但我在实现此功能时遇到困难。具体来说,当我尝试使用 BackHandler 时,遇到错误消息“No OnBackPressedDispatcherOwner wasprovided via LocalOnBackPressedDispatcherOwner”。

服务是这样的:

class OverlayService : Service() {

val windowManager get() = getSystemService(WINDOW_SERVICE) as WindowManager

override fun onCreate() {
    super.onCreate()
    this.updateAppLanguage()
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    // Handle the incoming intent
    handleIntent(intent)
    return super.onStartCommand(intent, flags, startId)
}


private fun handleIntent(intent: Intent?) {
    // Check if the intent is not null
    intent?.let {
        // Extract data from the intent
        val number = it.getStringExtra("number")
        val dateEnd = it.getLongExtra("date", 0)

        if (number != null) {
            showOverlay(number, dateEnd)
        }

    }
}

private fun showOverlay(number: String, date: Long) {
    val layoutFlag: Int =
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY

    val params = WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        layoutFlag,
        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT
    )

    PreviousCallCard.getTrackerInfo(this)



    val composeView = ComposeView(this)

    composeView.setContent {

        val context = LocalContext.current
        val rememberAds by remember {
            mutableStateOf(PreviousCallCard.showAd(context))
        }
        val animVisibleState = remember {
            MutableTransitionState(false)
                .apply { targetState = true }
        }
        if (!animVisibleState.targetState &&
            !animVisibleState.currentState
        ) {
            PreviousCallCard.finishedShowingCard(this)
            windowManager.removeView(composeView)
            [email protected]()

        }


        AnimatedVisibility(
            modifier = Modifier,
            visibleState = animVisibleState,
            enter = fadeIn(),
            exit = fadeOut()
        ) {

            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .background(Color.Black.copy(alpha = 0.5f))
                    .clickable(
                        interactionSource = remember { MutableInteractionSource() },
                        indication = null
                    ) {
                        animVisibleState.targetState = false
                    },
                verticalArrangement = Arrangement.Bottom

            ) {

                PreviousCallCard(
                    modifier = Modifier,
                    number = number,
                    endDate = date,
                    onWhatsAppClick = {
                        val whatsappPackage = "com.whatsapp"
                        val packageManager = context.packageManager
                        val isWhatsAppInstalled = try {
                            packageManager.getPackageInfo(
                                whatsappPackage,
                                PackageManager.GET_ACTIVITIES
                            )
                            true
                        } catch (e: PackageManager.NameNotFoundException) {
                            false
                        }

                        if (!isWhatsAppInstalled) {
                            val whatsappUrl =
                                "https://play.google.com/store/apps/details?id=$whatsappPackage"
                            val intent = Intent(Intent.ACTION_VIEW, Uri.parse(whatsappUrl))
                            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                            context.startActivity((intent))


                        } else {
                            val whatsappVideoId = getIdWhatsAppVideo(contentResolver, it)
                            if (whatsappVideoId != null) {
                                launchWhatsAppIntent(
                                    context,
                                    launcher = null,
                                    whatsappVideoId,
                                    true
                                )
                            } else {
                                launchWhatsAppMessageIntent(
                                    context = context,
                                    isWhatsAppInstalled = true,
                                    launcher = null,
                                    phoneNumber = number
                                )
                            }
                        }
                        animVisibleState.targetState = false

                    },
                    onViewProfile = {
                        context.startActivity(MainActivity.getStartIntent(context, ExtraDataType.VIEW_PROFILE))
                        animVisibleState.targetState = false
                    },
                    share = { name ->

                        if (name == "Unknown") {
                            launchLogShareIntent(
                                context,
                                number,
                                true
                            )

                        } else {
                            val lookUpContact =
                                getLookUpKey(contentResolver = contentResolver, name = name)
                            if (lookUpContact != null) {
                                launchContactShareIntent(context, lookUpContact, true)
                            }
                        }
                        animVisibleState.targetState = false


                    },
                    onClose = {
                        animVisibleState.targetState = false

                    },
                    navigateToCall = {

                    }
                )

                Spacer(modifier = Modifier.size(5.dp))

                if (rememberAds == AdsType.BANNER_ID) {
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .background(Color.White, RoundedCornerShape(20.dp))
                    ) {
                        AdsBannerMedium(modifier = Modifier.fillMaxWidth())
                    }
                } else {
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .background(Color.White, RoundedCornerShape(20.dp))
                    ) {
                        AdsWidget(
                            context = this@OverlayService,
                            modifier = Modifier.fillMaxWidth()
                        )
                    }
                }
            }
        }
    }

    // Trick The ComposeView into thinking we are tracking lifecycle
    val viewModelStore = ViewModelStore()
    val viewModelStoreOwner = object : ViewModelStoreOwner {
        override val viewModelStore: ViewModelStore
            get() = viewModelStore
    }
    val lifecycleOwner = MyLifecycleOwner()
    lifecycleOwner.performRestore(null)
    lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START)
    lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    composeView.setViewTreeLifecycleOwner(lifecycleOwner)
    composeView.setViewTreeSavedStateRegistryOwner(lifecycleOwner)
    composeView.setViewTreeViewModelStoreOwner(viewModelStoreOwner)

    windowManager.addView(composeView, params)
}

override fun onBind(intent: Intent): IBinder? {
    return null
}

}

我尝试了多种解决方案,但没有任何效果,我尝试的最后一件事是像这样在视图本身上设置侦听器键

composeView.requestFocus()
    composeView.setFocusableInTouchMode(true)
    composeView.setOnKeyListener(View.OnKeyListener { v, keyCode, event ->

        if (keyCode == KeyEvent.KEYCODE_BACK) {
            stopSelf()
            return@OnKeyListener true
        }
        false
    })

但不幸的是,我根本没有收到通知,而且效果也不佳。 我在网站上调查了一些问题,例如:

在android中按后退或主页按钮时是否可以使用WindowManager删除覆盖层? - 堆栈溢出

我尝试了该问题的正确答案,但它总是崩溃要求令牌,所以我想这个答案只有在活动没有被破坏的情况下才有效,这不是我的情况,因为我的撰写是一个覆盖层,即使应用程序关闭也可以工作

带有叠加层的服务 - 按返回按钮 - stackoverflow

我尝试了我之前在这个问题帖子中提到的关键侦听器的解决方案,但仍然对我不起作用,并且根本没有收到通知。

android kotlin android-jetpack-compose overlay
1个回答
0
投票

我找到了这个问题的解决方案,适用于 28 到 34 的 API。

解决方案是删除 来自此处的“FLAG_NOT_FOCUSABLE”标志

 val layoutFlag: Int =
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY

    val params = WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        layoutFlag,
        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN ,
        PixelFormat.TRANSLUCENT
    )

然后我们用我们的视图设置一个监听器,如下所示:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        composeView.addOnUnhandledKeyEventListener{ view, event ->

            if ( event.action == KeyEvent.KEYCODE_BACK  || event.action == KeyEvent.KEYCODE_SOFT_LEFT || event.action == KeyEvent.KEYCODE_SOFT_RIGHT || event.action == KeyEvent.KEYCODE_HOME || event.action == KeyEvent.KEYCODE_MOVE_HOME) {
                PreviousCallCard.finishedShowingCard(this)
                windowManager.removeView(composeView)
                [email protected]()
                true
            } else {
                false
            }
        }
    }

由于 28 以上的 API 有软左或右作为返回方式而不是后退按钮,我们处理所有这些键码来处理后退效果。

我仍然不知道这是否准确且实施良好,因此如果有人有任何改进,我会很高兴看到您的贡献。

© www.soinside.com 2019 - 2024. All rights reserved.