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

Android来电通知:如何让带声音频道仅用MediaPlayer播放铃声?

解决方案:一加口袋模式下来电通知与MediaPlayer冲突问题

核心思路

针对一加口袋模式下通知铃声被静音、但MediaPlayer不受影响的特性,通过动态判断口袋模式状态,分别调整通知配置和MediaPlayer的播放逻辑,既避免两者同时发声,又保证全屏Intent和通知正常显示。


具体实现步骤

1. 判断一加设备的口袋模式状态

一加的口袋模式可通过系统设置读取或监听自定义广播获取状态:

fun isPocketModeEnabled(context: Context): Boolean {
    return try {
        // 读取一加口袋模式系统设置值,1为开启,0为关闭
        Settings.System.getInt(context.contentResolver, "oneplus_pocket_mode", 0) == 1
    } catch (e: Settings.SettingNotFoundException) {
        // 非一加设备返回false
        false
    }
}

也可监听一加自定义广播com.oneplus.pocketmode.action.STATE_CHANGED,实时获取状态变化。

2. 动态配置通知与MediaPlayer

根据口袋模式状态,分别处理通知静音和铃声播放:

val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val fullScreenIntent = Intent(context, IncomingCallActivity::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

val notificationBuilder = NotificationCompat.Builder(context, CALL_CHANNEL_ID)
    .setFullScreenIntent(fullScreenIntent, true)
    .setCategory(Notification.CATEGORY_CALL)
    .setPriority(NotificationCompat.PRIORITY_HIGH)
    .setSmallIcon(R.drawable.ic_incoming_call)
    .setContentTitle("来电")
    .setContentText("XXX正在呼叫你")

if (isPocketModeEnabled(context)) {
    // 口袋模式开启:通知设为静音,用MediaPlayer播放铃声(避免通知铃声被系统静音)
    notificationBuilder.setSilent(true)
    startRingtoneWithMediaPlayer(context)
} else {
    // 口袋模式关闭:通知保留声音振动,不启动MediaPlayer(避免同时发声)
    notificationBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE))
    notificationBuilder.setVibrate(longArrayOf(0, 500, 1000))
}

notificationManager.notify(CALL_NOTIFICATION_ID, notificationBuilder.build())

3. 实现MediaPlayer的安全播放与销毁

务必处理MediaPlayer的生命周期,避免内存泄漏和后台残留播放:

private var mediaPlayer: MediaPlayer? = null

fun startRingtoneWithMediaPlayer(context: Context) {
    // 先释放原有实例
    mediaPlayer?.release()
    val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
    mediaPlayer = MediaPlayer.create(context, ringtoneUri).apply {
        isLooping = true
        start()
    }
}

fun stopRingtoneMediaPlayer() {
    mediaPlayer?.run {
        if (isPlaying) stop()
        release()
    }
    mediaPlayer = null
}

来电结束(比如用户接听/挂断)时,立即调用stopRingtoneMediaPlayer()。

4. 监听口袋模式状态变化(可选)

注册广播接收器,实时响应口袋模式的开关操作,动态更新通知和铃声:

class PocketModeReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action != "com.oneplus.pocketmode.action.STATE_CHANGED") return
        val isEnabled = intent.getBooleanExtra("state", false)
        val isInCall = // 自行实现判断当前是否处于来电状态的逻辑
        
        if (isInCall) {
            // 更新通知配置
            updateIncomingCallNotification(context, isEnabled)
            // 调整MediaPlayer
            if (isEnabled) startRingtoneWithMediaPlayer(context)
            else stopRingtoneMediaPlayer()
        }
    }
}

在Manifest中注册广播:

<receiver android:name=".PocketModeReceiver">
    <intent-filter>
        <action android:name="com.oneplus.pocketmode.action.STATE_CHANGED" />
    </intent-filter>
</receiver>

5. 确保通知渠道的优先级

创建通知渠道时必须设置为IMPORTANCE_HIGH,保证即使静音,通知仍能触发全屏Intent并显示:

val channel = NotificationChannel(CALL_CHANNEL_ID, "来电通知", NotificationManager.IMPORTANCE_HIGH).apply {
    setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE), AudioAttributes.DEFAULT_VIBRATE_SETTINGS)
    enableVibration(true)
}
notificationManager.createNotificationChannel(channel)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:46:18