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以下的会是不是的扫描是否有悬浮框,如果有,它就是自动禁止掉,这个很无奈啊!
资源下载