www windowmanager net flag_secure android android-windowmanager

android - net - windowmanager layoutparams flag_secure



Android: no se puede agregar la ventana. Permiso denegado para este tipo de ventana (11)

Buscar

Dibuja sobre otras aplicaciones

en su configuración y habilite su aplicación. Para Android 8 Oreo, prueba

Configuración> Aplicaciones y notificaciones> Información de la aplicación> Mostrar sobre otras aplicaciones> Habilitar

Estoy trabajando en una aplicación donde necesito mostrar una ventana con información en la pantalla de bloqueo (KeyGuard) sin desbloquear el teléfono. Pensé que probablemente podría hacerlo con WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG

Pero cada vez que mi aplicación falla con el siguiente error:

android.view.WindowManager $ BadTokenException: no se puede agregar la ventana android.view.ViewRootImpl$W@40ec8528 - permiso denegado para este tipo de ventana

Estas publicaciones ( here , here y here ) dan la misma respuesta. Para agregar el siguiente permiso en el archivo de manifiesto.

android.permission.SYSTEM_ALERT_WINDOW

Solución que he implementado pero sigo recibiendo el mismo error. ¿Alguna idea de lo que estoy haciendo mal?

Aquí están los permisos en mi archivo de manifiesto:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.droidpilot.keyguardwindow" > <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.VIBRATE" />

Y este es el código que uso para agregar la ventana a la pantalla de bloqueo

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); mView = mInflater.inflate(R.layout.lock_screen_notif, null); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, PixelFormat.TRANSLUCENT ); wm.addView(mView, params);

Alguien tiene alguna idea?

PD: Estoy probando en un HTC Desire 620 DS con Android 4.4.2


En primer lugar, asegúrese de tener permiso para agregar en el archivo de manifiesto.

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

¿Verifica si la aplicación tiene permiso sobre otras aplicaciones o no? Este permiso está disponible de forma predeterminada para API <23. Pero para API> 23 debe solicitar el permiso en tiempo de ejecución.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 1); }

Use este código:

public class ChatHeadService extends Service { private WindowManager mWindowManager; private View mChatHeadView; WindowManager.LayoutParams params; public ChatHeadService() { } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Language language = new Language(); //Inflate the chat head layout we created mChatHeadView = LayoutInflater.from(this).inflate(R.layout.dialog_incoming_call, null); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, PixelFormat.TRANSLUCENT); params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; params.x = 0; params.y = 100; mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); mWindowManager.addView(mChatHeadView, params); } else { params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, PixelFormat.TRANSLUCENT); params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; params.x = 0; params.y = 100; mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); mWindowManager.addView(mChatHeadView, params); } TextView tvTitle=mChatHeadView.findViewById(R.id.tvTitle); tvTitle.setText("Incoming Call"); //Set the close button. Button btnReject = (Button) mChatHeadView.findViewById(R.id.btnReject); btnReject.setText(language.getText(R.string.reject)); btnReject.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //close the service and remove the chat head from the window stopSelf(); } }); //Drag and move chat head using user''s touch action. final Button btnAccept = (Button) mChatHeadView.findViewById(R.id.btnAccept); btnAccept.setText(language.getText(R.string.accept)); LinearLayout linearLayoutMain=mChatHeadView.findViewById(R.id.linearLayoutMain); linearLayoutMain.setOnTouchListener(new View.OnTouchListener() { private int lastAction; private int initialX; private int initialY; private float initialTouchX; private float initialTouchY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //remember the initial position. initialX = params.x; initialY = params.y; //get the touch location initialTouchX = event.getRawX(); initialTouchY = event.getRawY(); lastAction = event.getAction(); return true; case MotionEvent.ACTION_UP: //As we implemented on touch listener with ACTION_MOVE, //we have to check if the previous action was ACTION_DOWN //to identify if the user clicked the view or not. if (lastAction == MotionEvent.ACTION_DOWN) { //Open the chat conversation click. Intent intent = new Intent(ChatHeadService.this, HomeActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); //close the service and remove the chat heads stopSelf(); } lastAction = event.getAction(); return true; case MotionEvent.ACTION_MOVE: //Calculate the X and Y coordinates of the view. params.x = initialX + (int) (event.getRawX() - initialTouchX); params.y = initialY + (int) (event.getRawY() - initialTouchY); //Update the layout with new X & Y coordinate mWindowManager.updateViewLayout(mChatHeadView, params); lastAction = event.getAction(); return true; } return false; } }); } @Override public void onDestroy() { super.onDestroy(); if (mChatHeadView != null) mWindowManager.removeView(mChatHeadView); }

}


Finalmente pude mostrar una ventana en la pantalla de bloqueo con el uso de TYPE_SYSTEM_OVERLAY lugar de TYPE_KEYGUARD_DIALOG . Esto funciona como se esperaba y agrega la ventana en la pantalla de bloqueo.

El problema con esto es que la ventana se agrega sobre todo lo que posiblemente puede. Es decir, la ventana incluso aparecerá en la parte superior del bloqueo del teclado / patrón en caso de pantallas de bloqueo seguro. En el caso de una pantalla de bloqueo no segura, aparecerá en la parte superior de la bandeja de notificaciones si la abre desde la pantalla de bloqueo.

Para mí, eso es inaceptable. Espero que esto pueda ayudar a cualquiera que se enfrente a este problema.


Hice todo lo posible para probar todos los ejemplos disponibles para este problema. Finalmente obtuve la respuesta para esto. No sé cuánto es confiable, pero mi aplicación no se bloquea ahora.

windowManager = (WindowManager)getSystemService(WINDOW_SERVICE); //here is all the science of params final LayoutParams myParams = new LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, LayoutParams.TYPE_SYSTEM_ERROR, WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, PixelFormat.TRANSLUCENT );

En tu archivo de manifiesto solo da el permiso

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

Además de esto, también puede verificar el nivel de API si es> = 23 y luego

if(Build.VERSION.SDK_INT >= 23) { if (!Settings.canDrawOverlays(Activity.this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 1234); } } else { Intent intent = new Intent(Activity.this, Service.class); startService(intent); }

Espero que ayude a alguien en alguna parte. Ejemplo completo https://anam-android-codes.blogspot.in/?m=1


LayoutParams.TYPE_PHONE está en desuso. He actualizado mi código como estos.

parameters = if (Build.VERSION.SDK_INT > 25) { LayoutParams( minHW * 2 / 3, minHW * 2 / 3, LayoutParams.TYPE_APPLICATION_OVERLAY, LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT) }else { LayoutParams( minHW * 2 / 3, minHW * 2 / 3, LayoutParams.TYPE_PHONE, LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT) }

LayoutParams.TYPE_APPLICATION_OVERLAY requiere un nivel de API 26 o superior.


Para el nivel de Android API 8.0.0, debe usar

WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY

en lugar de

LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL

o SYSTEM_ALERT .


Por razones que deberían ser completamente obvias, las aplicaciones comunes no pueden crear ventanas arbitrarias en la parte superior de la pantalla de bloqueo . ¿Qué crees que podría hacer si creara una ventana en tu pantalla de bloqueo que pudiera imitar perfectamente la pantalla de bloqueo real para que no pudieras notar la diferencia?

La razón técnica de su error es el uso del indicador TYPE_KEYGUARD_DIALOG : requiere android.permission.INTERNAL_SYSTEM_WINDOW que es un permiso de nivel de firma. Esto significa que solo las aplicaciones firmadas con el mismo certificado que el creador del permiso pueden usarlo.

El creador de android.permission.INTERNAL_SYSTEM_WINDOW es el sistema Android en sí mismo, por lo que a menos que su aplicación sea parte del sistema operativo, no tiene ninguna posibilidad.

Existen formas bien definidas y bien documentadas de notificar al usuario la información de la pantalla de bloqueo . Puede crear notificaciones personalizadas que se muestran en la pantalla de bloqueo y el usuario puede interactuar con ellas.


Supongo que deberías diferenciar el objetivo (antes y después de Oreo)

int LAYOUT_FLAG; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE; } params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, LAYOUT_FLAG, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);


cambie su marca el indicador de Windowmanger "TYPE_SYSTEM_OVERLAY" a "TYPE_APPLICATION_OVERLAY" en su proyecto para que sea compatible con Android O

WindowManager.LayoutParams.TYPE_PHONE a WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY


prueba este código funcionando perfectamente

int layout_parms; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { layout_parms = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { layout_parms = WindowManager.LayoutParams.TYPE_PHONE; } yourparams = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, layout_parms, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);


si usa apiLevel >= 19 , no use

WindowManager.LayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

que obtiene el siguiente error:

android.view.WindowManager $ BadTokenException: no se puede agregar la ventana android.view.ViewRootImpl$W@40ec8528 - permiso denegado para este tipo de ventana

Use esto en su lugar:

LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL