2017年3月21日 星期二

Set window flag by reflection

Reference:

http://stackoverflow.com/questions/10555407/android-how-to-get-an-instance-of-a-member-field-via-reflection
http://stackoverflow.com/questions/32218419/how-i-can-access-inner-class-variable-value-using-reflection-in-java
http://www.qingpingshan.com/m/view.php?aid=125698

Description:

為了讓 system dialog可以在 multi user裡顯示,必須要設定 PRIVATE_FLAG_SHOW_FOR_ALL_USERS flag,但是因為 setPrivateFlags是 Window.java的 hide API,PRIVATE_FLAG_SHOW_FOR_ALL_USERS是 WindowManager的 hide variable,除了直接 import framework.jar之外,還可以透過 reflection的機制

Code Snippet:

public static final int FRAMEWORK_PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010;
public static void setShowForAllUsers(Window window) {
    LogTool.d(TAG, "setShowForAllUsers");
    Class<?> windowClass = null;
    Class<?> windowManagerClass = null;
    try {
        try {
            windowClass = Class.forName("android.view.Window");
            windowManagerClass = Class.forName("android.view.WindowManager");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            Method method = windowClass.getDeclaredMethod("setPrivateFlags", int.class, int.class);
            method.setAccessible(true);

            try {
                try {
                    int allUsersFlag = FRAMEWORK_PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
                    Class<?>[] classes = windowManagerClass.getDeclaredClasses();
                    for(Class innerClass: classes){
                        if(innerClass.getName().contains("LayoutParams")){
                            Field field = innerClass.getDeclaredField("PRIVATE_FLAG_SHOW_FOR_ALL_USERS");
                            field.setAccessible(true);
                            allUsersFlag = field.getInt(window.getAttributes());
                            break;
                        }
                    }
                    LogTool.d(TAG, "allUsersFlag: " + allUsersFlag + " ; hex: " + Integer.toHexString(allUsersFlag));

                    method.invoke(window, allUsersFlag, allUsersFlag);
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (NullPointerException e1) {
            e1.printStackTrace();
        }
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch(NoSuchFieldException nsfe){
        nsfe.printStackTrace();
    }
}