update 修改用户备注;添加待办;重复拉人踢人优化;at优化;自动通过好友加标签;获取控件父节点异常;推断优化;卡bug优化;登录页;其他已知问题修复

This commit is contained in:
gallonyin
2022-11-23 19:53:11 +08:00
parent 24b4a656bf
commit 621d6fe2fa
23 changed files with 419 additions and 161 deletions

View File

@@ -36,12 +36,6 @@ dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//工具集
implementation 'com.blankj:utilcodex:1.31.0'

View File

@@ -1,24 +0,0 @@
package org.yameida.worktool
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("org.yameida.worktool", appContext.packageName)
}
}

View File

@@ -35,16 +35,18 @@
<activity
android:name="org.yameida.worktool.activity.ListenActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustUnspecified|stateHidden"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="org.yameida.worktool.activity.LoginActivity"
android:windowSoftInputMode="adjustUnspecified|stateHidden"
android:theme="@style/AppTheme">
</activity>
<service
android:name="org.yameida.worktool.service.WeworkService"
android:enabled="true"

View File

@@ -12,25 +12,32 @@ 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.utils.UpdateUtil
import android.content.*
import android.text.InputType
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.qmuiteam.qmui.widget.dialog.QMUIDialog
import org.yameida.worktool.utils.HostTestHelper
import org.yameida.worktool.utils.PermissionHelper
import org.yameida.worktool.utils.PermissionPageManagement
import org.yameida.worktool.utils.*
import org.yameida.worktool.utils.envcheck.CheckHook
import org.yameida.worktool.utils.envcheck.CheckRoot
class ListenActivity : AppCompatActivity() {
companion object {
/**
* @param type 0=游客登录
*/
fun enterActivity(context: Context, type: Int) {
context.startActivity(Intent(context, ListenActivity::class.java).apply {
putExtra("type", type)
})
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
title = "WorkTool"
setContentView(R.layout.activity_listen)
initView()
@@ -152,6 +159,7 @@ class ListenActivity : AppCompatActivity() {
override fun onGranted() {
ToastUtils.showLong("请同时打开后台弹出界面权限~")
PermissionPageManagement.goToSetting(this@ListenActivity)
FloatWindowHelper.showWindow()
}
override fun onDenied() { sw_accessibility.isChecked = false }
@@ -164,6 +172,9 @@ class ListenActivity : AppCompatActivity() {
}
}
})
if (PermissionUtils.isGrantedDrawOverlays()) {
FloatWindowHelper.showWindow()
}
}
/**

View File

@@ -0,0 +1,37 @@
package org.yameida.worktool.activity
import android.os.Bundle
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_login.*
import org.yameida.worktool.R
import java.util.*
/**
* 登录页
*/
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setContentView(R.layout.activity_login)
initView()
}
private fun initView() {
val hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
if (hour in 12..17) {
textView.text = "Afternoon"
} else if (hour in 18..24 || hour in 0..6) {
textView.text = "Night"
imageView.setImageResource(R.drawable.good_night_img)
}
tv_visitor_login.setOnClickListener {
ListenActivity.enterActivity(this, 0)
finish()
}
}
}

View File

@@ -3,10 +3,7 @@ package org.yameida.worktool.service
import android.content.Intent
import android.graphics.Rect
import android.view.accessibility.AccessibilityNodeInfo
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.Utils
import com.blankj.utilcode.util.*
import com.hjq.toast.ToastUtils
import org.yameida.worktool.Constant
import org.yameida.worktool.MyApplication
@@ -37,7 +34,7 @@ fun goHomeTab(title: String): Boolean {
while (!atHome) {
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "消息", exact = true)
for (item in list) {
if (item.parent.parent.parent.childCount == 5) {
if (item.parent?.parent?.parent?.childCount == 5) {
//处理侧边栏抽屉打开
if (title == "消息") {
val rect = Rect()
@@ -49,7 +46,7 @@ fun goHomeTab(title: String): Boolean {
atHome = true
val tempList = AccessibilityUtil.findAllOnceByText(getRoot(), title, exact = true)
for (tempItem in tempList) {
if (tempItem.parent.parent.parent.childCount == 5) {
if (tempItem.parent?.parent?.parent?.childCount == 5) {
AccessibilityUtil.performClick(tempItem)
sleep(300)
find = true
@@ -77,7 +74,7 @@ fun goHomeTab(title: String): Boolean {
*/
fun isAtHome(): Boolean {
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "消息", exact = true)
return list.count { it.parent.parent.parent.childCount == 5 } > 0
return list.count { it.parent?.parent?.parent?.childCount == 5 } > 0
}
/**
@@ -146,11 +143,19 @@ fun backPress() {
if (confirm != null) {
LogUtils.d("尝试点击确定/我知道了/暂不进入")
AccessibilityUtil.performClick(confirm)
} else {
LogUtils.d("未找到对话框 点击bar中心")
AccessibilityUtil.performXYClick(WeworkController.weworkService, ScreenUtils.getScreenWidth() / 2F, BarUtils.getStatusBarHeight() * 2F)
sleep(Constant.POP_WINDOW_INTERVAL)
val firstEmptyTextView = AccessibilityUtil.findAllByClazz(getRoot(), Views.TextView).firstOrNull { it.text.isNullOrEmpty() }
if (firstEmptyTextView != null && firstEmptyTextView.isClickable) {
AccessibilityUtil.performClick(firstEmptyTextView)
}
}
}
}
}
sleep(500)
sleep(Constant.POP_WINDOW_INTERVAL)
}
/**

View File

@@ -157,7 +157,7 @@ object WeworkGetImpl {
val groupNameTv = AccessibilityUtil.findOnceByText(getRoot(), "群聊名称", exact = true)
if (groupNameTv != null) {
val tvList = AccessibilityUtil.findAllOnceByClazz(
groupNameTv.parent.parent.parent,
groupNameTv.parent?.parent?.parent,
Views.TextView
)
if (tvList.size >= 2) {

View File

@@ -50,8 +50,8 @@ object WeworkLoopImpl {
fun getFriendRequest(): Boolean {
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "通讯录", exact = true)
for (item in list) {
if (item.parent.parent.parent.childCount == 5) {
if (item.parent.childCount > 1) {
if (item.parent?.parent?.parent?.childCount == 5) {
if (item.parent != null && item.parent.childCount > 1) {
LogUtils.d("通讯录有红点")
AccessibilityUtil.performClick(item)
val hasRecommendFriend = AccessibilityUtil.findOneByText(getRoot(), "可能的", timeout = Constant.POP_WINDOW_INTERVAL)
@@ -99,8 +99,10 @@ object WeworkLoopImpl {
* 聊天页
* 1.获取群名
* 2.获取消息列表
* @param needInfer 是否需要推断@me并等待回复
* @param timeout 在房间内等待回复的时长
*/
fun getChatMessageList(timeout: Long = 3000): Boolean {
fun getChatMessageList(needInfer: Boolean = true, timeout: Long = 3000): Boolean {
if (Constant.autoReply == 0) return true
AccessibilityUtil.performScrollDown(getRoot(), 0)
val roomType = WeworkRoomUtil.getRoomType()
@@ -133,24 +135,32 @@ object WeworkLoopImpl {
null
)
)
val lastMessage = messageList.lastOrNull { it.sender == 0 }
if (lastMessage != null) {
var tempContent = ""
for (itemMessage in lastMessage.itemMessageList) {
if (itemMessage.text.contains("@" + Constant.myName)
|| itemMessage.text.isDigitsOnly()) {
tempContent = itemMessage.text
//推测是否回复并在房间等待指令
if (needInfer) {
val lastMessage = messageList.lastOrNull { it.sender == 0 }
if (lastMessage != null) {
var tempContent = ""
for (itemMessage in lastMessage.itemMessageList) {
if (itemMessage.text.contains("@" + Constant.myName)
|| itemMessage.text.isDigitsOnly()
) {
tempContent = itemMessage.text
}
}
}
if (roomType == WeworkMessageBean.ROOM_TYPE_EXTERNAL_CONTACT
|| roomType == WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT
|| tempContent.isNotBlank()) {
LogUtils.v("推测需要回复: $tempContent")
val startTime = System.currentTimeMillis()
var currentTime = startTime
while (mainLoopRunning && currentTime - startTime <= timeout) {
sleep(Constant.POP_WINDOW_INTERVAL / 5)
currentTime = System.currentTimeMillis()
if (roomType == WeworkMessageBean.ROOM_TYPE_EXTERNAL_CONTACT
|| roomType == WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT
|| tempContent.isNotBlank()
) {
LogUtils.v("推测需要回复: $tempContent")
val startTime = System.currentTimeMillis()
var currentTime = startTime
while (mainLoopRunning && currentTime - startTime < timeout) {
sleep(Constant.POP_WINDOW_INTERVAL / 5)
currentTime = System.currentTimeMillis()
}
if (mainLoopRunning) {
return getChatMessageList(needInfer = false)
}
}
}
}
@@ -175,6 +185,10 @@ object WeworkLoopImpl {
if (filter.isNotEmpty()) {
val tvNick = filter[0]
LogUtils.d("好友请求: " + tvNick.text)
//设置标签
if (AccessibilityUtil.findTextAndClick(getRoot(), "标签")) {
WeworkOperationImpl.setFriendTags(arrayListOf("worktool自动通过"))
}
AccessibilityUtil.findTextAndClick(getRoot(), "通过验证")
AccessibilityUtil.findTextAndClick(getRoot(), "完成")
if (AccessibilityUtil.findTextAndClick(getRoot(), "确定")) {
@@ -211,8 +225,8 @@ object WeworkLoopImpl {
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "消息", exact = true)
for (item in list) {
if (item.parent.parent.parent.childCount == 5) {
if (item.parent.childCount > 1) {
if (item.parent?.parent?.parent?.childCount == 5) {
if (item.parent != null && item.parent.childCount > 1) {
LogUtils.d("消息有红点")
AccessibilityUtil.clickByNode(WeworkController.weworkService, item)
sleep(100)

View File

@@ -675,50 +675,15 @@ object WeworkOperationImpl {
//如果已经是好友的可以传name修改好友信息
if (friend.phone == null && friend.name != null) {
if (getFriendInfo(friend.name)) {
if (AccessibilityUtil.findOneByText(getRoot(), "标签", "电话", "描述", "设置备注和描述", exact = true) != null) {
var markTv =
AccessibilityUtil.findOnceByText(getRoot(), "设置备注和描述", exact = true)
if (markTv == null) {
markTv = AccessibilityUtil.findOnceByText(getRoot(), "企业", exact = true)
}
if (markTv == null) {
markTv = AccessibilityUtil.findOnceByText(getRoot(), "描述", exact = true)
}
//设置备注
if (markTv != null && (friend.markName != null
|| friend.markCorp != null || friend.markExtra != null)
) {
AccessibilityUtil.performClick(markTv)
val etList =
AccessibilityUtil.findAllByClazz(getRoot(), Views.EditText, minSize = 5)
if (etList.size >= 5) {
if (friend.markName != null) {
AccessibilityUtil.editTextInput(etList[0], friend.markName)
}
if (friend.markCorp != null) {
AccessibilityUtil.editTextInput(etList[1], friend.markCorp)
}
if (friend.markExtra != null) {
AccessibilityUtil.editTextInput(etList[4], friend.markExtra)
}
}
AccessibilityUtil.findTextAndClick(getRoot(), "保存")
}
//设置标签
if (!friend.tagList.isNullOrEmpty()) {
if (AccessibilityUtil.findTextAndClick(getRoot(), "标签")) {
setFriendTags(friend.tagList)
}
}
if (modifyFriendInfo(friend, addFriend = false)) {
LogUtils.d("修改好友信息成功: ${friend.name}")
uploadCommandResult(message, ExecCallbackBean.SUCCESS, "", startTime)
return true
} else {
LogUtils.e("未找到标签")
uploadCommandResult(message, ExecCallbackBean.ERROR_BUTTON, "未找到标签", startTime)
LogUtils.e("修改用户信息失败: ${friend.name}")
uploadCommandResult(message, ExecCallbackBean.ERROR_BUTTON, "修改用户信息失败: ${friend.name}", startTime)
return false
}
LogUtils.d("修改好友信息成功: ${friend.name}")
uploadCommandResult(message, ExecCallbackBean.SUCCESS, "", startTime)
sleep(3000)
return true
} else {
LogUtils.e("未找到用户: ${friend.name}")
uploadCommandResult(message, ExecCallbackBean.ERROR_TARGET, "未找到用户: ${friend.name}", startTime)
@@ -844,7 +809,7 @@ object WeworkOperationImpl {
//消息页搜索结果列表
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
val reverseRegexTitle = RegexHelper.reverseRegexTitle(trimTitle)
val regex1 = "^$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex1 = "^(微信昵称:)?$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex2 = ".*?\\($reverseRegexTitle\\)$"
val regex = "($regex1)|($regex2)"
val matchSelect = AccessibilityUtil.findOneByTextRegex(
@@ -858,7 +823,7 @@ object WeworkOperationImpl {
val item = selectListView.getChild(i)
val searchResult = AccessibilityUtil.findOnceByTextRegex(item, regex)
//过滤异常好友
if (searchResult != null && searchResult.parent.childCount < 3) {
if (searchResult?.parent != null && searchResult.parent.childCount < 3) {
item.refresh()
val imageView =
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
@@ -941,15 +906,15 @@ object WeworkOperationImpl {
val startTime = System.currentTimeMillis()
goHome()
val tvDiaryFlag = AccessibilityUtil.findOneByText(getRoot(), "日程", exact = true)
if (tvDiaryFlag != null && tvDiaryFlag.parent.childCount == 2) {
if (tvDiaryFlag != null && (tvDiaryFlag.parent?.childCount == 2 || tvDiaryFlag.parent?.childCount == 3)) {
AccessibilityUtil.performClick(tvDiaryFlag)
val tvNeedDealFlag = AccessibilityUtil.findOneByTextRegex(getRoot(), "^待办( · .*?)?$")
if (tvNeedDealFlag != null) {
AccessibilityUtil.performClick(tvNeedDealFlag)
sleep(Constant.POP_WINDOW_INTERVAL)
val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView)
if (rv != null) {
val frontNode = AccessibilityUtil.findFrontNode(rv.parent)
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ViewGroup, minChildCount = 2)
if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(if (list.className == Views.RecyclerView) list.parent else list)
val textViewList =
AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView)
if (textViewList.size >= 2) {
@@ -959,7 +924,7 @@ object WeworkOperationImpl {
AccessibilityUtil.findTextAndClick(getRoot(), "参与人")
if (relaySelectTarget(titleList, needSend = false)) {
LogUtils.e("添加参与人成功")
if (AccessibilityUtil.findTextAndClick(getRoot(), "保存并发送到聊天")) {
if (AccessibilityUtil.findTextAndClick(getRoot(), "保存并发送到聊天", "保存并建群发送")) {
uploadCommandResult(message, ExecCallbackBean.SUCCESS, "", startTime)
return true
} else {
@@ -1088,7 +1053,7 @@ object WeworkOperationImpl {
sleep(Constant.CHANGE_PAGE_INTERVAL)
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2)
val reverseRegexTitle = RegexHelper.reverseRegexTitle(trimTitle)
val regex1 = "^$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex1 = "^(微信昵称:)?$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex2 = ".*?\\($reverseRegexTitle\\)$"
val regex = "($regex1)|($regex2)"
val matchSelect = AccessibilityUtil.findOneByTextRegex(
@@ -1102,7 +1067,7 @@ object WeworkOperationImpl {
val item = selectListView.getChild(i)
val searchResult = AccessibilityUtil.findOnceByTextRegex(item, regex)
//过滤已退出的群聊
if (searchResult != null && searchResult.parent.childCount < 3) {
if (searchResult?.parent != null && searchResult.parent.childCount < 3) {
item.refresh()
val imageView =
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
@@ -1246,6 +1211,7 @@ object WeworkOperationImpl {
val textViewList = AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView)
if (textViewList.size >= 2) {
val multiButton = textViewList.lastOrNull()
var count = 0
for (select in selectList) {
val needTrim = select.contains(Constant.regTrimTitle)
val trimTitle = select.replace(Constant.regTrimTitle, "")
@@ -1254,7 +1220,7 @@ object WeworkOperationImpl {
sleep(Constant.POP_WINDOW_INTERVAL)
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2, firstChildClazz = Views.TextView)
val reverseRegexTitle = RegexHelper.reverseRegexTitle(trimTitle)
val regex1 = "^$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex1 = "^(微信昵称:)?$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex2 = ".*?\\($reverseRegexTitle\\)$"
val regex = "($regex1)|($regex2)"
val matchSelect = AccessibilityUtil.findOneByTextRegex(
@@ -1272,8 +1238,11 @@ object WeworkOperationImpl {
item.refresh()
val imageView =
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
if (AccessibilityUtil.performClick(imageView)) {
if (imageView != null && !imageView.isEnabled) {
flag = true
} else if (AccessibilityUtil.performClick(imageView)) {
flag = true
count += 1
}
}
}
@@ -1293,6 +1262,13 @@ object WeworkOperationImpl {
if (Constant.groupStrict) return false
}
}
if (count == 0) {
while (AccessibilityUtil.findOnceByText(getRoot(), "全部群成员", "微信用户创建") == null && !isAtHome()) {
backPress()
}
LogUtils.d("拉入0人")
return true
}
if (showMessageHistory) {
AccessibilityUtil.findTextAndClick(getRoot(), "聊天记录")
}
@@ -1300,6 +1276,7 @@ object WeworkOperationImpl {
AccessibilityUtil.findOneByTextRegex(getRoot(), "^确定(\\(.*?\\))?\$")
if (confirmButton != null) {
AccessibilityUtil.performClick(confirmButton)
return true
} else {
LogUtils.e("未发现确认按钮")
return false
@@ -1312,8 +1289,10 @@ object WeworkOperationImpl {
LogUtils.e("未找到成员列表")
return false
}
} else {
LogUtils.e("进入群详情失败")
return false
}
return true
}
/**
@@ -1328,6 +1307,7 @@ object WeworkOperationImpl {
.filter { it.text == null }.size
LogUtils.v("tvEmptySize: $tvEmptySize")
if (tvEmptySize <= 1) {
LogUtils.e("未找到踢人按钮")
return true
} else if (tvEmptySize == 2) {
AccessibilityUtil.performClick(gridView.getChild(gridView.childCount - 1))
@@ -1343,6 +1323,7 @@ object WeworkOperationImpl {
val textViewList = AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView)
if (textViewList.size >= 2) {
val multiButton = textViewList.lastOrNull()
var count = 0
for (select in removeList) {
val needTrim = select.contains(Constant.regTrimTitle)
val trimTitle = select.replace(Constant.regTrimTitle, "")
@@ -1351,7 +1332,7 @@ object WeworkOperationImpl {
sleep(Constant.POP_WINDOW_INTERVAL)
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView, Views.RecyclerView, Views.ViewGroup, minChildCount = 2, firstChildClazz = Views.RelativeLayout)
val reverseRegexTitle = RegexHelper.reverseRegexTitle(trimTitle)
val regex1 = "^$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex1 = "^(微信昵称:)?$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex2 = ".*?\\($reverseRegexTitle\\)$"
val regex = "($regex1)|($regex2)"
val matchSelect = AccessibilityUtil.findOneByTextRegex(
@@ -1368,7 +1349,9 @@ object WeworkOperationImpl {
item.refresh()
val imageView =
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
AccessibilityUtil.performClick(imageView)
if (AccessibilityUtil.performClick(imageView)) {
count += 1
}
}
}
}
@@ -1381,13 +1364,22 @@ object WeworkOperationImpl {
LogUtils.d("找到搜索结果: $select")
} else {
LogUtils.e("未搜索到结果: $select")
if (Constant.groupStrict) return false
//待踢人已经不在群里的不算失败
// if (Constant.groupStrict) return false
}
}
if (count == 0) {
while (AccessibilityUtil.findOnceByText(getRoot(), "全部群成员", "微信用户创建") == null && !isAtHome()) {
backPress()
}
LogUtils.d("移出0人")
return true
}
val confirmButton =
AccessibilityUtil.findOneByText(getRoot(), "移出(")
if (confirmButton != null) {
AccessibilityUtil.performClick(confirmButton)
return true
} else {
LogUtils.e("未发现移出按钮")
return false
@@ -1400,8 +1392,10 @@ object WeworkOperationImpl {
LogUtils.e("未找到成员列表")
return false
}
} else {
LogUtils.e("进入群详情失败")
return false
}
return true
}
/**
@@ -1522,13 +1516,14 @@ object WeworkOperationImpl {
* 发送消息+@at
*/
private fun sendChatMessage(text: String, at: String? = null, atList: List<String>? = null, reply: Boolean? = false): Boolean {
val roomType = WeworkRoomUtil.getRoomType()
val voiceFlag = AccessibilityUtil.findOnceByText(getRoot(), "按住 说话", "按住说话", exact = true)
if (voiceFlag != null) {
AccessibilityUtil.performClickWithSon(AccessibilityUtil.findFrontNode(voiceFlag))
}
var atFailed = false
val atList = if (!at.isNullOrEmpty()) listOf(at) else atList
if (!atList.isNullOrEmpty()) {
if (!atList.isNullOrEmpty() && (roomType == WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP || roomType == WeworkMessageBean.ROOM_TYPE_EXTERNAL_GROUP)) {
atList.forEachIndexed { index, at ->
if (index == 0) {
AccessibilityUtil.findTextInput(getRoot(), "@")
@@ -1572,6 +1567,7 @@ object WeworkOperationImpl {
}
}
}
LogUtils.v("atFailed: $atFailed")
val content = if (atFailed) "@${atList?.joinToString()} $text" else text
val append = (reply == true) || (!atList.isNullOrEmpty() && !atFailed)
if (AccessibilityUtil.findTextInput(getRoot(), content, append = append)) {
@@ -1614,7 +1610,7 @@ object WeworkOperationImpl {
//消息页搜索结果列表
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
val reverseRegexTitle = RegexHelper.reverseRegexTitle(trimTitle)
val regex1 = "^$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex1 = "^(微信昵称:)?$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex2 = ".*?\\($reverseRegexTitle\\)$"
val regex = "($regex1)|($regex2)"
val matchSelect = AccessibilityUtil.findOneByTextRegex(
@@ -1628,7 +1624,7 @@ object WeworkOperationImpl {
val item = selectListView.getChild(i)
val searchResult = AccessibilityUtil.findOnceByTextRegex(item, regex)
//过滤异常好友
if (searchResult != null && searchResult.parent.childCount < 3) {
if (searchResult?.parent != null && searchResult.parent.childCount < 3) {
item.refresh()
val imageView =
AccessibilityUtil.findOneByClazz(item, Views.ImageView, root = false)
@@ -1651,7 +1647,7 @@ object WeworkOperationImpl {
/**
* 修改好友信息
*/
private fun modifyFriendInfo(friend: WeworkMessageBean.Friend): Boolean {
private fun modifyFriendInfo(friend: WeworkMessageBean.Friend, addFriend: Boolean = true): Boolean {
if (AccessibilityUtil.findOneByText(getRoot(), "标签", "电话", "描述", "设置备注和描述", exact = true) != null) {
var markTv = AccessibilityUtil.findOnceByText(getRoot(), "设置备注和描述", exact = true)
if (markTv == null) {
@@ -1667,7 +1663,7 @@ object WeworkOperationImpl {
AccessibilityUtil.performClick(markTv)
val etList =
AccessibilityUtil.findAllByClazz(getRoot(), Views.EditText, minSize = 2)
if (etList.size >= 5) {
if (etList.size >= 4) {
//微信用户 备注/企业/电话/电话/描述
if (friend.markName != null) {
AccessibilityUtil.editTextInput(etList[0], friend.markName)
@@ -1676,7 +1672,7 @@ object WeworkOperationImpl {
AccessibilityUtil.editTextInput(etList[1], friend.markCorp)
}
if (friend.markExtra != null) {
AccessibilityUtil.editTextInput(etList[4], friend.markExtra)
AccessibilityUtil.editTextInput(etList[etList.size - 1], friend.markExtra)
}
} else if (etList.size == 2) {
//同企业内部用户 备注/描述
@@ -1684,7 +1680,7 @@ object WeworkOperationImpl {
AccessibilityUtil.editTextInput(etList[0], friend.markName)
}
if (friend.markExtra != null) {
AccessibilityUtil.editTextInput(etList[1], friend.markExtra)
AccessibilityUtil.editTextInput(etList[etList.size - 1], friend.markExtra)
}
} else if (etList.size == 3) {
//外部企业用户 备注/电话/描述
@@ -1692,7 +1688,7 @@ object WeworkOperationImpl {
AccessibilityUtil.editTextInput(etList[0], friend.markName)
}
if (friend.markExtra != null) {
AccessibilityUtil.editTextInput(etList[2], friend.markExtra)
AccessibilityUtil.editTextInput(etList[etList.size - 1], friend.markExtra)
}
}
AccessibilityUtil.findTextAndClick(getRoot(), "保存")
@@ -1703,6 +1699,9 @@ object WeworkOperationImpl {
setFriendTags(friend.tagList)
}
}
if (!addFriend) {
return true
}
//添加联系人
val imageView =
AccessibilityUtil.findOneByClazz(getRoot(), Views.ImageView)
@@ -1732,7 +1731,7 @@ object WeworkOperationImpl {
/**
* 设置好友标签
*/
private fun setFriendTags(tagList: List<String>): Boolean {
fun setFriendTags(tagList: List<String>): Boolean {
val tagList = if (tagList.size > 5) tagList.subList(0, 5) else tagList
val tvTag = AccessibilityUtil.findAllByText(getRoot(), "个人标签").lastOrNull()
val oldTagList = arrayListOf<String>()

View File

@@ -838,8 +838,9 @@ object AccessibilityUtil {
*/
fun clickByNode(
service: AccessibilityService,
nodeInfo: AccessibilityNodeInfo
nodeInfo: AccessibilityNodeInfo?
): Boolean {
if (nodeInfo == null) return false
nodeInfo.refresh()
val rect = Rect()
nodeInfo.getBoundsInScreen(rect)
@@ -869,8 +870,9 @@ object AccessibilityUtil {
*/
fun scrollDownByNode(
service: AccessibilityService,
nodeInfo: AccessibilityNodeInfo
nodeInfo: AccessibilityNodeInfo?
): Boolean {
if (nodeInfo == null) return false
val rect = Rect()
nodeInfo.getBoundsInScreen(rect)
val x: Int = (rect.left + rect.right) / 2
@@ -900,10 +902,11 @@ object AccessibilityUtil {
*/
fun scrollByNode(
service: AccessibilityService,
nodeInfo: AccessibilityNodeInfo,
nodeInfo: AccessibilityNodeInfo?,
distanceX: Int = 0,
distanceY: Int = 0
): Boolean {
if (nodeInfo == null) return false
val rect = Rect()
nodeInfo.getBoundsInScreen(rect)
val point = Point((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2)

View File

@@ -0,0 +1,12 @@
package org.yameida.worktool.utils
import com.blankj.utilcode.util.LogUtils
object FloatWindowHelper {
fun showWindow() {
LogUtils.d("FloatWindowHelper.showWindow()")
}
}

View File

@@ -57,7 +57,7 @@ object WeworkRoomUtil {
//聊天消息列表 1ListView 0RecycleView xViewGroup
val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView)
if (list != null) {
val frontNode = findFrontNode(list.parent.parent)
val frontNode = findFrontNode(list.parent?.parent)
val textViewList = findAllOnceByClazz(frontNode, Views.TextView)
for (textView in textViewList) {
if (!textView.text.isNullOrBlank()) {
@@ -105,7 +105,7 @@ object WeworkRoomUtil {
//消息页搜索结果列表
val selectListView = findOneByClazz(getRoot(), Views.ListView)
val reverseRegexTitle = RegexHelper.reverseRegexTitle(trimTitle)
val regex1 = "^$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex1 = "^(微信昵称:)?$reverseRegexTitle" + if (needTrim) ".*?" else "(-.*)?(…)?(\\(.*?\\))?$"
val regex2 = ".*?\\($reverseRegexTitle\\)$"
val regex = "($regex1)|($regex2)"
val searchResult = AccessibilityUtil.findAllByTextRegex(
@@ -117,7 +117,7 @@ object WeworkRoomUtil {
if (searchResult.isNotEmpty()) {
//过滤已退出的群聊
val searchItem = searchResult.firstOrNull {
it.parent.childCount < 3
it.parent != null && it.parent.childCount < 3
}
if (searchItem != null) {
AccessibilityUtil.performClick(searchItem)
@@ -150,7 +150,7 @@ object WeworkRoomUtil {
//群详情列表
val list = findOneByClazz(getRoot(), Views.ListView)
if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list.parent.parent)
val frontNode = AccessibilityUtil.findFrontNode(list.parent?.parent)
val textViewList = findAllOnceByClazz(frontNode, Views.TextView)
if (textViewList.size >= 2) {
val multiButton = textViewList.lastOrNull()
@@ -175,7 +175,7 @@ object WeworkRoomUtil {
//同群详情列表
val list = findOneByClazz(getRoot(), Views.ListView)
if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list.parent.parent)
val frontNode = AccessibilityUtil.findFrontNode(list.parent?.parent)
val textViewList = findAllOnceByClazz(frontNode, Views.TextView)
if (textViewList.size >= 2) {
val multiButton = textViewList.lastOrNull()

View File

@@ -212,7 +212,8 @@ object WeworkTextUtil {
tvCount == 1 && ivCount == 0 -> WeworkMessageBean.TEXT_TYPE_PLAIN
tvCount == 0 && ivCount == 1 -> WeworkMessageBean.TEXT_TYPE_IMAGE
tvCount == 2 && ivCount == 2 -> {
if (tvList[0].parent.childCount > 3) {
val parent = tvList[0].parent
if (parent != null && parent.childCount > 3) {
WeworkMessageBean.TEXT_TYPE_VIDEO
} else {
WeworkMessageBean.TEXT_TYPE_OFFICE

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="@android:color/transparent"/>
<stroke android:color="#96ffffff"
android:width="2dp"/>
</shape>
</item>
</selector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#96ffffff"
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#96ffffff"
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
</vector>

Binary file not shown.

View File

@@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/good_morning_img" />
</FrameLayout>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good "
android:textColor="#ffffff"
android:textSize="32sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Morning"
android:textColor="#ffffff"
android:textSize="32sp" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="2dp"
android:background="#deff00" />
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/linearLayout"
android:layout_centerHorizontal="true"
android:layout_marginTop="4dp"
android:gravity="center"
android:text="WorkTool 极致的自动化体验"
android:textColor="#9affffff"
android:textSize="10sp"
tools:ignore="SmallSp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp"
android:orientation="vertical"
android:paddingLeft="32dp"
android:paddingRight="32dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColorHint="#96ffffff"
android:theme="@style/EditScreenTextInputLayoutStyle">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawablePadding="16dp"
android:drawableEnd="@drawable/ic_email_white_24dp"
android:fontFamily="@font/calibri"
android:hint="邮件/用户名"
android:inputType="textEmailAddress"
android:maxLines="1"
android:textColor="@android:color/white"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColorHint="#96ffffff"
android:theme="@style/EditScreenTextInputLayoutStyle">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawablePadding="16dp"
android:drawableEnd="@drawable/ic_lock_white_24dp"
android:fontFamily="@font/calibri"
android:hint="密码"
android:inputType="textPassword"
android:maxLines="1"
android:textColor="@android:color/white"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:gravity="center"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="@drawable/buttonshapewhitebg"
android:fontFamily="@font/calibri"
android:text="注册"
android:textAllCaps="false"
android:textStyle="bold"
android:textColor="#96ffffff"
android:textSize="16sp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:background="@drawable/buttonshapewhitebg"
android:fontFamily="@font/calibri"
android:text="登录"
android:textAllCaps="false"
android:textColor="#96ffffff"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/tv_visitor_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="@font/calibri"
android:text="游客登录"
android:textAlignment="center"
android:textColor="#96ffffff"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>

View File

@@ -3,4 +3,6 @@
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#000000</color>
<color name="colorAccent">#03DAC5</color>
<color name="textInputLayout">#96ffffff</color>
</resources>

View File

@@ -13,4 +13,12 @@
<item name="windowNoTitle">true</item>
</style>
<style name="EditScreenTextInputLayoutStyle" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorControlNormal">@color/textInputLayout</item>
<item name="colorControlActivated">@color/textInputLayout</item>
<item name="colorControlHighlight">@color/textInputLayout</item>
<item name="colorAccent">@color/textInputLayout</item>
<item name="android:textColorHint">@color/textInputLayout</item>
</style>
</resources>

View File

@@ -1,17 +0,0 @@
package org.yameida.worktool
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}