当前位置:网站首页>WindowManager 简单悬浮框的实现
WindowManager 简单悬浮框的实现
2022-06-24 08:11:00 【Mars-xq】
参考:
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();
边栏推荐
- 【LeetCode】387. First unique character in string
- 正则匹配邮箱
- PHP使用递归和非递归方式实现创建多级文件夹
- Leetcode-- string
- Ordinary people have no education background. Can they earn more than 10000 yuan a month by Self-taught programming?
- 零基础自学SQL课程 | HAVING子句
- Get post: do you really know the difference between requests??????
- Some common pitfalls in getting started with jupyter:
- Leetcode -- linked list
- 获取带参数的微信小程序二维码-以及修改二维码LOGO源码分享
猜你喜欢
Depens:*** but it is not going to be installed

Leetcode -- wrong set

MySQL data (Linux Environment) scheduled backup

When programmers are asked if they can repair computers... | daily anecdotes

最新Windows下Go语言开发环境搭建+GoLand配置

Zero foundation self-study SQL course | related sub query

"I can't understand Sudoku, so I choose to play Sudoku."

Zero foundation self-study SQL course | sub query
![[bug] @jsonformat has a problem that the date is less than one day when it is used](/img/09/516799972cd3c18795826199aabc9b.png)
[bug] @jsonformat has a problem that the date is less than one day when it is used
Depens:*** but it is not going to be installed
随机推荐
浮点数表示法(总结自CS61C和CMU CSAPP)
2022.6.13-6.19 AI行业周刊(第102期):职业发展
Transplantation of xuantie e906 -- fanwai 0: Construction of xuantie c906 simulation environment
EasyExcel单sheet页与多sheet页写出
tp5 使用post接收数组数据时报variable type error: array错误的解决方法
Software system dependency analysis
Chapter 7 operation bit and bit string (III)
php单例模式详解
2020 China's provinces and cities, three-level linkage data, data agencies (data from the official website of the National Bureau of Statistics)
[noi Simulation Competition] send (tree DP)
Vidéo courte recommandée chaque semaine: Soyez sérieux en parlant de "métaunivers"
Webrtc series - network transmission 5: select the optimal connection switching
Framework tool class obtained by chance for self use
Jincang KFS replicator installation (oracle-kes)
牛客网 十进制整数转十六进制字符串
The native applet uses canvas to make posters, which are scaled to the same scale. It is similar to the uniapp, but the writing method is a little different
Mba-day25 best value problem - application problem
linux(centos7.9)安装部署mysql-cluster 7.6
Zero foundation self-study SQL course | syntax sequence and execution sequence of SQL statements
NETRCA: AN EFFECTIVE NETWORK FAULT CAUSE LOCALIZATION之论文阅读