前言贅述:
本博客只對使用Android AccessibilityService實作自動搶單測驗程式Demo的api使用,不對AccessibilityService的類結構及相關配置資訊做詳細說明,如需了解,請查閱谷歌安卓AccessibilityService的說明檔案,
google Android官網AccessibilityService的檔案說明:AccessibilityService | Android Developers
我最早是想在哈羅出行上做個腳本來搶單/找單,思考著要如何來實作這樣一個功能,用lua腳本?用Android Monkey?很明顯,這些都有局限性,實作不了,有一天,我想到某個電視臺中的情景:某個電視臺中,說的是小米集團(小米手機),在一個作業房間中的機架上整整齊齊的擺放著有上千乃至上萬臺的手機,每個手機的螢屏都在瘋狂的閃爍著,后來才知道原來那是在做自動化互動測驗,我在想:我的這個需求功能,是不是也是自動化互動測驗方面的技術點?百度了一下,并由此接觸到了Android AccessibilityService,
public abstract class AccessibilityService
extends Service
| java.lang.Object | ||||
| ? | android.content.Context | |||
| ? | android.content.ContextWrapper | |||
| ? | android.app.Service | |||
| ? | android.accessibilityservice.AccessibilityService | |||
繼承于android四大組件之Service,其使用方式與service基本相同,但它是一個系統級別的“監聽器”服務,可監聽手機上所有應用所產生的小變化、大變化(比如某個被監聽應用的發生的點擊事件、控制元件文本內容變化、訊息通知等),另它有自己獨立的生命周期(思路有點類似于微信公眾號開發中訊息與事件的處理),如下:
onCreate()
onServiceConnected()
onAccessibilityEvent(AccessibilityEvent event)//執行緒阻塞式
onInterrupt()
下面進入主題:
第一步.注冊服務
1.1在清單檔案中注冊服務
<service
android:name=".service.HaloAccessibilityServiceV5"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibilityservice_setting" />
</service>
1.2meta-data引入配置
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibilityservice_setting" />
1.3accessibilityservice.xml配置資訊項
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true"
android:description="@string/accessibilityservice_setting"
android:notificationTimeout="100"
android:packageNames="填寫你要監聽的應用完整包名以逗號隔開可填寫多個"></accessibility-service>
1.4須手動為apk應用程式打開無障礙權限開關,
位置在設定->快捷與輔助->無障礙,找到自己的apk輔助程式應用,手動將開關打開,
第二步.實作輔助功能
思路:實作輔助功能的關鍵是接受到事件,并使用AccessibilityService相關api來獲取應用控制元件資訊,以及回應適當的事件,來完成"輔助"功能,
1.1下面先來看一下AccessibilityService做為"系統級"服務可以監聽到指定應用的哪些事件,或者說可以監聽到應用的哪些變化,
Event types支持的事件型別(全面)
AccessibilityEvent#TYPE_VIEW_CLICKED//View控制元件點擊事件
AccessibilityEvent#TYPE_VIEW_LONG_CLICKED//長按事件
AccessibilityEvent#TYPE_VIEW_FOCUSED//焦點事件
AccessibilityEvent#TYPE_VIEW_SELECTED//選擇事件
AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED//文本變化
AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED//視窗狀態變化
AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED//訊息通知狀態變化
AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START//手勢START
AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END//手勢END
AccessibilityEvent#TYPE_VIEW_HOVER_ENTER//懸停
AccessibilityEvent#TYPE_VIEW_HOVER_EXIT//懸停
AccessibilityEvent#TYPE_VIEW_SCROLLED//滾動
AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED//文本選擇變化
AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED//視窗連接變化
AccessibilityEvent#TYPE_ANNOUNCEMENT//公告
AccessibilityEvent#TYPE_GESTURE_DETECTION_START//手指檢測START
AccessibilityEvent#TYPE_GESTURE_DETECTION_END//手指檢測END
AccessibilityEvent#TYPE_TOUCH_INTERACTION_START//觸摸互動START
AccessibilityEvent#TYPE_TOUCH_INTERACTION_END//觸摸互動END
AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED//可訪問性
AccessibilityEvent#TYPE_WINDOWS_CHANGED//視窗變化
AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED//可訪問性清除
1.2獲取應用控制元件資訊的方式有兩種
1).通過id尋找控制元件,id格式為:(包名:id/+制定控制元件的id),對第三方應用無效,
List<AccessibilityNodeInfo> list = rowNode.findAccessibilityNodeInfosByViewId("com.jingyao.easybike:id/tvAmount");
2).通過控制元件的text尋找控制元件
List<AccessibilityNodeInfo> list = rowNode.findAccessibilityNodeInfosByText("不拼車");
1.3.可回應的事件
1)節點可回應執行的操作
android.view.accessibility.AccessibilityNodeInfo#performAction(int action)
有
android.view.accessibility.AccessibilityNodeInfo#ACTION_CLICK//節點點擊
android.view.accessibility.AccessibilityNodeInfo#ACTION_FOCUS
android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
android.view.accessibility.AccessibilityNodeInfo#ACTION_SELECT
android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
android.view.accessibility.AccessibilityNodeInfo#ACTION_CLICK
android.view.accessibility.AccessibilityNodeInfo#ACTION_LONG_CLICK
android.view.accessibility.AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
android.view.accessibility.AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
android.view.accessibility.AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
android.view.accessibility.AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
android.view.accessibility.AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
android.view.accessibility.AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
android.view.accessibility.AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
android.view.accessibility.AccessibilityNodeInfo#ACTION_COPY//復制
android.view.accessibility.AccessibilityNodeInfo#ACTION_PASTE//粘貼
android.view.accessibility.AccessibilityNodeInfo#ACTION_CUT//剪切
android.view.accessibility.AccessibilityNodeInfo#ACTION_SET_SELECTION
android.view.accessibility.AccessibilityNodeInfo#ACTION_EXPAND
android.view.accessibility.AccessibilityNodeInfo#ACTION_COLLAPSE
android.view.accessibility.AccessibilityNodeInfo#ACTION_DISMISS
android.view.accessibility.AccessibilityNodeInfo#ACTION_SET_TEXT
android.view.accessibility.AccessibilityNodeInfo#LAST_LEGACY_STANDARD_ACTION
android.view.accessibility.AccessibilityNodeInfo#ACTION_TYPE_MASK
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_X
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_Y
android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN
2)全域回應可執行的操作
android.accessibilityservice.AccessibilityService#performGlobalAction(int action)
有
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK//后退,相當于手機后退按鍵
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_HOME//回到手機HOME螢屏
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_RECENTS
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_QUICK_SETTINGS
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_POWER_DIALOG
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_LOCK_SCREEN
android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TAKE_SCREENSHOT
第三步.寫個自動化測驗DEMO應用,
下面貼部分對哈羅出行自動化測驗搶單/找單的主要邏輯代碼,HaloAccessibilityServiceV5.java
/**
* Copyright (C), 2000-2021, XXX有限公司
* FileName: HaloAccessibilityServiceV5
* Author: wangyetao
* Date: 21-10-6 00:41:24
* Description:哈羅自動找單,無障礙服務編程V5
* History:
* <author>wangyetao
* <time>2021年 10月 04日 星期一 13:07:43 CST
* <version>V4
* <desc>1.添加語音提示功能 2.開關按鈕與回應事件頻率微調
*/
package com.example.driverslanguage.service;
import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.graphics.PixelFormat;
import android.os.Build;
import android.util.DisplayMetrics;
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.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import com.example.driverslanguage.MainActivity;
import com.example.driverslanguage.R;
import com.example.driverslanguage.TimerManager;
import com.example.driverslanguage.entity.FreerideOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @ClassName: HaloAccessibilityServiceV5
* @Description: 哈羅出行自動找單, 無障礙服務編程V5
* @Author: wangyetao
* @Date: 21-10-6 00:41:24
*/
public class HaloAccessibilityServiceV5 extends AccessibilityService {
private static String TAG = "HaloAccessibilityServiceV5";
private static int GETORDER_STATE = 0;//0默認值 1搶單結束 2搶單成功
public static AccessibilityService instance;
private boolean isStart = false;//搶單任務開啟標識
protected static TimerManager timerManager;
//定義浮動視窗布局
private LinearLayout mFloatLayout;
private TextView tv_targetsection;
private WindowManager.LayoutParams wmParams;
//創建浮動視窗設定布局引數的物件
private WindowManager mWindowManager;
private Button mFloatView;
private float DownX, DownY = 0;
private float moveX, moveY = 0;
private long currentMS, moveTime = 0;
String regex_double = "\\d+(?:\\.\\d+)?";
String regex_int = "\\d+(?:\\d+)?";
//android輸出語音提示、異步播放語音
private HaloTextToSpeech tts;
private String ttsText = "";
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// TODO Auto-generated method stub
timerManager = TimerManager.getInstance();
if (isStart == true) {
int eventType = event.getEventType();
String packageName = event.getPackageName() + "";
String page_eventText = "[" + packageName + "]";
switch (eventType) {
case AccessibilityEvent.TYPE_VIEW_CLICKED:
page_eventText += "TYPE_VIEW_CLICKED";
//入口1
allAutoOption(page_eventText);
break;
case AccessibilityEvent.TYPE_VIEW_FOCUSED:
page_eventText += "TYPE_VIEW_FOCUSED";
break;
case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
page_eventText += "TYPE_VIEW_LONG_CLICKED";
break;
case AccessibilityEvent.TYPE_VIEW_SELECTED:
page_eventText += "TYPE_VIEW_SELECTED";
break;
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
page_eventText += "TYPE_VIEW_TEXT_CHANGED";
break;
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
page_eventText += "TYPE_WINDOW_STATE_CHANGED";
//入口2
//allAutoOption(page_eventText);
break;
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
page_eventText += "TYPE_NOTIFICATION_STATE_CHANGED";
break;
case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
page_eventText += "TYPE_TOUCH_EXPLORATION_GESTURE_END";
break;
case AccessibilityEvent.TYPE_ANNOUNCEMENT:
page_eventText += "TYPE_ANNOUNCEMENT";
break;
case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
page_eventText += "TYPE_TOUCH_EXPLORATION_GESTURE_START";
break;
case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
page_eventText += "TYPE_VIEW_HOVER_ENTER";
break;
case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
page_eventText += "TYPE_VIEW_HOVER_EXIT";
break;
case AccessibilityEvent.TYPE_VIEW_SCROLLED:
page_eventText += "TYPE_VIEW_SCROLLED";
break;
case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
page_eventText += "TYPE_VIEW_TEXT_SELECTION_CHANGED";
break;
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
page_eventText += "TYPE_WINDOW_CONTENT_CHANGED";
break;
default:
throw new IllegalStateException("Unexpected value: " + eventType);
}
}
}
private void allAutoOption(String page_eventText) {
try {
try {
//微調450ms效果較佳,2021年 10月 03日 星期日 20:54:25 CST
Thread.sleep(450);//300ms,350ms,400ms,450ms,500ms
} catch (InterruptedException e) {
e.printStackTrace();
}
//獲得所有表單控制元件
AccessibilityNodeInfo rootInActiveWindow = getRootInActiveWindow();
//0.確定是哈羅出行應用
if (rootInActiveWindow != null && rootInActiveWindow.getPackageName().equals("com.jingyao.easybike")) {
//1.確定是市內路線/城際路線頁面
List<AccessibilityNodeInfo> routePage = rootInActiveWindow.findAccessibilityNodeInfosByText("城際路線");
if (routePage != null && routePage.size() > 0) {
//通過螢屏顯示的內容,比如:下一步、完成等字眼,獲取包含該文本的所有節點
//僅適用于城際路線不拼車自動搶單
String text_tip1 = "不拼車";
List<AccessibilityNodeInfo> nodeInfoList = rootInActiveWindow.findAccessibilityNodeInfosByText(text_tip1);
if (nodeInfoList != null && nodeInfoList.size() > 0) {
for (int i = 0; i < nodeInfoList.size(); i++) {
if (nodeInfoList.get(i).getClassName().equals("android.widget.TextView")) {
AccessibilityNodeInfo item_parent = nodeInfoList.get(i).getParent();
FreerideOrder freerideOrder = new FreerideOrder();
int counts = item_parent.getChildCount();
if (counts > 0) {
/*for (int j = 0; j < counts; j++)
Log.i(TAG, "[" + j + "]" + String.valueOf(item_parent.getChild(j).getText()));*/
freerideOrder.setInsertTime(String.valueOf(System.currentTimeMillis()));//1633338788891
freerideOrder.setPointoftime(String.valueOf(item_parent.getChild(0).getText()));//10月6日 15:00-15:15
freerideOrder.setBegin(String.valueOf(item_parent.getChild(1).getText()));//東莞市·赤馬路/赤崗西坊路路口
String tmpStrFromkm = String.valueOf(item_parent.getChild(2).getText());//41.7km,提取出double距離數值
List<Double> result_doubles = new ArrayList<Double>();
Matcher m = Pattern.compile(regex_double, Pattern.MULTILINE).matcher(tmpStrFromkm);
while (m.find()) {
result_doubles.add(Double.valueOf(m.group()));
}
freerideOrder.setFromkm(Double.valueOf(result_doubles.get(0)));//41.7
freerideOrder.setEnd(String.valueOf(item_parent.getChild(3).getText()));//廣州市·建興煙酒
freerideOrder.setPrice(Double.valueOf(String.valueOf(item_parent.getChild(4).getText())));//117
String tmpStrPNum = String.valueOf(item_parent.getChild(6).getText());
List<Integer> result_ints = new ArrayList<Integer>();
m = Pattern.compile(regex_int, Pattern.MULTILINE).matcher(tmpStrPNum);//4人,提取出int人數值
while (m.find()) {
result_ints.add(Integer.valueOf(m.group()));
}
freerideOrder.setPeopleNum(Integer.valueOf(result_ints.get(0)));//4
if (counts == 9) {
freerideOrder.setType(String.valueOf(item_parent.getChild(8).getText()));//不拼車
} else {
freerideOrder.setType(String.valueOf(item_parent.getChild(7).getText()));//不拼車
}
/*Log.i(TAG, freerideOrder.toString());*/
//檢測訂單是否符合指定目標
if (freerideOrder.getPrice() >= MainActivity.targetPriceMin && freerideOrder.getPrice() <= MainActivity.targetPriceMax && freerideOrder.getPrice() / 10 > freerideOrder.getFromkm()) {
item_parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
break;
}
}
}
}
}
}
//2.確定是訂單詳情頁面-確認同行
List<AccessibilityNodeInfo> detailPage = rootInActiveWindow.findAccessibilityNodeInfosByText("尾號");
if (detailPage != null && detailPage.size() > 0) {
//2.2確定是訂單詳情頁面-確認同行
String text_tip2 = "確認同行";
List<AccessibilityNodeInfo> tip2nodeInfoList = rootInActiveWindow.findAccessibilityNodeInfosByText(text_tip2);
if (tip2nodeInfoList != null && tip2nodeInfoList.size() > 0) {
//微調點擊3次效果較佳,2021年 10月 04日 星期一 12:54:03 CST
tip2nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
tip2nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
tip2nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
//2.4確定是訂單詳情頁面-搶單成功
String text_tip4 = "出發并通知乘客";
List<AccessibilityNodeInfo> tip4nodeInfoList = rootInActiveWindow.findAccessibilityNodeInfosByText(text_tip4);
if (tip4nodeInfoList != null && tip4nodeInfoList.size() > 0) {
GETORDER_STATE = 2;//搶單成功標識
stopTask(mFloatView, timerManager);
}
}
//2.3確定是訂單詳情頁面-確定
List<AccessibilityNodeInfo> popCheckTimePage = rootInActiveWindow.findAccessibilityNodeInfosByText("請選擇到達乘客起點的時間");
if (popCheckTimePage != null && popCheckTimePage.size() > 0) {
String text_tip3 = "確定";
List<AccessibilityNodeInfo> tip3nodeInfoList = rootInActiveWindow.findAccessibilityNodeInfosByText(text_tip3);
if (tip3nodeInfoList != null && tip3nodeInfoList.size() > 0) {
//微調點擊3次效果較佳,2021年 10月 04日 星期一 12:55:03 CST
tip3nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
tip3nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
tip3nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
//2.3.2確定是訂單詳情頁面-搶單結束
GETORDER_STATE = 1;//搶單結束
stopTask(mFloatView, timerManager);
}
}
}
} catch (Exception e) {
}
}
@Override
public void onInterrupt() {
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
instance = this;
}
@Override
public void onCreate() {
super.onCreate();
createFloatView();
tts = new HaloTextToSpeech(getApplicationContext());
}
@SuppressLint("ClickableViewAccessibility")
private void createFloatView() {
wmParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_TOAST,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
//通過getApplication獲取的是WindowManagerImpl.CompatModeWrapper
mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
//設定window type
//wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
//設定圖片格式,效果為背景透明
wmParams.format = PixelFormat.RGBA_8888;
//設定浮動視窗不可聚焦(實作操作除浮動視窗外的其他可見視窗的操作)
wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//調整懸浮窗顯示的停靠位置為左側置頂
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
// 以螢屏左上角為原點,設定x、y初始值,相對于gravity
wmParams.x = 0;
wmParams.y = 152;
//設定懸浮視窗長寬資料
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
LayoutInflater inflater = LayoutInflater.from(getApplication());
//獲取浮動視窗視圖所在布局
mFloatLayout = (LinearLayout) inflater.inflate(R.layout.alert_window_menu, null);
//添加mFloatLayout
mWindowManager.addView(mFloatLayout, wmParams);
//浮動視窗按鈕
mFloatView = (Button) mFloatLayout.findViewById(R.id.alert_window_imagebtn);
tv_targetsection = mFloatLayout.findViewById(R.id.tv_targetsection);
mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
//初始化設定監聽價格區間
tv_targetsection.setText(MainActivity.targetPriceMin + "-" + MainActivity.targetPriceMax);
//設定監聽浮動視窗的觸摸移動
mFloatView.setOnTouchListener(new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
DownX = event.getX();
DownY = event.getY();
currentMS = System.currentTimeMillis();
break;
case MotionEvent.ACTION_MOVE:
DownX = event.getX();
DownY = event.getY();
moveX += Math.abs(event.getRawX() - DownX);//x軸移動距離
moveY += Math.abs(event.getRawY() - DownY);//y軸移動距離
if ((DownX - event.getRawX()) > 20
|| (event.getRawX() - DownX) > 20
|| (DownY - event.getRawY()) > 20
|| (event.getRawY() - DownY) > 20
) {
// getRawX是觸摸位置相對于螢屏的坐標,getX是相對于按鈕的坐標
wmParams.x = (int) event.getRawX() - mFloatView.getMeasuredWidth() / 2;
// 減75為狀態欄的高度
wmParams.y = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2 - 75;
// 重繪
mWindowManager.updateViewLayout(mFloatLayout, wmParams);
}
break;
case MotionEvent.ACTION_UP:
moveTime = System.currentTimeMillis() - currentMS;
//判斷是滑動還是點擊操作、判斷是否繼續傳遞信號
if (moveTime < 300 && moveX < 20 && moveY < 20) {//點擊事件
return false;
} else {//滑動事件
wmParams.x = (int) event.getRawX();
wmParams.y = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2 - 75;
// 通過Resources獲取螢屏寬高及尺寸
DisplayMetrics dm2 = getResources().getDisplayMetrics();
int widthPixels = dm2.widthPixels;
// 重置wmParams引數后重繪view,實作浮動按鈕橫向貼邊效果
if (wmParams.x > widthPixels / 2) {
wmParams.x = widthPixels;
} else {
wmParams.x = 0;
}
// 重繪
mWindowManager.updateViewLayout(mFloatLayout, wmParams);
moveX = moveY = 0;//歸零
return true;//回傳true,表示不再執行后面的事件
}
default:
break;
}
return false;
}
});
mFloatView.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onClick(View v) {
//TODO home
//performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
isStart = !isStart;//取反
if (isStart == true) {
startTask(mFloatView, timerManager);
} else {
stopTask(mFloatView, timerManager);
}
}
});
mFloatView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//TODO home
return true;
}
});
}
private void stopTask(Button mFloatView, TimerManager timerManager) {
//開啟HaloAccessibilityServiceV2服務,僅修改按鈕顏色
if (GETORDER_STATE == 2) {
tts.notifyNewMessage("哈羅順風車搶到訂單啦,趕快去查看一下吧");
} else if (GETORDER_STATE == 1) {
tts.notifyNewMessage("哈羅順風車搶單結束啦,趕快去查看一下結果吧");
tts.notifyNewMessage("哈羅順風車搶單結束啦,趕快去查看一下結果吧");
tts.notifyNewMessage("哈羅順風車搶單結束啦,趕快去查看一下結果吧");
} else {
tts.notifyNewMessage("停止找單任務");
}
isStart = false;
GETORDER_STATE = 0;//重置
mFloatView.setText("開啟");
tv_targetsection.setText(MainActivity.targetPriceMin + "-" + MainActivity.targetPriceMax);
mFloatView.setBackgroundResource(R.drawable.dw_teal_200);
//timerManager.stopTimerTask();
}
private void startTask(Button mFloatView, TimerManager timerManager) {
//停止HaloAccessibilityServiceV2服務,僅修改按鈕顏色
tts.notifyNewMessage("開啟找單任務" + MainActivity.targetPriceMin + "-" + MainActivity.targetPriceMax);
isStart = true;
GETORDER_STATE = 0;//重置
mFloatView.setText("停止");
tv_targetsection.setText(MainActivity.targetPriceMin + "-" + MainActivity.targetPriceMax);
mFloatView.setBackgroundResource(R.drawable.dw_red);
//timerManager.startTimerTask();
}
}
部分Log日志與運行截圖(如需完整原始碼安裝包請郵件wangyetao_binary@126.com聯系博主):
城際路線
2021-10-06 02:51:04.218 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [0]10月12日 10:00-10:15
2021-10-06 02:51:04.224 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [1]東莞市·華為(鳳崗店)
2021-10-06 02:51:04.234 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [2]61.4km
2021-10-06 02:51:04.238 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [3]深圳市·深圳南北小筑客堆疊
2021-10-06 02:51:04.243 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [4]93.1
2021-10-06 02:51:04.252 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [5]元
2021-10-06 02:51:04.266 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [6]3人
2021-10-06 02:51:04.266 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [7]不拼車
2021-10-06 02:51:04.269 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: FreerideOrder{insertTime='1633459864266', pointoftime='10月12日 10:00-10:15', begin='東莞市·華為(鳳崗店)', end='深圳市·深圳南北小筑客堆疊', fromkm=61.4, price=93.1, peopleNum=3, type='不拼車'}
市內路線
2021-10-06 02:52:32.808 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [0]明天 15:30-15:40
2021-10-06 02:52:32.818 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [1]距你12.6km
2021-10-06 02:52:32.822 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [2]石龍廣場
2021-10-06 02:52:32.827 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [3]東莞市·南崗
2021-10-06 02:52:32.833 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [4]廣州新華學院東莞校區(西門)
2021-10-06 02:52:32.837 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [5]62.7
2021-10-06 02:52:32.841 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [6]元
2021-10-06 02:52:32.849 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [7]已預付
2021-10-06 02:52:32.852 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [8]2人
2021-10-06 02:52:32.852 22973-22973/com.example.driverslanguage I/HaloAccessibilityServiceV5: [9]不拼車



在此記錄與總結,2021年 10月 06日 星期三 02:29:23 CST,
免責宣告:本程式僅為輔助點擊工具與IT開發、測驗人員之間交流學習使用,無任何黑科技功能,禁止用于任何違法違規行為,否則后果自負,請遵紀守法,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/306264.html
標籤:其他
上一篇:記錄第一次完整安卓逆向程序筆記
