IT TIP

Android : 창을 추가 할 수 없습니다.

itqueen 2020. 10. 27. 23:55
반응형

Android : 창을 추가 할 수 없습니다. 이 창 유형에 대한 권한이 거부되었습니다.


나는 약간의 정보가있는 창을 표시해야하는 응용 프로그램에서 일하고 있어요 ON 전화를 잠금 해제하지 않고 잠금 화면 (키 가드). 아마도 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG로 할 수 있다고 생각했습니다.

하지만 내 앱이 다음 오류와 함께 충돌 할 때마다 :

android.view.WindowManager $ BadTokenException : 창을 추가 할 수 없음 android.view.ViewRootImpl$W@40ec8528-이 창 유형에 대한 권한이 거부되었습니다.

이 게시물 ( here , herehere )은 모두 동일한 답변을 제공합니다. 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" />

그리고 이것은 잠금 화면에 Window를 추가하는 데 사용하는 코드입니다.

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

아는 사람있어?

PS Android 4.4.2를 실행하는 HTC Desire 620 DS에서 테스트 중입니다.


완전히 명백한 이유 때문에 일반 앱은 잠금 화면 위에 임의의 창을 만들 수 없습니다 . 잠금 화면에 실제 잠금 화면을 완벽하게 모방하여 차이를 구분할 수없는 창을 만들면 어떻게 할 수 있을까요?

오류의 기술적 이유는 TYPE_KEYGUARD_DIALOG플래그를 사용하기 때문 android.permission.INTERNAL_SYSTEM_WINDOW입니다. 서명 수준의 권한이 필요합니다 . , 권한 작성자 와 동일한 인증서서명 된 앱만 사용할 수 있습니다.

제작자 android.permission.INTERNAL_SYSTEM_WINDOW는 Android 시스템 자체이므로 앱이 OS의 일부가 아니라면 기회가 없습니다.

잠금 화면에서 정보를 사용자에게 알리는 잘 정의되고 문서화 된 방법이 있습니다. 잠금 화면에 표시되는 사용자 지정 알림을 생성하고 사용자가 상호 작용할 수 있습니다.


사용하는 경우 사용 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

타겟을 구분해야 할 것 같아요 (오레오 전후)

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

이 문제에 사용할 수있는 모든 예제를 시도하기 위해 최선을 다했습니다. 마침내 나는 이것에 대한 답을 얻었습니다. 얼마나 신뢰할 수 있는지 모르겠지만 내 앱이 지금 충돌하지 않습니다.

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 인 경우 API 수준을 확인할 수도 있습니다.

 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


Android API 레벨 8.0.0의 경우 다음을 사용해야합니다.

WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY

대신에

LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL

또는 SYSTEM_ALERT.


이 코드가 완벽하게 작동하도록 시도하십시오.

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

검색

다른 앱 위에 그리기

설정에서 앱을 활성화하십시오. Android 8 Oreo의 경우

설정> 앱 및 알림> 앱 정보> 다른 앱 위에 표시> 사용


TYPE_SYSTEM_OVERLAY대신을 사용하여 잠금 화면에 마침내 창을 표시했습니다 TYPE_KEYGUARD_DIALOG. 이것은 예상대로 작동하며 잠금 화면에 창을 추가합니다.

이것의 문제는 가능한 모든 것 위에 창이 추가 된다는 것입니다. 즉, 보안 잠금 화면의 경우이 창이 키패드 / ​​패턴 잠금 상단에도 나타납니다. 보안되지 않은 잠금 화면의 경우 잠금 화면에서 열면 알림 트레이 상단에 나타납니다.

나에게는 그것은 용납 할 수없는 일입니다. 나는 이것이이 문제에 직면 한 다른 사람에게 도움이되기를 바랍니다.


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 이상이 필요합니다.


Android O와 호환되도록 프로젝트에서 플래그 Windowmanger 플래그 "TYPE_SYSTEM_OVERLAY"를 "TYPE_APPLICATION_OVERLAY"로 변경하십시오.

WindowManager.LayoutParams.TYPE_PHONE ...에 WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY


먼저 매니페스트 파일에 추가 권한이 있는지 확인하십시오.

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

}

참고 URL : https://stackoverflow.com/questions/32224452/android-unable-to-add-window-permission-denied-for-this-window-type

반응형