19

I am creating an educational app where school students can appear for 5 mins quick exams. Most of the time they are using their parent's mobile phone.

Now what I want is that when a student is giving the exam, no notification should come from any other app such as WhatsApp, FB or Gmail.

Is this possible? How?

milan m
  • 2,164
  • 3
  • 26
  • 40

5 Answers5

15

One possible solution would be to set the phone in DND (Do Not Disturb) mode. I haven't tested this but according to the documentation you should be able to do:

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int currentFilter = notificationManager.getCurrentInterruptionFilter();
notificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
// Run the exam...
// Restore the filter
notificationManager.setInterruptionFilter(currentFilter);

This requires a special DND access permission though, and it requires Android M:

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

That permission needs to be accepted by the user via Settings. See this question for more background and how you can launch the activity that leads to this setting.

A second option is to use Screen Pinning, which was introduced in Android L.

fejd
  • 2,545
  • 1
  • 16
  • 39
  • Is there any DND service in older Versions of android ? – Ranjan Jul 05 '18 at 05:54
  • I was thinking airplane mode but this is better. Needs code for onPause and onResume to handle foreground. This definitely is the answer. – danny117 Jul 05 '18 at 18:52
  • DnD has the drawback that the notification will still be apparent in the notification drawer but wont display as overlay on top of your app. And there is no possibility to disable the notification drawer. If you want to deny the students access to their notifications, check the expansion of the drawer with onfocuschanged and collapse it using reflection API: https://stackoverflow.com/a/54092080/1849612 – Xerusial Jun 23 '19 at 22:02
3

This seems like an interesting question.

Personally, I like the DND idea. It is simple, less messy and effective.

But say we need to reach out to lower APIs, You can use one approach to be like this.

You can have your own Notification Listener.

import android.annotation.SuppressLint;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;

@SuppressLint("OverrideAbstract")
public class NotificationListener  extends NotificationListenerService {

    public static String TAG = NotificationListener.class.getSimpleName();

    @Override
    public void onNotificationPosted(StatusBarNotification sbm) {

        /**
         * This condition will define how you will identify your test is running
         * You can have an in memory variable regarding it, or persistant variable,
         * Or you can use Settings to store current state.
         * You can have your own approach
         */
        boolean condition = true; // say your test is running
        
        if(condition)
            cancelAllNotifications(); //Cancel all the notifications . No Disturbance 
        
        //else
            // nothing.
    }
}

Add this to Manifest

 <service android:name=".NotificationListener"
        android:label="@string/app_name"
        android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
        <intent-filter>
            <action android:name="android.service.notification.NotificationListenerService" />
        </intent-filter>
    </service>

Now, you will need Notification Access Permission for this. In your application, entry points(or before test as per your logic) you can check this

if (!NotificationManagerCompat.getEnabledListenerPackages(getApplicationContext())
            .contains(getApplicationContext().getPackageName())) {
        //We dont have access
        Intent intent= new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
         //For API level 22+ you can directly use Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS

        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivityForResult(intent,NOTIFICATION_REQUEST_CODE);
    } else {
        //Your own logic
        Log.d(TAG, "You have Notification Access");

    }

This intent will open a page like below, which user will have to enable for giving you Access.

enter image description here

Hope this helps.

Community
  • 1
  • 1
Bhavita Lalwani
  • 903
  • 1
  • 9
  • 19
1

You can close all notification from other app by using NotificationListenerService:

public class NotificationListener extends NotificationListenerService {

    @Override
    public void onNotificationPosted(StatusBarNotification statusBarNotification) {
      cancelNotification(statusBarNotification.getKey());
    }
}

You must declare the service in your manifest file with the Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE permission and include an intent filter with the SERVICE_INTERFACE action. For example:

 <service android:name=".NotificationListener"
          android:label="@string/service_name"
          android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
     <intent-filter>
         <action android:name="android.service.notification.NotificationListenerService" />
     </intent-filter>
 </service>

https://developer.android.com/reference/android/service/notification/NotificationListenerService.html

Anisuzzaman Babla
  • 6,510
  • 7
  • 36
  • 53
0

If it is an exam you would likely be using your own device and not be running on students devices.

In this case your application can be a "device owner". See Device owner documentation

This will let you use Lock Task mode. See Lock task mode documentation This link also has lock task vs pinning comparison. You can use screen pinning if your application cannot be a "device owner"

I would highly recommend using Lock Task mode for any exam application to block access to the rest of the device (and not just notifications)

Note in your layout add "android:fitsSystemWindows="true" to block access to topline completely.

RocketRandom
  • 1,102
  • 7
  • 20
0

Please try this to activate DND:

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);

It will require:

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

or for manually asking to enable DND:

NotificationManager mNotificationManager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE);

 if (!mNotificationManager.isNotificationPolicyAccessGranted()) {
     Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
     startActivity(intent);
 }

or you can also turn on pin mode which keeps the app always at foreground and all notifications (even notification bar is disabled) is available from Lollipop onwards: to access pinning mode: Settings->Security->Screen Pinning->turn it on now when you press recent apps button you can see a pin in whim, click on it, the app which is first in the stack will be pinned, for more detail: https://www.cnet.com/how-to/ho-to-pin-apps-in-android-5-lollipop/

Hope this helps Happy coding... :)

Abdul Aziz
  • 442
  • 5
  • 12