update 1.主动加好友可修改附言;2.移除[自动回复]前缀;3.群内回复可@真提醒;4.学校类型企业兼容;5.搜索更加精准;6.其他已知问题修复
This commit is contained in:
@@ -1,21 +1,34 @@
|
||||
package org.yameida.worktool
|
||||
|
||||
import com.blankj.utilcode.util.SPUtils
|
||||
import org.yameida.worktool.config.WebConfig
|
||||
|
||||
object Constant {
|
||||
|
||||
val AVAILABLE_VERSION = arrayListOf("4.0.2", "4.0.6", "4.0.8", "4.0.10", "4.0.12")
|
||||
val AVAILABLE_VERSION = arrayListOf("4.0.2", "4.0.6", "4.0.8", "4.0.10", "4.0.12", "4.0.16")
|
||||
const val PACKAGE_NAMES = "com.tencent.wework"
|
||||
val BASE_URL = WebConfig.HOST.replace("wss", "https").replace("ws", "http")
|
||||
val URL_CHECK_UPDATE = "$BASE_URL/appUpdate/checkUpdate"
|
||||
const val LISTEN_CHANNEL_ID = "LISTEN_CHANNEL_ID"
|
||||
const val WEWORK_NOTIFY = "wework_notify"
|
||||
const val CHANGE_PAGE_INTERVAL = 1000L
|
||||
const val POP_WINDOW_INTERVAL = 500L
|
||||
private const val DEFAULT_HOST = "wss://worktool.asrtts.cn"
|
||||
|
||||
var myName = ""
|
||||
var regTrimTitle = "(…$)|(-.*$)|(\\(.*?\\)$)".toRegex()
|
||||
var key = "9876543210abcdef".toByteArray()
|
||||
var iv = "0123456789abcdef".toByteArray()
|
||||
val transformation = "AES/CBC/PKCS7Padding"
|
||||
var encryptType = SPUtils.getInstance().getInt("encryptType", 1)
|
||||
var autoReply = SPUtils.getInstance().getInt("autoReply", 1)
|
||||
var host: String
|
||||
get() = SPUtils.getInstance().getString("host", DEFAULT_HOST)
|
||||
set(value) {
|
||||
SPUtils.getInstance().put("host", value)
|
||||
}
|
||||
|
||||
fun getWsUrl() = "$host/webserver/wework/" + SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID)
|
||||
|
||||
fun getCheckUpdateUrl() = "${getBaseUrl()}/appUpdate/checkUpdate"
|
||||
|
||||
private fun getBaseUrl() = host.replace("wss", "https").replace("ws", "http")
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@ import com.umeng.analytics.MobclickAgent
|
||||
import kotlinx.android.synthetic.main.activity_listen.*
|
||||
import org.yameida.worktool.*
|
||||
import org.yameida.worktool.service.WeworkService
|
||||
import org.yameida.worktool.config.WebConfig
|
||||
import org.yameida.worktool.utils.UpdateUtil
|
||||
import android.app.Dialog
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
|
||||
|
||||
class ListenActivity : AppCompatActivity() {
|
||||
|
||||
@@ -42,12 +45,12 @@ class ListenActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
et_channel.setText(SPUtils.getInstance().getString(WebConfig.LISTEN_CHANNEL_ID))
|
||||
et_channel.setText(SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID))
|
||||
bt_save.setOnClickListener {
|
||||
val channel = et_channel.text.toString().trim()
|
||||
SPUtils.getInstance().put(WebConfig.LISTEN_CHANNEL_ID, channel)
|
||||
SPUtils.getInstance().put(Constant.LISTEN_CHANNEL_ID, channel)
|
||||
ToastUtils.showLong("保存成功")
|
||||
sendBroadcast(Intent(WebConfig.WEWORK_NOTIFY).apply {
|
||||
sendBroadcast(Intent(Constant.WEWORK_NOTIFY).apply {
|
||||
putExtra("type", "modify_channel")
|
||||
})
|
||||
MobclickAgent.onProfileSignIn(channel)
|
||||
@@ -64,7 +67,11 @@ class ListenActivity : AppCompatActivity() {
|
||||
Constant.autoReply = if (isChecked) 1 else 0
|
||||
SPUtils.getInstance().put("autoReply", Constant.autoReply)
|
||||
})
|
||||
tv_host.text = WebConfig.HOST
|
||||
tv_host.text = Constant.host
|
||||
tv_host.setOnLongClickListener {
|
||||
showInputDialog()
|
||||
true
|
||||
}
|
||||
val version = "${AppUtils.getAppVersionName()} Android ${DeviceUtils.getSDKVersionName()} ${DeviceUtils.getManufacturer()} ${DeviceUtils.getModel()}"
|
||||
tv_version.text = version
|
||||
val workVersionName = AppUtils.getAppInfo(Constant.PACKAGE_NAMES)?.versionName
|
||||
@@ -92,7 +99,7 @@ class ListenActivity : AppCompatActivity() {
|
||||
sw_accessibility.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||
LogUtils.i("sw_accessibility onCheckedChanged: $isChecked")
|
||||
if (isChecked) {
|
||||
if (SPUtils.getInstance().getString(WebConfig.LISTEN_CHANNEL_ID).isNullOrBlank()) {
|
||||
if (SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID).isNullOrBlank()) {
|
||||
sw_accessibility.isChecked = false
|
||||
ToastUtils.showLong("请先填写并保存链接号~")
|
||||
} else if (!isAccessibilitySettingOn()) {
|
||||
@@ -193,4 +200,32 @@ class ListenActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showInputDialog() {
|
||||
ToastUtils.showLong("请输入专线网络")
|
||||
val commentDialog = Dialog(this)
|
||||
commentDialog.setContentView(R.layout.dialog_input)
|
||||
val et: EditText = commentDialog.findViewById(R.id.body) as EditText
|
||||
val okBtn: Button = commentDialog.findViewById(R.id.ok) as Button
|
||||
okBtn.setOnClickListener {
|
||||
val text = et.text.toString()
|
||||
if (text.isNotBlank()) {
|
||||
if (text.matches("ws{1,2}://[^/]+.*".toRegex())) {
|
||||
Constant.host = text
|
||||
tv_host.text = text
|
||||
ToastUtils.showLong("保存成功")
|
||||
commentDialog.dismiss()
|
||||
} else {
|
||||
ToastUtils.showLong("格式异常!")
|
||||
}
|
||||
} else {
|
||||
ToastUtils.showLong("请勿为空!")
|
||||
}
|
||||
}
|
||||
val cancelBtn: Button = commentDialog.findViewById(R.id.cancel) as Button
|
||||
cancelBtn.setOnClickListener {
|
||||
commentDialog.dismiss()
|
||||
}
|
||||
commentDialog.show()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package org.yameida.worktool.config;
|
||||
public class WebConfig {
|
||||
public static final String WEWORK_NOTIFY = "wework_notify";
|
||||
|
||||
public static final String HOST = "wss://worktool.asrtts.cn";
|
||||
public static final String WEWORK_URL = HOST + "/webserver/wework/";
|
||||
public static String LISTEN_CHANNEL_ID = "LISTEN_CHANNEL_ID";
|
||||
}
|
||||
@@ -139,8 +139,6 @@ public class WeworkMessageBean {
|
||||
public String receivedName;
|
||||
//内容移除了@me
|
||||
public String receivedContent;
|
||||
//回复内容前缀
|
||||
public String prefix;
|
||||
//想要at的昵称
|
||||
public String at;
|
||||
//原始内容text
|
||||
@@ -254,6 +252,8 @@ public class WeworkMessageBean {
|
||||
public List<String> tagList;
|
||||
//是否是新好友
|
||||
public Boolean newFriend;
|
||||
//留言
|
||||
public String leavingMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -266,7 +266,7 @@ public class WeworkMessageBean {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(titleList, messageList, log, roomType, receivedName, receivedContent, originalContent, nameList, extraText, textType, groupName, groupOwner, selectList, groupNumber, groupAnnouncement, newGroupName, newGroupAnnouncement, removeList, showMessageHistory, myInfo, objectName, type);
|
||||
return Objects.hash(titleList, messageList, log, roomType, receivedName, receivedContent, originalContent, nameList, extraText, textType, groupName, groupOwner, selectList, groupNumber, groupAnnouncement, newGroupName, newGroupAnnouncement, removeList, showMessageHistory, myInfo, objectName, type, friend);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -107,23 +107,23 @@ fun getRoot(ignoreCheck: Boolean): AccessibilityNodeInfo {
|
||||
*/
|
||||
fun backPress() {
|
||||
val textView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.TextView)
|
||||
if (textView != null && textView.text.isNullOrBlank() && AccessibilityUtil.performClick(textView)) {
|
||||
if (textView != null && textView.text.isNullOrBlank() && AccessibilityUtil.performClick(textView, retry = false)) {
|
||||
LogUtils.v("找到回退按钮")
|
||||
} else {
|
||||
val ivButton = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ImageView)
|
||||
if (ivButton != null && ivButton.isClickable && AccessibilityUtil.findFrontNode(ivButton) == null) {
|
||||
LogUtils.d("未找到回退按钮 点击第一个IV按钮")
|
||||
AccessibilityUtil.performClick(ivButton)
|
||||
AccessibilityUtil.performClick(ivButton, retry = false)
|
||||
} else {
|
||||
LogUtils.d("未找到回退按钮 点击第一个BT按钮")
|
||||
val button = AccessibilityUtil.findOnceByClazz(getRoot(), Views.Button)
|
||||
if (button != null && button.childCount > 0) {
|
||||
AccessibilityUtil.performClick(button.getChild(0))
|
||||
AccessibilityUtil.performClick(button.getChild(0), retry = false)
|
||||
} else if (button != null) {
|
||||
AccessibilityUtil.performClick(button)
|
||||
AccessibilityUtil.performClick(button, retry = false)
|
||||
} else {
|
||||
LogUtils.d("未找到BT按钮")
|
||||
val confirm = AccessibilityUtil.findOnceByText(getRoot(), "确定", "我知道了", "暂不进入", "不用了", "取消")
|
||||
val confirm = AccessibilityUtil.findOnceByText(getRoot(), "确定", "我知道了", "暂不进入", "不用了", "取消", "暂不", exact = true)
|
||||
if (confirm != null) {
|
||||
LogUtils.d("尝试点击确定/我知道了/暂不进入")
|
||||
AccessibilityUtil.performClick(confirm)
|
||||
|
||||
@@ -80,7 +80,6 @@ object MyLooper {
|
||||
WeworkController.enableLoopRunning = true
|
||||
} else {
|
||||
WeworkController.mainLoopRunning = false
|
||||
getInstance().removeMessages(message.type * message.hashCode())
|
||||
getInstance().sendMessage(Message.obtain().apply {
|
||||
what = message.type * message.hashCode()
|
||||
obj = message
|
||||
|
||||
@@ -59,7 +59,6 @@ object WeworkController {
|
||||
* @param message#originalContent 原始消息的内容
|
||||
* @param message#textType 原始消息的消息类型
|
||||
* @param message#receivedContent 回复内容
|
||||
* @param message#prefix 回复内容前缀
|
||||
* @see WeworkMessageBean.TEXT_TYPE
|
||||
*/
|
||||
@RequestMapping
|
||||
|
||||
@@ -53,7 +53,7 @@ object WeworkGetImpl {
|
||||
goHomeTab("消息")
|
||||
val firstTv = AccessibilityUtil.findAllByClazz(getRoot(), Views.TextView)
|
||||
.firstOrNull { it.text == null }
|
||||
AccessibilityUtil.performClick(firstTv)
|
||||
AccessibilityUtil.performClick(firstTv, retry = false)
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL)
|
||||
val newFirstTv = AccessibilityUtil.findOneByClazz(getRoot(), Views.TextView)
|
||||
val nickname = newFirstTv?.text?.toString()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.yameida.worktool.service
|
||||
|
||||
import android.os.Build
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
@@ -185,7 +184,7 @@ object WeworkLoopImpl {
|
||||
//回到上一页
|
||||
var retry = 5
|
||||
while (retry-- > 0 && !isAtHome()) {
|
||||
val textView = AccessibilityUtil.findOnceByText(getRoot(), "新的客户", "新的居民", exact = true)
|
||||
val textView = AccessibilityUtil.findOnceByText(getRoot(), "新的客户", "新的居民", "新的学员", exact = true)
|
||||
if (textView == null) {
|
||||
backPress()
|
||||
}
|
||||
@@ -202,30 +201,20 @@ object WeworkLoopImpl {
|
||||
if (Constant.autoReply == 0) return true
|
||||
if (!isAtHome()) return true
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "消息", exact = true)
|
||||
for (item in list) {
|
||||
if (item.parent.parent.parent.childCount == 5) {
|
||||
if (item.parent.childCount > 1) {
|
||||
LogUtils.d("消息有红点")
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, item)
|
||||
sleep(100)
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, item)
|
||||
}
|
||||
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "消息", exact = true)
|
||||
for (item in list) {
|
||||
if (item.parent.parent.parent.childCount == 5) {
|
||||
if (item.parent.childCount > 1) {
|
||||
LogUtils.d("消息有红点")
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, item)
|
||||
sleep(100)
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, item)
|
||||
}
|
||||
}
|
||||
if (logIndex % 120 == 0) {
|
||||
goHomeTab("通讯录")
|
||||
goHomeTab("消息")
|
||||
}
|
||||
} else {
|
||||
if (logIndex % 3 == 0) {
|
||||
AccessibilityUtil.performScrollUp(getRoot(), 0)
|
||||
AccessibilityUtil.performScrollUp(getRoot(), 0)
|
||||
AccessibilityUtil.performScrollUp(getRoot(), 0)
|
||||
} else if (logIndex % 120 < 3) {
|
||||
AccessibilityUtil.performScrollDown(getRoot(), 0)
|
||||
}
|
||||
}
|
||||
if (logIndex % 120 == 0) {
|
||||
goHomeTab("通讯录")
|
||||
goHomeTab("消息")
|
||||
}
|
||||
if (!isAtHome()) return true
|
||||
if (logIndex++ % 30 == 0) {
|
||||
@@ -277,12 +266,7 @@ object WeworkLoopImpl {
|
||||
if (AccessibilityUtil.performClick(spotNodeList.first())) {
|
||||
//进入聊天页 下一步 getChatMessageList
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
AccessibilityUtil
|
||||
.clickByNode(WeworkController.weworkService, spotNodeList.first().parent)
|
||||
} else {
|
||||
LogUtils.e("请将手机版本提升到 Android 7.0+ 或将企业微信版本回退到 4.0.8之前(4.0.6可用)")
|
||||
}
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, spotNodeList.first().parent)
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.yameida.worktool.service
|
||||
|
||||
import android.os.Build
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import org.yameida.worktool.Constant
|
||||
import org.yameida.worktool.model.WeworkMessageBean
|
||||
@@ -25,7 +24,11 @@ object WeworkOperationImpl {
|
||||
* @param at 要at的昵称
|
||||
* @see WeworkMessageBean.TEXT_TYPE
|
||||
*/
|
||||
fun sendMessage(titleList: List<String>, receivedContent: String, at: String? = null): Boolean {
|
||||
fun sendMessage(titleList: List<String>, receivedContent: String?, at: String? = null): Boolean {
|
||||
if (receivedContent.isNullOrEmpty()) {
|
||||
LogUtils.d("未发现发送内容")
|
||||
return false
|
||||
}
|
||||
for (title in titleList) {
|
||||
if (WeworkRoomUtil.intoRoom(title)) {
|
||||
sendChatMessage(receivedContent, at = at)
|
||||
@@ -45,7 +48,6 @@ object WeworkOperationImpl {
|
||||
* @param originalContent 原始消息的内容
|
||||
* @param textType 原始消息的消息类型
|
||||
* @param receivedContent 回复内容
|
||||
* @param prefix 回复内容前缀
|
||||
* @see WeworkMessageBean.TEXT_TYPE
|
||||
*/
|
||||
fun replyMessage(
|
||||
@@ -53,9 +55,12 @@ object WeworkOperationImpl {
|
||||
receivedName: String?,
|
||||
originalContent: String,
|
||||
textType: Int,
|
||||
receivedContent: String,
|
||||
prefix: String = "[自动回复]"
|
||||
receivedContent: String?
|
||||
): Boolean {
|
||||
if (receivedContent.isNullOrEmpty()) {
|
||||
LogUtils.d("未发现回复内容")
|
||||
return false
|
||||
}
|
||||
for (title in titleList) {
|
||||
if (WeworkRoomUtil.intoRoom(title)) {
|
||||
if (WeworkTextUtil.longClickMessageItem(
|
||||
@@ -68,17 +73,25 @@ object WeworkOperationImpl {
|
||||
)
|
||||
) {
|
||||
LogUtils.v("开始回复")
|
||||
sendChatMessage(receivedContent, prefix)
|
||||
sendChatMessage(receivedContent, reply = true)
|
||||
LogUtils.d("$title: 回复成功")
|
||||
WeworkLoopImpl.getChatMessageList()
|
||||
return true
|
||||
} else {
|
||||
LogUtils.d("$title: 回复失败 直接发送答案")
|
||||
error("$title: 回复失败 直接发送答案 $receivedContent")
|
||||
if (receivedName == null) {
|
||||
sendChatMessage(receivedContent, "$prefix【$originalContent】\n")
|
||||
if (originalContent.isNotEmpty()) {
|
||||
if (receivedName == null) {
|
||||
sendChatMessage("【$originalContent】\n$receivedContent")
|
||||
} else {
|
||||
sendChatMessage("【$originalContent】\n$receivedContent", receivedName)
|
||||
}
|
||||
} else {
|
||||
sendChatMessage(receivedContent, "$prefix【$originalContent】@$receivedName\n")
|
||||
if (receivedName == null) {
|
||||
sendChatMessage(receivedContent)
|
||||
} else {
|
||||
sendChatMessage(receivedContent, receivedName)
|
||||
}
|
||||
}
|
||||
WeworkLoopImpl.getChatMessageList()
|
||||
}
|
||||
@@ -167,7 +180,8 @@ object WeworkOperationImpl {
|
||||
|| !groupChangeAnnouncement(groupAnnouncement)
|
||||
) return false
|
||||
}
|
||||
getGroupQrcode(groupName)
|
||||
//TODO 暂移除获取群二维码
|
||||
// getGroupQrcode(groupName)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -222,15 +236,8 @@ object WeworkOperationImpl {
|
||||
goHomeTab("工作台")
|
||||
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(), "微盘", exact = true) != null) {
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, node)
|
||||
}
|
||||
} else {
|
||||
AccessibilityUtil.performClick(node)
|
||||
}
|
||||
AccessibilityUtil.performClick(node)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
val buttonList = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button)
|
||||
if (buttonList.size >= 4) {
|
||||
AccessibilityUtil.performClick(buttonList[2])
|
||||
@@ -272,15 +279,8 @@ object WeworkOperationImpl {
|
||||
goHomeTab("工作台")
|
||||
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(), "微盘", exact = true) != null) {
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, node)
|
||||
}
|
||||
} else {
|
||||
AccessibilityUtil.performClick(node)
|
||||
}
|
||||
AccessibilityUtil.performClick(node)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
val buttonList = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button)
|
||||
if (buttonList.size >= 4) {
|
||||
AccessibilityUtil.performClick(buttonList[2])
|
||||
@@ -401,17 +401,10 @@ object WeworkOperationImpl {
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
val list = AccessibilityUtil.findAllByClazz(getRoot(), Views.ListView).lastOrNull()
|
||||
if (list != null) {
|
||||
val button = AccessibilityUtil.findOneByText(list, "添加客户", "添加居民", "加微信")
|
||||
val button = AccessibilityUtil.findOneByText(list, "添加客户", "添加居民", "加微信", "加学员", exact = true)
|
||||
if (button != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
AccessibilityUtil.performClick(button)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
if (AccessibilityUtil.findOnceByText(list, "添加客户", "添加居民", "加微信", exact = true) != null) {
|
||||
AccessibilityUtil.clickByNode(WeworkController.weworkService, button)
|
||||
}
|
||||
} else {
|
||||
AccessibilityUtil.performClick(button)
|
||||
}
|
||||
AccessibilityUtil.performClick(button)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
AccessibilityUtil.findTextAndClick(getRoot(), "搜索手机号添加")
|
||||
AccessibilityUtil.findTextInput(getRoot(), friend.phone.trim())
|
||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "网络查找手机")) {
|
||||
@@ -475,7 +468,10 @@ object WeworkOperationImpl {
|
||||
}
|
||||
}
|
||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "添加为联系人")) {
|
||||
LogUtils.d("添加好友成功: " + friend.phone)
|
||||
LogUtils.d("准备发送好友邀请: " + friend.phone)
|
||||
if (!friend.leavingMsg.isNullOrEmpty()) {
|
||||
AccessibilityUtil.findTextInput(getRoot(), friend.leavingMsg)
|
||||
}
|
||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "发送添加邀请", "发送申请")) {
|
||||
LogUtils.d("发送添加邀请成功: " + friend.phone)
|
||||
}
|
||||
@@ -553,17 +549,39 @@ object WeworkOperationImpl {
|
||||
AccessibilityUtil.performClick(multiButton)
|
||||
AccessibilityUtil.performClick(searchButton)
|
||||
for (select in selectList) {
|
||||
AccessibilityUtil.findTextInput(getRoot(), select.replace("…", "").replace("-.*$".toRegex(), ""))
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL * 2)
|
||||
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)
|
||||
}
|
||||
val needTrim = select.contains(Constant.regTrimTitle)
|
||||
val trimTitle = select.replace(Constant.regTrimTitle, "")
|
||||
AccessibilityUtil.findTextInput(getRoot(), trimTitle)
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL)
|
||||
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2)
|
||||
val regex = "^$trimTitle(-.*)?(…)?(\\(.*?\\))?" + if (needTrim) "" else "$"
|
||||
val matchSelect = AccessibilityUtil.findOneByTextRegex(
|
||||
selectListView,
|
||||
regex,
|
||||
timeout = 2000,
|
||||
root = false
|
||||
)
|
||||
if (selectListView != null && matchSelect != null) {
|
||||
for (i in 0 until selectListView.childCount) {
|
||||
val item = selectListView.getChild(i)
|
||||
val searchResult = AccessibilityUtil.findOnceByTextRegex(item, regex)
|
||||
if (searchResult != null) {
|
||||
item.refresh()
|
||||
val imageView =
|
||||
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
|
||||
AccessibilityUtil.performClick(imageView)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchSelect != null) {
|
||||
LogUtils.d("找到搜索结果: $select")
|
||||
} else {
|
||||
LogUtils.e("未搜索到结果")
|
||||
}
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
}
|
||||
val confirmButton =
|
||||
AccessibilityUtil.findOneByText(getRoot(), "确定(${selectList.size})")
|
||||
AccessibilityUtil.findOneByTextRegex(getRoot(), "^确定(\\(.*?\\))?\$")
|
||||
if (confirmButton != null) {
|
||||
AccessibilityUtil.performClick(confirmButton)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
@@ -571,12 +589,10 @@ object WeworkOperationImpl {
|
||||
LogUtils.d("extraText: $extraText")
|
||||
AccessibilityUtil.findTextInput(getRoot(), extraText)
|
||||
}
|
||||
val sendButtonList = AccessibilityUtil.findAllByText(getRoot(), "发送")
|
||||
for (sendButton in sendButtonList.filter { it.text != null }) {
|
||||
if (sendButton.text == "发送" || sendButton.text == "发送(${selectList.size})") {
|
||||
AccessibilityUtil.performClick(sendButton)
|
||||
return true
|
||||
}
|
||||
val sendButton = AccessibilityUtil.findOneByTextRegex(getRoot(), "^发送(\\(.*?\\))?\$")
|
||||
if (sendButton != null) {
|
||||
AccessibilityUtil.performClick(sendButton)
|
||||
return true
|
||||
}
|
||||
LogUtils.e("未发现发送按钮: ")
|
||||
return false
|
||||
@@ -598,28 +614,14 @@ object WeworkOperationImpl {
|
||||
*/
|
||||
private fun createGroup(): Boolean {
|
||||
goHomeTab("工作台")
|
||||
val node = AccessibilityUtil.scrollAndFindByText(WeworkController.weworkService, 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)
|
||||
if (AccessibilityUtil.findOnceByText(getRoot(), "客户群", "居民群", exact = true) != 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)
|
||||
}
|
||||
AccessibilityUtil.performClick(node)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
LogUtils.d("进入客户群应用")
|
||||
val textView =
|
||||
AccessibilityUtil.findOneByText(getRoot(), "创建一个客户群", "创建一个居民群", "创建一个学员群")
|
||||
return AccessibilityUtil.performClick(textView)
|
||||
}
|
||||
LogUtils.e("未找到客户群应用")
|
||||
log("未找到客户群应用")
|
||||
@@ -696,28 +698,47 @@ object WeworkOperationImpl {
|
||||
if (textViewList.size >= 2) {
|
||||
val multiButton = textViewList.lastOrNull()
|
||||
for (select in selectList) {
|
||||
val needTrim = select.contains(Constant.regTrimTitle)
|
||||
val trimTitle = select.replace(Constant.regTrimTitle, "")
|
||||
AccessibilityUtil.performClick(multiButton)
|
||||
AccessibilityUtil.findTextInput(getRoot(), select)
|
||||
AccessibilityUtil.findTextInput(getRoot(), trimTitle)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
val selectListView =
|
||||
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)
|
||||
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2, firstChildClazz = Views.TextView)
|
||||
val regex = "^$trimTitle(-.*)?(…)?(\\(.*?\\))?" + if (needTrim) "" else "$"
|
||||
val matchSelect = AccessibilityUtil.findOneByTextRegex(
|
||||
selectListView,
|
||||
regex,
|
||||
timeout = 2000,
|
||||
root = false
|
||||
)
|
||||
if (selectListView != null && matchSelect != null) {
|
||||
for (i in 0 until selectListView.childCount) {
|
||||
val item = selectListView.getChild(i)
|
||||
val searchResult = AccessibilityUtil.findOnceByTextRegex(item, regex)
|
||||
if (searchResult != null) {
|
||||
item.refresh()
|
||||
val imageView =
|
||||
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
|
||||
AccessibilityUtil.performClick(imageView)
|
||||
}
|
||||
}
|
||||
}
|
||||
val textView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.TextView)
|
||||
if (textView != null && textView.text.isNullOrBlank()) {
|
||||
AccessibilityUtil.performClick(textView)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
}
|
||||
if (matchSelect != null) {
|
||||
LogUtils.d("找到搜索结果: $select")
|
||||
} else {
|
||||
LogUtils.e("未查到列表结果")
|
||||
LogUtils.e("未搜索到结果")
|
||||
}
|
||||
}
|
||||
if (showMessageHistory) {
|
||||
AccessibilityUtil.findTextAndClick(getRoot(), "聊天记录")
|
||||
}
|
||||
val confirmButton =
|
||||
AccessibilityUtil.findOneByText(getRoot(), "确定(${selectList.size})")
|
||||
AccessibilityUtil.findOneByTextRegex(getRoot(), "^确定(\\(.*?\\))?\$")
|
||||
if (confirmButton != null) {
|
||||
AccessibilityUtil.performClick(confirmButton)
|
||||
} else {
|
||||
@@ -764,21 +785,44 @@ object WeworkOperationImpl {
|
||||
if (textViewList.size >= 2) {
|
||||
val multiButton = textViewList.lastOrNull()
|
||||
for (select in removeList) {
|
||||
val needTrim = select.contains(Constant.regTrimTitle)
|
||||
val trimTitle = select.replace(Constant.regTrimTitle, "")
|
||||
AccessibilityUtil.performClick(multiButton)
|
||||
AccessibilityUtil.findTextInput(getRoot(), select)
|
||||
AccessibilityUtil.findTextInput(getRoot(), trimTitle)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
val selectListView =
|
||||
AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2)
|
||||
val imageView =
|
||||
AccessibilityUtil.findOneByClazz(selectListView, Views.ImageView, root = false)
|
||||
AccessibilityUtil.performClick(imageView)
|
||||
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2, firstChildClazz = Views.RelativeLayout)
|
||||
val regex = "^$trimTitle(-.*)?(…)?(\\(.*?\\))?" + if (needTrim) "" else "$"
|
||||
val matchSelect = AccessibilityUtil.findOneByTextRegex(
|
||||
selectListView,
|
||||
regex,
|
||||
timeout = 2000,
|
||||
root = false
|
||||
)
|
||||
if (selectListView != null && matchSelect != null) {
|
||||
for (i in 0 until selectListView.childCount) {
|
||||
val item = selectListView.getChild(i)
|
||||
val searchResult = AccessibilityUtil.findOnceByTextRegex(item, regex)
|
||||
if (searchResult != null) {
|
||||
item.refresh()
|
||||
val imageView =
|
||||
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
|
||||
AccessibilityUtil.performClick(imageView)
|
||||
}
|
||||
}
|
||||
}
|
||||
val textView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.TextView)
|
||||
if (textView != null && textView.text.isNullOrBlank()) {
|
||||
AccessibilityUtil.performClick(textView)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
}
|
||||
if (matchSelect != null) {
|
||||
LogUtils.d("找到搜索结果: $select")
|
||||
} else {
|
||||
LogUtils.e("未搜索到结果")
|
||||
}
|
||||
}
|
||||
val confirmButton =
|
||||
AccessibilityUtil.findOneByText(getRoot(), "移出(${removeList.size})")
|
||||
AccessibilityUtil.findOneByText(getRoot(), "移出(")
|
||||
if (confirmButton != null) {
|
||||
AccessibilityUtil.performClick(confirmButton)
|
||||
} else {
|
||||
@@ -847,7 +891,7 @@ object WeworkOperationImpl {
|
||||
/**
|
||||
* 发送消息+@at
|
||||
*/
|
||||
private fun sendChatMessage(text: String, prefix: String = "", at: String? = null) {
|
||||
private fun sendChatMessage(text: String, at: String? = null, reply: Boolean? = false) {
|
||||
val voiceFlag = AccessibilityUtil.findOnceByText(getRoot(), "按住 说话", "按住说话", exact = true)
|
||||
if (voiceFlag != null) {
|
||||
AccessibilityUtil.performClickWithSon(AccessibilityUtil.findFrontNode(voiceFlag))
|
||||
@@ -889,8 +933,8 @@ object WeworkOperationImpl {
|
||||
}
|
||||
}
|
||||
}
|
||||
val content = if (atFailed) "@$at $prefix$text" else "$prefix$text"
|
||||
val append = !at.isNullOrEmpty() && !atFailed
|
||||
val content = if (atFailed) "@$at $text" else "$text"
|
||||
val append = (reply == true) || (!at.isNullOrEmpty() && !atFailed)
|
||||
if (AccessibilityUtil.findTextInput(getRoot(), content, append = append)) {
|
||||
val sendButton = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button)
|
||||
.firstOrNull { it.text == "发送" }
|
||||
|
||||
@@ -5,17 +5,14 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.blankj.utilcode.util.*
|
||||
import okhttp3.Response
|
||||
import okhttp3.WebSocket
|
||||
import okhttp3.WebSocketListener
|
||||
import org.yameida.worktool.Constant
|
||||
import org.yameida.worktool.Demo
|
||||
import org.yameida.worktool.config.WebConfig
|
||||
import org.yameida.worktool.utils.*
|
||||
import java.lang.Exception
|
||||
|
||||
@@ -31,9 +28,7 @@ class WeworkService : AccessibilityService() {
|
||||
override fun onServiceConnected() {
|
||||
LogUtils.i("初始化成功")
|
||||
//隐藏软键盘模式
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
softKeyboardController.showMode = SHOW_MODE_HIDDEN
|
||||
}
|
||||
softKeyboardController.showMode = SHOW_MODE_HIDDEN
|
||||
WeworkController.weworkService = this
|
||||
//初始化长连接
|
||||
initWebSocket()
|
||||
@@ -51,12 +46,11 @@ class WeworkService : AccessibilityService() {
|
||||
initWebSocket()
|
||||
}
|
||||
}
|
||||
}, IntentFilter(WebConfig.WEWORK_NOTIFY))
|
||||
}, IntentFilter(Constant.WEWORK_NOTIFY))
|
||||
}
|
||||
|
||||
private fun initWebSocket() {
|
||||
val url =
|
||||
WebConfig.WEWORK_URL + SPUtils.getInstance().getString(WebConfig.LISTEN_CHANNEL_ID)
|
||||
val url = Constant.getWsUrl()
|
||||
val listener = EchoWebSocketListener()
|
||||
LogUtils.d("initWebSocket: $url")
|
||||
webSocketManager = WebSocketManager(url, listener)
|
||||
@@ -67,7 +61,6 @@ class WeworkService : AccessibilityService() {
|
||||
* TYPE_VIEW_SCROLLED 列表滚动
|
||||
* @param event
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
override fun onAccessibilityEvent(event: AccessibilityEvent) {
|
||||
}
|
||||
|
||||
@@ -79,9 +72,7 @@ class WeworkService : AccessibilityService() {
|
||||
super.onDestroy()
|
||||
LogUtils.i("onDestroy")
|
||||
//隐藏软键盘模式
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
softKeyboardController.showMode = SHOW_MODE_AUTO
|
||||
}
|
||||
softKeyboardController.showMode = SHOW_MODE_AUTO
|
||||
webSocketManager.close(1000, "service Destroy")
|
||||
}
|
||||
|
||||
@@ -91,7 +82,7 @@ class WeworkService : AccessibilityService() {
|
||||
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||
socket = webSocket
|
||||
Log.e(TAG, "链接建立")
|
||||
val robotId = SPUtils.getInstance().getString(WebConfig.LISTEN_CHANNEL_ID, "")
|
||||
val robotId = SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID, "")
|
||||
val appVersion = SPUtils.getInstance().getString("appVersion", "")
|
||||
val workVersion= SPUtils.getInstance().getString("workVersion", "")
|
||||
log("链接建立: $robotId appVersion: $appVersion workVersion: $workVersion")
|
||||
|
||||
@@ -4,13 +4,11 @@ import android.accessibilityservice.AccessibilityService
|
||||
import android.accessibilityservice.AccessibilityService.GestureResultCallback
|
||||
import android.accessibilityservice.GestureDescription
|
||||
import android.accessibilityservice.GestureDescription.StrokeDescription
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.graphics.Path
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
@@ -19,7 +17,6 @@ import com.blankj.utilcode.util.LogUtils
|
||||
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
|
||||
|
||||
@@ -56,8 +53,8 @@ import org.yameida.worktool.service.WeworkController
|
||||
*/
|
||||
object AccessibilityUtil {
|
||||
private const val tag = "AccessibilityUtil"
|
||||
private const val SHORT_INTERVAL = 100L
|
||||
private const val SCROLL_INTERVAL = 300L
|
||||
private const val SHORT_INTERVAL = 150L
|
||||
private const val SCROLL_INTERVAL = 500L
|
||||
|
||||
//编辑EditView(非粘贴 推荐)
|
||||
fun editTextInput(nodeInfo: AccessibilityNodeInfo?, text: String): Boolean {
|
||||
@@ -154,7 +151,6 @@ object AccessibilityUtil {
|
||||
}
|
||||
|
||||
//输入x, y坐标模拟点击事件
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
fun performXYClick(service: AccessibilityService, x: Float, y: Float): Boolean {
|
||||
val path = Path()
|
||||
path.moveTo(x, y)
|
||||
@@ -175,16 +171,23 @@ object AccessibilityUtil {
|
||||
/**
|
||||
* 对某个节点或父节点进行点击
|
||||
*/
|
||||
fun performClick(nodeInfo: AccessibilityNodeInfo?): Boolean {
|
||||
var nodeInfo: AccessibilityNodeInfo? = nodeInfo ?: return false
|
||||
while (nodeInfo != null) {
|
||||
if (nodeInfo.isClickable) {
|
||||
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
||||
fun performClick(nodeInfo: AccessibilityNodeInfo?, retry: Boolean = true): Boolean {
|
||||
var tempNodeInfo: AccessibilityNodeInfo? = nodeInfo ?: return false
|
||||
while (tempNodeInfo != null) {
|
||||
if (tempNodeInfo.isClickable) {
|
||||
tempNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
||||
LogUtils.v("performClick success! ${nodeInfo.className}")
|
||||
return true
|
||||
}
|
||||
nodeInfo = nodeInfo.parent
|
||||
tempNodeInfo = tempNodeInfo.parent
|
||||
}
|
||||
LogUtils.e("performClick failed! retry: $retry ${nodeInfo.className}")
|
||||
if (retry) {
|
||||
sleep(SHORT_INTERVAL * 2)
|
||||
nodeInfo.refresh()
|
||||
val click = clickByNode(WeworkController.weworkService, nodeInfo)
|
||||
LogUtils.e("performClick failed! clickByNode: $click")
|
||||
}
|
||||
LogUtils.e("performClick failed! ${nodeInfo?.className}")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -380,6 +383,54 @@ object AccessibilityUtil {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 按正则表达式寻找节点和子节点内的一个匹配项
|
||||
* @param node 节点
|
||||
* @param regex 表达式
|
||||
* @param timeout 检查超时时间
|
||||
*/
|
||||
fun findOneByTextRegex(
|
||||
node: AccessibilityNodeInfo?,
|
||||
regex: String,
|
||||
timeout: Long = 5000,
|
||||
root: Boolean = true
|
||||
): AccessibilityNodeInfo? {
|
||||
var node = node ?: return null
|
||||
val startTime = System.currentTimeMillis()
|
||||
var currentTime = startTime
|
||||
while (currentTime - startTime <= timeout) {
|
||||
val result = findOnceByTextRegex(node, regex)
|
||||
if (result != null) return result
|
||||
sleep(SHORT_INTERVAL)
|
||||
if (root) {
|
||||
node = getRoot(true)
|
||||
} else {
|
||||
node.refresh()
|
||||
}
|
||||
currentTime = System.currentTimeMillis()
|
||||
}
|
||||
Log.e(tag, "findOneByTextRegex: not found: $regex")
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 按正则表达式寻找节点和子节点内的一个匹配项
|
||||
* @param node 节点
|
||||
* @param regex 表达式
|
||||
*/
|
||||
fun findOnceByTextRegex(
|
||||
node: AccessibilityNodeInfo?,
|
||||
regex: String
|
||||
): AccessibilityNodeInfo? {
|
||||
if (node == null) return null
|
||||
val textNodeList = findAllOnceByTextRegex(node, regex)
|
||||
LogUtils.v("regex: $regex count: " + textNodeList.size)
|
||||
if (textNodeList.size > 0) {
|
||||
return textNodeList[0]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 按文本(关键词)寻找节点和子节点内的一个匹配项
|
||||
* @param node 节点
|
||||
@@ -495,6 +546,60 @@ object AccessibilityUtil {
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 按正则表达式寻找节点和子节点内的所有匹配项
|
||||
* @param node 节点
|
||||
* @param regex 关键词
|
||||
* @param timeout 检查超时时间
|
||||
*/
|
||||
fun findAllByTextRegex(
|
||||
node: AccessibilityNodeInfo?,
|
||||
regex: String,
|
||||
timeout: Long = 5000,
|
||||
root: Boolean = true,
|
||||
minSize: Int = 1
|
||||
): List<AccessibilityNodeInfo> {
|
||||
var node = node ?: return arrayListOf()
|
||||
val startTime = System.currentTimeMillis()
|
||||
var currentTime = startTime
|
||||
while (currentTime - startTime <= timeout) {
|
||||
val result = findAllOnceByTextRegex(node, regex)
|
||||
LogUtils.v("regex: $regex count: " + result.size)
|
||||
if (result.size >= minSize) return result
|
||||
sleep(SHORT_INTERVAL)
|
||||
if (root) {
|
||||
node = getRoot(true)
|
||||
} else {
|
||||
node.refresh()
|
||||
}
|
||||
currentTime = System.currentTimeMillis()
|
||||
}
|
||||
Log.e(tag, "findAllByTextRegex: not found: $regex")
|
||||
return arrayListOf()
|
||||
}
|
||||
|
||||
/**
|
||||
* 按正则表达式寻找节点和子节点内的所有匹配项
|
||||
* node 节点
|
||||
* clazz 类名
|
||||
* limitDepth 深度 限制深度搜索深度必须匹配提供值且类名相同才返回 不填默认不限制
|
||||
*/
|
||||
fun findAllOnceByTextRegex(
|
||||
node: AccessibilityNodeInfo?,
|
||||
regex: String,
|
||||
list: ArrayList<AccessibilityNodeInfo> = ArrayList()
|
||||
): ArrayList<AccessibilityNodeInfo> {
|
||||
if (node == null) return list
|
||||
val nodeText = node.text?.toString()
|
||||
if (nodeText != null && nodeText.matches(regex.toRegex())) {
|
||||
list.add(node)
|
||||
}
|
||||
for (i in 0 until node.childCount) {
|
||||
findAllOnceByTextRegex(node.getChild(i), regex, list = list)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 按类名寻找节点和子节点内的一个匹配项
|
||||
* node 节点
|
||||
@@ -509,13 +614,14 @@ object AccessibilityUtil {
|
||||
depth: Int = 0,
|
||||
timeout: Long = 5000,
|
||||
root: Boolean = true,
|
||||
minChildCount: Int = 0
|
||||
minChildCount: Int = 0,
|
||||
firstChildClazz: String? = null
|
||||
): 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, minChildCount = minChildCount)
|
||||
val result = findOnceByClazz(node, *clazzList, limitDepth = limitDepth, depth = depth, minChildCount = minChildCount, firstChildClazz = firstChildClazz)
|
||||
LogUtils.v("clazz: ${clazzList.joinToString()} result == null: ${result == null}")
|
||||
if (result != null) return result
|
||||
sleep(SHORT_INTERVAL)
|
||||
@@ -542,15 +648,18 @@ object AccessibilityUtil {
|
||||
vararg clazzList: String,
|
||||
limitDepth: Int? = null,
|
||||
depth: Int = 0,
|
||||
minChildCount: Int = 0
|
||||
minChildCount: Int = 0,
|
||||
firstChildClazz: String? = null
|
||||
): AccessibilityNodeInfo? {
|
||||
if (node == null) return null
|
||||
if (node.className in clazzList) {
|
||||
if ((limitDepth == null || limitDepth == depth) && node.childCount >= minChildCount)
|
||||
return node
|
||||
if (firstChildClazz == null || (node.childCount > 0 && firstChildClazz == node.getChild(0).className)) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
for (i in 0 until node.childCount) {
|
||||
val result = findOnceByClazz(node.getChild(i), *clazzList, limitDepth = limitDepth, depth = depth + 1, minChildCount = minChildCount)
|
||||
val result = findOnceByClazz(node.getChild(i), *clazzList, limitDepth = limitDepth, depth = depth + 1, minChildCount = minChildCount, firstChildClazz = firstChildClazz)
|
||||
if (result != null) return result
|
||||
}
|
||||
return null
|
||||
@@ -696,7 +805,7 @@ object AccessibilityUtil {
|
||||
for (i in 0 until depth) {
|
||||
s += "---"
|
||||
}
|
||||
Log.d(tag, "$s depth: $depth className: " + node.className)
|
||||
Log.d(tag, "$s depth: $depth className: " + node.className + " isClickable: " + node.isClickable)
|
||||
if (printText && node.text != null) {
|
||||
Log.d(tag, "$s depth: $depth text: " + node.text)
|
||||
}
|
||||
@@ -712,11 +821,11 @@ object AccessibilityUtil {
|
||||
* Gesture手势实现点击(Android7+)
|
||||
* 解决 clickable=false 无法点击问题
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
fun clickByNode(
|
||||
service: AccessibilityService,
|
||||
nodeInfo: AccessibilityNodeInfo
|
||||
): Boolean {
|
||||
nodeInfo.refresh()
|
||||
val rect = Rect()
|
||||
nodeInfo.getBoundsInScreen(rect)
|
||||
val x: Int = (rect.left + rect.right) / 2
|
||||
@@ -743,7 +852,6 @@ object AccessibilityUtil {
|
||||
* Gesture手势实现滚动(Android7+)
|
||||
* 解决 scrollable=false 无法滚动问题
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
fun scrollDownByNode(
|
||||
service: AccessibilityService,
|
||||
nodeInfo: AccessibilityNodeInfo
|
||||
@@ -781,29 +889,24 @@ object AccessibilityUtil {
|
||||
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")
|
||||
}
|
||||
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
|
||||
}
|
||||
override fun onCancelled(gestureDescription: GestureDescription) {
|
||||
LogUtils.v("scroll ok onCancelled")
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -819,25 +922,20 @@ object AccessibilityUtil {
|
||||
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")
|
||||
}
|
||||
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
|
||||
}
|
||||
override fun onCancelled(gestureDescription: GestureDescription) {
|
||||
LogUtils.v("scroll ok onCancelled")
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import update.UpdateAppUtils
|
||||
object UpdateUtil {
|
||||
|
||||
fun checkUpdate() {
|
||||
OkGo.get<String>(Constant.URL_CHECK_UPDATE)
|
||||
OkGo.get<String>(Constant.getCheckUpdateUrl())
|
||||
.execute(object : StringCallback() {
|
||||
override fun onSuccess(response: Response<String>) {
|
||||
val commonResult =
|
||||
|
||||
@@ -6,10 +6,7 @@ import org.yameida.worktool.utils.AccessibilityUtil.findFrontNode
|
||||
import org.yameida.worktool.model.WeworkMessageBean
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import org.yameida.worktool.Constant
|
||||
import org.yameida.worktool.service.backPress
|
||||
import org.yameida.worktool.service.getRoot
|
||||
import org.yameida.worktool.service.goHome
|
||||
import org.yameida.worktool.service.sleep
|
||||
import org.yameida.worktool.service.*
|
||||
import org.yameida.worktool.utils.AccessibilityUtil.findAllOnceByClazz
|
||||
|
||||
/**
|
||||
@@ -101,13 +98,21 @@ object WeworkRoomUtil {
|
||||
val searchButton: AccessibilityNodeInfo = textViewList[textViewList.size - 2]
|
||||
val multiButton: AccessibilityNodeInfo = textViewList[textViewList.size - 1]
|
||||
AccessibilityUtil.performClick(searchButton)
|
||||
AccessibilityUtil.findTextInput(getRoot(), title.replace("…", "").replace("-.*$".toRegex(), ""))
|
||||
val needTrim = title.contains(Constant.regTrimTitle)
|
||||
val trimTitle = title.replace(Constant.regTrimTitle, "")
|
||||
AccessibilityUtil.findTextInput(getRoot(), trimTitle)
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL)
|
||||
//消息页搜索结果列表
|
||||
val selectListView = findOneByClazz(getRoot(), Views.ListView)
|
||||
val imageView = AccessibilityUtil.findOnceByClazz(selectListView, Views.ImageView)
|
||||
if (imageView != null) {
|
||||
AccessibilityUtil.performClick(imageView)
|
||||
val searchResult = AccessibilityUtil.findOneByText(
|
||||
selectListView,
|
||||
trimTitle,
|
||||
exact = !needTrim,
|
||||
timeout = 2000,
|
||||
root = false
|
||||
)
|
||||
if (searchResult != null) {
|
||||
AccessibilityUtil.performClick(searchResult)
|
||||
LogUtils.d("进入房间: $title")
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL)
|
||||
return true
|
||||
|
||||
37
app/src/main/res/layout/dialog_input.xml
Normal file
37
app/src/main/res/layout/dialog_input.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#fff"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/body"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:hint="wss://"
|
||||
android:lines="3"
|
||||
android:textColor="#000000" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/ok"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="#169BD5"
|
||||
android:text="确定" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="#F4F4F4"
|
||||
android:text="@android:string/cancel" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -6,7 +6,7 @@
|
||||
<dimen name="setting_start_padding">22dp</dimen>
|
||||
<dimen name="setting_end_start_padding">25dp</dimen>
|
||||
<dimen name="setting_end_padding">10dp</dimen>
|
||||
<dimen name="setting_vertical_padding">7dp</dimen>
|
||||
<dimen name="setting_vertical_padding">5dp</dimen>
|
||||
<dimen name="setting_start_font_width">150dp</dimen>
|
||||
<dimen name="setting_end_font_width">60dp</dimen>
|
||||
<dimen name="setting_start_image_width">20dp</dimen>
|
||||
|
||||
Reference in New Issue
Block a user