Android 悬浮窗踩坑体验

来源:互联网 发布:美国硕士一年花费知乎 编辑:程序博客网 时间:2024/05/17 11:34

Android 悬浮窗踩坑体验

大家都知道,悬浮窗的问题,一直都是众开发者比较恶心的问题,加上 google 在7.0之后,更是对悬浮窗加大了管理,原本设置悬浮窗类型为 TYPE_TOAST 还能显示,现在是直接关闭掉了;不过值得提一下的是,TYPE_TOAST 类型的悬浮窗,在国内的一些机型,也不能显示,这要怎么处理呢?

1、判断是否开启了悬浮窗的权限

1、如果用户开启了悬浮窗的权限,那就好办啦,直接使用我们悬浮窗。判断方法:

/** * 判断悬浮窗口权限是否打开 */public static boolean hasFloatWindowAccessPermission(Context context) {    if (Build.VERSION.SDK_INT >= 23) {        return Settings.canDrawOverlays(context);    }    try {        Object object = context.getSystemService(Context.APP_OPS_SERVICE);        if (object == null) {            return false;        }        Class localClass = object.getClass();        Class[] arrayOfClass = new Class[3];        arrayOfClass[0] = Integer.TYPE;        arrayOfClass[1] = Integer.TYPE;        arrayOfClass[2] = String.class;        Method method = localClass.getMethod("checkOp", arrayOfClass);        if (method == null) {            return false;        }        Object[] arrayOfObject1 = new Object[3];        arrayOfObject1[0] = Integer.valueOf(24);        arrayOfObject1[1] = Integer.valueOf(Binder.getCallingUid());        arrayOfObject1[2] = context.getPackageName();        int m = ((Integer) method.invoke(object, arrayOfObject1)).intValue();        return m == AppOpsManager.MODE_ALLOWED;    } catch (Exception e) {        e.printStackTrace();    }    return false;}

2、使用悬浮窗类型为 TYPE_TOAST 的窗口

1、部分手机,在没有开启悬浮窗的权限的时候,可以使用 TYPE_TOAST 类型,弹出悬浮窗。例如:

    mTaskProgressParams.type = WindowManager.LayoutParams.TYPE_TOAST;

3、利用反射,自定义Toast来弹出悬浮窗

1、我们都知道,吐司的显示,也是悬浮窗的级别的,但是不需要悬浮窗的权限,那我们就在Toast基础上,通过反射来,设置悬浮窗。这种对于设置 TYPE_TOAST 类型,也不生效的手机,可以适用。
public class MyToast {

private Toast mToast;private Context mContext;private boolean isShow = false;private TaskView mView;private Object mTN;private Method show;private Method hide;private WindowManager.LayoutParams mLayoutParams;public MyToast(Context context) {    this.mContext = context;    if (mToast == null) {        mToast = new Toast(mContext);    }    mView = new TaskView(mContext);    mToast.setView(mView);}public void setNextOnClickListener(View.OnClickListener l) {    mView.setNextOnClickListener(l);}public void setTimeCountDown(int times) {    mView.setTimeCountDown(times);}public void show() {    if (isShow)        return;    initTN();    try {        if (Build.VERSION.SDK_INT <= 23) {            show.invoke(mTN);        } else {            show.invoke(mTN, mView.getWindowToken());        }    } catch (Exception e) {        e.printStackTrace();    }    isShow = true;    Log.i("czc", "SettingSlideLockToast is showing");}public void hide() {    if (!isShow)        return;    try {        hide.invoke(mTN);    } catch (Exception e) {        e.printStackTrace();    }    isShow = false;    mView.stopTimeCountDown();    Log.i("czc", "SettingSlideLockToast is hided");}private void initTN() {    try {        Field tnField = mToast.getClass().getDeclaredField("mTN");        tnField.setAccessible(true);        mTN = tnField.get(mToast);        Field tnParamsField = mTN.getClass().getDeclaredField("mParams");        tnParamsField.setAccessible(true);        mLayoutParams = (WindowManager.LayoutParams) tnParamsField.get(mTN);        mLayoutParams.format = PixelFormat.TRANSLUCENT;        //this flag set view don't interrupt touch event        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                | FLAG_NOT_TOUCH_MODAL;        mLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;        mLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;        mLayoutParams.windowAnimations = R.style.SettingClickToastAnim;        mLayoutParams.width = ScreenUtil.getRawScreenWidth();        mLayoutParams.height = ScreenUtil.dp2px(70);        mLayoutParams.x = 0;        mLayoutParams.y = 0;        /**调用tn.show()之前一定要先设置mNextView*/        Field tnNextViewField = mTN.getClass().getDeclaredField("mNextView");        tnNextViewField.setAccessible(true);        tnNextViewField.set(mTN, mToast.getView());        if (Build.VERSION.SDK_INT <= 23) {            show = mTN.getClass().getMethod("show");        } else {            show = mTN.getClass().getMethod("show", new Class[]{IBinder.class});            mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;        }        hide = mTN.getClass().getMethod("hide");    } catch (Exception e) {        e.printStackTrace();    }    mToast.setGravity(Gravity.LEFT | Gravity.TOP, 0, 0);}}
原创粉丝点击