Search code examples
androidandroid-notificationsandroid-preferencesandroid-audiomanagerandroid-7.0-nougat

Android N: checking for DND state changed before updating checkbox preference


My app sets the ringer mode to silent but with Android N I get a java.lang.SecurityException: Not allowed to change Do Not Disturb state.

I followed the steps from this post and the following code will open an activity which contains a toggle button for enabling the permission to change the ringer mode. This activity can be "backed" from without the enabling of the permission.

Intent intent = new Intent(
                        android.provider.Settings
                        .ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);

    startActivity(intent);

The problem is that I want to ensure that the permission is granted before attempting to use the silent ringer mode functionality.

I'm adding a CheckBoxPreference to enable and disable of this ringer mode toggling. So if the checkbox is checked, I can set the ringer mode to silent and if it's not, I will not change the ringer mode.

Until now I managed to start this permission request when the user clicks the checkbox:

disableSoundCheckboxPreference.setOnPreferenceChangeListener(
                new Preference.OnPreferenceChangeListener() {
                    @Override
                    public boolean onPreferenceChange(Preference preference, Object o) {
...
// check for Android N and start the activity mentioned above

But what is the correct way to enable this checkbox only if the permission was granted? I guess it should have something to do with ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGEDand a listener but I would need some ideas to implement this.

Thanks!


Solution

  • I managed to solve this and will post the answer in case someone else needs it.

    A BroadcastListener is not needed in this case. You just need to request the permission when the user first clicks on the preference with an OnPreferenceClickListener:

    private void requestNotificationPolicyAccess() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !isNotificationPolicyAccessGranted()) {
                Intent intent = new Intent(android.provider.Settings.
                        ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
                startActivity(intent);
    

    If the user grants the permission, when he will click again, you will allow the user to change the state of the CheckBox. If the permission is not granted, you will continue updating the CheckBox with "false" and maybe write in it's android:summary that permission must be granted first. You can verify with:

    private boolean isNotificationPolicyAccessGranted()  {
        NotificationManager notificationManager = (NotificationManager)
                getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
        return notificationManager.isNotificationPolicyAccessGranted();
    }