Запретить вытаскивание панели уведомлений

@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();
        }

    }

Моя цель - создать киоск-приложение. Я проверил множество кодов для этого, таких как этот и это. С их помощью я добился скрытия панели навигации. Теперь я хочу запретить пользователю перетаскивать панель уведомлений вниз, как это делает Surelock. Я пробовал общие ответы, данные в сообщениях SO, таких как здесь. Но это не работает в моем Redmi Note 5 Pro с Android Pie. Есть ли другой способ сделать это?


person Somnath Pal    schedule 01.07.2019    source источник
comment
можете ли вы опубликовать код, который вы пробовали до сих пор   -  person Manoj Perumarath    schedule 25.07.2019
comment
@ManojPerumarat конечно.   -  person Somnath Pal    schedule 25.07.2019
comment
@ManojPerumarath Я добавил свой код. Он включает в себя обычный блокирующий класс CustomViewGroup. Но это ничего не ограничивает. Я обнаружил, что onWindowFocusChanged() можно использовать, но он тоже не работает.   -  person Somnath Pal    schedule 25.07.2019
comment
Вы можете использовать этот код до Lollipop api 22, после чего используйте решение, рекомендованное bwt, любым способом, которым вам нужно ваше приложение в качестве администратора @Somnath Pal   -  person Manoj Perumarath    schedule 25.07.2019
comment
Это не правильное решение. Пожалуйста, проверьте Surelock. Это не требует, чтобы устройство было администратором.   -  person Somnath Pal    schedule 25.07.2019


Ответы (2)


В этом решении панель уведомлений не блокируется полностью, но закрывается после того, как пользователь открывает ее. Вам нужен сервис, который проверяет, открыта ли панель уведомлений повторно. Этот сервис использует отражение, чтобы получить необходимый метод для закрытия панели уведомлений после ее открытия, поэтому я думаю, что он не будет работать на устройствах Android 9 (только что проверил, что он работает нормально с compilesdk 28 на устройстве 7.1.1). вам нужно использовать это разрешение:

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

это код службы:

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();
            }
        }

    }

}

Слабая ссылка — убрать возможность возникновения утечек памяти.

person Sina    schedule 26.07.2019
comment
Я бы сказал, что это работает в Android Pie. Я все равно проверю другие версии Android, чтобы быть уверенным. В случае успеха я приму ваш ответ. Большое спасибо. - person Somnath Pal; 27.07.2019

Если ваше киоск-приложение является владельцем устройства (как объяснено в одном из приведенных вами примеров), вы можете использовать DevicePolicyManager.setStatusBarDisabled() :

Отключение строки состояния блокирует уведомления, быстрые настройки и другие экранные наложения, которые позволяют уйти от одноразового использования устройства.

Он доступен с Android 6 (API 23), строка состояния по-прежнему отображается (с временем, уровнем Wi-Fi, индикатором Bluetooth, ...), но уведомлений нет, и вы не можете его расширить.

person bwt    schedule 22.07.2019
comment
Нет. Мое приложение не является владельцем устройства. Как я проверил, чтобы стать владельцем устройства, вам нужно удалить любую ассоциацию Google a/c, а затем установить приложение. Это не мой случай. - person Somnath Pal; 22.07.2019
comment
Я использовал его только в приложениях владельца устройства, но API говорит, что этот метод также может использоваться приложением владельца профиля. - person bwt; 22.07.2019
comment
Я проверил это. Сначала требуется API 23, но minSDk приложения — 22. Также требуется, чтобы приложение было владельцем устройства. - person Somnath Pal; 22.07.2019
comment
Я немного странный, весь смысл владельца профиля в том, чтобы позволить пользователям приносить свое собственное устройство. Но все равно с API 22 работать не будет. - person bwt; 22.07.2019
comment
Есть ли другой способ для API 22 и ниже? - person Somnath Pal; 22.07.2019
comment
К сожалению, все решения, которые я когда-либо видел, являются хаками, они могут работать, если вы можете управлять устройством / Android, но не являются надежными / долговечными. - person bwt; 22.07.2019
comment
Давайте продолжим это обсуждение в чате. - person Somnath Pal; 22.07.2019