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

为何AudioManager切换铃声模式时崩溃?已授予PHONE_STATE权限

Hey there! Let's dig into why your app is crashing when trying to override the silent mode for specific incoming calls. Based on your setup and the code snippet you shared, here are the most common issues and fixes to get this working smoothly:

1. You're Missing Critical Permissions

The biggest culprit here is likely missing permissions—especially for newer Android versions. Modifying the ringer mode isn't just about PHONE_STATE:

  • For Android 10 (API 29) and above, you need the ACCESS_NOTIFICATION_POLICY permission to bypass silent mode. This can't be granted via a normal runtime permission prompt; users have to enable it manually in system settings.
  • You also need the basic MODIFY_AUDIO_SETTINGS permission to adjust audio modes at all.

First, add these to your AndroidManifest.xml:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- Already have this for PHONE_STATE events -->

Then, in your code, check if the notification policy permission is granted before modifying the ringer mode:

override fun onReceive(context: Context, intent: Intent) {
    val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
    val incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
    val targetNumber = "your-specified-number-here" // Replace with your target number

    if (state == TelephonyManager.EXTRA_STATE_RINGING && incomingNumber == targetNumber) {
        // Check permission for API 29+
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            if (!notificationManager.isNotificationPolicyAccessGranted) {
                // Redirect user to settings to enable permission
                val settingsIntent = Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS)
                settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                context.startActivity(settingsIntent)
                return // Exit until permission is granted
            }
        }

        // Now safely modify the ringer mode
        val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        audioManager.ringerMode = AudioManager.RINGER_MODE_NORMAL
    }
}
2. BroadcastReceiver Restrictions (Android 8.0+)

If you're using a statically registered PhoneStateReceiver (declared in AndroidManifest.xml), it won't receive the PHONE_STATE broadcast on Android 8.0 (API 26) and above—this can lead to unexpected crashes or untriggered code.

Fix this by either:

  • Dynamically registering the receiver in an Activity/Service:
// In your Activity's onCreate()
val receiver = PhoneStateReceiver()
val filter = IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED)
registerReceiver(receiver, filter)

// Don't forget to unregister in onDestroy()
override fun onDestroy() {
    super.onDestroy()
    unregisterReceiver(receiver)
}
  • Or, if you prefer static registration (Android 12+ requires android:exported="true"):
<receiver
    android:name=".PhoneStateReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>
</receiver>
3. Null Pointer Exceptions

Crash logs often point to null values—make sure you handle cases where incomingNumber or the TelephonyManager state might be null:

incomingNumber?.let { number ->
    if (state == TelephonyManager.EXTRA_STATE_RINGING && number == targetNumber) {
        // Proceed with ringer mode changes
    }
}
4. Bonus: Restore Original Ringer Mode

Don't forget to switch back to the user's original ringer mode once the call ends (e.g., when the phone state changes to EXTRA_STATE_IDLE):

// Store original mode when you switch to normal
private var originalRingerMode: Int? = null

// In onReceive()
if (state == TelephonyManager.EXTRA_STATE_RINGING && incomingNumber == targetNumber) {
    val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    originalRingerMode = audioManager.ringerMode
    audioManager.ringerMode = AudioManager.RINGER_MODE_NORMAL
} else if (state == TelephonyManager.EXTRA_STATE_IDLE && originalRingerMode != null) {
    val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    audioManager.ringerMode = originalRingerMode!!
    originalRingerMode = null
}

内容的提问来源于stack exchange,提问作者Hasan A Yousef

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:36:31