一、悬浮窗点击后的界面:
主要有四个功能,返回、应用程序、退出和主界面。其他功能也可以类似添加。
界面布局代码就不贴出来了,源码(切记需要签名才能让功能实现):下载地址
二、主要是检测系统启动或者app启动的时候出现悬浮窗,并且只有当检测到前台运行了特定程序才会隐藏图标。
添加检测BOOT_COMPLETED,需要添加权限,
三、开始写service,调用自定义的view。
public void onCreate() {
super.onCreate();
new EasyTouchView(this, this).initTouchViewEvent();
}
四、自定义view的实现,主要是touchview的显示,以及移动操作和点击事件注册。
public EasyTouchView(Context context, ServiceListener listener) {
super(context);
mContext = context;
mSerLisrener = listener;
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 100) {
if (isCellaretteAppforeground(mContext)) {//检测到“com.xxx.xxx“程序,将隐藏touchview
mTouchView.setVisibility(View.INVISIBLE);
} else {
mTouchView.setVisibility(View.VISIBLE);//否则显示touchview
}
this.sendEmptyMessageDelayed(100, 500);
}
}
};
}
/*
* 检测是否存在某个应用com.xxx.xxx在前台运行。
*/
public boolean isCellaretteAppforeground(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List appProcesses = am.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
if ("com.xxx.xxx".equals(appProcess.processName)) {
return true;
}
break;
}
}
return false;
}
public void initTouchViewEvent() {
initEasyTouchViewEvent();
initSettingTableView();
}
private void initEasyTouchViewEvent() {
// 设置载入view WindowManager参数,获取WindowManager
mWManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
midX = mWManager.getDefaultDisplay().getWidth() / 2 - 25;
midY = mWManager.getDefaultDisplay().getHeight() / 2 - 44;
mTouchView = LayoutInflater.from(mContext).inflate(R.layout.easy_touch_view, null);
mIconImageView = (ImageView) mTouchView.findViewById(R.id.easy_touch_view_imageview);
mTouchView.setBackgroundColor(Color.TRANSPARENT);
mTouchView.setOnTouchListener(mTouchListener);
WindowManager wm = mWManager;
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
mWMParams = wmParams;
wmParams.type = 2003; // 这里的2002表示系统级窗口,你也可以试试2003。
wmParams.flags = 40; // 设置桌面可控
wmParams.width = 100;
wmParams.height = 100;
wmParams.format = -3; // 透明
wm.addView(mTouchView, wmParams);
mTouchView.setVisibility(View.INVISIBLE);
mHandler.sendEmptyMessageDelayed(100, 1000);//发送消息
}
private void initSettingTableView() {
mSettingTable = LayoutInflater.from(mContext).inflate(R.layout.floatmenu, null);//将悬浮窗布局载入,继而可以获取里面的控件进行点击事件注册
btnback = (Button) mSettingTable.findViewById(R.id.btn_back);
btnhome = (Button) mSettingTable.findViewById(R.id.btn_home_screen);
btnexit = (Button) mSettingTable.findViewById(R.id.btn_exit);
btnapps = (Button) mSettingTable.findViewById(R.id.btn_apps);
btnback.setOnClickListener(mClickListener);
btnhome.setOnClickListener(mClickListener);
btnexit.setOnClickListener(mClickListener);
btnapps.setOnClickListener(mClickListener);
}
private OnClickListener mClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_back: //执行了两次是因为第一次是回到小图标,然后在执行返回当前程序
sendKeyCode(KeyEvent.KEYCODE_BACK);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
sendKeyCode(KeyEvent.KEYCODE_BACK);
}
}, 500);
break;
case R.id.btn_home_screen:
sendKeyCode(KeyEvent.KEYCODE_HOME);
break;
case R.id.btn_exit:
sendKeyCode(KeyEvent.KEYCODE_BACK);
break;
case R.id.btn_apps:
sendKeyCode(KeyEvent.KEYCODE_APP_SWITCH);
break;
}
}
};
//借用 input keyevent keycode命令,不同功能改变keycode即可,keycode对应值就百度~
private void sendKeyCode(final int keyCode) {
new Thread() {
public void run() {
String keyCommand = "input keyevent " + keyCode;
try {
Process process = Runtime.getRuntime().exec(keyCommand);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
//监听touch
private OnTouchListener mTouchListener = new OnTouchListener() {
float lastX, lastY;
int paramX, paramY;
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
float x = event.getRawX();
float y = event.getRawY();
if (mTag == 0) {
mOldOffsetX = mWMParams.x;
mOldOffsetY = mWMParams.y;
}
switch (action) {
case MotionEvent.ACTION_DOWN:
motionActionDownEvent(x, y);
break;
case MotionEvent.ACTION_MOVE:
motionActionMoveEvent(x, y);
break;
case MotionEvent.ACTION_UP:
motionActionUpEvent(x, y);
break;
default:
break;
}
return true;
}
private void motionActionDownEvent(float x, float y) {
lastX = x;
lastY = y;
paramX = mWMParams.x;
paramY = mWMParams.y;
}
private void motionActionMoveEvent(float x, float y) {
int dx = (int) (x - lastX);
int dy = (int) (y - lastY);
mWMParams.x = paramX + dx;
mWMParams.y = paramY + dy;
mTag = 1;
mWManager.updateViewLayout(mTouchView, mWMParams);
}
private void motionActionUpEvent(float x, float y) {
int newOffsetX = mWMParams.x;
int newOffsetY = mWMParams.y;
if (mOldOffsetX == newOffsetX && mOldOffsetY == newOffsetY) {
mPopuWin = new PopupWindow(mSettingTable, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mPopuWin.setTouchInterceptor(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
hideSettingTable();
return true;
}
return false;
}
});
mPopuWin.setBackgroundDrawable(new BitmapDrawable());
mPopuWin.setTouchable(true);
mPopuWin.setFocusable(true);
mPopuWin.setOutsideTouchable(true);
mPopuWin.setContentView(mSettingTable);
if (Math.abs(mOldOffsetX) > midX) {
if (mOldOffsetX > 0) {
mOldOffsetX = midX;
} else {
mOldOffsetX = -midX;
}
}
if (Math.abs(mOldOffsetY) > midY) {
if (mOldOffsetY > 0) {
mOldOffsetY = midY;
} else {
mOldOffsetY = -midY;
}
}
mPopuWin.setAnimationStyle(R.style.AnimationPreview);
mPopuWin.setFocusable(true);
mPopuWin.update();
mPopuWin.showAtLocation(mTouchView, Gravity.CENTER, -mOldOffsetX, -mOldOffsetY);
// TODO
mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent));
catchSettingTableDismiss();
} else {
mTag = 0;
}
}
};
private void catchSettingTableDismiss() {
mTimer = new Timer();
mTask = new TimerTask() {
@Override
public void run() {
if (mPopuWin == null || !mPopuWin.isShowing()) {
handler.sendEmptyMessage(0x0);
}
}
};
mTimer.schedule(mTask, 0, 100);
}
private void clearTimerThead() {
if (mTask != null) {
mTask.cancel();
mTask = null;
}
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
Handler handler = new Handler() {
public void handleMessage(Message msg) {
mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.touch_ic));
};
};
public void showToast(Context context, String text) {
if (mToast == null) {
mToast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
mToast.setDuration(Toast.LENGTH_SHORT);
}
mToast.show();
}
private void hideSettingTable(String content) {
hideSettingTable();
showToast(mContext, content);
}
private void hideSettingTable() {
if (null != mPopuWin) {
mPopuWin.dismiss();
}
}
public interface ServiceListener {
public void OnCloseService(boolean isClose);
}
切记:需要签名,才可以实现input keyevent keycode
源码下载: 下载地址个人主页:www.ctrlqun.com
个人微信:18305165010
个人联系方式:有问题可以相互交流 ,备注CSDN