it-swarm-eu.dev

SYSTEM_ALERT_WINDOW PERMISSION su API 26 non funziona come previsto. Autorizzazione negata per il tipo di finestra 2002

Sto usando il permesso di sovrapposizione per visualizzare determinate informazioni nella mia app. Eseguendolo su API 23-25 ​​funziona perfettamente (chiedendo il permesso, la concessione, ecc. Secondo

Impossibile aggiungere la finestra [email protected] - autorizzazione negata per questo tipo di finestra ). (Mille grazie a ceph3us!)

Provare lo stesso su API 26 Ricevo un errore, in pratica "autorizzazione negata per il tipo di finestra 2002" durante la chiamata

windowManager.addView(frameLayout, params);

Google ha cambiato il modo, la sovrapposizione funziona? Qualche idea, come ottenere il mio testo come una sovrapposizione sullo schermo in Android 8 (Oreo), API 26? Grazie per le tue idee!

Questo è il log degli errori:

08-24 16:41:56.730 2615-2615/net.zwittscha.testoverlay E/AndroidRuntime: FATAL EXCEPTION: main
Process: net.zwittscha.testoverlay, PID: 2615
Java.lang.RuntimeException: Unable to start activity ComponentInfo{net.zwittscha.testoverlay/net.zwittscha.testoverlay.MainActivity}: 
                Android.view.WindowManager$BadTokenException: Unable to add window [email protected] -- 
                permission denied for window type 2002
 at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2817)
 at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2892)
 at Android.app.ActivityThread.-wrap11(Unknown Source:0)
 at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1593)
 at Android.os.Handler.dispatchMessage(Handler.Java:105)
 at Android.os.Looper.loop(Looper.Java:164)
 at Android.app.ActivityThread.main(ActivityThread.Java:6541)
 at Java.lang.reflect.Method.invoke(Native Method)
 at com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240)
 at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767)
            Caused by: Android.view.WindowManager$BadTokenException: 
            Unable to add window [email protected] -- 
            permission denied for window type 2002
 at Android.view.ViewRootImpl.setView(ViewRootImpl.Java:789)
 at Android.view.WindowManagerGlobal.addView(WindowManagerGlobal.Java:356)
 at Android.view.WindowManagerImpl.addView(WindowManagerImpl.Java:92)
 at net.zwittscha.testoverlay.MainActivity.createOnTopView(MainActivity.Java:46)
 at net.zwittscha.testoverlay.MainActivity.checkDrawOverlayPermission(MainActivity.Java:66)
 at net.zwittscha.testoverlay.MainActivity.onCreate(MainActivity.Java:28)
 at Android.app.Activity.performCreate(Activity.Java:6975)
 at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1213)
 at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2770)
 at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2892) 
 at Android.app.ActivityThread.-wrap11(Unknown Source:0) 
 at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1593) 
 at Android.os.Handler.dispatchMessage(Handler.Java:105) 
 at Android.os.Looper.loop(Looper.Java:164) 
 at Android.app.ActivityThread.main(ActivityThread.Java:6541) 
 at Java.lang.reflect.Method.invoke(Native Method) 
 at com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240) 
 at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767) 

Nel mio Manifesto, ho:

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

<uses-permission Android:name="Android.permission.ACTION_MANAGE_OVERLAY_PERMISSION"/>

Questa è la mia MainActivity:

    public class MainActivity extends AppCompatActivity {

DrawView dv;
FrameLayout frameLayout;
WindowManager windowManager;
LayoutInflater layoutInflater;
/** code to post/handler request for permission */
public final static int REQUEST_CODE = 1234;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    checkDrawOverlayPermission();
}

public void createOnTopView() {

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_PHONE,
            WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
            PixelFormat.TRANSLUCENT);
    params.gravity = Gravity.CENTER;

    if (frameLayout == null) frameLayout = new FrameLayout(getApplicationContext());
    if (dv == null) dv = new DrawView(getApplicationContext());

    windowManager = (WindowManager)
            getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
    windowManager.addView(frameLayout, params);
    windowManager.addView(dv, params);

    layoutInflater = (LayoutInflater)
            getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    // Here is the place where you can inject whatever layout you want.
    layoutInflater.inflate(R.layout.activity_main, frameLayout);
}

public void checkDrawOverlayPermission() {
    /* check if we already  have permission to draw over other apps */
    if (Android.os.Build.VERSION.SDK_INT > 22) {
        if (!Settings.canDrawOverlays(this)) {
        /* 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);
        }
        else {
            createOnTopView();
        }
    }
}

@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 && Android.os.Build.VERSION.SDK_INT > 22) {
   /* if so check once again if we have permission */
        if (Settings.canDrawOverlays(this)) {
            createOnTopView();
        }
    }
}
}

E questo è il DrawView:

    public class DrawView extends View {

int w;
int h;
int r;
float screenFactor;
TextPaint startTextPaint;

public DrawView(Context activity) {
    super(activity);
}

@Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {

        w = width;
        h = height;
        r = w / 2;

    screenFactor = (r / 160f);

    if (startTextPaint == null) startTextPaint = new TextPaint();

    startTextPaint.setTextSize(100);
    startTextPaint.setTextAlign(Paint.Align.CENTER);
    startTextPaint.setTypeface(Typeface.create("Roboto Condensed", Typeface.BOLD));

    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {

        startTextPaint.setARGB(255,255,0,0);
        canvas.drawText("Test", w / 2, h / 2, startTextPaint);
}
}
19
tomseitz

Secondo la documentazione su Modifiche al comportamento di Android 8.0 per le app che hanno come target Android 8.0:

Le app che utilizzano l'autorizzazione SYSTEM_ALERT_WINDOW non possono più utilizzare i seguenti tipi di finestre per visualizzare finestre di avviso sopra altre app e finestre di sistema:

TYPE_PHONE
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR

Invece, le app devono utilizzare un nuovo tipo di finestra chiamato TYPE_APPLICATION_OVERLAY.

Quindi la tua app potrebbe essere indirizzata a una versione inferiore. In questo caso, la finestra di avviso verrà ...

appaiono sempre sotto le finestre che usano il tipo di finestra TYPE_APPLICATION_OVERLAY. Se un'app sceglie Android 8.0 (livello API 26), l'app utilizza il tipo di finestra TYPE_APPLICATION_OVERLAY per visualizzare le finestre di avviso.

(citato dalla stessa fonte)

41
0X0nosugar

Android Oreo (e versioni future) non consente l'uso di WindowManager.LayoutParams.TYPE_PHONE perché è deprecato, invece usa WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY 

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,
                    PixelFormat.TRANSLUCENT);
        }else{
            params = new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    PixelFormat.TRANSLUCENT);
        }
}

prova questo codice perfettamente funzionante

 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);
5
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR
}
else
{
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
}

cambia solo in questo parametro di Window manager

1
Makvin

Usa il seguente codice 

int LAYOUT_FLAG = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_PHONE;
    mWindowParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
            LAYOUT_FLAG, // Overlay over the other apps.
            LayoutParams.FLAG_NOT_FOCUSABLE    // This flag will enable the back key press.
                    | LayoutParams.FLAG_NOT_TOUCH_MODAL, // make the window to deliver the focus to the BG window.
            PixelFormat.TRANSPARENT);
0
MKY