Android.view.ViewRoot$W@44da9bc0 penceresi eklenemiyor - bu pencere türü için izin reddedildi


82

Örneğin bu gönderiyi tercih ettim ama viewgroup'u windowmanager nesnesine eklerken hatayı aldım, soruya gönderilen aynı sınıfı Hizmet için kullandım ve nerede hata yapabileceğimi fark etmedim.

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params); // here

WindowManger'a görünüm eklediğimde

işte benim manifest dosyam

<?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>

hata

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

Yanıtlar:


154

Bu izni şurada kullanmayı deneyin AndroidManifest.

android.permission.SYSTEM_ALERT_WINDOW

API üzerinde> = 23 bakın


@ ceph3us bunu> = M için nasıl başaracağınızı biliyor musunuz? ActivityCompat.requestPermissions (bu, yeni String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW); Hiçbir şeyi ateşlemeyecek. Şununla aynı: ActivityCompat.requestPermissions (bu, yeni String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);
Martin Pfeffer

Ek olarak, telefonunuzdaki ayarlardan programlı veya manuel olarak açık bir şekilde izin vermeniz gerekebilir. Huawei Nexus 6p kullanıyordum ve uygulamamın ayarlarında ekran bölümündeki diğer uygulamalar üzerinde çizim yaparken "Evet" e tıkladım.
emir

iyi bir çözüm için buna bakın: github.com/facebook/react-native/issues/…
WiRa

144

" @ ceph3us bunu> = M için nasıl başaracağınızı biliyor musunuz? ActivityCompat.requestPermissions (bu, yeni String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."

  1. API'de SYSTEM_ALERT_WINDOW PERMISSION> = 23 (Diğer uygulamaların üzerine çiz vb.):

    • artık Uygulamanın İzinler ekranında görünmez.
    • tuhaf bir şekilde kafa karıştıran yeni "Tüm izinler" ekranında bile görünmüyor
  2. Activity.requestPermissions () bu izinle çağrılıyor,

    • kullanıcının İzin vermesi / Reddetmesi için herhangi bir iletişim kutusu göstermez.
    • bunun yerine, Activity.onRequestPermissionsResult () geri araması, reddedilen bir bayrakla hemen çağrılır.

Çözüm:

Uygulama API seviyesi 23 veya üzerini hedefliyorsa, uygulama kullanıcısı bu izni bir izin yönetimi ekranı aracılığıyla uygulamaya açıkça vermelidir. Uygulama , ACTION_MANAGE_OVERLAY_PERMISSION eylemi içeren bir niyet göndererek kullanıcının onayını ister . Uygulama, Settings.canDrawOverlays () öğesini çağırarak bu yetkiye sahip olup olmadığını kontrol edebilir.

örnek kod:

/** 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 
       }
    }
}

"Ve kullanıcı bu izni nasıl devre dışı bırakabilir? Ayarlar-> uygulamalar ->" Uygulamam "-> izinlerdeki izinlerde gösterilmez. Ayrıca ... bu iznin neden diğerlerinden farklı olduğuna dair herhangi bir açıklama biz bunu talep etme şeklimiz - Anonim 12 Şubat 21:01 "

Normal ve tehlikeli izinler gibi davranmayan birkaç izin vardır. SYSTEM_ALERT_WINDOW ve WRITE_SETTINGS özellikle hassastır, bu nedenle çoğu uygulama bunları kullanmamalıdır. Bir uygulama bu izinlerden birine ihtiyaç duyuyorsa, manifestte izni beyan etmeli ve kullanıcının yetkilendirmesini isteyen bir niyet göndermelidir. Sistem kullanıcıya detaylı bir yönetim ekranı göstererek amaca cevap verir.

Özel İzinler

düzenleme II:

Bu kodu FragmentActivity'yi genişleten bir Activity'de kullandım ve Exception aldım java.lang.IllegalArgumentException: Kullanılan istek kodu 0 .. 65535 aralığında olmadığından yalnızca requestCode için daha düşük 16 bit kullanabilir. İstek kodunuzu olarak değiştirmeyi düşünebilirsiniz. uygun bir değer. - mtsahakis

dediği gibi:

istek kodu 0 .. 65535 aralığında olmalıdır .

bunun nedeni:

  • Java'da tam sayı 32 bit ile temsil edilir
  • requestCode için daha düşük 16 bit kullanma izniniz var
  • diğer bitler istek işlemede kullanılır

Yani mesela:

integer value:  5463             ///hi 16 bits //   |    // lo 16 bits //
as binary string will look like: 0000 0000 0000 0000 0001 0101 0101 0111 

verilen aralıktaki basit kullanım kodu

düzenleme III:

AOSP API 26'yı hedefleyen uygulamalar için (android oreo / 8+)

SYSTEM_ALERT_WINDOW iznini kullanan uygulamalar, artık diğer uygulamaların ve sistem pencerelerinin üzerinde uyarı pencereleri görüntülemek için aşağıdaki pencere türlerini kullanamaz:

TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR

Bunun yerine, uygulamalar TYPE_APPLICATION_OVERLAY adlı yeni bir pencere türü kullanmalıdır.

TYPE_APPLICATION_OVERLAY

Pencere türü: Uygulama bindirme pencereleri, tüm etkinlik pencerelerinin üzerinde (FIRST_APPLICATION_WINDOW ve LAST_APPLICATION_WINDOW arasındaki türler) ancak durum çubuğu veya IME gibi kritik sistem pencerelerinin altında görüntülenir.

Sistem, kullanıcının görsel karmaşasını azaltmak ve ayrıca kaynakları yönetmek için bu pencerelerin konumunu, boyutunu veya görünürlüğünü herhangi bir zamanda değiştirebilir.

SYSTEM_ALERT_WINDOW izni gerektirir.

Sistem, düşük bellek katilinin onları öldürme olasılığını azaltmak için bu pencere türü ile işlemlerin önemini ayarlayacaktır. Çok kullanıcılı sistemlerde yalnızca sahip olan kullanıcının ekranında gösterilir.

WindowManager.LayoutParams wLp = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
      ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
      : WindowManager.LayoutParams.TYPE_PHONE;

Window.setAttributes(WindowManager.LayoutParams)

2
Ve kullanıcı bu izni nasıl devre dışı bırakabilir? Ayarlar-> uygulamalar -> "Uygulamam" -> izinlerdeki izinlerde gösterilmez. Ayrıca ... bu iznin talep ettiğimiz şekilde diğerlerinden neden farklı olduğuna dair herhangi bir açıklama var mı?
Anonim

1
Bu kodu FragmentActivity'yi genişleten bir Activity'de kullandım ve java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCodekullanılan istek kodu 0 .. 65535 aralığında olmadığı için Exception aldım . İstek kodunuzu uygun bir değere değiştirmeyi düşünebilirsiniz.
mtsahakis

1
Bu istek kodunu kullanın ....... public final static int REQUEST_CODE = 5463 & 0xffffff00;
Muhammad Adil

@MuhammadAdil buradaki bitselliğin amacı nedir? u değeri 5376 olarak değiştir
ceph3us

@ ceph3us burada REQUEST_CODE ..... java.lang.IllegalArgumentException kullanırsak bu hatayı alırız: requestCode için sadece daha düşük 16 bit kullanabilir ........ Bu yüzden düzeltilmesi gerekir.
Muhammad Adil

3

Bir Uyarı İletişim Kutusu eklemek için ceph3us yanıtını takiben , bu iyi çalıştı

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

Ancak TYPE_SYSTEM_ALERT kullanılması, Google'ın tehlikeli izinler kullanan uygulamaları yayından kaldırma politikasını tetikleyebilir. Google'ın gerektirmesi durumunda geçerli bir gerekçeniz olduğundan emin olun.


TYPE_APPLICATION_OVERLAY'i kullanmamak, ancak Android 7.1.1 veya daha düşük olan telefonlar için başka bir tür (benim durumumda TYPE_PHONE), benim durumumda bu sinir bozucu BadTokenException'dan kurtulmama yardımcı oldu. Stackoverflow.com/questions/32224452/… sayfasına
Martin Vysny

-8

Hedef SDK'nızı 22 veya daha azına değiştirebilirsiniz, ardından API 23'te de çalışır.

Gradle.Build'de değiştirin.


3
@Hulk Belki de en iyi çözüm değil, ama bunu belirtmek güzel.
Quark

Bu, sorunu çözmez, kullanabileceğiniz hızlı bir çözümdür ancak api> 23'ü hedefleyemezsiniz
Aaron
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.