Previniendo la expansión de la barra de estado

¿Hay alguna forma de evitar que los usuarios deslicen la barra de estado (expandir) o colapsar?

Estoy probando un reemplazo de pantalla de locking y parece que es una característica imprescindible. ¿Hay alguna manera posible de hacerlo sin requerir privilegios de root?

Respuesta corta: ¡esto es imposible!

Ahora debería estar interesado en saber por qué esto es imposible:

Hay dos permisos para manipular la barra de estado del sistema, EXPAND_STATUS_BAR y STATUS_BAR . El primero puede ser solicitado por cualquier aplicación, pero el último está reservado para aplicaciones firmadas con la firma de la plataforma (aplicaciones del sistema, no de terceros). Es posible expandir / contraer la barra de estado del sistema (consulte “¿Cómo abrir o expandir la barra de estado a través del bash?” ), Pero tenga en cuenta que se requiere reflexión porque la clase StatusBarManager no es parte del SDK. El método de deshabilitar, que usa el marcador Android para evitar que se expanda la barra de estado, no puede accederse mediante una aplicación sin el permiso STATUS_BAR mencionado anteriormente.

Fuentes: experiencia personal 🙂

En realidad, puede evitar que la barra de estado se expanda, sin enrutar el teléfono. Ver este enlace Esto dibuja una ventana a la altura de la barra de estado y consume todos los eventos táctiles.

Llame al siguiente código justo después de 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; } } 

En primer lugar , es imposible modificar la barra de estado si su aplicación no está firmada con la ROM del teléfono certificada, si intenta modificarla obtendrá una excepción de seguridad.

Actualización : en nuevas API, el método es “collagesPaneles” en lugar de “colapsar”.

La única forma que he encontrado después de varias horas de trabajo es anulando el método “onWindowFocusChanged” de la actividad y cuando pierde el foco (tal vez el usuario ha tocado la barra de notificaciones), fuerza a colapsar la barra de estado, aquí está el código (trabajando en un Defy + 2.3.5).

Debe declarar el siguiente permiso en el manifiesto:

   

Y anule el siguiente método:

 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) { } } 

Actualización : Tendrá que usar su propio cuadro de diálogo de alerta al anular su método onWindowFocusChanged también, porque los cuadros de diálogo de alerta tienen su propio enfoque.

Esto realmente se puede hacer a través de un pequeño hack que descubrí accidentalmente, pero requiere el permiso android.permission.SYSTEM_ALERT_WINDOW :

Lo que hace es agregar una vista del tamaño exacto de la barra de estado directamente al Administrador de ventanas con los parámetros específicos que cubren la barra de estado y evita que reciba eventos táctiles:

 View disableStatusBarView = new View(context); WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.FILL_PARENT, , // 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); 

Esto básicamente creará una vista transparente sobre la barra de estado que recibirá todos los eventos táctiles y bloqueará los eventos para que no lleguen a la barra de estado y por lo tanto evita que se expanda.

NOTA: Este código no se ha probado, pero el concepto funciona.

Probé las soluciones mencionadas por GrantLand y PoOk, pero ambas no funcionaron en mi caso. Sin embargo, otra solución Clear / Hide Recent Tasks List hizo el truco para mí. Estoy escribiendo una aplicación de lanzamiento para la que tuve que deshabilitar un menú de aplicaciones recientes para que el usuario no pueda abrir una aplicación bloqueada. Además, tuve que evitar la expansión de la barra de notificaciones y este truco me hizo lograr ambos. Anule el método OnWindowFocusChanged en su actividad y verifique si esto es lo que desea.

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

Para una pantalla de locking ¿Por qué no utilizas lo siguiente en tu actividad principal?

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

Si el usuario no tiene un set de pantalla de locking seguro, la aplicación le permitirá al usuario tirar de la barra de estado hacia abajo y abrir actividades, pero eso no importa ya que el usuario obviamente no quiere una pantalla segura de todos modos.

Si el usuario tiene un conjunto locksreen seguro, la aplicación mostrará la barra de estado, pero no permitirá las interacciones con él. Esto se debe a que el teléfono todavía está bloqueado y solo su actividad puede funcionar hasta que el usuario desbloquee el teléfono. Además, si cierras tu aplicación de todos modos, se abrirá la pantalla de locking segura estándar. Todo esto es muy conveniente porque no tiene que pasar todo ese tiempo codificando funciones seguras que no puede garantizar que sean tan seguras como las de stock.

Si realmente no desea que el usuario pueda interactuar con la barra de estado, tal vez pueda omitir la llamada FLAG_DISMISS_KEYGUARD . Luego, justo antes de que esté a punto de desbloquear el teléfono, configure la bandera como la que mostré en el primer bloque. No sé si esta última parte funciona, pero vale la pena intentarlo.

Espero que ayude

Lo siento pero no funciona. usar FLAG_LAYOUT_IN_SCREEN evita que FLAG_LAYOUT_IN_SCREEN eventos táctiles.

Y por cierto: para agregar una vista a la ventana usa el administrador de ventanas:

 WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE); winMgr.addView(disableStatusBar, handleParams); 
 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);