Yunpeng Lee
Yunpeng Lee

Reputation: 595

How do I check whether my app is allowed to post notifications?

Users can turn off notifications for individual apps in Android settings. Is there a method like isNotificationsAllowed() that allows me to check whether my app is allowed to post notifications? Also, how do I open the Android settings screen to guide my users to turn on notifications?

Upvotes: 57

Views: 47986

Answers (9)

Mohd Danish
Mohd Danish

Reputation: 204

fun Context.areNotificationsEnabled(): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.POST_NOTIFICATIONS,
        ) == PackageManager.PERMISSION_GRANTED
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val manager =
            this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (!manager.areNotificationsEnabled()) {
            return false
        }
        val channels = manager.notificationChannels
        for (channel in channels) {
            if (channel.importance == NotificationManager.IMPORTANCE_NONE) {
                return false
            }
        }
        true
    } else {
        NotificationManagerCompat.from(this).areNotificationsEnabled()
    }
}

Upvotes: 0

ZhouX
ZhouX

Reputation: 2156

2023-03-18: Android 13 (SDK 33 TIRAMISU) has introduced a new runtime permission (android.permission.POST_NOTIFICATIONS) for app to post notifications (which was allowed by default before Android 13).

If you app's target SDK is lower than 33 and running on Android 13 device, the first time user opens your app system will automatically request this permission then it's up to user to decide if your app is allowed to post notifications.

If your app targets to SDK 33 and running and Android 13 device, posting notification is NOT ALLOWED by default, until you explicitly request it and user allows it.

And note that user may allow your app to post notifications but meanwhile disable a specific notification channel, therefore it is not good enough to only test if the permission is granted, but also need to test if the notification channel is enabled.

Below is a sample helper function (in Kotlin) to check is notification allowed:

fun isPermissionGranted(context: Context, permission: String): Boolean =
    ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED

fun isNotificationAllowed(context: Context, channelId: String? = null): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (!isPermissionGranted(Manifest.permission.POST_NOTIFICATIONS)) return false
    }
    if (!NotificationManagerCompat.from(context).areNotificationsEnabled()) return false

    if (channelId == null) return true
    runCatching {
        val mgr = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val channel = mgr.getNotificationChannel(channelId)
        return channel.importance != NotificationManager.IMPORTANCE_NONE
    }
    return false
}

Upvotes: 1

Anand Nishad
Anand Nishad

Reputation: 126

public class MainActivity extends AppCompatActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

//Main Code Below-
//NotificationManagerCompat.from(context).areNotificationsEnabled()
       if(NotificationManagerCompat.from(this).areNotificationsEnabled())
       {
           Toast.makeText(this, "Notification is on for this Application", Toast.LENGTH_SHORT).show();
       }
       else
       {
           Toast.makeText(this, "Notification is off for this Application", Toast.LENGTH_SHORT).show();
       }
   }

}

Upvotes: 0

Abhishek Bansal
Abhishek Bansal

Reputation: 5335

Here is more complete answer to this question

fun areNotificationsEnabled(context: Context, channelId: String = "fcm_fallback_notification_channel"): Boolean {
    // check if global notification switch is ON or OFF
    if (NotificationManagerCompat.from(context).areNotificationsEnabled())
        // if its ON then we need to check for individual channels in OREO
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            val channel = manager.getNotificationChannel(channelId)
            return channel?.importance != NotificationManager.IMPORTANCE_NONE
        } else {
            // if this less then OREO it means that notifications are enabled
            true
        }
    // if this is less then OREO it means that notifications are disabled
    return false
}

Upvotes: 12

Ravichandra S V
Ravichandra S V

Reputation: 149

if(NotificationManagerCompat.from(context).areNotificationsEnabled())
{
 //Do your Work
}
else
{
     //Ask for permission
}

Upvotes: 0

Kasra
Kasra

Reputation: 3145

EDIT - New Answer:

Seems like google added the proper API call: NotificationManagerCompat.from(context).areNotificationsEnabled()


OLD ANSWER:

For anyone who is looking at this question, note that NotificationListenerService is different from "Show Notification". These two are different things! If an app has access to NotificationListenerService does not mean that its notifications are shown and vice versa. In order to check if user has blocked notification from your app or not, you can use reflection:

public class NotificationsUtils {

private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

public static boolean isNotificationEnabled() {

    AppOpsManager mAppOps = (AppOpsManager) GlobalContext.getContext().getSystemService(Context.APP_OPS_SERVICE);

    ApplicationInfo appInfo = GlobalContext.getContext().getApplicationInfo();

    String pkg = GlobalContext.getContext().getApplicationContext().getPackageName();

    int uid = appInfo.uid;

    Class appOpsClass = null; /* Context.APP_OPS_MANAGER */

    try {

        appOpsClass = Class.forName(AppOpsManager.class.getName());

        Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);

        Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
        int value = (int)opPostNotificationValue.get(Integer.class);

        return ((int)checkOpNoThrowMethod.invoke(mAppOps,value, uid, pkg) == AppOpsManager.MODE_ALLOWED);

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return false;
}
}

Source: https://code.google.com/p/android/issues/detail?id=38482

Upvotes: 111

asamoylenko
asamoylenko

Reputation: 2455

NotificationManagerCompat.from(context).areNotificationsEnabled()

seems like a way to go.

Upvotes: 68

user5961381
user5961381

Reputation: 9

Try this:

if (Settings.Secure.getString(getActivity().getContentResolver(), "enabled_notification_listeners").contains(getActivity().getPackageName())) {
    // Notification access service already enabled
    Toast.makeText(getActivity(),"notification enabled",Toast.LENGTH_LONG).show();
} else {
    Intent intent = new Intent();
    intent.setClassName("com.android.settings", "com.android.settings.Settings$AppNotificationSettingsActivity");
    intent.putExtra("app_package", getPackageName());
    intent.putExtra("app_uid", getApplicationInfo().uid);
    startActivity(intent);
}

Upvotes: -1

Related Questions