You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android非锁屏状态下showFullScreenIntent无法全屏显示来电界面求助

解决非锁屏状态下showFullScreenIntent仅显示Heads-up通知的问题

我之前也碰到过一模一样的问题——Android系统默认在设备未锁屏时,setFullScreenIntent只会弹出heads-up通知,不会直接拉起全屏的来电界面。这是系统的行为限制,不过我们可以通过几个关键配置绕过这个限制,让来电界面在任何状态下都能全屏显示。

下面结合你的代码给出具体修改步骤:

1. 申请必要的系统权限

首先,你的App需要获得在其他应用之上显示和唤醒屏幕的权限。在AndroidManifest.xml中添加:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

注意SYSTEM_ALERT_WINDOW是特殊权限,无法在安装时自动授予,你需要在App首次启动时引导用户开启:

private const val OVERLAY_PERMISSION_REQUEST_CODE = 1001

// 在App启动或首次调用来电功能前调用
fun requestOverlayPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
        val intent = Intent(
            Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
            Uri.parse("package:$packageName")
        )
        startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE)
    }
}

2. 配置来电Activity的窗口属性

你的CallingScreen需要设置窗口标记,确保它能在锁屏/非锁屏状态下全屏显示,并且覆盖其他应用。在CallingScreen的onCreate方法中添加:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    // 设置全屏及锁屏相关标记
    window.setFlags(
        WindowManager.LayoutParams.FLAG_FULLSCREEN or
        WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
        WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
        WindowManager.LayoutParams.FLAG_FULLSCREEN or
        WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
        WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
    )
    
    // Android 8+ 设置窗口类型为应用覆盖层
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
    } else {
        // 低版本使用TYPE_PHONE
        window.setType(WindowManager.LayoutParams.TYPE_PHONE)
    }
    
    setContentView(R.layout.activity_calling_screen)
    // 你的其他初始化逻辑...
}

这些标记的作用:

  • FLAG_DISMISS_KEYGUARD:自动解锁屏幕
  • FLAG_SHOW_WHEN_LOCKED:允许Activity在锁屏状态下显示
  • FLAG_TURN_SCREEN_ON:点亮熄灭的屏幕
  • FLAG_KEEP_SCREEN_ON:保持屏幕唤醒直到通话结束
  • TYPE_APPLICATION_OVERLAY:确保Activity能在其他应用之上显示(Android 8+)

3. 优化通知渠道和PendingIntent配置

确保通知渠道的高优先级

检查你的NotificationUtils.createChannel方法,必须把渠道重要性设置为IMPORTANCE_HIGH,这样才能触发heads-up通知并配合全屏意图:

fun createChannel(context: Context, notificationManager: NotificationManager) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            CHANNEL_ID,
            "Incoming Calls",
            NotificationManager.IMPORTANCE_HIGH
        ).apply {
            description = "Handles incoming call notifications"
            val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/" + R.raw.rongtone_incoming)
            setSound(soundUri, AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build())
            enableVibration(true)
        }
        notificationManager.createNotificationChannel(channel)
    }
}

修复PendingIntent的标记和requestCode

Android 12+对PendingIntent的标记有新要求,同时要确保不同操作的PendingIntent使用不同的requestCode,避免互相覆盖:

// 统一处理PendingIntent标记
val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
} else {
    PendingIntent.FLAG_UPDATE_CURRENT
}

// 全屏启动Activity的PendingIntent
val showingCallScreenPendingIntent = PendingIntent.getActivity(this, 0, showingCallScreenIntent, pendingFlags)
// 接听按钮的PendingIntent(requestCode用1,和上面区分)
val acceptCallPendingIntent = PendingIntent.getActivity(this, 1, acceptIntent, pendingFlags)

4. 调整你的sendFullScreenCall方法

最后,优化通知构建代码,移除不需要的setContentIntent(全屏意图已经会拉起Activity),确保setFullScreenIntent的第二个参数为true:

private fun sendFullScreenCall(callInfoModel: CallInfoModel) {
    val icon = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
    val showingCallScreenIntent = Intent(applicationContext, CallingScreen::class.java).apply {
        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        action = "Accept"
        putExtra("callObj", callInfoModel)
        putExtra(STATE, INCOMING)
    }
    val acceptIntent = Intent(applicationContext, SingleCallScreen::class.java).apply {
        putExtra("callObj", callInfoModel)
    }

    val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
    } else {
        PendingIntent.FLAG_UPDATE_CURRENT
    }

    val showingCallScreenPendingIntent = PendingIntent.getActivity(this, 0, showingCallScreenIntent, pendingFlags)
    val acceptCallPendingIntent = PendingIntent.getActivity(this, 1, acceptIntent, pendingFlags)
    val dimissCallPendingIntent = DismissCallKolinActivity.getDismissIntent(Random().nextInt(), this@FirebaseMessagingService, callInfoModel)

    val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + applicationContext.packageName + "/" + R.raw.rongtone_incoming)
    val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setContentTitle("Incoming call")
        .setContentText(callInfoModel.CallerDisplay)
        .setAutoCancel(true)
        .setOnlyAlertOnce(true)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setLargeIcon(icon)
        .setSound(soundUri)
        .addAction(R.mipmap.ic_video_enabled, getActionText("Answer", R.color.green_color), acceptCallPendingIntent)
        .addAction(R.mipmap.ic_clear, getActionText("Dismiss", R.color.red), dimissCallPendingIntent)
        .setFullScreenIntent(showingCallScreenPendingIntent, true)
        .setPriority(NotificationCompat.PRIORITY_MAX) // 适配Android 7及以下的高优先级

    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        notificationManager.getNotificationChannel(CHANNEL_ID)?.let { 
            notificationManager.deleteNotificationChannel(it.id) 
        }
    }
    NotificationUtils.createChannel(this@FirebaseMessagingService, notificationManager)
    notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
}

完成这些修改后,你的来电界面应该就能在锁屏和非锁屏状态下都全屏显示了。核心是通过权限和窗口属性让Activity能覆盖其他应用,同时确保通知的高优先级触发全屏意图。

内容的提问来源于stack exchange,提问作者famfamfam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:59:53