From 9ecfa8de27e4681c94ea67f3ac890be91dbd303b Mon Sep 17 00:00:00 2001 From: tongtongstudio Date: Sat, 21 Jun 2025 15:13:55 +0800 Subject: [PATCH] =?UTF-8?q?version:1.6.6=20fix:=20update:=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E7=94=B5=E8=AF=9D=E7=9B=B4=E6=8E=A5=E4=BB=8E=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E6=8B=A8=E6=89=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 +- .../selecttospeak/SelectToSpeakService.java | 143 ++++++++++++++++-- 2 files changed, 130 insertions(+), 17 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ce0dfd3..6f5b3ad 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "com.xxpatx.os" minSdkVersion 24 targetSdkVersion 29 - versionCode 1065 - versionName "1.6.5" + versionCode 1066 + versionName "1.6.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/google/android/accessibility/selecttospeak/SelectToSpeakService.java b/app/src/main/java/com/google/android/accessibility/selecttospeak/SelectToSpeakService.java index 797d7ea..faeebab 100644 --- a/app/src/main/java/com/google/android/accessibility/selecttospeak/SelectToSpeakService.java +++ b/app/src/main/java/com/google/android/accessibility/selecttospeak/SelectToSpeakService.java @@ -10,6 +10,8 @@ import android.content.IntentFilter; import android.graphics.Path; import android.graphics.Point; import android.graphics.Rect; +import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.util.DisplayMetrics; @@ -27,6 +29,8 @@ import com.xxpatx.os.config.CommonConfig; import com.xxpatx.os.utils.ForegroundAppUtil; import java.util.List; +import java.util.Optional; +import java.util.Random; /** * 通过微信标签最高支持8.0.49,8.0.50 获取不到数据 @@ -37,9 +41,12 @@ public class SelectToSpeakService extends AccessibilityService { private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + private static final int ACTION_IME_ENTER_VERSION = 30; + private static final int ACTION_IME_ENTER_ID = 16908372; private static final String DIALER_TEXT = "音视频通话"; private static final String CONTACT_TEXT = "通讯录"; + private static final String SEARCH_TEXT = "搜索"; private static final String TAG_TEXT = "标签"; private static final String TAG_NAME = "孝心通"; private static final String MORE_NAME = "更多功能按钮,已折叠"; @@ -56,7 +63,7 @@ public class SelectToSpeakService extends AccessibilityService { public static final int TYPE_VOICE = 0; public static final int TYPE_VIDEO = 1; - private static final int WAIT_TIME = 1000; + private static final int WAIT_TIME = 1200; private int mCallType = TYPE_VOICE; @@ -101,7 +108,7 @@ public class SelectToSpeakService extends AccessibilityService { } else { mTagName = groupTag; } - mCurrentStep = Step.CLICK_CONTACT; + mCurrentStep = Step.CLICK_HOME; launchWeChat(); } return super.onStartCommand(intent, flags, startId); @@ -147,9 +154,9 @@ public class SelectToSpeakService extends AccessibilityService { if (!TextUtils.isEmpty(currentClassName)) { switch (currentClassName) { case "com.tencent.mm.ui.LauncherUI": - if (mCurrentStep != Step.FIND_CONTACT) { - mCurrentStep = Step.CLICK_CONTACT; - } +// if (mCurrentStep != Step.FIND_CONTACT) { +// mCurrentStep = Step.CLICK_CONTACT; +// } break; case "com.tencent.mm.plugin.account.ui.WelcomeActivity": case "com.tencent.mm.plugin.account.ui.LoginPasswordUI": @@ -201,13 +208,30 @@ public class SelectToSpeakService extends AccessibilityService { } break; case CLICK_HOME://主页能找到直接点击进去更多 - stepHome(Property.TEXT, mName); + if (stepHome(Property.TEXT, mName)) { + Log.e(TAG, "_onAccessibilityEvent: not found contact in home"); + } else { + clickViewById("com.tencent.mm:id/jha", Step.CLICK_SEARCH); +// step(Property.DESCRIPTION, SEARCH_TEXT, Step.CLICK_SEARCH); + } + break; + case CLICK_SEARCH: + putString(mName, Step.CLICK_SEARCH_CONTACT); + break; + case CLICK_SEARCH_CONTACT: + if (findSearchContact(Step.FIND_CONTACT)) { + findSearchContact(Property.TEXT, mName, Step.CLICK_QUICK_WECHAT_CALL); + } else { + Toaster.show("没有找到联系人"); + } break; case CLICK_QUICK_WECHAT_CALL://点击更多页面 - step(Property.DESCRIPTION, MORE_NAME, Step.CLICK_TARGET); + clickViewById("com.tencent.mm:id/bjz", Step.CLICK_TARGET); +// step(Property.DESCRIPTION, MORE_NAME, Step.CLICK_TARGET); break; case CLICK_TARGET://点击视频通话 stepCall(Property.TEXT, PARENT_VIDEO_TEXT); +// clickVideoCall(); break; case CLICK_CONTACT://进入通讯录界面 @@ -218,13 +242,13 @@ public class SelectToSpeakService extends AccessibilityService { } break; case FIND_CONTACT://模拟滑动找到联系人 - findContact(Property.TEXT, mName, Step.CLICK_NAME); + findSearchContact(Property.TEXT, mName, Step.CLICK_QUICK_WECHAT_CALL); break; case FIND_TAG: step(Property.TEXT, TAG_TEXT, Step.CLICK_TAG); break; case CLICK_TAG: - if (!step(Property.TEXT, mTagName, Step.CLICK_NAME)){ + if (!step(Property.TEXT, mTagName, Step.CLICK_NAME)) { Toaster.show("没有找到标签"); mCurrentStep = Step.WAITING; } @@ -347,6 +371,60 @@ public class SelectToSpeakService extends AccessibilityService { } } + private boolean findSearchContact(Step nextStep) { + List nodeInfos = findNodesByViewId("com.tencent.mm:id/gzf"); + Log.e(TAG, "findSearchContact: " + nodeInfos); + Optional optional = nodeInfos.stream().findAny(); + return optional.isPresent(); + } + + private void findSearchContact(Property type, String text, Step nextStep) { + List nodeInfos = findNodesByViewId("com.tencent.mm:id/odf"); + Log.e(TAG, "findSearchContact: " + nodeInfos); + Optional optional = nodeInfos.stream().findAny(); + if (optional.isPresent()) { + AccessibilityNodeInfo nodeInfo = optional.get(); + clickNode(nodeInfo); + mCurrentStep = nextStep; + } else { + Toaster.show("没有找到联系人"); + mCurrentStep = Step.WAITING; + } + } + + private void putString(String text, Step nextStep) { + List nodeInfos = findNodesByViewId("com.tencent.mm:id/d98"); + Optional optional = nodeInfos.stream().findAny(); + if (optional.isPresent()) { + AccessibilityNodeInfo nodeInfo = optional.get(); + Bundle args = new Bundle(); + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); + nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); + nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); // 确保焦点在输入框 + + if (Build.VERSION.SDK_INT >= ACTION_IME_ENTER_VERSION) { + //see https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo.AccessibilityAction#ACTION_IME_ENTER + nodeInfo.performAction(ACTION_IME_ENTER_ID); + } + mCurrentStep = nextStep; + } else { + Toaster.show("没有找到搜索框"); + mCurrentStep = Step.WAITING; + } + } + + private void clickViewById(String id, Step nextStep) { + List nodeInfos = findNodesByViewId(id); + Optional optional = nodeInfos.stream().findAny(); + if (optional.isPresent()) { + AccessibilityNodeInfo nodeInfo = optional.get(); + clickNode(nodeInfo); + mCurrentStep = nextStep; + } else { + Toaster.show("没有找到搜索按钮"); + } + } + private List findNodesByViewId(String id) { List accessibilityNodeInfos = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(id); return accessibilityNodeInfos; @@ -407,11 +485,11 @@ public class SelectToSpeakService extends AccessibilityService { if (node != null) { clickNode(node); Log.e(TAG, "stepHome: mCurrentStep: " + mCurrentStep + " done"); - mCurrentStep = mCurrentStep.next(); + mCurrentStep = Step.CLICK_QUICK_WECHAT_CALL; Log.e(TAG, "stepHome: next: " + mCurrentStep); return true; } else { - mCurrentStep = Step.CLICK_CONTACT; + mCurrentStep = Step.CLICK_SEARCH; return false; } } @@ -500,6 +578,14 @@ public class SelectToSpeakService extends AccessibilityService { Log.e(TAG, "clickNode: e = " + e.getMessage()); } if (node.isClickable()) { + //防检测机制: + //添加随机延迟(避免高频操作) +// handler.postDelayed(new Runnable() { +// @Override +// public void run() { +// +// } +// }, 1000 + new Random().nextInt(100)); boolean performAction = node.performAction(AccessibilityNodeInfo.ACTION_CLICK); Log.e(TAG, "clickNode: performAction = " + performAction); if (!performAction) { @@ -528,12 +614,13 @@ public class SelectToSpeakService extends AccessibilityService { // } } + @Deprecated private boolean stepCall(Property type, String text) { AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text); if (node != null) { Point point = getPointtByNode(node); Log.e(TAG, "stepCall: " + point); - clickByPoint(point.x, point.y + 30); + clickByPoint(point.x, point.y); // clickNode(node); Log.e(TAG, "stepCall: mCurrentStep " + mCurrentStep + " done"); mCurrentStep = Step.CLICK_CALL; @@ -545,6 +632,18 @@ public class SelectToSpeakService extends AccessibilityService { } } + private void clickVideoCall() { + List nodeInfos = findNodesByViewId("com.tencent.mm:id/a12"); + Optional accessibilityNodeInfo = nodeInfos.stream().findAny(); + if (accessibilityNodeInfo.isPresent()) { + AccessibilityNodeInfo nodeInfo = accessibilityNodeInfo.get(); + clickNode(nodeInfo); + mCurrentStep = Step.CLICK_CALL; + } else { + Toaster.show("没有找到通话按钮"); + } + } + private boolean stepAnswer(Property type, String text) { AccessibilityNodeInfo node = findNode(getWindows(), type, text); if (node != null) { @@ -628,7 +727,9 @@ public class SelectToSpeakService extends AccessibilityService { Path path = new Path(); path.moveTo(point.x, point.y); GestureDescription.Builder builder = new GestureDescription.Builder(); - builder.addStroke(new GestureDescription.StrokeDescription(path, 0, 200)); + //防检测机制: + //添加随机延迟(避免高频操作) + builder.addStroke(new GestureDescription.StrokeDescription(path, 0, 200 + new Random().nextInt(100))); GestureDescription gesture = builder.build(); boolean dispatched = dispatchGesture(gesture, new GestureResultCallback() { @Override @@ -694,16 +795,28 @@ public class SelectToSpeakService extends AccessibilityService { private enum Step { WAITING, + //微信免提 WECHAT_HANDS_FREE, + //电话免提 DIALER_HANDS_FREE, + //微信主页找用户名 CLICK_HOME, + //进入搜索界面 + CLICK_SEARCH, + //是否弹出了联系人列表 + CLICK_SEARCH_CONTACT, + //聊天界面+号 CLICK_QUICK_WECHAT_CALL, + //更多里面视频通话 CLICK_TARGET, - + //主页点击导航栏通讯录 CLICK_CONTACT, + FIND_CONTACT, - CLICK_TAG, + //通讯录页面点击标签 FIND_TAG, + //点击对应的标签名 + CLICK_TAG, CLICK_NAME, CLICK_INFO,