问题
I am using overlay permission to display certain information in my app. Running it on API 23 - 25 it works fine (asking for permission, granting, etc. according to
Unable to add window android.view.ViewRoot$W@44da9bc0 -- permission denied for this window type ). (Many thanks to ceph3us!)
Trying the same on API 26 I am getting an error, basically "permission denied for window type 2002" when calling
windowManager.addView(frameLayout, params);
Did Google change the way, overlay works? Any idea, how to get my text as an overlay onto the screen in Android 8 (Oreo), API 26? Thanks for your ideas!
This is the error-log:
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 android.view.ViewRootImpl$W@6fa0089 --
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 android.view.ViewRootImpl$W@6fa0089 --
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 my Manifest, I have:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION"/>
This is my 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();
}
}
}
}
And this is the 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);
}
}
回答1:
According to the documentation on Android 8.0 Behavior Changes for apps targeting Android 8.0:
Apps that use the SYSTEM_ALERT_WINDOW permission can no longer use the following window types to display alert windows above other apps and system windows:
TYPE_PHONE
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR
Instead, apps must use a new window type called
TYPE_APPLICATION_OVERLAY
.
So your app could target some lower version. In this case, your alert window will ...
always appear beneath the windows that use the TYPE_APPLICATION_OVERLAY window type. If an app targets Android 8.0 (API level 26), the app uses the TYPE_APPLICATION_OVERLAY window type to display alert windows.
(quoted from the same source)
回答2:
Android Oreo (and future versions) doesn't allow use WindowManager.LayoutParams.TYPE_PHONE because is deprecated instead use 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);
}
}
回答3:
try this code working perfect
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);
回答4:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR
}
else
{
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
}
only change in this parameter of Window manager
回答5:
Use following 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);
回答6:
Instead of going directly on your Page, you must request for permission first something like this (in my project main page is target page) you can find more in FIX PERMISSION DENIED FOR THIS WINDOW TYPE
private static final int OVERLAY_PERMISSION_CODE =5463 ; // can be anything
@Override
public void onCreate(...) {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
// Open the permission page
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_CODE);
return;
}
}
}
来源:https://stackoverflow.com/questions/45867533/system-alert-window-permission-on-api-26-not-working-as-expected-permission-den