Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android request ACCESS_NOTIFICATION_POLICY and mute phone

I am a beginner Android developer and I have an interesting question at hand. I am trying to mute the phone with

AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);

But I am getting the following error

java.lang.SecurityException: Not allowed to change Do Not Disturb state

Now I do not understand this, as I am using EasyPermissions (https://github.com/googlesamples/easypermissions) and requesting the permission

Manifest.permission.ACCESS_NOTIFICATION_POLICY

But it does not ask me to allow anything on app startup. I figured this is because ACCESS_NOTIFICATION_POLICY is a non dangerous permission and thus granted at installation time, for which I also added it to my manifest.xml as thus

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

But it is still not working, my app is crashing because it throws the "Not allowed to change to Do Not Disturb state" error. Wierdly I found that I can request to go to the "Do Not Disturb access" screen with the following code

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

What am I doing wrong here? Why cannot I request this permissions as a normal permission? Do I really have to go through the intent to allow my app to mute the phone?

like image 993
Karl Johan Vallner Avatar asked Mar 30 '17 16:03

Karl Johan Vallner


2 Answers

From the AudioManager#setRingerMode() reference:

From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed unless the app has been granted Do Not Disturb Access.

From API level 23 and onward, you have to declare ACCESS_NOTIFICATION_POLICY permission in the manifest AND then the user needs to grant your app access to toggle Do Not Disturb. You can check if the access is granted with NotificationManager#isNotificationPolicyAccessGranted(). If your package do not have access, start an ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS intent so the user can give your app access.

NotificationManager n = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if(n.isNotificationPolicyAccessGranted()) {
  AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
  audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
}else{
  // Ask the user to grant access
  Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
  startActivityForResult(intent);
}
like image 85
rckrd Avatar answered Oct 23 '22 04:10

rckrd


I will post an answer on how I managed to solve this issue for androids over 23 and under 23 with a startActivityForResult callback

the requestMutePhonePermsAndMutePhone() function is called in the main actions onCreate function.

Mind you the code is very much intrusive, since the Settings menu is permacalled until you accept the Do Not Disturb permissions, but one can easily accomodate this code for their personal needs and maybe build a question prompt, etc...

private void requestMutePhonePermsAndMutePhone() {
    try {
        if (Build.VERSION.SDK_INT < 23) {
            AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
            audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
        } else if( Build.VERSION.SDK_INT >= 23 ) {
            this.requestDoNotDisturbPermissionOrSetDoNotDisturbApi23AndUp();
        }
    } catch ( SecurityException e ) {

    }
}

private void requestDoNotDisturbPermissionOrSetDoNotDisturbApi23AndUp() {
    //TO SUPPRESS API ERROR MESSAGES IN THIS FUNCTION, since Ive no time to figrure our Android SDK suppress stuff
    if( Build.VERSION.SDK_INT < 23 ) {
        return;
    }

    NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
    if ( notificationManager.isNotificationPolicyAccessGranted()) {
        AudioManager audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
        audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
    } else{
        // Ask the user to grant access
        Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
        startActivityForResult( intent, MainActivity.ON_DO_NOT_DISTURB_CALLBACK_CODE );
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Check which request we're responding to
    if (requestCode == MainActivity.ON_DO_NOT_DISTURB_CALLBACK_CODE ) {
        this.requestDoNotDisturbPermissionOrSetDoNotDisturbApi23AndUp();
    }
}
like image 10
Karl Johan Vallner Avatar answered Oct 23 '22 03:10

Karl Johan Vallner