wake-up-neo.net

SYSTEM_ALERT_WINDOW PERMISSION auf API 26 funktioniert nicht wie erwartet. Genehmigung für Fenstertyp 2002 verweigert

Ich verwende Overlay-Berechtigung, um bestimmte Informationen in meiner App anzuzeigen. Wenn Sie es auf API 23 - 25 ausführen, funktioniert es einwandfrei (Erlaubnis, Erteilung usw.)

Fenster kann nicht hinzugefügt werden [email protected] - Für diesen Fenstertyp wurde keine Berechtigung erteilt ). (Vielen Dank an ceph3us!)

Wenn ich dasselbe auf API 26 ausprobiere, erhalte ich beim Aufruf eine Fehlermeldung, im Grunde "Berechtigung für Fenstertyp 2002 verweigert"

windowManager.addView(frameLayout, params);

Hat Google die Art der Überlagerung geändert? Irgendeine Idee, wie ich meinen Text als Überlagerung auf dem Bildschirm in Android 8 (Oreo), API 26 erhalten kann? Vielen Dank für Ihre Ideen!

Dies ist das Fehlerprotokoll:

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) 

In meinem Manifest habe ich:

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

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

Dies ist meine Hauptaktivität:

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

Und das ist das 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

Laut der Dokumentation zu Verhaltensänderungen in Android 8.0 für Apps, die auf Android 8.0 abzielen:

Apps, die die Berechtigung SYSTEM_ALERT_WINDOW verwenden, können die folgenden Fenstertypen nicht mehr verwenden, um Alarmfenster über anderen Apps und Systemfenstern anzuzeigen:

TYPE_PHONE
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR

Apps müssen stattdessen einen neuen Fenstertyp mit dem Namen TYPE_APPLICATION_OVERLAY verwenden.

Ihre App könnte also auf eine niedrigere Version ausgerichtet sein. In diesem Fall wird Ihr Benachrichtigungsfenster ...

unter den Fenstern immer angezeigt, die den Fenstertyp TYPE_APPLICATION_OVERLAY verwenden. Wenn eine App auf Android 8.0 (API-Ebene 26) zielt, verwendet die App den Fenstertyp TYPE_APPLICATION_OVERLAY, um Warnfenster anzuzeigen.

(zitiert aus derselben Quelle)

41
0X0nosugar

Android Oreo (und zukünftige Versionen) erlaubt die Verwendung von WindowManager.LayoutParams.TYPE_PHONE nicht, da es veraltet ist. Verwenden Sie stattdessen 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);
        }
}

probieren Sie diesen Code aus, der perfekt funktioniert

 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
}

nur in diesem Parameter des Fenstermanagers ändern

1
Makvin

Verwenden Sie folgenden Code 

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