Android 系统覆盖 window

Android System overlay window

我正在尝试创建系统覆盖。但我不断收到 "permission denied"。我使用的是 SDK 版本 23。

我的清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test" >

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

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".activity.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>

我用来创建叠加层的代码:

    //mView = new HUDView(this);
    mButton = new Button(this);
    mButton.setText("Overlay button");
    mButton.setOnTouchListener(this);

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);
    params.gravity = Gravity.RIGHT | Gravity.TOP;
    params.setTitle("Load Average");
    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    wm.addView(mButton, params);

首先,没有名为SYSTEM_OVERLAY_WINDOW的权限。是SYSTEM_ALERT_WINDOW.

其次,如果你的 targetSdkVersion 是 23 或更高,而你是 运行 在 Android 6.0+ 设备上,你的应用一开始不会获得此权限。调用 Settings.canDrawOverlays() 查看您是否有权限,如果没有,请使用 ACTION_MANAGE_OVERLAY_PERMISSION 将用户引导至设置。

在 AndroidManifest 中(版本 < 23)

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


public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE= 5469;
//Random value

    public void testPermission() {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
        }
    }

结果:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
        if (Settings.canDrawOverlays(this)) {
            // You have permission
        }
    }
}

您还可以将用户引导至特定应用的叠加页面。文档 states:

Input: Optionally, the Intent's data URI can specify the application package name to directly invoke the management GUI specific to the package name. For example "package:com.my.app".

所以像这样:

intent.setData(Uri.fromParts("package", getPackageName(), null));

作为替代解决方案,您可以尝试 WindowManager.LayoutParams.TYPE_TOAST 而不是 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT。 这不需要任何许可。 我用它来显示图像,也许按钮可以工作

以下用户和android8以上用户使用

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
   LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}

我在这里处理了我 library. Please see the gist 中每个 android 版本的所有覆盖权限。

要在其他应用程序上显示需要在清单中添加的权限是

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

检查您的应用是否有权限

Settings.canDrawOverlays(context)

检查权限checkOverlayPermission

private const val CODE_DRAW_OVER_OTHER_APP_PERMISSION = 2084

private fun checkOverlayPermission(){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
        //If the draw over permission is not available open the settings screen
        //to grant the permission.
        val intent = Intent(
            Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
            Uri.parse("package:$packageName")
        )
        startActivityForResult(
            intent,
            CODE_DRAW_OVER_OTHER_APP_PERMISSION
        )
    }
}

并且在 onActivityResult 中你可以检查权限是否被授予

override fun onActivityResult(
    requestCode: Int,
    resultCode: Int,
    data: Intent?
) {
    if (requestCode == CODE_DRAW_OVER_OTHER_APP_PERMISSION) {
        if (Settings.canDrawOverlays(this)) {
            // Permission Granted
        } else {
            // Permission not Granted
            // If you want then call again checkOverlayPermission until permission granted
        }
    } 
}