当前位置:网站首页>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();
边栏推荐
- EasyExcel单sheet页与多sheet页写出
- From the Huawei weautomate digital robot forum, we can see the "new wisdom of government affairs" in the field of government and enterprises
- 嵌入式 | 硬件转软件的几条建议
- 学习太极创客 — ESP8226 (十三)OTA
- 十二、所有功能实现效果演示
- ApplicationContextInitializer的三种使用方法
- Target detection series fast r-cnn
- MYCAT read / write separation and MySQL master-slave synchronization
- 【LeetCode】541. Reverse string II
- How to configure environment variables and distinguish environment packaging for multi terminal project of uniapp development
猜你喜欢
![The printed object is [object object]. Solution](/img/fc/9199e26b827a1c6304fcd250f2301e.png)
The printed object is [object object]. Solution

Cdga | how can we do well in data governance?

Alibaba Senior Software Testing Engineer recommends testers to learn -- Introduction to security testing

Lu Qi: I am most optimistic about these four major technology trends

Redis implements a globally unique ID

Rpiplay implementation of raspberry pie airplay projector

ApplicationContextInitializer的三种使用方法

Ebanb B1 Bracelet brush firmware abnormal interrupt handling

Netrca: an effective network fault cause localization

零基础自学SQL课程 | HAVING子句
随机推荐
从618看京东即时零售的野心
金仓KFS replicator安装(Oracle-KES)
P6698-[BalticOI 2020 Day2]病毒【AC自动机,dp,SPFA】
Zero foundation self-study SQL course | related sub query
LeetCode之最长公共前缀
Remote connection of raspberry pie without display by VNC viewer
Leetcode -- wrong set
零基础自学SQL课程 | 子查询
【Redis實現秒殺業務①】秒殺流程概述|基本業務實現
Digital cloud released the 2022 white paper on digital operation of global consumers in the beauty industry: global growth solves marketing problems
Software system dependency analysis
荐书丨《好奇心的秘密》:一个针尖上可以站多少跳舞的小天使?
When to use RDD and dataframe/dataset
Linux MySQL installation
Every (), map (), forearch () methods. There are objects in the array
What do you mean by waiting for insurance records? Where should I go for filing?
Mba-day25 best value problem - application problem
[e325: attention] VIM editing error
CDGA|到底怎么才能做好数据治理呢?
CF566E-Restoring Map【bitset】