如何在MIUI中打开绘制悬浮窗权限弹出窗口?

19

我想在MIUI中打开这个权限弹出窗口。我尝试了这段代码,但它并不能为特定的应用程序打开权限管理器弹出窗口。

public static Intent toPermissionManager(Context context, String packageName) {
    Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
    String version = getVersionName();
    if (MIUI_V5.equals(version)) {
        PackageInfo pInfo;
        try {
            pInfo = context.getPackageManager().getPackageInfo(packageName, 0);
        } catch (PackageManager.NameNotFoundException ignored) {
            return null;
        }
        intent.setClassName("com.android.settings", "com.miui.securitycenter.permission.AppPermissionsEditor");
        intent.putExtra("extra_package_uid", pInfo.applicationInfo.uid);
    } else { // MIUI_V6 and above
        final String PKG_SECURITY_CENTER = "com.miui.securitycenter";
        try {
            context.getPackageManager().getPackageInfo(PKG_SECURITY_CENTER, PackageManager.GET_ACTIVITIES);
        } catch (PackageManager.NameNotFoundException ignored) {
            return null;
        }
        intent.setClassName(PKG_SECURITY_CENTER, "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
        intent.putExtra("extra_pkgname", packageName);
    }
    return intent;
}

如果您已经找到了解决方案,请在此处添加跟进。 - Sanved
抱歉,我仍然没有解决方案。 - Sagar
你找到解决方案了吗? - okarakose
仍然没有解决方案。 - Sagar
@OmerKarakose,@Mohammad Rizky Kurniawan,@SanVed 我已经上传了答案,请检查一下。希望它能解决你的问题。 - Sagar
显示剩余2条评论
3个回答

18

在您需要使用此权限的位置直接调用此方法onDisplayPopupPermission()

要检查授权未授权,我已经添加了另一个答案,请查看。

private void onDisplayPopupPermission() {
    if (!isMIUI()) {
        return;
    }
    try {
        // MIUI 8
        Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
        localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
        localIntent.putExtra("extra_pkgname", getPackageName());
        startActivity(localIntent);
        return;
    } catch (Exception ignore) {
    }
    try {
        // MIUI 5/6/7
        Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
        localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
        localIntent.putExtra("extra_pkgname", getPackageName());
        startActivity(localIntent);
        return;
    } catch (Exception ignore) {
    }
    // Otherwise jump to application details
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    Uri uri = Uri.fromParts("package", getPackageName(), null);
    intent.setData(uri);
    startActivity(intent);
 }


private static boolean isMIUI() {
    String device = Build.MANUFACTURER;
    if (device.equals("Xiaomi")) {
        try {
            Properties prop = new Properties();
            prop.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
            return prop.getProperty("ro.miui.ui.version.code", null) != null
                    || prop.getProperty("ro.miui.ui.version.name", null) != null
                    || prop.getProperty("ro.miui.internal.storage", null) != null;
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    return false;
}
它将重定向到显示弹出窗口权限屏幕,您可以手动将其更改为开启或关闭。

有没有办法知道用户选择了接受还是拒绝? - Srikar Reddy
@SrikarReddy 你找到知道是否选择了接受或拒绝的解决方案了吗? - Gautam
@Gautam 你可以尝试一下我上传的解决方案。 - Sagar
@chengsam 使用 getSystemProperty(String propName) 方法,来源于 https://stackoverflow.com/q/59974951/4232793。 - target33
在MIUI 11中无法工作。 - D_K
显示剩余3条评论

6
这段代码对我有效。您需要这两个类:MIUIUtils.javaBuildProperties.java

MIUIUtils.java

public class MIUIUtils {
    private static final String MIUI_V5 = "V5";
    private static final String MIUI_V6 = "V6";

    private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
    private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
    private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";

    public static boolean isMIUI() {
        try {
            final BuildProperties prop = BuildProperties.newInstance();
            return prop.getProperty(KEY_MIUI_VERSION_CODE, null) != null
                || prop.getProperty(KEY_MIUI_VERSION_NAME, null) != null
                || prop.getProperty(KEY_MIUI_INTERNAL_STORAGE, null) != null;
        } catch (IOException e) {
            return false;
        }
    }

    public static boolean isMIUIV5() {
        return getVersionName().equals(MIUI_V5);
    }

    public static boolean isMIUIV6() {
        return getVersionName().equals(MIUI_V6);
    }

    public static String getVersionName() {
        try {
            final BuildProperties prop = BuildProperties.newInstance();
            return prop.getProperty(KEY_MIUI_VERSION_NAME);
        } catch (IOException e) {
            return "";
        }
    }

    public static boolean isFloatWindowOptionAllowed(Context context) {
        AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        Class localClass = manager.getClass();
        Class[] arrayOfClass = new Class[3];
        arrayOfClass[0] = Integer.TYPE;
        arrayOfClass[1] = Integer.TYPE;
        arrayOfClass[2] = String.class;
        try {
            Method method = localClass.getMethod("checkOp", arrayOfClass);
            if (method == null) {
                return false;
            }
            Object[] arrayOfObjects = new Object[3];
            arrayOfObjects[0] = Integer.valueOf(24);
            arrayOfObjects[1] = Integer.valueOf(Binder.getCallingUid());
            arrayOfObjects[2] = context.getPackageName();
            int m = ((Integer) method.invoke((Object) manager, arrayOfObjects)).intValue();
            return m == AppOpsManager.MODE_ALLOWED;
        } catch (Exception e) {
            return false;
        }
    }

    public static Intent toPermissionManager(Context context, String packageName) {
        Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
        String version = getVersionName();
        if (MIUI_V5.equals(version)) {
            PackageInfo pInfo;
            try {
                pInfo = context.getPackageManager().getPackageInfo(packageName, 0);
            } catch (PackageManager.NameNotFoundException ignored) {
                return null;
            }
            intent.setClassName("com.android.settings", "com.miui.securitycenter.permission.AppPermissionsEditor");
            intent.putExtra("extra_package_uid", pInfo.applicationInfo.uid);
        } else { // MIUI_V6 and above
            final String PKG_SECURITY_CENTER = "com.miui.securitycenter";
            try {
           context.getPackageManager().getPackageInfo(PKG_SECURITY_CENTER, PackageManager.GET_ACTIVITIES);
            } catch (PackageManager.NameNotFoundException ignored) {
                return null;
            }
            intent.setClassName(PKG_SECURITY_CENTER, "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
            intent.putExtra("extra_pkgname", packageName);
        }
        return intent;
    }


    public static Intent toFloatWindowPermission(Context context, String packageName) {
        Uri packageUri = Uri.parse("package:" + packageName);
        Intent detailsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageUri);
        detailsIntent.addCategory(Intent.CATEGORY_DEFAULT);
        if (isMIUIV5()) {
            return detailsIntent;
        } else {
            Intent permIntent = toPermissionManager(context, packageName);
            return permIntent == null ? detailsIntent : permIntent;
        }
    }
}

BuildProperties.java

public class BuildProperties {

    private final Properties properties;

    private BuildProperties() throws IOException {
        InputStream in = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));
        properties = new Properties();
        properties.load(in);
        in.close();
    }

    public static BuildProperties newInstance() throws IOException {
        return new BuildProperties();
    }

    public boolean containsKey(final Object key) {
        return properties.containsKey(key);
    }

    public boolean containsValue(final Object value) {
        return properties.containsValue(value);
    }

    public Set<Map.Entry<Object, Object>> entrySet() {
        return properties.entrySet();
    }

    public String getProperty(final String name) {
        return properties.getProperty(name);
    }

    public String getProperty(final String name, final String defaultValue) {
        return properties.getProperty(name, defaultValue);
    }

    public boolean isEmpty() {
        return properties.isEmpty();
    }

    public Enumeration<Object> keys() {
        return properties.keys();
    }

    public Set<Object> keySet() {
        return properties.keySet();
    }

    public int size() {
        return properties.size();
    }

    public Collection<Object> values() {
        return properties.values();
    }
}

请按照以下方式调用您的代码:

     if (Build.VERSION.SDK_INT >= 19 && MIUIUtils.isMIUI() && !MIUIUtils.isFloatWindowOptionAllowed(context)) {
            Log.i(TAG, "MIUI DEVICE: Screen Overlay Not allowed");
            startActivityForResult(MIUIUtils.toFloatWindowPermission(context, getPackageName()), REQUEST_OVERLAY_PERMISSION);
        } else if (Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)) {
            Log.i(TAG, "SDK_INT > 23: Screen Overlay Not allowed");
            startActivityForResult(new Intent(
                            "android.settings.action.MANAGE_OVERLAY_PERMISSION", 
                            Uri.parse("package:" +getPackageName()))
                    , REQUEST_OVERLAY_PERMISSION
            );
        } else {
            Log.i(TAG, "SKK_INT < 19 or Have overlay permission");

        }

它只在Android 5.1上的MIUI8中打开应用程序信息页面。 - Vikas Patidar
在Android O上,会抛出异常:java.io.FileNotFoundException: /system/build.prop(权限被拒绝) - chengsam

1

为了检查是否授予“显示弹出窗口”权限,使用我上面回答中的onDisplayPopupPermission()方法。

我正在使用canDrawOverlayViewsreflection来检查权限是否被授予,但这可能已经在最新版本中被删除/更改

我已经尝试过这种解决方案,适用于MIUI8,可以工作,但不确定最新更新。请在评论中更新,以便其他人可以获得更新。

1.Step

if (!canDrawOverlayViews() && isXiaomi()) {
        //permission not granted
        Log.e("canDrawOverlayViews", "-No-");
       onDisplayPopupPermission(); 
        //write above answered permission code for MIUI here
    }else {

    }

第2步:检查是否已授予权限

public boolean canDrawOverlayViews() {
    if (Build.VERSION.SDK_INT < 21) {
        return true;
    }
    Context con = this;
    try {
        return Settings.canDrawOverlays(con);
    } catch (NoSuchMethodError e) {
        return canDrawOverlaysUsingReflection(con);
    }
}

public static boolean isXiaomi() {
    return "xiaomi".equalsIgnoreCase(Build.MANUFACTURER);
}

canDrawOverlaysUsingReflection() 我在这里找到了解决方案 这里翻译这个页面

public static boolean canDrawOverlaysUsingReflection(Context context) {

try {

    AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
    Class clazz = AppOpsManager.class;
    Method dispatchMethod = clazz.getMethod("checkOp", new Class[] { int.class, int.class, String.class });
    //AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
    int mode = (Integer) dispatchMethod.invoke(manager, new Object[] { 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName() });

    return AppOpsManager.MODE_ALLOWED == mode;

} catch (Exception e) {  return false;  }

}


什么是 canDrawOverlaysUsingReflection() 方法? - javadhme
@javaDroid,请检查更新。我已经很久没有处理它了,请确保它能够正常工作并进行更新。 - Sagar
我已经尝试了这个解决方案,但在MIUI 10及以上版本上无法工作,未在小于10的版本上尝试过。 - Gastón Saillén
@GastónSaillén,这个解决方案我已经尝试过到MIUI8,它可以工作。对于MIUI > 8,请更新你的答案。 - Sagar
我进行了检查,但是canDrawOverlayViews()方法中的 Settings.canDrawOverlays(con);总是返回false。 - javadhme
有没有人找到了这个问题的解决方案? - Aditya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接