diff --git a/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt b/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt index 4b2a246..68ca9e3 100644 --- a/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt +++ b/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt @@ -65,7 +65,8 @@ class ListenActivity : AppCompatActivity() { SPUtils.getInstance().put("autoReply", Constant.autoReply) }) tv_host.text = WebConfig.HOST - tv_version.text = AppUtils.getAppVersionName() + val version = "${AppUtils.getAppVersionName()} Android ${DeviceUtils.getSDKVersionName()} ${DeviceUtils.getManufacturer()} ${DeviceUtils.getModel()}" + tv_version.text = version val workVersionName = AppUtils.getAppInfo(Constant.PACKAGE_NAMES)?.versionName when (workVersionName) { null -> { @@ -83,7 +84,7 @@ class ListenActivity : AppCompatActivity() { tv_work_version.text = tip } } - SPUtils.getInstance().put("appVersion", AppUtils.getAppVersionName()) + SPUtils.getInstance().put("appVersion", version) SPUtils.getInstance().put("workVersion", workVersionName) } diff --git a/app/src/main/java/org/yameida/worktool/service/WeworkGetImpl.kt b/app/src/main/java/org/yameida/worktool/service/WeworkGetImpl.kt index 2205100..a032ebb 100644 --- a/app/src/main/java/org/yameida/worktool/service/WeworkGetImpl.kt +++ b/app/src/main/java/org/yameida/worktool/service/WeworkGetImpl.kt @@ -49,6 +49,7 @@ object WeworkGetImpl { fun getMyInfo(): Boolean { if (!goHomeTab("我")) { LogUtils.d("未找到我的信息") + log("未找到我的信息") goHomeTab("消息") val firstTv = AccessibilityUtil.findAllByClazz(getRoot(), Views.TextView) .firstOrNull { it.text == null } @@ -57,13 +58,14 @@ object WeworkGetImpl { val newFirstTv = AccessibilityUtil.findOneByClazz(getRoot(), Views.TextView) val nickname = newFirstTv?.text?.toString() if (nickname != null) { + log("找到我的昵称") var corp: String? = null val info = StringBuilder() if (AccessibilityUtil.performClick(newFirstTv)) { sleep(Constant.CHANGE_PAGE_INTERVAL) - val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView) - if (rv != null && rv.childCount > 0) { - val myInfoLayout = rv.getChild(0) + val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup, minChildCount = 2) + if (list != null) { + val myInfoLayout = list.getChild(0) val tvList = AccessibilityUtil.findAllByClazz(myInfoLayout, Views.TextView) .filter { it.text != null } if (tvList.isNotEmpty()) { @@ -88,6 +90,7 @@ object WeworkGetImpl { return true } else { LogUtils.d("未找到我的昵称") + log("未找到我的昵称") return false } } @@ -141,15 +144,16 @@ object WeworkGetImpl { fun getGroupInfoDetail(): WeworkMessageBean { val weworkMessageBean = WeworkMessageBean() weworkMessageBean.type = WeworkMessageBean.GET_GROUP_INFO - val tvManagerFlag = AccessibilityUtil.findOneByText(getRoot(), "微信用户创建", timeout = 2000) - //不是管理员的群可能没有微信用户创建 todo -// AccessibilityUtil.findOneByText(getRoot(), "全部群成员", timeout = 2000) - val button = AccessibilityUtil.findFrontNode(tvManagerFlag) - val tvGroupName = AccessibilityUtil.findOnceByClazz(button, Views.TextView) - if (tvGroupName != null && tvGroupName.text != null) { - LogUtils.d("群名: " + tvGroupName.text) - weworkMessageBean.groupName = tvGroupName.text.toString() - } else { + val tvManagerFlag = AccessibilityUtil.findOneByText(getRoot(), "全部群成员", "微信用户创建", timeout = 2000) + if (tvManagerFlag != null && tvManagerFlag.text.contains("微信用户创建")) { + val button = AccessibilityUtil.findFrontNode(tvManagerFlag) + val tvGroupName = AccessibilityUtil.findOnceByClazz(button, Views.TextView) + if (tvGroupName != null && tvGroupName.text != null) { + LogUtils.d("群名: " + tvGroupName.text) + weworkMessageBean.groupName = tvGroupName.text.toString() + } + } + if (weworkMessageBean.groupName.isNullOrEmpty()) { val groupNameTv = AccessibilityUtil.findOnceByText(getRoot(), "群聊名称") if (groupNameTv != null) { val tvList = AccessibilityUtil.findAllOnceByClazz( diff --git a/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt b/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt index 0148e44..2f5fbca 100644 --- a/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt +++ b/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt @@ -227,11 +227,11 @@ object WeworkLoopImpl { } } if (!isAtHome()) return true - if (logIndex++ % 15 == 0) { + if (logIndex++ % 30 == 0) { LogUtils.i("读取首页聊天列表") - log("读取首页聊天列表") + if (logIndex % 120 == 0) log("读取首页聊天列表") } - val listview = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView) + val listview = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup) if (listview != null) { if (listview.childCount >= 2) { if (checkUnreadChatRoom(listview)) { diff --git a/app/src/main/java/org/yameida/worktool/service/WeworkOperationImpl.kt b/app/src/main/java/org/yameida/worktool/service/WeworkOperationImpl.kt index e4ce250..259e267 100644 --- a/app/src/main/java/org/yameida/worktool/service/WeworkOperationImpl.kt +++ b/app/src/main/java/org/yameida/worktool/service/WeworkOperationImpl.kt @@ -273,11 +273,14 @@ object WeworkOperationImpl { extraText: String? = null ): Boolean { goHomeTab("工作台") - val node = AccessibilityUtil.scrollAndFindByText(getRoot(), "微盘") + val node = AccessibilityUtil.scrollAndFindByText(WeworkController.weworkService, getRoot(), "微盘") if (node != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + AccessibilityUtil.performClick(node) sleep(Constant.POP_WINDOW_INTERVAL) - AccessibilityUtil.clickByNode(WeworkController.weworkService, node) + if (AccessibilityUtil.findOnceByText(getRoot(), "微盘") != null) { + AccessibilityUtil.clickByNode(WeworkController.weworkService, node) + } } else { AccessibilityUtil.performClick(node) } @@ -320,11 +323,14 @@ object WeworkOperationImpl { extraText: String? = null ): Boolean { goHomeTab("工作台") - val node = AccessibilityUtil.scrollAndFindByText(getRoot(), "微盘") + val node = AccessibilityUtil.scrollAndFindByText(WeworkController.weworkService, getRoot(), "微盘") if (node != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + AccessibilityUtil.performClick(node) sleep(Constant.POP_WINDOW_INTERVAL) - AccessibilityUtil.clickByNode(WeworkController.weworkService, node) + if (AccessibilityUtil.findOnceByText(getRoot(), "微盘") != null) { + AccessibilityUtil.clickByNode(WeworkController.weworkService, node) + } } else { AccessibilityUtil.performClick(node) } @@ -363,7 +369,7 @@ object WeworkOperationImpl { extraText: String? = null ): Boolean { goHomeTab("工作台") - val node = AccessibilityUtil.scrollAndFindByText(getRoot(), "用过的小程序") + val node = AccessibilityUtil.scrollAndFindByText(WeworkController.weworkService, getRoot(), "用过的小程序") if (node != null) { AccessibilityUtil.performClick(node) sleep(Constant.CHANGE_PAGE_INTERVAL) @@ -591,7 +597,7 @@ object WeworkOperationImpl { for (select in selectList) { AccessibilityUtil.findTextInput(getRoot(), select.replace("…", "").replace("-.*$".toRegex(), "")) sleep(Constant.CHANGE_PAGE_INTERVAL * 2) - val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) + val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2) val imageView = AccessibilityUtil.findOneByClazz(selectListView, Views.ImageView) if (imageView != null) { AccessibilityUtil.performClick(imageView) @@ -634,21 +640,31 @@ object WeworkOperationImpl { */ private fun createGroup(): Boolean { goHomeTab("工作台") - val node = AccessibilityUtil.scrollAndFindByText(getRoot(), "客户群", "居民群") - ?: return false - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - sleep(Constant.POP_WINDOW_INTERVAL) - if (AccessibilityUtil.clickByNode(WeworkController.weworkService, node)) { + val node = AccessibilityUtil.scrollAndFindByText(WeworkController.weworkService, getRoot(), "客户群", "居民群") + if (node != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + AccessibilityUtil.performClick(node) + sleep(Constant.POP_WINDOW_INTERVAL) + if (AccessibilityUtil.findOnceByText(getRoot(), "客户群", "居民群") != null) { + if (AccessibilityUtil.clickByNode(WeworkController.weworkService, node)) { + LogUtils.d("进入客户群应用") + val textView = + AccessibilityUtil.findOneByText(getRoot(), "创建一个客户群", "创建一个居民群") + return AccessibilityUtil.performClick(textView) + } + } else { + LogUtils.d("进入客户群应用") + val textView = AccessibilityUtil.findOneByText(getRoot(), "创建一个客户群", "创建一个居民群") + return AccessibilityUtil.performClick(textView) + } + } else if (AccessibilityUtil.performClick(node)) { LogUtils.d("进入客户群应用") val textView = AccessibilityUtil.findOneByText(getRoot(), "创建一个客户群", "创建一个居民群") return AccessibilityUtil.performClick(textView) } - } else if (AccessibilityUtil.performClick(node)) { - LogUtils.d("进入客户群应用") - val textView = AccessibilityUtil.findOneByText(getRoot(), "创建一个客户群", "创建一个居民群") - return AccessibilityUtil.performClick(textView) } - LogUtils.d("未找到客户群应用") + LogUtils.e("未找到客户群应用") + log("未找到客户群应用") return false } @@ -657,19 +673,32 @@ object WeworkOperationImpl { */ private fun groupRename(groupName: String): Boolean { if (WeworkRoomUtil.intoGroupManager()) { - val textView = AccessibilityUtil.findOneByText(getRoot(), "微信用户创建") - //todo 微信用户创建可能找不到 - val button = AccessibilityUtil.findFrontNode(textView) - if (button != null) { - AccessibilityUtil.performClick(button) - AccessibilityUtil.findTextInput(getRoot(), groupName) - val confirmButton = AccessibilityUtil.findOneByText(getRoot(), "确定") - AccessibilityUtil.performClick(confirmButton) - sleep(2000) - return true + val textView = AccessibilityUtil.findOneByText(getRoot(), "全部群成员", "微信用户创建") + ?: return false + if (textView.text.contains("微信用户创建")) { + val button = AccessibilityUtil.findFrontNode(textView) + if (button != null) { + AccessibilityUtil.performClick(button) + AccessibilityUtil.findTextInput(getRoot(), groupName) + val confirmButton = AccessibilityUtil.findOneByText(getRoot(), "确定") + AccessibilityUtil.performClick(confirmButton) + sleep(2000) + return true + } else { + LogUtils.e("未找到填写群名按钮") + return false + } } else { - LogUtils.e("未找到填写群名按钮") - return false + val result = AccessibilityUtil.findTextAndClick(getRoot(), "群聊名称") + if (result) { + AccessibilityUtil.findTextInput(getRoot(), groupName) + val confirmButton = AccessibilityUtil.findOneByText(getRoot(), "确定") + AccessibilityUtil.performClick(confirmButton) + sleep(2000) + return true + } else { + LogUtils.e("未找到群聊名称按钮") + } } } return false @@ -687,9 +716,14 @@ object WeworkOperationImpl { if (WeworkRoomUtil.intoGroupManager()) { val gridView = AccessibilityUtil.findOneByClazz(getRoot(), Views.GridView) if (gridView != null && gridView.childCount >= 2) { - if (gridView.childCount == 2) { + val tvEmptySize = AccessibilityUtil.findAllOnceByClazz(gridView, Views.TextView) + .filter { it.text == null }.size + LogUtils.v("tvEmptySize: $tvEmptySize") + if (tvEmptySize == 0) { + return true + } else if (tvEmptySize == 1) { AccessibilityUtil.performClick(gridView.getChild(gridView.childCount - 1)) - } else { + } else if (tvEmptySize == 2) { AccessibilityUtil.performClick(gridView.getChild(gridView.childCount - 2)) } } else { @@ -706,16 +740,18 @@ object WeworkOperationImpl { AccessibilityUtil.performClick(multiButton) AccessibilityUtil.findTextInput(getRoot(), select) sleep(Constant.POP_WINDOW_INTERVAL) - val selectListViewTemp = - AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) val selectListView = - AccessibilityUtil.findOnceByClazz(getRoot(), Views.RecyclerView) ?: selectListViewTemp - val imageView = - AccessibilityUtil.findOneByClazz(selectListView, Views.ImageView, root = false) - AccessibilityUtil.performClick(imageView) - val textView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.TextView) - if (textView != null && textView.text.isNullOrBlank()) { - AccessibilityUtil.performClick(textView) + AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2) + if (selectListView != null) { + val imageView = + AccessibilityUtil.findOneByClazz(selectListView, Views.ImageView, root = false) + AccessibilityUtil.performClick(imageView) + val textView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.TextView) + if (textView != null && textView.text.isNullOrBlank()) { + AccessibilityUtil.performClick(textView) + } + } else { + LogUtils.e("未查到列表结果") } } if (showMessageHistory) { @@ -749,9 +785,12 @@ object WeworkOperationImpl { if (WeworkRoomUtil.intoGroupManager()) { val gridView = AccessibilityUtil.findOneByClazz(getRoot(), Views.GridView) if (gridView != null && gridView.childCount >= 2) { - if (gridView.childCount == 2) { + val tvEmptySize = AccessibilityUtil.findAllOnceByClazz(gridView, Views.TextView) + .filter { it.text == null }.size + LogUtils.v("tvEmptySize: $tvEmptySize") + if (tvEmptySize <= 1) { return true - } else { + } else if (tvEmptySize == 2) { AccessibilityUtil.performClick(gridView.getChild(gridView.childCount - 1)) } } else { @@ -767,8 +806,9 @@ object WeworkOperationImpl { for (select in removeList) { AccessibilityUtil.performClick(multiButton) AccessibilityUtil.findTextInput(getRoot(), select) + sleep(Constant.POP_WINDOW_INTERVAL) val selectListView = - AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) + AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2) val imageView = AccessibilityUtil.findOneByClazz(selectListView, Views.ImageView, root = false) AccessibilityUtil.performClick(imageView) @@ -808,11 +848,16 @@ object WeworkOperationImpl { val textView = AccessibilityUtil.findOneByText(getRoot(), "群公告") if (textView != null) { AccessibilityUtil.performClick(textView) - val editButton = AccessibilityUtil.findOneByText(getRoot(), "编辑", timeout = 2000) + val editButton = AccessibilityUtil.findOneByText(getRoot(), "编辑", timeout = 2000, exact = true) if (editButton != null) { LogUtils.d("群公告编辑中: $groupAnnouncement") - AccessibilityUtil.performClick(editButton) - sleep(1000) + var retry = 0 + while (retry++ < 10) { + AccessibilityUtil.performClick(editButton) + sleep(Constant.POP_WINDOW_INTERVAL) + if (AccessibilityUtil.findOnceByText(getRoot(), "编辑", exact = true) == null) + break + } } if (AccessibilityUtil.findTextInput(getRoot(), groupAnnouncement)) { LogUtils.d("群公告发布中: $groupAnnouncement") @@ -849,16 +894,35 @@ object WeworkOperationImpl { val atFlag = AccessibilityUtil.findOneByText(getRoot(), "选择提醒的人", timeout = 2000) if (atFlag != null) { val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView) - AccessibilityUtil.findTextInput(getRoot(), at) - val atNode = AccessibilityUtil.findOneByText(rv, at, root = false, timeout = 2000) - if (atNode != null) { - AccessibilityUtil.performClick(atNode) + if (rv != null) { + AccessibilityUtil.findTextInput(getRoot(), at) + val atNode = + AccessibilityUtil.findOneByText(rv, at, root = false, timeout = 2000) + if (atNode != null) { + AccessibilityUtil.performClick(atNode) + } else { + LogUtils.e("未找到at人: $at") + atFailed = true + backPress() + } + sleep(Constant.POP_WINDOW_INTERVAL) } else { - LogUtils.e("未找到at人: $at") - atFailed = true - backPress() + val searchFlag = AccessibilityUtil.findOnceByText(getRoot(), "搜索", exact = true) + val list = AccessibilityUtil.findBackNode(searchFlag, minChildCount = 2) + if (list != null) { + AccessibilityUtil.findTextInput(getRoot(), at) + val atNode = + AccessibilityUtil.findOneByText(list, at, root = false, timeout = 2000) + if (atNode != null) { + AccessibilityUtil.performClick(atNode) + } else { + LogUtils.e("未找到at人: $at") + atFailed = true + backPress() + } + sleep(Constant.POP_WINDOW_INTERVAL) + } } - sleep(Constant.POP_WINDOW_INTERVAL) } } val content = if (atFailed) "@$at $prefix$text" else "$prefix$text" @@ -866,8 +930,8 @@ object WeworkOperationImpl { val sendButton = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button) .firstOrNull { it.text == "发送" } if (sendButton != null) { - LogUtils.d("发送消息: \n$text") - log("发送消息: \n$text") + LogUtils.d("发送消息: \n$content") + log("发送消息: \n$content") AccessibilityUtil.performClick(sendButton) } else { LogUtils.e("未找到发送按钮") diff --git a/app/src/main/java/org/yameida/worktool/utils/AccessibilityUtil.kt b/app/src/main/java/org/yameida/worktool/utils/AccessibilityUtil.kt index c2f83aa..b8457a2 100644 --- a/app/src/main/java/org/yameida/worktool/utils/AccessibilityUtil.kt +++ b/app/src/main/java/org/yameida/worktool/utils/AccessibilityUtil.kt @@ -20,6 +20,8 @@ import org.yameida.worktool.service.getRoot import java.lang.Exception import java.lang.Thread.sleep import androidx.annotation.RequiresApi +import com.blankj.utilcode.util.ScreenUtils +import org.yameida.worktool.service.WeworkController /** * 1.查询类 @@ -96,33 +98,53 @@ object AccessibilityUtil { //寻找第一个列表并点击指定条目(默认点击第一个条目) fun findListOneAndClick(nodeInfo: AccessibilityNodeInfo, index: Int = 0): Boolean { - val rv = findOnceByClazz(nodeInfo, "androidx.recyclerview.widget.RecyclerView") - val lv = findOnceByClazz(nodeInfo, "android.widget.ListView") - if (rv == null && lv == null) return false - if (rv != null && rv.childCount > index) { - performClick(rv.getChild(index)) - } else if (lv != null && lv.childCount > index) { - performClick(lv.getChild(index)) + val list = findOnceByClazz(nodeInfo, "androidx.recyclerview.widget.RecyclerView", "android.widget.ListView") + if (list != null && list.childCount > index) { + return performClick(list.getChild(index)) } - return true + return false } //滚动并按文本寻找第一个控件 fun scrollAndFindByText( + service: AccessibilityService, nodeInfo: AccessibilityNodeInfo, vararg textList: String, maxRetry: Int = 3 ): AccessibilityNodeInfo? { var index = 0 while (index++ < maxRetry) { + performScrollDown(nodeInfo, 0) + val node = findOnceByText(nodeInfo, *textList) + if (node != null) { + return node + } + } + index = 0 + while (index++ < maxRetry * 2) { performScrollUp(nodeInfo, 0) val node = findOnceByText(nodeInfo, *textList) if (node != null) { return node } } + + LogUtils.d("未找到可滚动列表 使用手势滚动") + val width = ScreenUtils.getScreenWidth() + val height = ScreenUtils.getScreenHeight() + index = 0 while (index++ < maxRetry * 2) { - performScrollDown(nodeInfo, 0) + scrollByXY(service, width / 2, height / 2, 0, -height / 2) + sleep(SCROLL_INTERVAL) + val node = findOnceByText(nodeInfo, *textList) + if (node != null) { + return node + } + } + index = 0 + while (index++ < maxRetry * 3) { + scrollByXY(service, width / 2, height / 2, 0, height / 2) + sleep(SCROLL_INTERVAL) val node = findOnceByText(nodeInfo, *textList) if (node != null) { return node @@ -141,11 +163,11 @@ object AccessibilityUtil { val gesture = builder.build() return service.dispatchGesture(gesture, object : GestureResultCallback() { override fun onCompleted(gestureDescription: GestureDescription) { - LogUtils.v("click okk onCompleted") + LogUtils.v("click ok onCompleted") } override fun onCancelled(gestureDescription: GestureDescription) { - LogUtils.v("click okk onCancelled") + LogUtils.v("click ok onCancelled") } }, null) } @@ -397,7 +419,7 @@ object AccessibilityUtil { if (node == null) return null val textNodeList = findAllOnceByText(node, *textList, exact = exact) LogUtils.v("text: ${textList.joinToString()} count: " + textNodeList.size) - if (exact) return textNodeList[0] + if (exact && textNodeList.size > 0) return textNodeList[0] else if (textNodeList.size > 0) { for (textNode in textNodeList) { for (text in textList) { @@ -486,13 +508,14 @@ object AccessibilityUtil { limitDepth: Int? = null, depth: Int = 0, timeout: Long = 5000, - root: Boolean = true + root: Boolean = true, + minChildCount: Int = 0 ): AccessibilityNodeInfo? { var node = node ?: return null val startTime = System.currentTimeMillis() var currentTime = startTime while (currentTime - startTime <= timeout) { - val result = findOnceByClazz(node, *clazzList, limitDepth = limitDepth, depth = depth) + val result = findOnceByClazz(node, *clazzList, limitDepth = limitDepth, depth = depth, minChildCount = minChildCount) LogUtils.v("clazz: ${clazzList.joinToString()} result == null: ${result == null}") if (result != null) return result sleep(SHORT_INTERVAL) @@ -503,7 +526,7 @@ object AccessibilityUtil { } currentTime = System.currentTimeMillis() } - LogUtils.e("findOneByClazz Exception()") + LogUtils.e("findOneByClazz Exception(): ${clazzList.joinToString()}") Exception().printStackTrace() return null } @@ -518,15 +541,16 @@ object AccessibilityUtil { node: AccessibilityNodeInfo?, vararg clazzList: String, limitDepth: Int? = null, - depth: Int = 0 + depth: Int = 0, + minChildCount: Int = 0 ): AccessibilityNodeInfo? { if (node == null) return null if (node.className in clazzList) { - if (limitDepth == null || limitDepth == depth) + if ((limitDepth == null || limitDepth == depth) && node.childCount >= minChildCount) return node } for (i in 0 until node.childCount) { - val result = findOnceByClazz(node.getChild(i), *clazzList, limitDepth = limitDepth, depth = depth + 1) + val result = findOnceByClazz(node.getChild(i), *clazzList, limitDepth = limitDepth, depth = depth + 1, minChildCount = minChildCount) if (result != null) return result } return null @@ -560,7 +584,7 @@ object AccessibilityUtil { } currentTime = System.currentTimeMillis() } - LogUtils.e("findAllByClazz Exception()") + LogUtils.e("findAllByClazz Exception(): ${clazzList.joinToString()}") Exception().printStackTrace() return arrayListOf() } @@ -705,12 +729,115 @@ object AccessibilityUtil { val gesture = builder.build() return service.dispatchGesture(gesture, object : GestureResultCallback() { override fun onCompleted(gestureDescription: GestureDescription) { - LogUtils.v("click okk onCompleted") + LogUtils.v("click ok onCompleted") } override fun onCancelled(gestureDescription: GestureDescription) { - LogUtils.v("click okk onCancelled") + LogUtils.v("click ok onCancelled") } }, null) } + + /** + * 向下滚动 + * Gesture手势实现滚动(Android7+) + * 解决 scrollable=false 无法滚动问题 + */ + @RequiresApi(api = Build.VERSION_CODES.N) + fun scrollDownByNode( + service: AccessibilityService, + nodeInfo: AccessibilityNodeInfo + ): Boolean { + val rect = Rect() + nodeInfo.getBoundsInScreen(rect) + val x: Int = (rect.left + rect.right) / 2 + val y: Int = (rect.top + rect.bottom) / 2 + val point = Point(x, y) + val builder = GestureDescription.Builder() + val path = Path() + path.moveTo(point.x.toFloat(), point.y.toFloat()) + builder.addStroke(StrokeDescription(path, 0L, 300L)) + val gesture = builder.build() + return service.dispatchGesture(gesture, object : GestureResultCallback() { + override fun onCompleted(gestureDescription: GestureDescription) { + LogUtils.v("click ok onCompleted") + } + + override fun onCancelled(gestureDescription: GestureDescription) { + LogUtils.v("click ok onCancelled") + } + }, null) + } + + /** + * Gesture手势实现滚动(Android7+) + * 解决滚动距离不可控制问题 + * @param distanceX 向右滚动为负值 向左滚动为正值 + * @param distanceY 向下滚动为负值 向上滚动为正值 + */ + fun scrollByNode( + service: AccessibilityService, + nodeInfo: AccessibilityNodeInfo, + distanceX: Int = 0, + distanceY: Int = 0 + ): Boolean { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val rect = Rect() + nodeInfo.getBoundsInScreen(rect) + val point = Point((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2) + val builder = GestureDescription.Builder() + val path = Path() + path.moveTo(point.x.toFloat(), point.y.toFloat()) + path.lineTo(point.x.toFloat() + distanceX, point.y.toFloat() + distanceY) + builder.addStroke(StrokeDescription(path, 0L, 300L)) + val gesture = builder.build() + return service.dispatchGesture(gesture, object : GestureResultCallback() { + override fun onCompleted(gestureDescription: GestureDescription) { + LogUtils.v("scroll ok onCompleted") + } + + override fun onCancelled(gestureDescription: GestureDescription) { + LogUtils.v("scroll ok onCancelled") + } + }, null) + } else { + LogUtils.e("系统版本<7.0 不支持手势操作") + return false + } + } + + /** + * Gesture手势实现滚动(Android7+) + * 解决滚动距离不可控制问题 + * @param distanceX 向右滚动为负值 向左滚动为正值 + * @param distanceY 向下滚动为负值 向上滚动为正值 + */ + fun scrollByXY( + service: AccessibilityService, + x: Int = 0, + y: Int = 0, + distanceX: Int = 0, + distanceY: Int = 0 + ): Boolean { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val builder = GestureDescription.Builder() + val path = Path() + path.moveTo(x.toFloat(), y.toFloat()) + path.lineTo(x.toFloat() + distanceX, y.toFloat() + distanceY) + builder.addStroke(StrokeDescription(path, 0L, 300L)) + val gesture = builder.build() + return service.dispatchGesture(gesture, object : GestureResultCallback() { + override fun onCompleted(gestureDescription: GestureDescription) { + LogUtils.v("scroll ok onCompleted") + } + + override fun onCancelled(gestureDescription: GestureDescription) { + LogUtils.v("scroll ok onCancelled") + } + }, null) + } else { + LogUtils.e("系统版本<7.0 不支持手势操作") + return false + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/yameida/worktool/utils/WeworkRoomUtil.kt b/app/src/main/java/org/yameida/worktool/utils/WeworkRoomUtil.kt index 556d4eb..75eb171 100644 --- a/app/src/main/java/org/yameida/worktool/utils/WeworkRoomUtil.kt +++ b/app/src/main/java/org/yameida/worktool/utils/WeworkRoomUtil.kt @@ -92,7 +92,7 @@ object WeworkRoomUtil { return true } goHome() - val list = findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView) + val list = findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup) if (list != null) { val frontNode = findFrontNode(list) val textViewList = findAllOnceByClazz(frontNode, Views.TextView) @@ -106,6 +106,7 @@ object WeworkRoomUtil { val imageView = AccessibilityUtil.findOnceByClazz(selectListView, Views.ImageView) if (imageView != null) { AccessibilityUtil.performClick(imageView) + LogUtils.d("进入房间: $title") sleep(Constant.CHANGE_PAGE_INTERVAL) return true } else { @@ -125,8 +126,7 @@ object WeworkRoomUtil { * @return true 成功进入群管理页 */ fun intoGroupManager(): Boolean { - if (AccessibilityUtil.findOnceByText(getRoot(), "全部群成员") != null - || AccessibilityUtil.findOnceByText(getRoot(), "微信用户创建") != null) { + if (AccessibilityUtil.findOnceByText(getRoot(), "全部群成员", "微信用户创建") != null) { return true } val list = findOneByClazz(getRoot(), Views.ListView) diff --git a/app/src/main/java/org/yameida/worktool/utils/WeworkTextUtil.kt b/app/src/main/java/org/yameida/worktool/utils/WeworkTextUtil.kt index 8a8cc70..8b3b68d 100644 --- a/app/src/main/java/org/yameida/worktool/utils/WeworkTextUtil.kt +++ b/app/src/main/java/org/yameida/worktool/utils/WeworkTextUtil.kt @@ -2,8 +2,10 @@ package org.yameida.worktool.utils import android.view.accessibility.AccessibilityNodeInfo import com.blankj.utilcode.util.LogUtils +import org.yameida.worktool.Constant import org.yameida.worktool.model.WeworkMessageBean import org.yameida.worktool.service.getRoot +import org.yameida.worktool.service.sleep import org.yameida.worktool.utils.AccessibilityUtil.findAllByClazz import org.yameida.worktool.utils.AccessibilityUtil.findAllOnceByClazz import java.util.* @@ -319,14 +321,13 @@ object WeworkTextUtil { private fun longClickMessageItem(item: AccessibilityNodeInfo, roomType: Int, key: String): Boolean { val backNode = getMessageListNode(item, roomType) AccessibilityUtil.performLongClickWithSon(backNode) - val optionRvList = findAllByClazz(getRoot(), Views.RecyclerView) + sleep(Constant.POP_WINDOW_INTERVAL) + val optionRvList = findAllByClazz(getRoot(), Views.RecyclerView, Views.ViewGroup) for (optionRv in optionRvList) { - val optionTvList = findAllOnceByClazz(optionRv, Views.TextView) - for (optionTv in optionTvList) { - if (optionTv.text == key) { - AccessibilityUtil.performClick(optionTv) - return true - } + val keyTv = AccessibilityUtil.findOnceByText(optionRv, key, exact = true) + if (keyTv != null) { + AccessibilityUtil.performClick(keyTv) + return true } } return false