java.lang.SecurityException: Not allowed to change Do Not Disturb state - 免打扰模式异常

今天在使用 AudioManager 调节系统音量大小和切换静音的时候抛出了异常:

System.err: java.lang.SecurityException: Not allowed to change Do Not Disturb state
System.err: at android.os.Parcel.readException(Parcel.java:1683)
System.err: at android.os.Parcel.readException(Parcel.java:1636)
System.err: at android.media.IAudioService$Stub$Proxy.setRingerModeExternal(IAudioService.java:962)
System.err: at android.media.AudioManager.setRingerMode(AudioManager.java:1022)

查了一下发现是在 Android 6.0(API 23)之后,如果应用需要在免打扰模式下切换音量大小或者通知策略,首先需要在清单文件 AndroidManifest.xml 注册相应的权限:

<!-- 在这里注册不是为了在代码中申请该权限,而是能在跳转到的免打扰权限清单中看到该应用 -->
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>

然后在需要改变音量大小或通知策略的代码中进行判断:

val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !notificationManager.isNotificationPolicyAccessGranted) {
    startActivity(Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS))
}

这时候会跳转到免打扰权限的清单界面,开启权限之后就可以在免打扰模式下进行音量修改等相关操作了,这个开启权限的操作也是跟其他权限申请的方式有所不同。
在这里插入图片描述
此外,从 NotificationManager 的源码中可以看到,我们还可以通过广播的方式来监听应用对于该权限申请的变化:

/**
 * Intent that is broadcast when the state of {@link #isNotificationPolicyAccessGranted()}
 * changes.
 *
 * This broadcast is only sent to registered receivers, and only to the apps that have changed.
 */
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED
        = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";

参考:In Android 7 (API level 24) my app is not allowed to mute phone (set ringer mode to silent)

当非系统应用尝试绑定到具有`android.uid.system`权限的服务时,会收到`SecurityException`,因为这样做通常是为了访问系统的功能,而普通应用并不具备这样的权限。这个异常通常是Android操作系统为了保障安全性和隐私控制而设计的。 解决这个问题通常有以下几个步骤: 1. **权限检查**:确保你的应用在运行时获得了正确的权限。对于需要`android.uid.system`权限的服务操作,你需要在AndroidManifest.xml文件中添加相应的`<uses-permission>`标签,并在运行时通过`PackageManager`检查当前应用是否拥有该权限。 ```xml <uses-permission android:name="android.permission.BIND_SERVICE" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 如果服务需要显示系统通知 --> ``` 2. **申请权限**:如果应用在运行时没有这些权限,可以在代码中动态请求它们,例如使用`ActivityCompat.requestPermissions()`。 3. **特殊授权**:某些系统服务可能需要用户明确授予应用权限才能绑定。在这种情况下,你需要引导用户通过设置或权限管理界面进行手动授权。 4. **服务代理**:如果业务上确实需要,可以考虑创建一个中间服务作为桥梁,由系统服务提供者负责处理实际任务,然后将结果返回给你的应用,而不是直接绑定。 5. **使用IntentService**: 考虑使用`IntentService`来间接实现服务,这种方式可以避直接绑定,同时保持一定的响应能力。 记住,滥用系统权限可能会导致应用被拒,因此一定要确保你的需求合理并且遵守Google Play Store的政策。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值