Không thể thêm cửa sổ android.view.ViewRoot$W@44da9bc0 - quyền bị từ chối đối với loại cửa sổ này


82

Ví dụ, tôi thích bài đăng này hơn nhưng tôi gặp lỗi khi thêm viewgroup vào đối tượng windowmanager, tôi đã sử dụng cùng một lớp cho Dịch vụ như đã đăng trong câu hỏi mà không có thay đổi nào, tôi có thể nhầm lẫn là tôi đã không hiểu nó

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

khi tôi thêm chế độ xem vào WindowManger

đây là tệp kê khai của tôi

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

lỗi

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

Câu trả lời:


154

Hãy thử sử dụng quyền này trong AndroidManifest.

android.permission.SYSTEM_ALERT_WINDOW

trên API> = 23 xem


@ ceph3us bạn có biết làm thế nào để đạt được nó cho> = M không? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW); Sẽ không bắn bất cứ điều gì. Tương tự với: ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);
Martin Pfeffer

Ngoài ra, bạn có thể cần cấp quyền một cách rõ ràng, theo chương trình hoặc thủ công từ cài đặt trên điện thoại của bạn. Tôi đang sử dụng Huawei Nexus 6p và trong cài đặt cho ứng dụng của mình, tôi đã nhấp vào "Có" khi vẽ trên các ứng dụng khác trên phần màn hình.
emir

xem phần này để có giải pháp tốt: github.com/facebook/react-native/issues/…
WiRa

144

" @ ceph3us bạn có biết cách đạt được nó cho> = M không? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."

  1. SYSTEM_ALERT_WINDOW PERMISSION trên API> = 23 (Vẽ qua các ứng dụng khác, v.v.):

    • không còn xuất hiện trong màn hình Quyền của ứng dụng.
    • nó thậm chí không xuất hiện trong màn hình "Tất cả các quyền" mới khó hiểu
  2. Gọi Activity.requestPermissions () với quyền này,

    • sẽ không hiển thị bất kỳ hộp thoại nào để người dùng Cho phép / Từ chối.
    • thay vào đó, lệnh gọi lại Activity.onRequestPermissionsResult () sẽ được gọi ngay lập tức với một cờ bị từ chối.

Giải pháp:

Nếu ứng dụng nhắm mục tiêu API cấp 23 trở lên, người dùng ứng dụng phải cấp rõ ràng quyền này cho ứng dụng thông qua màn hình quản lý quyền. Ứng dụng yêu cầu sự chấp thuận của người dùng bằng cách gửi một ý định với hành động ACTION_MANAGE_OVERLAY_PERMISSION . Ứng dụng có thể kiểm tra xem nó có ủy quyền này hay không bằng cách gọi Settings.canDrawOverlays ()

mã ví dụ:

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

"Và làm thế nào người dùng có thể vô hiệu hóa quyền này? Nó không hiển thị trong các quyền trong cài đặt-> ứng dụng ->" MyApp "-> quyền. Ngoài ra ... bất kỳ lời giải thích nào về lý do tại sao quyền này khác với các quyền khác trong theo cách chúng tôi yêu cầu? - Ẩn danh ngày 12 tháng 2 lúc 21:01 "

Có một số quyền không hoạt động như các quyền bình thường và nguy hiểm. SYSTEM_ALERT_WINDOW và WRITE_SETTINGS đặc biệt nhạy cảm, vì vậy hầu hết các ứng dụng không nên sử dụng chúng. Nếu một ứng dụng cần một trong những quyền này, thì ứng dụng đó phải khai báo quyền đó trong tệp kê khai và gửi ý định yêu cầu ủy quyền của người dùng. Hệ thống đáp ứng mục đích bằng cách hiển thị màn hình quản lý chi tiết cho người dùng.

Quyền đặc biệt

chỉnh sửa II:

Tôi đã sử dụng mã này trong Hoạt động mở rộng FragmentActivity và nhận được Ngoại lệ java.lang.IllegalArgumentException: Chỉ có thể sử dụng 16 bit thấp hơn cho Mã yêu cầu vì mã yêu cầu được sử dụng không nằm trong phạm vi 0 .. 65535. Bạn có thể cân nhắc thay đổi mã yêu cầu của mình thành một giá trị thích hợp. - mtsahakis

như nó đã xảy ra:

mã yêu cầu phải nằm trong khoảng 0 .. 65535 .

đây là vì:

  • số nguyên trong java được biểu diễn bằng 32 bit
  • bạn được phép sử dụng 16 bit thấp hơn cho Mã yêu cầu
  • các bit khác được sử dụng trong xử lý yêu cầu

ví dụ:

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

mã sử dụng đơn giản trong phạm vi nhất định

chỉnh sửa III:

cho các ứng dụng nhắm mục tiêu AOSP API 26 (android oreo / 8+)

Các ứng dụng sử dụng quyền SYSTEM_ALERT_WINDOW không còn có thể sử dụng các loại cửa sổ sau để hiển thị cửa sổ cảnh báo phía trên các ứng dụng và cửa sổ hệ thống khác:

TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR

Thay vào đó, các ứng dụng phải sử dụng loại cửa sổ mới có tên TYPE_APPLICATION_OVERLAY.

TYPE_APPLICATION_OVERLAY

Loại cửa sổ: Các cửa sổ lớp phủ ứng dụng được hiển thị phía trên tất cả các cửa sổ hoạt động (loại giữa FIRST_APPLICATION_WINDOW và LAST_APPLICATION_WINDOW) nhưng bên dưới các cửa sổ hệ thống quan trọng như thanh trạng thái hoặc IME.

Hệ thống có thể thay đổi vị trí, kích thước hoặc khả năng hiển thị của các cửa sổ này bất cứ lúc nào để giảm bớt sự lộn xộn cho người dùng và cũng quản lý tài nguyên.

Yêu cầu quyền SYSTEM_ALERT_WINDOW.

Hệ thống sẽ điều chỉnh tầm quan trọng của các quy trình với kiểu cửa sổ này để giảm khả năng kẻ giết người có bộ nhớ thấp giết chúng. Trong hệ thống nhiều người dùng chỉ hiển thị trên màn hình của người dùng riêng.

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
Và làm cách nào để người dùng có thể tắt quyền này? Nó không hiển thị trong các quyền trong cài đặt-> ứng dụng -> "MyApp" -> quyền. Ngoài ra ... bất kỳ lời giải thích nào tại sao quyền này khác với các quyền khác theo cách chúng tôi yêu cầu?
Ẩn danh

1
Tôi đã sử dụng mã này trong Hoạt động mở rộng FragmentActivity và tôi nhận được Ngoại lệ java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCodevì mã yêu cầu được sử dụng không nằm trong phạm vi 0 .. 65535. Bạn có thể xem xét thay đổi mã yêu cầu của mình thành một giá trị thích hợp.
mtsahakis

1
Sử dụng mã yêu cầu này ....... public final static int REQUEST_CODE = 5463 & 0xffffff00;
Muhammad Adil

@MuhammadAdil mục đích của bitwise ở đây là gì? u thay đổi giá trị 5376
ceph3us

@ ceph3us ở đây chúng tôi gặp lỗi này nếu chúng tôi sử dụng REQUEST_CODE đó ..... java.lang.IllegalArgumentException: Chỉ có thể sử dụng 16 bit thấp hơn cho requestCode ........ Vì vậy, tôi mặc dù nó nên được sửa.
Muhammad Adil

3

Làm theo câu trả lời ceph3us để thêm Hộp thoại cảnh báo, điều này hoạt động tố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();

Nhưng việc sử dụng TYPE_SYSTEM_ALERT có thể kích hoạt chính sách gỡ xuống của Google đối với các ứng dụng sử dụng quyền nguy hiểm. Hãy chắc chắn rằng bạn có một lời biện minh hợp lệ trong trường hợp google yêu cầu.


Không sử dụng TYPE_APPLICATION_OVERLAY nhưng một số loại khác (TYPE_PHONE trong trường hợp của tôi) cho điện thoại chạy Android 7.1.1 trở xuống đã giúp tôi loại bỏ BadTokenException khó chịu này trong trường hợp của mình. Xem stackoverflow.com/questions/32224452/…
Martin Vysny,

-8

Bạn có thể thay đổi SDK mục tiêu của mình thành 22 hoặc thấp hơn, sau đó nó cũng hoạt động trên API 23.

Thay đổi nó trong Gradle.Build.


3
@Hulk Có thể đây không phải là giải pháp tốt nhất, nhưng bạn nên chỉ ra nó.
Quark

Điều này sẽ không giải quyết được vấn đề này, đó là một cách giải quyết nhanh chóng, bạn có thể sử dụng nhưng bạn không bao giờ có thể nhắm mục tiêu api> 23
Aaron
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.