Подтвердить что ты не робот

Предотвращение расширения строки состояния

В любом случае, чтобы пользователи не могли сдвинуть строку состояния (развернуть) или свернуть обратно?

Я пытаюсь заменить lockscreen и кажется, что это обязательная функция. Есть ли способ сделать это, не требуя привилегий root?

4b9b3361

Ответ 1

Короткий ответ: это невозможно!

Теперь вам должно быть интересно узнать, почему это невозможно:

Существует два разрешения для управления строкой состояния системы, EXPAND_STATUS_BAR и STATUS_BAR. Первое может быть запрошено любым приложением, но позднее зарезервировано для приложений, подписанных с сигнатурой платформы (системные приложения, а не сторонние). Можно развернуть/свернуть строку состояния системы (см. "Как открыть или развернуть строку состояния через намерение?" ), но обратите внимание, что требуется отражение, потому что StatusBarManager класс не является частью SDK. Метод disable, который используется дозвонщиком Android для предотвращения расширения строки состояния, недоступен приложению без вышеупомянутого разрешения STATUS_BAR.

Источники: личный опыт: -)

Ответ 2

Прежде всего, невозможно изменить строку состояния, если ваше приложение не подписано с сертифицированным телефоном, если вы попытаетесь его изменить, вы получите исключение безопасности.

Обновление. В новых API-методах метод "collapsePanels" вместо "свернуть".

Единственный способ, который я нашел после нескольких часов работы, - это переопределить метод активности onWindowFocusChanged и когда он теряет фокус (возможно, пользователь коснулся панели уведомлений), принудительно свернуть StatusBar, здесь это код (работает с Defy + 2.3.5).

Вам нужно объявить следующее манифест:

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

И переопределите следующий метод:

public void onWindowFocusChanged(boolean hasFocus)
{
        try
        {
           if(!hasFocus)
           {
                Object service  = getSystemService("statusbar");
                Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
                Method collapse = statusbarManager.getMethod("collapse");
                collapse .setAccessible(true);
                collapse .invoke(service);
           }
        }
        catch(Exception ex)
        {
        }
}

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

Ответ 3

На самом деле это можно сделать с помощью небольшого взлома, который я случайно обнаружил, но требует разрешения android.permission.SYSTEM_ALERT_WINDOW:

То, что вы делаете, - это добавить точный размер строки состояния непосредственно в WindowManager с определенными параметрами, которые покрывают строку состояния и не позволяют получать события касания:

View disableStatusBarView = new View(context);

WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.FILL_PARENT,
    <height of the status bar>,
    // This allows the view to be displayed over the status bar
    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
    // this is to keep button presses going to the background window
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
    // this is to enable the notification to recieve touch events
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
    // Draws over status bar
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
    PixelFormat.TRANSLUCENT);

handleParams.gravity = Gravity.TOP;
context.getWindow().addView(disableStatusBarView, handleParams);

Это будет в основном создавать прозрачный вид в строке состояния, который будет получать все события касания и блокировать события до выхода из строки состояния и, следовательно, предотвращает его расширение.

ПРИМЕЧАНИЕ. Этот код не проверен, но концепция работает.

Ответ 4

Фактически вы можете запретить расширение строки состояния, не укореняя телефон. См. эту ссылку. Это рисует окно высотой строки состояния и потребляет все события касания.

Вызвать следующий код сразу после onCreate().

public static void preventStatusBarExpansion(Context context) {
    WindowManager manager = ((WindowManager) context.getApplicationContext()
            .getSystemService(Context.WINDOW_SERVICE));

    Activity activity = (Activity)context;
    WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
    localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
    localLayoutParams.gravity = Gravity.TOP;
    localLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|

    // this is to enable the notification to recieve touch events
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |

    // Draws over status bar
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

    localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
    //https://stackoverflow.com/questions/1016896/get-screen-dimensions-in-pixels
    int resId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
    int result = 0;
    if (resId > 0) {
        result = activity.getResources().getDimensionPixelSize(resId);
    }

    localLayoutParams.height = result;

    localLayoutParams.format = PixelFormat.TRANSPARENT;

    customViewGroup view = new customViewGroup(context);

    manager.addView(view, localLayoutParams);
}

public static 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) {
        Log.v("customViewGroup", "**********Intercepted");
        return true;
    }
}

Ответ 5

Я попробовал решения, упомянутые GrantLand и PoOk, но оба они не работали в моем случае. Хотя, Еще одно решение Очистить/Скрыть Недавние Задачи Список помогло. Я пишу приложение launcher, для которого мне пришлось отключить последнее меню приложений, чтобы пользователь не мог открыть из него заблокированное приложение. Кроме того, я должен был предотвратить распространение расширений уведомлений, и этот трюк заставил меня обойти оба. Переопределите метод OnWindowFocusChanged в своей деятельности и проверьте, действительно ли это нужно.

public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

        Log.d("Focus debug", "Focus changed !");

    if(!hasFocus) {
        Log.d("Focus debug", "Lost focus !");

        Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        sendBroadcast(closeDialog);
    }
}

Ответ 6

Для блокировки экрана. Почему бы вам просто не использовать следующее в своем основном действии:

@Override
public void onAttachedToWindow() {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}

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

Если у пользователя есть безопасный набор блокировок, приложение отобразит строку состояния, но не позволит взаимодействовать с ним. Это связано с тем, что телефон по-прежнему заблокирован, и только ваша деятельность разрешена для работы до тех пор, пока пользователь не разблокирует телефон. Кроме того, закрытие вашего приложения в любом случае откроет стандартный защищенный экран блокировки. Все это очень желательно, потому что вам не нужно тратить все время на кодирование защищенных функций, которые вы не можете гарантировать, будет столь же безопасным, как и запасные.

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

Надеюсь, что поможет

Ответ 7

Извините, но это не сработает. использование FLAG_LAYOUT_IN_SCREEN предотвращает попадание любых событий касания.

И BTW: для добавления окна в окно используйте диспетчер окон:

WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE);
winMgr.addView(disableStatusBar, handleParams); 

Ответ 8

requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                            WindowManager.LayoutParams.FLAG_FULLSCREEN);