Android: ไม่สามารถเพิ่มหน้าต่างได้ ปฏิเสธการอนุญาตสำหรับประเภทหน้าต่างนี้


86

ฉันกำลังทำงานกับแอพที่ฉันต้องแสดงหน้าต่างพร้อมข้อมูลบางอย่างบนหน้าจอล็อก (KeyGuard) โดยไม่ต้องปลดล็อกโทรศัพท์ ฉันคิดว่าฉันสามารถทำได้ด้วยWindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG

แต่ทุกครั้งที่แอปของฉันขัดข้องโดยมีข้อผิดพลาดต่อไปนี้:

android.view.WindowManager $ BadTokenException: ไม่สามารถเพิ่มหน้าต่าง android.view.ViewRootImpl$W@40ec8528 - การอนุญาตถูกปฏิเสธสำหรับประเภทหน้าต่างนี้

โพสต์เหล่านี้ ( ที่นี่ , ที่นี่และที่นี่ ) ทั้งหมดให้คำตอบเดียวกัน ในการเพิ่มสิทธิ์ต่อไปนี้ในไฟล์ Manifest

android.permission.SYSTEM_ALERT_WINDOW

วิธีแก้ไขที่ฉันได้ติดตั้ง แต่ฉันยังคงได้รับข้อผิดพลาดเดิม มีความคิดว่าฉันทำอะไรผิดหรือเปล่า?

นี่คือสิทธิ์ในไฟล์รายการของฉัน:

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

และนี่คือรหัสที่ฉันใช้เพื่อเพิ่มหน้าต่างลงในหน้าจอล็อก

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

ใครมีความคิด?

ป.ล. ฉันกำลังทดสอบ HTC Desire 620 DS ที่ใช้ Android 4.4.2

คำตอบ:


31

สำหรับสิ่งที่ควรจะมีเหตุผลที่ชัดเจนสมบูรณ์Apps สามัญจะไม่ได้รับอนุญาตให้สร้างหน้าต่างโดยพลการในด้านบนของหน้าจอล็อค คุณคิดว่าฉันจะทำอย่างไรถ้าฉันสร้างหน้าต่างบนหน้าจอล็อกของคุณที่สามารถเลียนแบบหน้าจอล็อกจริงได้อย่างสมบูรณ์แบบคุณจึงไม่สามารถบอกความแตกต่างได้

เหตุผลทางเทคนิคสำหรับข้อผิดพลาดของคุณคือการใช้TYPE_KEYGUARD_DIALOGแฟล็กandroid.permission.INTERNAL_SYSTEM_WINDOWซึ่งต้องการการอนุญาตระดับลายเซ็น ซึ่งหมายความว่ามีเพียงแอปที่ลงนามด้วยใบรับรองเดียวกับผู้สร้างสิทธิ์เท่านั้นที่สามารถใช้งานได้

ผู้สร้างandroid.permission.INTERNAL_SYSTEM_WINDOWคือระบบ Android เองดังนั้นหากแอปของคุณไม่ได้เป็นส่วนหนึ่งของระบบปฏิบัติการคุณจะไม่มีโอกาส

มีกำหนดไว้อย่างดีและเอกสารที่ดีวิธีการในการแจ้งให้ผู้ใช้ข้อมูลจากหน้าจอล็อก คุณสามารถสร้างการแจ้งเตือนที่กำหนดเองซึ่งแสดงบนหน้าจอล็อกและผู้ใช้สามารถโต้ตอบกับพวกเขาได้


2
โดยส่วนตัวแล้วฉันกำลังมองหาบางอย่างเช่นการแจ้งเตือนหน้าจอล็อกของแอพ Facebook ฉันรู้แล้วเกี่ยวกับการแจ้งเตือนหน้าจอล็อกใหม่ แต่ตอนนี้ใช้ได้เฉพาะใน Android 22 เท่านั้น ฉันต้องการโซลูชันที่ใช้ได้กับ Android 16 ขึ้นไป แต่คำตอบของคุณสมเหตุสมผลและฉันจะยอมรับในสิ่งนั้น ฉันจัดการเพื่อแสดงหน้าต่างบนหน้าจอล็อค แต่ไม่ใช่สิ่งที่ฉันต้องการฉันจะโพสต์วิธีแก้ปัญหาที่พบด้านล่าง
DroidPilot

1
หากแอปต้องการสิทธิ์ดังกล่าวสามารถให้สิทธิ์ได้หลังจากติดตั้งและเปิดแล้ว
SkorpEN

ฉันคิดว่าเนื่องจากโอรีโอนี่เป็นคำตอบที่ถูกต้องstackoverflow.com/a/48481628/504179
ATom

108

ถ้าคุณใช้apiLevel >= 19อย่าใช้

WindowManager.LayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT 

ซึ่งได้รับข้อผิดพลาดต่อไปนี้:

android.view.WindowManager $ BadTokenException: ไม่สามารถเพิ่มหน้าต่าง android.view.ViewRootImpl$W@40ec8528 - การอนุญาตถูกปฏิเสธสำหรับประเภทหน้าต่างนี้

ใช้สิ่งนี้แทน:

LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL

3
ฉันTYPE_SYSTEM_ALERTทำงานได้ดีบน Android 5.1 ด้วยการandroid.permission.SYSTEM_ALERT_WINDOWให้สิทธิ์ในไฟล์ Manifest
แซม

ต้องใช้android.permission.SYSTEM_ALERT_WINDOWกับ LayoutParams.TYPE_TOASTอะไร?
t0m

1
ฉันลอง LayoutParams.TYPE_TOAST มันใช้งานได้สำหรับฉันใน Lollipop และ Marshmallow ทั้ง API ระดับ 6.0.1 ก่อนหน้านั้นฉันใช้ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT ซึ่งใช้ได้กับ Lollipop เท่านั้น
Prashant

น่าเสียดายที่ทำให้เกิด "การตรวจพบการซ้อนทับหน้าจอ" ในกรณีที่แอปพลิเคชันบางตัวขอกล่องโต้ตอบการอนุญาต (หากมุมมองของคุณใช้งานอยู่)
Siarhei

สิ่งนี้จะไม่ได้ผลหากคุณพยายามแสดงหน้าต่างจากภายในบริการหรือเครื่องรับสัญญาณออกอากาศ
FindOutIslamNow

80

ฉันเดาว่าคุณควรแยกแยะเป้าหมาย (ก่อนและหลังโอรีโอ)

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

ฉันพยายามที่จะใช้เทคนิคที่คล้ายกัน แต่หุ่นยนต์สตูดิโอไม่สามารถที่จะรับรู้และBuild.VERSION_CODES.O WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAYmy targetSdkVersion คือ 26
Gabe O'Leary

ขอบคุณความช่วยเหลือของคุณ +1 จากด้านข้างของฉัน
Saveen

@ GabeO'Leary ฉันกำลังประสบปัญหาเดียวกันคุณมีวิธีแก้ปัญหานี้หรือไม่?
Sagar

51

ฉันพยายามอย่างเต็มที่เพื่อลองใช้ตัวอย่างทั้งหมดที่มีให้สำหรับปัญหานี้ ในที่สุดฉันก็ได้คำตอบสำหรับสิ่งนี้ฉันไม่รู้ว่ามันเชื่อถือได้มากแค่ไหน แต่แอพของฉันไม่ล่ม

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

ในไฟล์รายการของคุณเพียงแค่ให้สิทธิ์

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

นอกจากนี้คุณยังสามารถตรวจสอบระดับ API ได้หาก> = 23 แล้ว

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

ฉันหวังว่ามันจะช่วยใครสักคน ตัวอย่างเต็ม https://anam-android-codes.blogspot.in/?m=1


13

สำหรับ Android API ระดับ 8.0.0 คุณควรใช้

WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY

แทน

LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL

หรือSYSTEM_ALERT.


TYPE_APPLICATION_OVERLAY ไม่อยู่ในรายการตัวเลือกที่แสดงใน Android Studio ฉันได้รับ "ไม่สามารถแก้ไขประเภทสัญลักษณ์" ฉันขาดอะไรไป?
philcruz

11

ลองใช้รหัสนี้ทำงานได้อย่างสมบูรณ์

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

คุณช่วยชีวิตฉัน
Fo Nko

@BakaWaii ที่คุณต้องการแสดงวิดเจ็ตเพื่อใส่รหัสนี้จะใช้งานได้ดี
shakirullah orakzai

6

ค้นหา

วาดทับแอพอื่น ๆ

ในการตั้งค่าของคุณและเปิดใช้งานแอปของคุณ สำหรับ Android 8 Oreo ลอง

การตั้งค่า> แอพและการแจ้งเตือน> ข้อมูลแอพ> แสดงทับแอพอื่น> เปิดใช้งาน


1
คุณคือผู้ช่วยชีวิต
Noor Hossain

5

ประการแรกคุณต้องแน่ใจว่าคุณได้เพิ่มสิทธิ์ในไฟล์รายการ

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

ตรวจสอบว่าแอปพลิเคชันได้รับอนุญาตจากแอปอื่นหรือไม่? การอนุญาตนี้เป็นค่าเริ่มต้นสำหรับ API <23 แต่สำหรับ API> 23 คุณต้องขออนุญาตในรันไทม์

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

ใช้รหัสนี้:

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

}


1
คุณสามารถแบ่งปันรหัส xml ของคุณและดูใน github หรืออย่างอื่นที่จะเป็นประโยชน์สำหรับฉัน
พาเวล

4

เปลี่ยนค่าสถานะ Windowmanger ค่าสถานะ "TYPE_SYSTEM_OVERLAY" เป็น "TYPE_APPLICATION_OVERLAY" ในโปรเจ็กต์ของคุณเพื่อให้เข้ากันได้กับ Android O

WindowManager.LayoutParams.TYPE_PHONE ถึง WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY


3

ในที่สุดฉันก็จัดการแสดงหน้าต่างบนหน้าจอล็อกด้วยการใช้TYPE_SYSTEM_OVERLAYแทนTYPE_KEYGUARD_DIALOG. ทำงานได้ตามที่คาดไว้และเพิ่มหน้าต่างบนหน้าจอล็อก

ปัญหานี้คือหน้าต่างจะถูกเพิ่มไว้ด้านบนของทุกสิ่งที่เป็นไปได้ นั่นคือหน้าต่างจะปรากฏที่ด้านบนของปุ่มกด / ล็อครูปแบบของคุณในกรณีของหน้าจอล็อกที่ปลอดภัย ในกรณีของหน้าจอล็อกที่ไม่มีหลักประกันหน้าจอจะปรากฏที่ด้านบนของถาดการแจ้งเตือนหากคุณเปิดจากหน้าจอล็อก

สำหรับฉันนั่นเป็นสิ่งที่ยอมรับไม่ได้ ฉันหวังว่าสิ่งนี้จะช่วยให้ใครก็ตามที่ประสบปัญหานี้


ขอบคุณมากสำหรับการแก้ปัญหา มีวิธียกเลิกหรือไม่? TYPE_SYSTEM_OVERLAYผมไม่สามารถที่จะยกเลิกการโต้ตอบเมื่อฉันเพิ่มเป็น setOnDismissListener ของฉันบน AlertDialog ไม่ได้รับการเรียกใช้
Tom Taylor

3

ฉันเพิ่งเพิ่มมุมมองง่ายๆWindowManagerด้วยขั้นตอนต่อไปนี้:

  1. สร้างไฟล์เลย์เอาต์หนึ่งไฟล์เพื่อแสดง (dummy_layout ในกรณีของฉัน)
  2. เพิ่มสิทธิ์ในรายการและแบบไดนามิก
// 1. Show view
private void showCustomPopupMenu()
{
    windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
    // LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    // View view = layoutInflater.inflate(R.layout.dummy_layout, null);
    ViewGroup valetModeWindow = (ViewGroup) View.inflate(this, R.layout.dummy_layout, null);
    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;
    }
    WindowManager.LayoutParams params=new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        LAYOUT_FLAG,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);

    params.gravity= Gravity.CENTER|Gravity.CENTER;
    params.x=0;
    params.y=0;
    windowManager.addView(valetModeWindow, params);
}

// 2. Get permissions by asking
if (!Settings.canDrawOverlays(this)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, 1234);
}

ด้วยวิธีนี้คุณสามารถเพิ่มมุมมองให้กับ WM

ทดสอบในพาย


2

LayoutParams.TYPE_PHONE เลิกใช้งานแล้ว ฉันได้อัปเดตรหัสของฉันเช่นนี้

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 ต้องการ api ระดับ 26 ขึ้นไป


0

เหตุผลหลักสำหรับการปฏิเสธการอนุญาตคือเราไม่ได้รับอนุญาตให้วาดทับแอพอื่นเราต้องให้สิทธิ์ในการวาดทับแอพอื่น ๆ ที่สามารถทำได้โดยใช้รหัสต่อไปนี้

ขอรหัสสำหรับการอนุญาต

    public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469;

เพิ่มสิ่งนี้ในMainActivityของคุณ


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
            askPermission();
}


private void askPermission() {
        Intent intent= new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:"+getPackageName()));
        startActivityForResult(intent,ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
}

เพิ่มสิ่งนี้ด้วย

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE){
            if(!Settings.canDrawOverlays(this)){
                askPermission();
            }
        }
    }


0

ฉันพยายามหาวิธีแก้ปัญหาที่ใช้งานได้ApplicationContextและTYPE_SYSTEM_ALERTพบวิธีแก้ปัญหาที่สับสนในกรณีที่คุณต้องการให้กล่องโต้ตอบเปิดจากกิจกรรมใด ๆ แม้กล่องโต้ตอบจะเป็นแบบซิงเกิลที่คุณต้องใช้getApplicationContext()และหากต้องการให้กล่องโต้ตอบTYPE_SYSTEM_ALERTคุณจะต้องทำตามขั้นตอนต่อไปนี้ :

ก่อนอื่นให้รับอินสแตนซ์ของกล่องโต้ตอบที่มีธีมที่ถูกต้องและคุณต้องจัดการความเข้ากันได้ของเวอร์ชันตามที่ฉันทำในตัวอย่างต่อไปนี้:

AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext(), R.style.Theme_AppCompat_Light);

หลังจากตั้งชื่อข้อความและปุ่มแล้วคุณต้องสร้างกล่องโต้ตอบเป็น:

AlertDialog alert = builder.create();

ตอนนี้typeเล่นเป็นม้วนหลักที่นี่เนื่องจากนี่เป็นสาเหตุของความผิดพลาดฉันจึงจัดการความเข้ากันได้ดังต่อไปนี้:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        alert.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY - 1);

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    }

หมายเหตุ : หากคุณใช้กล่องโต้ตอบแบบกำหนดเองAppCompatDialogดังต่อไปนี้:

AppCompatDialog dialog = new AppCompatDialog(getApplicationContext(), R.style.Theme_AppCompat_Light);

คุณสามารถกำหนดประเภทของคุณให้กับAppCompatDialogอินสแตนซ์ได้โดยตรงดังต่อไปนี้:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY - 1);

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    }

อย่าลืมเพิ่มสิทธิ์รายการ:

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

0
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    WindowManager.LayoutParams 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.START | Gravity.TOP;
    params.x = left;
    params.y = top;
    windowManager.addView(view, params);

} else {
    WindowManager.LayoutParams 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.START | Gravity.TOP;
    params.x = left;
    params.y = top;
    windowManager.addView(view, params);
}

0

ตรวจสอบให้แน่ใจว่าWindowManager.LayoutParams.TYPE_SYSTEM_ERRORได้เพิ่ม OS เวอร์ชัน <Oreo เนื่องจากเลิกใช้งานแล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.