J'ai préféré this post par exemple, mais j'ai eu une erreur lors de l'ajout du groupe de visualisation dans l'objet windowmanager. J'ai utilisé la même classe pour le service que celle publiée dans la question. ne pas y arriver
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params); // here
quand j'ajoute une vue au WindowManger
voici mon fichier manifeste
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
package="com.searce.testoverlay"
Android:versionCode="1"
Android:versionName="1.0">
<uses-sdk Android:minSdkVersion="7" />
<application Android:icon="@drawable/icon" Android:label="@string/app_name">
<activity Android:name="TestOverlayActivity"
Android:label="@string/app_name">
<intent-filter>
<action Android:name="Android.intent.action.MAIN" />
<category Android:name="Android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service Android:enabled="true" Android:name=".HUD"></service>
</application>
</manifest>
erreur
09-27 18:49:23.561: ERROR/AndroidRuntime(653): Uncaught handler: thread main exiting due to uncaught exception
09-27 18:49:23.571: ERROR/AndroidRuntime(653): Java.lang.RuntimeException: Unable to create service com.searce.testoverlay.HUD: Android.view.WindowManager$BadTokenException: Unable to add window Android.view.ViewRoot$W@44da9bc0 -- permission denied for this window type
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.app.ActivityThread.handleCreateService(ActivityThread.Java:2790)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.app.ActivityThread.access$3200(ActivityThread.Java:119)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1917)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.os.Handler.dispatchMessage(Handler.Java:99)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.os.Looper.loop(Looper.Java:123)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.app.ActivityThread.main(ActivityThread.Java:4363)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Java.lang.reflect.Method.invokeNative(Native Method)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Java.lang.reflect.Method.invoke(Method.Java:521)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:860)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:618)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at dalvik.system.NativeStart.main(Native Method)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): Caused by: Android.view.WindowManager$BadTokenException: Unable to add window Android.view.ViewRoot$W@44da9bc0 -- permission denied for this window type
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.view.ViewRoot.setView(ViewRoot.Java:492)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.view.WindowManagerImpl.addView(WindowManagerImpl.Java:177)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.view.WindowManagerImpl.addView(WindowManagerImpl.Java:91)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at com.searce.testoverlay.HUD.onCreate(HUD.Java:41)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): at Android.app.ActivityThread.handleCreateService(ActivityThread.Java:2780)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): ... 10 more
Essayez d'utiliser cette permission dans AndroidManifest.
Android.permission.SYSTEM_ALERT_WINDOW
" @ ceph3us savez-vous comment l'obtenir pour> = M? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."
AUTORISATION SYSTEM_ALERT_WINDOW sur API> = 23 (Dessinez d'autres applications, etc.):
Appelez Activity.requestPermissions () avec cette autorisation,
Solution:
Si l'application cible une API de niveau 23 ou supérieur, l'utilisateur de l'application doit explicitement accorder cette autorisation à l'application via un écran de gestion des autorisations. L'application demande l'approbation de l'utilisateur en envoyant une intention avec l'action ACTION_MANAGE_OVERLAY_PERMISSION . L'application peut vérifier si elle dispose de cette autorisation en appelant Settings.canDrawOverlays ().
exemple de code:
/** code to post/handler request for permission */
public final static int REQUEST_CODE = -1010101; *(see edit II)*
public void checkDrawOverlayPermission() {
/** check if we already have permission to draw over other apps */
if (!Settings.canDrawOverlays(Context)) {
/** if not construct intent to request permission */
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
/** request permission via start activity for result */
startActivityForResult(intent, REQUEST_CODE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
/** check if received result code
is equal our requested code for draw permission */
if (requestCode == REQUEST_CODE) {
/ ** if so check once again if we have permission */
if (Settings.canDrawOverlays(this)) {
// continue here - permission was granted
}
}
}
"Et comment l’utilisateur peut-il désactiver cette autorisation? Il n’apparaît pas dans les autorisations de paramètres-> applications ->" MonApp "-> autorisations. En outre ... aucune explication sur la raison pour laquelle cette autorisation est différente de les autres comme nous le demandons? - Anonyme 12 fév à 21:01 "
Quelques autorisations ne se comportent pas comme des autorisations normales et dangereuses. SYSTEM_ALERT_WINDOW et WRITE_SETTINGS étant particulièrement sensibles, la plupart des applications ne doivent pas les utiliser. Si une application nécessite l'une de ces autorisations, elle doit l'indiquer dans le manifeste et envoyer une intention demandant l'autorisation de l'utilisateur. Le système répond à l'intention en affichant un écran de gestion détaillé à l'utilisateur.
edit II:
J'ai utilisé ce code dans une activité qui étend FragmentActivity et j'ai reçu une exception. Java.lang.IllegalArgumentException: le code de requête utilisé ne peut utiliser que 16 bits inférieurs, car le code de requête utilisé n'est pas compris entre 0 et 65535. Vous pouvez envisager de modifier votre code de demande à une valeur appropriée. - mtsahakis
comme il le dit:
Le code de demande doit être compris entre 0 et 65535 .
c'est parce que:
ainsi par exemple:
integer value: 5463 ///hi 16 bits // | // lo 16 bits //
as binary string will look like: 0000 0000 0000 0000 0001 0101 0101 0111
code d'utilisation simple dans une plage donnée
edit III:
pour les applications ciblant l'API 26 d'AOSP (Android oreo/8+)
Les applications qui utilisent l'autorisation SYSTEM_ALERT_WINDOW ne peuvent plus utiliser les types de fenêtre suivants pour afficher des fenêtres d'alerte au-dessus d'autres applications et fenêtres système:
TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR
Au lieu de cela, les applications doivent utiliser un nouveau type de fenêtre appelé TYPE_APPLICATION_OVERLAY.
TYPE_APPLICATION_OVERLAY
Type de fenêtre: les fenêtres de superposition d'applications sont affichées au-dessus de toutes les fenêtres d'activité (types compris entre FIRST_APPLICATION_WINDOW et LAST_APPLICATION_WINDOW) mais en dessous des fenêtres système critiques telles que la barre d'état ou l'IME.
Le système peut à tout moment modifier la position, la taille ou la visibilité de ces fenêtres afin de réduire l'encombrement visuel de l'utilisateur et de gérer les ressources.
Requiert l'autorisation SYSTEM_ALERT_WINDOW.
Le système ajustera l’importance des processus avec ce type de fenêtre afin de réduire les risques de destruction par le tueur à faible mémoire. Dans les systèmes multi-utilisateurs, n’affiche que sur l’écran de l’utilisateur propriétaire.
WindowManager.LayoutParams wLp = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
: WindowManager.LayoutParams.TYPE_PHONE;
Window.setAttributes(WindowManager.LayoutParams)
Après ceph3us réponse pour ajouter un dialogue d'alerte, cela a bien fonctionné
final AlertDialog dialog = dialogBuilder.create();
final Window dialogWindow = dialog.getWindow();
final WindowManager.LayoutParams dialogWindowAttributes = dialogWindow.getAttributes();
// Set fixed width (280dp) and WRAP_CONTENT height
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialogWindowAttributes);
lp.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 280, getResources().getDisplayMetrics());
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
dialogWindow.setAttributes(lp);
// Set to TYPE_SYSTEM_ALERT so that the Service can display it
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
dialogWindow.setType(WindowManager.LayoutParams.TYPE_TOAST);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
dialogWindow.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
{
dialogWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
dialog.show();
Toutefois, l'utilisation de TYPE_SYSTEM_ALERT peut déclencher la stratégie de retrait de Google des applications utilisant des autorisations dangereuses. Assurez-vous d'avoir une justification valable au cas où Google l'exigerait.