WindowManager 简单悬浮框的实现
Posted Mars-xq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WindowManager 简单悬浮框的实现相关的知识,希望对你有一定的参考价值。
参考:
permission denied for window type 2003
权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.GET_TASKS" />
//检查权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
if (!Settings.canDrawOverlays(this))
//启动Activity让用户授权
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(intent);
return;
定义service :
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import java.util.ArrayList;
import java.util.List;
public class MainService extends Service
private boolean isAdded = false; // 是否已增加悬浮窗
public static final int OPERATION_SHOW = 100;
public static final int OPERATION_HIDE = 101;
private static final int HANDLE_CHECK_ACTIVITY = 200;
public static final String OPERATION = "operation";
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;
private Button btnView;
private ActivityManager mActivityManager;
private List<String> homeList; // 桌面应用程序包名列表
//定义一个更新界面的Handler
@SuppressLint("HandlerLeak")
private final Handler mHandler = new Handler()
@Override
public void handleMessage(Message msg)
switch (msg.what)
case HANDLE_CHECK_ACTIVITY:
if (isHome())
if (!isAdded)
mWindowManager.addView(btnView, mLayoutParams);
isAdded = true;
new Thread(new Runnable()
public void run()
for (int i = 0; i < 10; i++)
try
Thread.sleep(1000);
catch (InterruptedException e)
e.printStackTrace();
Message m = new Message();
m.what = 2;
mHandler.sendMessage(m);
).start();
else
if (isAdded)
mWindowManager.removeView(btnView);
isAdded = false;
mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 0);
break;
;
@Override
public void onCreate()
super.onCreate();
homeList = getHomes();
createWindowView();
@Override
public int onStartCommand(Intent intent, int flags, int startId)
int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);
switch (operation)
case OPERATION_SHOW:
mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
break;
case OPERATION_HIDE:
mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
break;
return super.onStartCommand(intent, flags, startId);
// 定义一个创建悬浮框的方法:
@SuppressLint("ClickableViewAccessibility", "RtlHardcoded")
private void createWindowView()
btnView = new Button(getApplicationContext());
btnView.setBackgroundResource(R.mipmap.ic_launcher);
mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
mLayoutParams = new WindowManager.LayoutParams();
// 设置Window Type
//【注意】检查版本,注意当type为TYPE_APPLICATION_OVERLAY时,铺满活动窗口,但在关键的系统窗口下面,如状态栏或IME
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
else
mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// 设置悬浮框不可触摸
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应
mLayoutParams.format = PixelFormat.RGBA_8888;
// 设置悬浮框的宽高
mLayoutParams.width = 200;
mLayoutParams.height = 200;
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.x = 200;
mLayoutParams.y = 0;
// 设置悬浮框的Touch监听
btnView.setOnTouchListener(new View.OnTouchListener()
//保存悬浮框最后位置的变量
int lastX, lastY;
int paramX, paramY;
@Override
public boolean onTouch(View v, MotionEvent event)
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
paramX = mLayoutParams.x;
paramY = mLayoutParams.y;
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
mLayoutParams.x = paramX + dx;
mLayoutParams.y = paramY + dy;
// 更新悬浮窗位置
mWindowManager.updateViewLayout(btnView, mLayoutParams);
break;
return true;
);
mWindowManager.addView(btnView, mLayoutParams);
isAdded = true;
/**
* 判断当前界面是否是桌面
*/
public boolean isHome()
if (mActivityManager == null)
mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
return homeList.contains(rti.get(0).topActivity.getPackageName());
/**
* 获得属于桌面的应用的应用包名称
*
* @return 返回包含所有包名的字符串列表
*/
private List<String> getHomes()
List<String> names = new ArrayList<String>();
PackageManager packageManager = this.getPackageManager();
// 属性
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
@SuppressLint("QueryPermissionsNeeded")
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo ri : resolveInfo)
names.add(ri.activityInfo.packageName);
return names;
@Override
public IBinder onBind(Intent intent)
return null;
启动service :
Intent mIntent = new Intent(MainActivity5.this, MainService.class);
mIntent.putExtra(MainService.OPERATION, MainService.OPERATION_SHOW);
startService(mIntent);
Toast.makeText(MainActivity5.this, "悬浮框已开启~", Toast.LENGTH_SHORT).show();
以上是关于WindowManager 简单悬浮框的实现的主要内容,如果未能解决你的问题,请参考以下文章
Android WindowManager悬浮窗:不需要申请权限实现悬浮
Android 使用WindowManager实现悬浮窗及源码解析