4

@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?

Somnath Pal
  • 1,570
  • 4
  • 23
  • 42

2 Answers2

1

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.

Sina
  • 2,683
  • 1
  • 13
  • 25
  • 1
    I would say its working in Android Pie. I'll still check in other android versions just to be sure. If successful, I'll accept your answer. Thanks a lot. – Somnath Pal Jul 27 '19 at 08:37
0

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.

bwt
  • 17,292
  • 1
  • 42
  • 60
  • No. My app is not device owner. As I checked that to make a device owner, you have to remove any Google a/c association and then install the app. That is not my case. – Somnath Pal Jul 22 '19 at 11:06
  • I only used it in device owner apps, but the API says that the method can also be used by a profile owner app – bwt Jul 22 '19 at 11:21
  • I checked this. First it requires API 23 but app's minSDk is 22. Also it requires the app to be device owner. – Somnath Pal Jul 22 '19 at 15:43
  • I is a bit strange, the whole point of a profile owner is to allow users to bring their own device. But anyway, it will not work with API 22. – bwt Jul 22 '19 at 15:58
  • Is there any other way for API 22 and below? – Somnath Pal Jul 22 '19 at 16:00
  • Unfortunately, all the solutions I have ever seen are hacks, they may work if you can control the device / Android, but are not robust / durable – bwt Jul 22 '19 at 16:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/196817/discussion-between-somnath-pal-and-bwt). – Somnath Pal Jul 22 '19 at 16:01