最近用到悬浮窗的功能,android6.0以下的系统可以进行正常的显示,而android6.0及以上的则创建不了,运行直接崩溃,报如下错误:

Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@96872e8 -- permission denied for this window type

但是我在清单文件明明加了这个权限,为什么还是不行呢?原因是自从android6.0之后,权限改了,权限的授权不是在应用第一次安装时对所有的权限进行授权,而是在需要用到某个权限时对其动态授权。

查看android的官方文档:Note:If the app targets API level 23 or higher, the app user must explicitly grant this permission to the app through a permission management screen. The app requests the user's approval by sending an intent with action ACTION_MANAGE_OVERLAY_PERMISSION . The app can check whether it has this authorization by calling Settings.canDrawOverlays() .

能够熟练阅读各类英文文档也是一门非常重要的技能。上面的描述大概意思就是说,如果我们的 targetSdkVersion指定成了23或者更高,在使用 SYSTEM_ALERT_WINDOW权限时,需要先调用 Settings.canDrawOverlays() 来判断一下是否允许创建悬浮窗,如果允许的话就可以创建了,不允许的话还要发送一个action值为 ACTION_MANAGE_OVERLAY_PERMISSION 的Intent来让用户同意创建悬浮窗。

先上效果图:


那下面就这样试着写一下,代码如下:

package com.cool.floatviewdemo;import android.annotation.TargetApi;import android.app.Activity;import android.content.Intent;import android.os.Build;import android.os.Bundle;import android.provider.Settings;import android.util.Log;import android.view.View;import android.widget.Toast;public class MainActivity extends Activity {    private final static int REQUEST_CODE = 100;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void callPhone(View v){        startActivity(new Intent(this, CallPhoneActivity.class));    }    /**     *显示悬浮窗     * @param v     */    public void showFloatView(View v) {        if (Build.VERSION.SDK_INT >= 23) {            if (Settings.canDrawOverlays(this)) {                showFloatView();            } else {                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);                startActivityForResult(intent, REQUEST_CODE);            }        } else {            showFloatView();        }    }    @TargetApi(Build.VERSION_CODES.M)    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if(requestCode == REQUEST_CODE){            if (Settings.canDrawOverlays(this)) {                showFloatView();            } else {                Toast.makeText(this,"授权失败",Toast.LENGTH_SHORT).show();            }        }    }    /**     * 显示悬浮窗     */    private void showFloatView() {        FloatView.showFloatView(getApplication(), R.layout.layout_float_window);        FloatView.setOnClickListener(new FloatView.OnClickListener() {            @Override            public void onClick(View view) {                Log.e("399", "点击了");            }        });    }    /**     * 隐藏悬浮窗     * @param v     */    public void hideFloatView(View v){        FloatView.hideFloatView();    }}


悬浮窗的View如下:

package com.cool.floatviewdemo;import android.content.Context;import android.graphics.PixelFormat;import android.view.Gravity;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;/** * Created by cool on 2016/8/30. */public class FloatView {    private static Context mContext;    private static WindowManager mWindowManager;    private static WindowManager.LayoutParams wmParams;    private static View mView;    private static boolean isShow = false;//悬浮框是否已经显示    private static OnClickListener mListener;//view的点击回调listener    public static void setOnClickListener(OnClickListener listener){        mListener = listener;    }    interface OnClickListener{        void onClick(View view);    }    /**     * 显示悬浮框     */    public static void showFloatView(Context context,int layoutId){        mContext = context;        if(isShow){            return;        }        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        wmParams = new WindowManager.LayoutParams();        wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;        wmParams.gravity = Gravity.CENTER;        wmParams.format = PixelFormat.RGBA_8888;        wmParams.x = context.getResources().getDisplayMetrics().widthPixels;        wmParams.y = 0;        wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;        wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;        mView = LayoutInflater.from(context).inflate(layoutId, null);        mWindowManager.addView(mView, wmParams);        mView.setOnTouchListener(new View.OnTouchListener() {            float downX = 0;            float downY = 0;            int oddOffsetX = 0;            int oddOffsetY = 0;            @Override            public boolean onTouch(View v, MotionEvent event) {                switch(event.getAction()){                    case MotionEvent.ACTION_DOWN:                        downX =  event.getX();                        downY =  event.getY();                        oddOffsetX = wmParams.x;                        oddOffsetY = wmParams.y;                        break;                    case MotionEvent.ACTION_MOVE:                        float moveX = event.getX();                        float moveY =  event.getY();                        //不除以3,拖动的view抖动的有点厉害                        wmParams.x += (moveX - downX)/3;                        wmParams.y += (moveY - downY)/3;                        if(mView != null){                            mWindowManager.updateViewLayout(mView,wmParams);                        }                        break;                    case MotionEvent.ACTION_UP:                        int newOffsetX = wmParams.x;                        int newOffsetY = wmParams.y;                        if(Math.abs(newOffsetX - oddOffsetX) <=20 && Math.abs(newOffsetY - oddOffsetY) <=20){                            if(mListener != null){                                mListener.onClick(mView);                            }                        }                    break;                }                return true;            }        });        isShow = true;    }    /**     * 隐藏悬浮窗     */    public static void hideFloatView(){        if(mWindowManager != null && isShow){            mWindowManager.removeView(mView);            isShow = false;        }    }}


更多相关文章

  1. Android版本更新(断点下载)
  2. android之监控各个程序的流量
  3. android superuser.apk 管理root权限原理分析
  4. android7.1 外置SD卡三方应用没有读写权限
  5. [置顶] Android学习系列-把文件保存到SD卡上面(6)
  6. 使用mount修改你的android中/system为只读权限
  7. android――SharedPreferences存放数据
  8. Android无需申请权限拨打电话的两种方式
  9. Android中XML文件解析

随机推荐

  1. Android(安卓)检测SD卡是否可用
  2. Android Activity弹出框、PopupWindow弹
  3. java中线程与线程池的利弊(android适用)
  4. 【Android】ABIs [armeabi] are not supp
  5. Android(安卓)资源文件的命名规范问题
  6. Android(安卓)studio 3.4.1NDK开发
  7. Android cts4.2 windows环境搭建说明
  8. Android(安卓)Handler(五)
  9. Android填充多边形
  10. android中,handler处理信息中弹出提示框注