首先说一下需求吧,看看是不是你们想要的:
在IM音视频聊天页面,点击页面上的最小化按钮,将Activity最小化并开启一个悬浮窗,悬浮窗可拖动可点击,点击进入当前通话页面。
1、听到开启悬浮窗,第一时间就想到了要开启一个Service,在Service中进行布局的设置及拖动、点击逻辑的设定。
2、通话界面点击最小化按钮,将Activity最小化并保持后台运行,同时开启Service展示悬浮窗
1、创建FloatVideoWindowService继承Service类
2、实现父类抽象方法
3、在onCreate()中进行布局设置,并获得WindowManager对象。
4、在onStartCommand()方法中将布局、参数添加到WindowManager中
5、增加全局变量boolean isStarted记录悬浮窗是否已打开。
6、在onDestroy()中将布局从WindowManager中移除
7、在onStartCommand()中进行控件的点击、拖动监听
8、点击最小化按钮执行moveTaskToBack(true),并启动Service,isStarted = true;
9、onRestart()中关闭Service;
以下是代码
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
public class FloatVideoWindowService extends Service {
private WindowManager mWindowManager;
private WindowManager.LayoutParams wmParams;
private LayoutInflater inflater;
public static boolean isStarted = false;
//view
private View mFloatingLayout; //布局View
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
isStarted = true;
initWindow();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
showFloatingWindow();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mWindowManager != null) {
mWindowManager.removeView(mFloatingLayout);
isStarted = false;
}
}
/**
* 设置悬浮框基本参数(位置、宽高等)
*/
private void initWindow() {
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
wmParams = getParams();
inflater = LayoutInflater.from(getApplicationContext());
mFloatingLayout = inflater.inflate(R.layout.layout_window, null);
}
private WindowManager.LayoutParams getParams() {
wmParams = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
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.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
//这是悬浮窗居中位置
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
//70、210是我项目中的位置哦
wmParams.x = 70;
wmParams.y = 210;
return wmParams;
}
private void showFloatingWindow() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本
if (Settings.canDrawOverlays(this)) {
mFloatingLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), VoiceCallActivity.class);
startActivity(intent);
}
});
mFloatingLayout.setOnTouchListener(new FloatingListener());
mWindowManager.addView(mFloatingLayout, wmParams);
}
} else {
mFloatingLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), VoiceCallActivity.class);
startActivity(intent);
}
});
mFloatingLayout.setOnTouchListener(new FloatingListener());
mWindowManager.addView(mFloatingLayout, wmParams);
}
}
private int mTouchStartX, mTouchStartY, mTouchCurrentX, mTouchCurrentY;
private int mStartX, mStartY, mStopX, mStopY;
private boolean isMove;
private class FloatingListener implements View.OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
isMove = false;
mTouchStartX = (int) event.getRawX();
mTouchStartY = (int) event.getRawY();
mStartX = (int) event.getX();
mStartY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
mTouchCurrentX = (int) event.getRawX();
mTouchCurrentY = (int) event.getRawY();
wmParams.x += mTouchCurrentX - mTouchStartX;
wmParams.y += mTouchCurrentY - mTouchStartY;
mWindowManager.updateViewLayout(mFloatingLayout, wmParams);
mTouchStartX = mTouchCurrentX;
mTouchStartY = mTouchCurrentY;
break;
case MotionEvent.ACTION_UP:
mStopX = (int) event.getX();
mStopY = (int) event.getY();
if (Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1) {
isMove = true;
}
break;
}
return isMove;
}
}
}
private Intent serviceIntent;
private static HomeWatcherReceiver mHomeKeyReceiver = null;
public void openMinWindow() {
if (!FloatVideoWindowService.isStarted) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);
} else {
serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class);
startService(serviceIntent);
moveTaskToBack(true);
}
} else {
serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class);
startService(serviceIntent);
moveTaskToBack(true);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class);
startService(serviceIntent);
moveTaskToBack(true);
}
}
}
}
@Override
protected void onRestart() {
super.onRestart();
if (serviceIntent != null) {
stopService(serviceIntent);
}
}
//以下为Home键监听,最小化到桌面时也让悬浮窗启动
@Subscribe
public void onEvent(String event) {
if (event.equals("startService")) {
openMinWindow();
}
}
@Override
protected void onResume() {
super.onResume();
registerHomeKeyReceiver(this);
}
@Override
protected void onPause() {
super.onPause();
unregisterHomeKeyReceiver(this);
}
private static void registerHomeKeyReceiver(Context context) {
mHomeKeyReceiver = new HomeWatcherReceiver();
final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
context.registerReceiver(mHomeKeyReceiver, homeFilter);
}
private static void unregisterHomeKeyReceiver(Context context) {
if (null != mHomeKeyReceiver) {
context.unregisterReceiver(mHomeKeyReceiver);
}
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import de.greenrobot.event.EventBus;
/**
* PROJECT_NAME:meteor_dog_android
* Created by ENZO on 2018/10/19,16:18
* Description: Home键监听
*/
public class HomeWatcherReceiver extends BroadcastReceiver {
private static final String LOG_TAG = "HomeReceiver";
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
private static final String SYSTEM_DIALOG_REASON_LOCK = "lock";
private static final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(LOG_TAG, "onReceive: action: " + action);
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
Log.i(LOG_TAG, "reason: " + reason);
if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
//发送通知,启动Service
EventBus.getDefault().post("startService");
}
else if (SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
// 长按Home键 或者 activity切换键
}
else if (SYSTEM_DIALOG_REASON_LOCK.equals(reason)) {
// 锁屏
}
else if (SYSTEM_DIALOG_REASON_ASSIST.equals(reason)) {
// samsung 长按Home键
}
}
}
}