version:1.4.8
fix:修复一键拨号 update:优化联系人闹钟
This commit is contained in:
@@ -17,14 +17,20 @@ import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityWindowInfo;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.xxpatx.os.bean.Contact;
|
||||
import com.xxpatx.os.config.CommonConfig;
|
||||
import com.xxpatx.os.utils.ForegroundAppUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通过微信标签最高支持8.0.49,8.0.50 获取不到数据
|
||||
* 通过 {@link android.accessibilityservice.AccessibilityService#getWindows}和修改accessibility-service 配置能遍历屏幕元素
|
||||
*/
|
||||
public class WeAccessibilityService extends AccessibilityService {
|
||||
private static final String TAG = "WeAccessibilityService";
|
||||
@@ -132,10 +138,30 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
Log.e(TAG, "_onAccessibilityEvent: " + mCurrentStep);
|
||||
switch (mCurrentStep) {
|
||||
case WAITING:
|
||||
if (!mAutoAccept) return;
|
||||
break;
|
||||
default:
|
||||
if (!TextUtils.isEmpty(event.getClassName())) {
|
||||
if ("com.tencent.mm.ui.LauncherUI".contentEquals(event.getClassName())) {
|
||||
if (mCurrentStep != Step.FIND_CONTACT) {
|
||||
mCurrentStep = Step.CLICK_CONTACT;
|
||||
}
|
||||
} else if ("com.tencent.mm.plugin.label.ui.ContactLabelManagerUI".contentEquals(event.getClassName())) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (mCurrentStep) {
|
||||
case WAITING:
|
||||
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
|
||||
Log.e(TAG, "_onAccessibilityEvent: mAutoAccept = " + mAutoAccept);
|
||||
if (!mAutoAccept) {
|
||||
return;
|
||||
}
|
||||
if (stepAnswer(Property.DESCRIPTION, RECEIVE_DESCRIPTION)) {
|
||||
mCurrentStep = Step.WAITING;
|
||||
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
// clickAnswer();
|
||||
}
|
||||
break;
|
||||
case CLICK_HOME://主页能找到直接点击进去更多
|
||||
@@ -149,10 +175,15 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
break;
|
||||
|
||||
case CLICK_CONTACT://进入通讯录界面
|
||||
step(Property.TEXT, CONTACT_TEXT, Step.FIND_TAG);
|
||||
if (stepHome(Property.TEXT, CONTACT_TEXT, Step.FIND_TAG)) {
|
||||
Log.e(TAG, "_onAccessibilityEvent: enter contact");
|
||||
} else {
|
||||
touchContact();
|
||||
}
|
||||
break;
|
||||
case FIND_CONTACT://模拟滑动找到联系人
|
||||
findContact(Property.TEXT, mName, Step.CLICK_NAME);
|
||||
break;
|
||||
case FIND_TAG:
|
||||
step(Property.TEXT, TAG_TEXT, Step.CLICK_TAG);
|
||||
break;
|
||||
@@ -210,9 +241,32 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void clickAnswer() {
|
||||
String className = ForegroundAppUtil.getForegroundActivityName(WeAccessibilityService.this);
|
||||
Log.e(TAG, "clickAnswer: " + className);
|
||||
if (!TextUtils.isEmpty(className)) {
|
||||
if ("com.tencent.mm.plugin.voip.ui.VideoActivity".contentEquals(className)) {
|
||||
boolean successful = clickByPoint(595, 1376);
|
||||
Log.e(TAG, "clickAnswer: " + successful);
|
||||
if (successful) {
|
||||
Toast.makeText(this, "已自动接听视频/语音", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "clickAnswer: Not in the answering interface");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean step(Property type, String text, Step nextStep) {
|
||||
AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text);
|
||||
if (node != null) {
|
||||
Rect rect = new Rect();
|
||||
node.getBoundsInScreen(rect);
|
||||
Log.e(TAG, "step: rect = " + rect);
|
||||
if (rect.left < 0 || rect.top < 0 || rect.right < 0 || rect.bottom < 0) {
|
||||
return false;
|
||||
}
|
||||
clickNode(node);
|
||||
Log.e(TAG, "step: mCurrentStep: " + mCurrentStep + " done");
|
||||
mCurrentStep = nextStep;
|
||||
@@ -223,6 +277,61 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 2025/2/8 先把通讯录点击的换成node
|
||||
private boolean stepHome(Property type, String text, Step nextStep) {
|
||||
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
|
||||
if (node != null) {
|
||||
Rect rect = new Rect();
|
||||
node.getBoundsInScreen(rect);
|
||||
Log.e(TAG, "step: rect = " + rect);
|
||||
if (rect.left < 0 || rect.top < 0 || rect.right < 0 || rect.bottom < 0) {
|
||||
return false;
|
||||
}
|
||||
clickNode(node);
|
||||
Log.e(TAG, "step: mCurrentStep: " + mCurrentStep + " done");
|
||||
mCurrentStep = nextStep;
|
||||
Log.e(TAG, "step: next: " + mCurrentStep);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void touchContact() {
|
||||
boolean successful = clickByPoint(268, 1440);
|
||||
if (successful) {
|
||||
mCurrentStep = Step.FIND_TAG;
|
||||
} else {
|
||||
mCurrentStep = Step.WAITING;
|
||||
Toaster.show("点击失败,请重试");
|
||||
}
|
||||
}
|
||||
|
||||
private List<AccessibilityNodeInfo> findNodesByViewId(String id) {
|
||||
List<AccessibilityNodeInfo> accessibilityNodeInfos = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(id);
|
||||
return accessibilityNodeInfos;
|
||||
}
|
||||
|
||||
private AccessibilityNodeInfo findNodeByText(AccessibilityNodeInfo root, String text) {
|
||||
if (root == null) return null;
|
||||
Log.e(TAG, "findNodeByText: getText = " + root.getText());
|
||||
Log.e(TAG, "findNodeByText: getContentDescription = " + root.getContentDescription());
|
||||
boolean found = root.getText() != null && text.contentEquals(root.getText());
|
||||
if (found) {
|
||||
return root;
|
||||
} else {
|
||||
for (int i = 0; i < root.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo result = findNodeByText(root.getChild(i), text);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
root.recycle();
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean stepCallDialog(Property type, String text, Step nextStep) {
|
||||
AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text);
|
||||
if (node != null) {
|
||||
@@ -234,12 +343,23 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
Log.e(TAG, "stepCallDialog: next: " + mCurrentStep);
|
||||
return true;
|
||||
} else {
|
||||
scrolDown();
|
||||
scrollDown();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
scrolDown();
|
||||
return false;
|
||||
if (mFindCount == mMaxCount) {
|
||||
Log.e("stepCallDialog", "mCurrentStep: max");
|
||||
Toast.makeText(this, "没有找到联系人", Toast.LENGTH_LONG).show();
|
||||
mCurrentStep = Step.WAITING;
|
||||
mFindCount = 0;
|
||||
return false;
|
||||
} else {
|
||||
Log.e("stepCallDialog", "mCurrentStep: not found");
|
||||
mFindCount++;
|
||||
Log.e("stepCallDialog", "mCurrentStep: mFindCount = " + mFindCount);
|
||||
scrollDown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +401,7 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
Log.e("findContact", "mCurrentStep: not found");
|
||||
mFindCount++;
|
||||
Log.e("findContact", "mCurrentStep: mFindCount = " + mFindCount);
|
||||
scrolDown();
|
||||
scrollDown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -321,35 +441,52 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
return null;
|
||||
}
|
||||
|
||||
private AccessibilityNodeInfo findNode(List<AccessibilityWindowInfo> windows, Property type, String text) {
|
||||
for (AccessibilityWindowInfo accessibilityWindowInfo : windows) {
|
||||
AccessibilityNodeInfo nodeInfo = findNode(accessibilityWindowInfo.getRoot(), type, text);
|
||||
if (nodeInfo != null) {
|
||||
return nodeInfo;
|
||||
}
|
||||
}
|
||||
Log.e(TAG, "findNode windows: not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void clickNode(AccessibilityNodeInfo node) {
|
||||
try {
|
||||
Log.e(TAG, "clickNode: getText = " + node.getText());
|
||||
Log.e(TAG, "clickNode: isClickable = " + node.isClickable());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "clickNode: e = " + e.getMessage());
|
||||
}
|
||||
Log.e(TAG, "clickNode: isClickable = " + node.isClickable());
|
||||
if (node.isClickable()) {
|
||||
boolean performAction = node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
|
||||
Log.e(TAG, "clickNode: performAction = " + performAction);
|
||||
if (!performAction) {
|
||||
Rect rect = new Rect();
|
||||
node.getBoundsInScreen(rect);
|
||||
int x = rect.left;
|
||||
int y = rect.top;
|
||||
Log.e(TAG, "clickNode: x = " + x);
|
||||
Log.e(TAG, "clickNode: y = " + y);
|
||||
int width = rect.width();
|
||||
int height = rect.height();
|
||||
Log.e(TAG, "clickNode: width = " + width);
|
||||
Log.e(TAG, "clickNode: height = " + height);
|
||||
Log.e(TAG, "clickNode: clickByNode = " + clickByNode(x + width / 2, y + height / 2));
|
||||
Log.e(TAG, "clickNode: rect = " + rect);
|
||||
// 点击节点的中心位置
|
||||
int centerX = (rect.left + rect.right) / 2;
|
||||
int centerY = (rect.top + rect.bottom) / 2;
|
||||
Log.e(TAG, "clickNode: clickByNode = " + clickByPoint(centerX, centerY));
|
||||
}
|
||||
node.recycle();
|
||||
} else {
|
||||
AccessibilityNodeInfo parent = node.getParent();
|
||||
node.recycle();
|
||||
clickNode(parent);
|
||||
Rect rect = new Rect();
|
||||
node.getBoundsInScreen(rect);
|
||||
Log.e(TAG, "clickNode: rect = " + rect);
|
||||
// 点击节点的中心位置
|
||||
int centerX = (rect.left + rect.right) / 2;
|
||||
int centerY = (rect.top + rect.bottom) / 2;
|
||||
Log.e(TAG, "clickNode: clickByNode = " + clickByPoint(centerX, centerY));
|
||||
}
|
||||
// else {
|
||||
// AccessibilityNodeInfo parent = node.getParent();
|
||||
// node.recycle();
|
||||
// clickNode(parent);
|
||||
// }
|
||||
}
|
||||
|
||||
private boolean stepCall(Property type, String text) {
|
||||
@@ -357,7 +494,7 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
if (node != null) {
|
||||
Point point = getPointtByNode(node);
|
||||
Log.e(TAG, "stepCall: " + point);
|
||||
clickByNode(point.x, point.y + 30);
|
||||
clickByPoint(point.x, point.y + 30);
|
||||
// clickNode(node);
|
||||
Log.e(TAG, "stepCall: mCurrentStep " + mCurrentStep + " done");
|
||||
mCurrentStep = Step.CLICK_CALL;
|
||||
@@ -370,12 +507,12 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
}
|
||||
|
||||
private boolean stepAnswer(Property type, String text) {
|
||||
AccessibilityNodeInfo node = findNode(getRootInActiveWindow(), type, text);
|
||||
AccessibilityNodeInfo node = findNode(getWindows(), type, text);
|
||||
if (node != null) {
|
||||
Point point = getPointtByNode(node);
|
||||
Log.e(TAG, "stepAnswer: " + point);
|
||||
clickByNode(point.x, point.y - 50);
|
||||
clickByNode(point.x, point.y);
|
||||
clickByPoint(point.x, point.y - 50);
|
||||
clickByPoint(point.x, point.y);
|
||||
// clickNode(node);
|
||||
Log.e(TAG, "stepAnswer: mCurrentStep " + mCurrentStep + " done");
|
||||
mCurrentStep = Step.WAITING;
|
||||
@@ -399,14 +536,16 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
}
|
||||
|
||||
//实现对(x,y)坐标进行点击操作。
|
||||
private boolean clickByNode(int x, int y) {
|
||||
private boolean clickByPoint(int x, int y) {
|
||||
Log.e(TAG, "clickByNode: x = " + x);
|
||||
Log.e(TAG, "clickByNode: y = " + y);
|
||||
Point point = new Point(x, y);
|
||||
Path path = new Path();
|
||||
path.moveTo(point.x, point.y);
|
||||
GestureDescription.Builder builder = new GestureDescription.Builder();
|
||||
builder.addStroke(new GestureDescription.StrokeDescription(path, 0, 200));
|
||||
GestureDescription gesture = builder.build();
|
||||
boolean isDispatched = dispatchGesture(gesture, new GestureResultCallback() {
|
||||
boolean dispatched = dispatchGesture(gesture, new GestureResultCallback() {
|
||||
@Override
|
||||
public void onCompleted(GestureDescription gestureDescription) {
|
||||
super.onCompleted(gestureDescription);
|
||||
@@ -419,10 +558,10 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
Log.e("clickByNode", "onCompleted: ");
|
||||
}
|
||||
}, null);
|
||||
return isDispatched;
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
private boolean scrolDown() {
|
||||
private boolean scrollScreen(double startY, double endY) {
|
||||
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getRealMetrics(dm);
|
||||
@@ -433,34 +572,40 @@ public class WeAccessibilityService extends AccessibilityService {
|
||||
// 屏幕宽度算法:屏幕宽度(像素)/屏幕密度
|
||||
// int screenWidth = (int) (width / density); // 屏幕宽度(dp)
|
||||
// int screenHeight = (int) (height / density);// 屏幕高度(dp)
|
||||
Log.e(TAG, "scrolDown: screenWidth = " + width);
|
||||
Log.e(TAG, "scrolDown: screenHeight = " + height);
|
||||
Log.e(TAG, "scrollScreen: screenWidth = " + width);
|
||||
Log.e(TAG, "scrollScreen: screenHeight = " + height);
|
||||
int center_X = width / 2;
|
||||
int center_Y = height / 2;
|
||||
Log.e("scrolDown", "center position:" + "(" + center_X + "," + center_Y + ")");
|
||||
Log.e("scrollScreen", "center position:" + "(" + center_X + "," + center_Y + ")");
|
||||
Path path = new Path();
|
||||
path.moveTo(center_X, (int) (center_Y * 1.5)); //起点坐标。
|
||||
path.lineTo(center_X, (int) (center_Y * 0.5)); //终点坐标。
|
||||
path.moveTo(center_X, (int) (center_Y * startY)); //起点坐标。
|
||||
path.lineTo(center_X, (int) (center_Y * endY)); //终点坐标。
|
||||
GestureDescription.Builder builder = new GestureDescription.Builder();
|
||||
GestureDescription gestureDescription = builder.addStroke(new GestureDescription.StrokeDescription(path, 0, 200)).build();
|
||||
boolean isDispatched = dispatchGesture(gestureDescription, new GestureResultCallback() {
|
||||
boolean dispatched = dispatchGesture(gestureDescription, new GestureResultCallback() {
|
||||
@Override
|
||||
public void onCompleted(GestureDescription gestureDescription) {
|
||||
super.onCompleted(gestureDescription);
|
||||
Log.d("scrolDown", "dispatchGesture ScrollUp onCompleted.");
|
||||
Log.d("scrollScreen", "dispatchGesture ScrollUp onCompleted.");
|
||||
path.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelled(GestureDescription gestureDescription) {
|
||||
super.onCancelled(gestureDescription);
|
||||
Log.d("scrolDown", "dispatchGesture ScrollUp cancel.");
|
||||
Log.d("scrollScreen", "dispatchGesture ScrollUp cancel.");
|
||||
}
|
||||
}, null);
|
||||
|
||||
return isDispatched;
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
private boolean scrollDown() {
|
||||
return scrollScreen(1.5, 0.5);
|
||||
}
|
||||
|
||||
private boolean scrollUp() {
|
||||
return scrollScreen(0.5, 1.5);
|
||||
}
|
||||
|
||||
private enum Step {
|
||||
WAITING,
|
||||
|
||||
Reference in New Issue
Block a user