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() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if (msg.what == 100) {if (isCellaretteAppforeground(mContext)) {//检测到“com.xxx.xxx“程序,将隐藏touchviewmTouchView.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参数,获取WindowManagermWManager = (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() {@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_back: //执行了两次是因为第一次是回到小图标,然后在执行返回当前程序sendKeyCode(KeyEvent.KEYCODE_BACK);new Handler().postDelayed(new Runnable() {@Overridepublic 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();}
//监听touchprivate 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);// TODOmIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent));catchSettingTableDismiss();} else {mTag = 0;}}};private void catchSettingTableDismiss() {mTimer = new Timer();mTask = new TimerTask() {@Overridepublic 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