Somnath Pal
Somnath Pal

Reputation: 1512

Restrict Notification Bar from pulling

@Override
    public void onWindowFocusChanged(boolean hasFocus){
        super.onWindowFocusChanged(hasFocus);
        try{
            if(!hasFocus && enableKioskMode){
                Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
                sendBroadcast(closeDialog);

                ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
                am.moveTaskToFront(getTaskId(), ActivityManager.MOVE_TASK_WITH_HOME);

                // sametime required to close opened notification area
                Timer timer = new Timer();
                timer.schedule(new TimerTask(){
                    public void run() {
                        Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
                        sendBroadcast(closeDialog);
                    }
                }, 500);

            }
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
private class CustomViewGroup extends ViewGroup {

        public CustomViewGroup(Context context) {
            super(context);
        }

        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            return true;
        }

    }
private void addBlockingViews() {

        try {
            WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));

            //For Bottom View
            WindowManager.LayoutParams bottomlocalLayoutParams = new WindowManager.LayoutParams();
            bottomlocalLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;

            bottomlocalLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
            bottomlocalLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
            bottomlocalLayoutParams.height = (int) (50 * getResources().getDisplayMetrics().scaledDensity);

            bottomlocalLayoutParams.format = PixelFormat.RGBX_8888;
            bottomlocalLayoutParams.gravity = Gravity.BOTTOM;

            bottomView = new CustomViewGroup(BaseActivity.this);
            ViewGroup.LayoutParams layoutParams1 = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 50);
            bottomView.setLayoutParams(layoutParams1);
            manager.addView(bottomView, bottomlocalLayoutParams);

            WindowManager.LayoutParams toplocalLayoutParams = new WindowManager.LayoutParams();
            toplocalLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;

            toplocalLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
            int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
            int result = 0;
            if (resId > 0) {
                result = getResources().getDimensionPixelSize(resId);
            } else {
                // Use Fallback size:
                result = 60; // 60px Fallback
            }
            //toplocalLayoutParams.height = result;
            toplocalLayoutParams.height = (int) (50 * getResources().getDisplayMetrics().scaledDensity);
            toplocalLayoutParams.gravity = Gravity.TOP;
            toplocalLayoutParams.format = PixelFormat.TRANSPARENT;
            topView = new CustomViewGroup(BaseActivity.this);
            ViewGroup.LayoutParams layoutParams2 = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    25);
            topView.setLayoutParams(layoutParams2);
            manager.addView(topView, toplocalLayoutParams);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

My aim is to create a Kiosk app. I checked many codes for that like this and this. With their help I have achieved navigation bar hiding. Now I want to block user from dragging the notification bar down just like Surelock does. I've tried the common answers given in SO posts like here. But it does not work in my Redmi Note 5 Pro with Android Pie. Is there any other way to accomplish this?

Upvotes: 4

Views: 308

Answers (2)

Sina
Sina

Reputation: 2883

In this solution notification bar is not blocked entirely but it gets closed after user opens it. You need a service that checks if the notification bar is open repeatedly. This service uses reflection to get needed method to close the notification bar after it gets opened so I think it wont work on android 9 devices(just checked it working fine with compilesdk 28 on a 7.1.1 device). you need to use this permission:

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

this is the code for the service:

public class CollapseService extends Service {
    ScheduledExecutorService scheduler;


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public void onCreate() {
        super.onCreate();
        MyRunnable runnable = new MyRunnable(this);

        scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate
                (runnable, 0, 100, TimeUnit.MILLISECONDS);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        return Service.START_STICKY;
    }

    private void collapseNow() {
        Object statusBarService = getSystemService("statusbar");
        Class<?> statusBarManager = null;

        try {
            statusBarManager = Class.forName("android.app.StatusBarManager");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Method collapseStatusBar = null;

        try {
            collapseStatusBar = statusBarManager.getMethod("collapsePanels");

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        collapseStatusBar.setAccessible(true);

        try {
            collapseStatusBar.invoke(statusBarService);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        scheduler.shutdown();
    }

    static class MyRunnable implements Runnable{
        CollapseService aService = null;
        MyRunnable(CollapseService service){
            WeakReference<CollapseService> weakReference = new WeakReference<>(service);
            aService = weakReference.get();
        }

        @Override
        public void run(){
            if(aService != null) {
                aService.collapseNow();
            }
        }

    }

}

Weak reference is to remove the possibility of occurrence of memory leaks.

Upvotes: 1

Philippe Banwarth
Philippe Banwarth

Reputation: 17755

If your kiosk app is a device owner (as explained in one of your referenced examples) you can use DevicePolicyManager.setStatusBarDisabled() :

Disabling the status bar blocks notifications, quick settings and other screen overlays that allow escaping from a single use device.

It is available since Android 6 (API 23), the status bar is still displayed (with the time, wifi level, bluetooth indicator, ...) but the notifications are not and you cannot expand it.

Upvotes: 0

Related Questions