Android 悬浮窗在5.0以上,特别是小米手机,魅族手机,就算给到了
2
这个权限也是不会显示出来的,还需要在设置把悬浮权限开关给打开





最近公司项目要用到一个应用内的悬浮框,需要在当前的这个应用每个页面都显示出来,并且悬浮框可随手指移动,但是停止时,要靠边,可以点击,其实这些问题都不是大问题,就是Android5.0,6.0这些机Android类型,又或者不同机型,权限问题的解决掉,啥也不说了,直接看代码吧!



## 1.自定义悬浮View


    package com.amei.floatwindow.view;


    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.WindowManager;
    import android.widget.ImageView;
    import android.widget.Toast;


    import com.amei.floatwindow.application.MyApplication;


    /**
     * Created by kitchee on 2017/1/10.
     * Description:全局悬浮窗口
     */


    public class FloatScanView extends ImageView {




    private final int statusHeight;
    int sW;
    int sH;
    private float mTouchStartX;
    private float mTouchStartY;
    private float x;
    private float y;
    private boolean isMove=false;
    private Context context;


    private WindowManager wm = (WindowManager) getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
    //此wmParams变量为获取的全局变量,用以保存悬浮窗口的属性
    private WindowManager.LayoutParams wmParams = ((MyApplication) getContext().getApplicationContext()).getMywmParams();
    private float mLastX;
    private float mLastY;
    private float mStartX;
    private float mStartY;
    private long mLastTime ;
    private long mCurrentTime;




    public FloatScanView(Context context) {
        this(context,null);
        this.context = context;
    }


    public FloatScanView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }


    public FloatScanView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        sW = wm.getDefaultDisplay().getWidth();
        sH = wm.getDefaultDisplay().getHeight();
        statusHeight = getStatusHeight(context);


    }


    /**
     * 获得状态栏的高度
     *
     * @param context
     * @return
     */
    public static int getStatusHeight(Context context) {


        int statusHeight = -1;
        try {
            Class clazz = Class.forName("com.android.internal.R$dimen");
            Object object = clazz.newInstance();
            int height = Integer.parseInt(clazz.getField("status_bar_height")
                    .get(object).toString());
            statusHeight = context.getResources().getDimensionPixelSize(height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return statusHeight;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //获取相对屏幕的坐标,即以屏幕左上角为原点
        x = event.getRawX();
        y = event.getRawY() - statusHeight;   //statusHeight是系统状态栏的高度
        Log.i("currP", "currX" + x + "====currY" + y);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:    //捕获手指触摸按下动作
                //获取相对View的坐标,即以此View左上角为原点
                mTouchStartX = event.getX();
                mTouchStartY = event.getY();
                mStartX = event.getRawX();
                mStartY = event.getRawY();
                mLastTime = System.currentTimeMillis();
                Log.i("startP", "startX" + mTouchStartX + "====startY" + mTouchStartY);
                isMove = false;
                break;


            case MotionEvent.ACTION_MOVE:   //捕获手指触摸移动动作
                updateViewPosition();
                isMove = true;
                break;


            case MotionEvent.ACTION_UP:    //捕获手指触摸离开动作
                mLastX = event.getRawX();
                mLastY = event.getRawY();


                // 抬起手指时让floatView紧贴屏幕左右边缘
                wmParams.x = wmParams.x <= (sW / 2) ? 0 : sW;
                wmParams.y = (int) (y - mTouchStartY);
                wm.updateViewLayout(this, wmParams);




                mCurrentTime = System.currentTimeMillis();
                if(mCurrentTime - mLastTime < 800){
                    if(Math.abs(mStartX- mLastX )< 10.0 && Math.abs(mStartY - mLastY) < 10.0){
                        //处理点击的事件
                        Toast.makeText(context,"可以处理点击事件",Toast.LENGTH_SHORT).show();
                    }
                }


                break;
        }
        return true;
    }




    private void updateViewPosition() {
        //更新浮动窗口位置参数
        wmParams.x = (int) (x - mTouchStartX);
        wmParams.y = (int) (y - mTouchStartY);
        wm.updateViewLayout(this, wmParams);  //刷新显示


    }


    }
    
## 2.定义一个MyApplication


    在里面进行WindowManager的初始化




    public class MyApplication extends Application {


    private WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();


    public WindowManager.LayoutParams getMywmParams(){
        return wmParams;
    }


    @Override
    public void onCreate() {
        super.onCreate();


    }
    }


## 3.最后看看主页MainActivity
    
    public class MainActivity extends AppCompatActivity {


    private WindowManager wm = null;
    private WindowManager.LayoutParams wmParams = null;
    private FloatScanView fsv = null;


    private AlertDialog dialog;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        dialog = new AlertDialog.Builder(this)
                .setTitle("悬浮窗权限管理")
                .setMessage("是否去开启悬浮窗权限?")
                .setPositiveButton("是", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        //打开权限设置
                        openSetting();
                    }
                })
                .setNegativeButton("否",null)
                .create();


        //创建悬浮框
        createFloatView();


        }


    private void createFloatView() {


        //开启悬浮窗前先请求权限
        if ("Xiaomi".equals(Build.MANUFACTURER)) {//小米手机
    //            LogUtil.E("小米手机");
            requestPermission();
        } else if ("Meizu".equals(Build.MANUFACTURER)) {//魅族手机
    //            LogUtil.E("魅族手机");
            requestPermission();
        } else {//其他手机
    //            LogUtil.E("其他手机");
            if (Build.VERSION.SDK_INT >= 23) {
                if (!Settings.canDrawOverlays(this)) {
                    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                    startActivityForResult(intent, 12);
                } else {
    //
                }
            } else {


            }
        }


        wm=(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
    //        wmParams = new WindowManager.LayoutParams();
        wmParams = ((MyApplication)getApplication()).getMywmParams();


    //        wmParams.type=2002;          //type是关键,这里的2002表示系统级窗口
        wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        wmParams.format= PixelFormat.RGBA_8888;//设置图片格式,效果为背景透明


        wmParams.flags= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE ;//
        wmParams.gravity = Gravity.LEFT|Gravity.TOP;//
        wmParams.x = 0;
        wmParams.y = 0;
        wmParams.width=100;
        wmParams.height=100;
        fsv = new FloatScanView(getApplicationContext());
        fsv.setImageResource(R.mipmap.add_coupon_by_scan);
        fsv.setBackgroundColor(getResources().getColor(R.color.piegps_bg_new));
        wm.addView(fsv, wmParams);
    }




    @Override
    protected void onRestart() {
        super.onRestart();
        wm.addView(fsv,wmParams);
    }




    @Override
    protected void onStop() {
        if(fsv != null){
            wm.removeView(fsv);
        }
        super.onStop();
    }
    //
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(fsv != null){
            wm.removeView(fsv);
        }
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 11) {
            if (isFloatWindowOpAllowed(this)) {//已经开启
            } else {
                Toast.makeText(this,"开启悬浮窗失败",Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == 12) {
            if (Build.VERSION.SDK_INT >= 23) {
                if (!Settings.canDrawOverlays(MainActivity.this)) {


                    Toast.makeText(this,"权限授予失败,无法开启悬浮窗",Toast.LENGTH_SHORT).show();
                } else {
                }
            }
        }


    }
    /**
     * 判断悬浮窗权限
     *
     * @param context
     * @return
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean isFloatWindowOpAllowed(Context context) {
        final int version = Build.VERSION.SDK_INT;
        if (version >= 19) {
            return checkOp(context, 24);  // AppOpsManager.OP_SYSTEM_ALERT_WINDOW
        } else {
            if ((context.getApplicationInfo().flags & 1 << 27) == 1 << 27) {
                return true;
            } else {
                return false;
            }
        }
    }


    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean checkOp(Context context, int op) {
        final int version = Build.VERSION.SDK_INT;


        if (version >= 19) {
            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            try {
                Class<?> spClazz = Class.forName(manager.getClass().getName());
                Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
                int property = (Integer) method.invoke(manager, op,
                        Binder.getCallingUid(), context.getPackageName());
                Log.e("399", " property: " + property);


                if (AppOpsManager.MODE_ALLOWED == property) {
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Log.e("399", "Below API 19 cannot invoke!");
        }
        return false;
    }




    /**
     * 请求用户给予悬浮窗的权限
     */
    public void requestPermission() {
        if (isFloatWindowOpAllowed(this)) {//已经开启


        } else {
            dialog.show();
        }
    }




    /**
     * 打开权限设置界面
     */
    public void openSetting() {
        try {
            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());
            startActivityForResult(localIntent, 11);
    //            LogUtil.E("启动小米悬浮窗设置界面");
        } catch (ActivityNotFoundException localActivityNotFoundException) {
            Intent intent1 = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            Uri uri = Uri.fromParts("package", getPackageName(), null);
            intent1.setData(uri);
            startActivityForResult(intent1, 11);
    //            LogUtil.E("启动悬浮窗界面");
        }




    }


    }
    

    其实这里面还是有一个问题,就是对于华为手机5.0以下的会是不是的扫描是否有悬浮框,如果有,它就是自动禁止掉,这个很无奈啊!

资源下载

更多相关文章

  1. android app在系统重启绕过USB授权对话框,自动获取USB权限
  2. 面面具到!android重力传感器
  3. 刷机总结(阿里云os-->android4.2.2)注明:本文不是教程
  4. 小米科技宣布定价1999元MIUI+Android智能手机
  5. Android之权限问题
  6. Android(安卓)刘海屏适配方案---NotchTools,适配国内四大厂商(华
  7. Android(安卓)11 中的隐私权更新 : 权限更新
  8. Android(安卓)手机端与服务器端通过http交换数据 Json
  9. Android6.0------权限申请管理(单个权限和多个权限申请)

随机推荐

  1. Android(安卓)assets目录资源读取
  2. Android布局之二——Relative Layout
  3. 【攻克Android(安卓)(43)】WebView (网络
  4. Android之Handler与线程
  5. Android(安卓)动态移动控件实现
  6. android动态获取权限方法
  7. android Cursor的自动管理方式
  8. # Android中Activity四种启动模式和taskA
  9. Android(安卓)Studio 安装虚拟机,报错:emul
  10. 【Android(安卓)Developers Training】 7