android仿assistivetouch悬浮窗实现(带功能实现)

一、悬浮窗点击后的界面:

主要有四个功能,返回、应用程序、退出和主界面。其他功能也可以类似添加。

界面布局代码就不贴出来了,源码(切记需要签名才能让功能实现):下载地址

二、主要是检测系统启动或者app启动的时候出现悬浮窗,并且只有当检测到前台运行了特定程序才会隐藏图标。

<receiver android:name="com.bumblebee.remindeasy.StartupReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <service android:name="com.bumblebee.remindeasy.service.AuxiliaryService" />

添加检测BOOT_COMPLETED,需要添加权限,

<uses-permission android:name="android.permission.RECEIVE_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<ActivityManager.RunningAppProcessInfo> 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.rebootvip.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孔乙己大叔

你看我有机会吗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值