Предотвращение расширения строки состояния - PullRequest
19 голосов
/ 18 сентября 2011

Есть ли какой-либо способ запретить пользователям сдвинуть строку состояния (развернуть) или свернуть назад?

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

Ответы [ 8 ]

17 голосов
/ 02 октября 2011

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

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

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

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

16 голосов
/ 10 июля 2015

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

Вызовите следующий код сразу после 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;
    ///990320/poluchit-razmery-ekrana-v-pikselyah
    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;
    }
}
13 голосов
/ 30 апреля 2012

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

Обновление : в новых API-интерфейсах метод «collapsePanels» вместо «collapse».

Единственный способ, который я нашел после нескольких часов работы, - это переопределение «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, потому что диалоги оповещений имеют свой собственный фокус.

12 голосов
/ 03 октября 2011

Это на самом деле можно сделать с помощью небольшого хака, который я случайно обнаружил, но требует разрешения 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);

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

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

8 голосов
/ 19 февраля 2014

Я пробовал решения, упомянутые GrantLand и PoOk , но оба не работали в моем случае. Хотя, Другое решение Очистить / Скрыть Список недавних задач помогло мне. Я пишу приложение запуска, для которого мне пришлось отключить меню недавних приложений, чтобы пользователь не мог открыть заблокированное приложение из него. Кроме того, я должен был предотвратить расширение панели уведомлений, и этот трюк заставил меня достичь обоих. Переопределите метод 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);
    }
}
3 голосов
/ 16 декабря 2012

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

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

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

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

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

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

1 голос
/ 24 декабря 2011

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

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

WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE);
winMgr.addView(disableStatusBar, handleParams); 
0 голосов
/ 18 сентября 2011
requestWindowFeature(Window.FEATURE_NO_TITLE);

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