update 全面兼容企业微信最新版本(4.0.10)和政务微信;控件搜索优化;已知问题修复;
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.yameida.worktool">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
@@ -17,6 +18,8 @@
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
|
||||
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
|
||||
<application
|
||||
android:name="org.yameida.worktool.MyApplication"
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.yameida.worktool.config.WebConfig
|
||||
|
||||
object Constant {
|
||||
|
||||
val AVAILABLE_VERSION = arrayListOf("4.0.2", "4.0.6", "4.0.8", "4.0.10")
|
||||
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"
|
||||
@@ -15,5 +16,6 @@ object Constant {
|
||||
var key = "9876543210abcdef".toByteArray()
|
||||
var iv = "0123456789abcdef".toByteArray()
|
||||
val transformation = "AES/CBC/PKCS7Padding"
|
||||
var encryptType = SPUtils.getInstance().getInt("encryptType", 0)
|
||||
var encryptType = SPUtils.getInstance().getInt("encryptType", 1)
|
||||
var autoReply = SPUtils.getInstance().getInt("autoReply", 1)
|
||||
}
|
||||
|
||||
@@ -107,13 +107,14 @@ object Demo {
|
||||
"titleList":[
|
||||
"$name"
|
||||
],
|
||||
"receivedContent":"你好~我是机器人,你可以和我聊天,你也可以通过API文档来让我发送消息或完成建群等任务。接口文档:https://www.apifox.cn/apidoc/project-1035094/api-23520034"
|
||||
"receivedContent":"你好~我是机器人,你可以@我和我聊天,你也可以通过API文档来让我发送消息或完成建群等任务。接口文档:https://www.apifox.cn/apidoc/project-1035094/api-23520034"
|
||||
},
|
||||
{
|
||||
"type": 206,
|
||||
"groupName": "$groupName",
|
||||
"selectList": [
|
||||
"$name"
|
||||
"$name",
|
||||
"尹甲仑"
|
||||
],
|
||||
"groupAnnouncement": "(自动填写群公告) WorkTool欢迎大家~WorkTool管家是机器人,有问题可以在QQ群反馈~@我可以聊天~"
|
||||
}
|
||||
|
||||
@@ -52,15 +52,39 @@ class ListenActivity : AppCompatActivity() {
|
||||
})
|
||||
MobclickAgent.onProfileSignIn(channel)
|
||||
}
|
||||
Constant.encryptType = SPUtils.getInstance().getInt("encryptType", 0)
|
||||
sw_encrypt.isChecked = Constant.encryptType == 1
|
||||
sw_encrypt.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||
LogUtils.i("sw_encrypt onCheckedChanged: $isChecked")
|
||||
Constant.encryptType = if (isChecked) 1 else 0
|
||||
SPUtils.getInstance().put("encryptType", Constant.encryptType)
|
||||
})
|
||||
sw_auto_reply.isChecked = Constant.autoReply == 1
|
||||
sw_auto_reply.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||
LogUtils.i("sw_auto_reply onCheckedChanged: $isChecked")
|
||||
Constant.autoReply = if (isChecked) 1 else 0
|
||||
SPUtils.getInstance().put("autoReply", Constant.autoReply)
|
||||
})
|
||||
tv_host.text = WebConfig.HOST
|
||||
tv_version.text = AppUtils.getAppVersionName()
|
||||
val workVersionName = AppUtils.getAppInfo(Constant.PACKAGE_NAMES)?.versionName
|
||||
when (workVersionName) {
|
||||
null -> {
|
||||
LogUtils.e("系统检测到您尚未安装企业微信,请先安装企业微信")
|
||||
tv_work_version.text = "检测到您尚未安装企业微信,请先安装登录!"
|
||||
}
|
||||
in Constant.AVAILABLE_VERSION -> {
|
||||
LogUtils.i("当前企业微信版本已适配: $workVersionName")
|
||||
val tip = "$workVersionName 已适配,可放心使用~"
|
||||
tv_work_version.text = tip
|
||||
}
|
||||
else -> {
|
||||
LogUtils.e("当前企业微信版本未兼容: $workVersionName")
|
||||
val tip = "$workVersionName 可能存在部分兼容性问题!"
|
||||
tv_work_version.text = tip
|
||||
}
|
||||
}
|
||||
SPUtils.getInstance().put("appVersion", AppUtils.getAppVersionName())
|
||||
SPUtils.getInstance().put("workVersion", workVersionName)
|
||||
}
|
||||
|
||||
private fun initAccessibility() {
|
||||
|
||||
@@ -30,7 +30,7 @@ fun goHomeTab(title: String): Boolean {
|
||||
var atHome = false
|
||||
var find = false
|
||||
while (!atHome) {
|
||||
val list = AccessibilityUtil.findAllByText(getRoot(), "消息", timeout = 0)
|
||||
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "消息", exact = true)
|
||||
for (item in list) {
|
||||
if (item.parent.parent.parent.childCount == 5) {
|
||||
//处理侧边栏抽屉打开
|
||||
@@ -42,7 +42,7 @@ fun goHomeTab(title: String): Boolean {
|
||||
}
|
||||
}
|
||||
atHome = true
|
||||
val tempList = AccessibilityUtil.findAllByText(getRoot(), title, timeout = 0)
|
||||
val tempList = AccessibilityUtil.findAllOnceByText(getRoot(), title, exact = true)
|
||||
for (tempItem in tempList) {
|
||||
if (tempItem.parent.parent.parent.childCount == 5) {
|
||||
AccessibilityUtil.performClick(tempItem)
|
||||
@@ -64,7 +64,7 @@ fun goHomeTab(title: String): Boolean {
|
||||
* 当前是否在首页
|
||||
*/
|
||||
fun isAtHome(): Boolean {
|
||||
val list = AccessibilityUtil.findAllByText(getRoot(), "消息", timeout = 0)
|
||||
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "消息", exact = true)
|
||||
return list.count { it.parent.parent.parent.childCount == 5 } > 0
|
||||
}
|
||||
|
||||
@@ -85,8 +85,7 @@ fun getRoot(ignoreCheck: Boolean): AccessibilityNodeInfo {
|
||||
val root = WeworkController.weworkService.rootInActiveWindow
|
||||
if (tempRoot != root) {
|
||||
LogUtils.e("tempRoot != root")
|
||||
}
|
||||
if (root != null) {
|
||||
} else if (root != null) {
|
||||
if (root.packageName == Constant.PACKAGE_NAMES) {
|
||||
return root
|
||||
} else {
|
||||
@@ -124,9 +123,7 @@ fun backPress() {
|
||||
AccessibilityUtil.performClick(button)
|
||||
} else {
|
||||
LogUtils.d("未找到BT按钮")
|
||||
val confirm = AccessibilityUtil.findOnceByText(getRoot(), "确定")
|
||||
?: AccessibilityUtil.findOnceByText(getRoot(), "我知道了")
|
||||
?: AccessibilityUtil.findOnceByText(getRoot(), "暂不进入")
|
||||
val confirm = AccessibilityUtil.findOnceByText(getRoot(), "确定", "我知道了", "暂不进入", "不用了", "取消")
|
||||
if (confirm != null) {
|
||||
LogUtils.d("尝试点击确定/我知道了/暂不进入")
|
||||
AccessibilityUtil.performClick(confirm)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.yameida.worktool.service
|
||||
|
||||
import com.blankj.utilcode.util.GsonUtils
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import org.yameida.worktool.Constant
|
||||
import org.yameida.worktool.model.WeworkMessageBean
|
||||
@@ -104,7 +105,7 @@ object WeworkGetImpl {
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtils.d("我的信息", myInfo)
|
||||
LogUtils.d("我的信息", GsonUtils.toJson(myInfo))
|
||||
val weworkMessageBean = WeworkMessageBean()
|
||||
weworkMessageBean.type = WeworkMessageBean.GET_MY_INFO
|
||||
weworkMessageBean.myInfo = myInfo
|
||||
|
||||
@@ -26,7 +26,7 @@ object WeworkLoopImpl {
|
||||
mainLoopRunning = true
|
||||
try {
|
||||
while (mainLoopRunning) {
|
||||
if (WeworkRoomUtil.getRoomType(getRoot(), false) != WeworkMessageBean.ROOM_TYPE_UNKNOWN
|
||||
if (WeworkRoomUtil.getRoomType(false) != WeworkMessageBean.ROOM_TYPE_UNKNOWN
|
||||
&& getChatMessageList()) {
|
||||
}
|
||||
if (!mainLoopRunning) break
|
||||
@@ -49,7 +49,7 @@ object WeworkLoopImpl {
|
||||
* 读取通讯录好友请求
|
||||
*/
|
||||
fun getFriendRequest(): Boolean {
|
||||
val list = AccessibilityUtil.findAllByText(getRoot(), "通讯录", timeout = 0)
|
||||
val list = AccessibilityUtil.findAllOnceByText(getRoot(), "通讯录", exact = true)
|
||||
for (item in list) {
|
||||
if (item.parent.parent.parent.childCount == 5) {
|
||||
if (item.parent.childCount > 1) {
|
||||
@@ -94,9 +94,10 @@ object WeworkLoopImpl {
|
||||
* 2.获取消息列表
|
||||
*/
|
||||
fun getChatMessageList(timeout: Long = 3000): Boolean {
|
||||
if (Constant.autoReply == 0) return true
|
||||
AccessibilityUtil.performScrollDown(getRoot(), 0)
|
||||
val roomType = WeworkRoomUtil.getRoomType(getRoot())
|
||||
var titleList = WeworkRoomUtil.getRoomTitle(getRoot())
|
||||
val roomType = WeworkRoomUtil.getRoomType()
|
||||
var titleList = WeworkRoomUtil.getRoomTitle()
|
||||
if (titleList.contains("对方正在输入…")) {
|
||||
titleList = WeworkRoomUtil.getFriendName()
|
||||
}
|
||||
@@ -183,7 +184,7 @@ object WeworkLoopImpl {
|
||||
//回到上一页
|
||||
var retry = 5
|
||||
while (retry-- > 0 && !isAtHome()) {
|
||||
val textView = AccessibilityUtil.findOnceByText(getRoot(), "新的客户")
|
||||
val textView = AccessibilityUtil.findOnceByText(getRoot(), "新的客户", "新的居民")
|
||||
if (textView == null) {
|
||||
backPress()
|
||||
}
|
||||
@@ -197,6 +198,7 @@ object WeworkLoopImpl {
|
||||
* 读取聊天列表
|
||||
*/
|
||||
private fun getChatroomList(): Boolean {
|
||||
if (Constant.autoReply == 0) return true
|
||||
if (!isAtHome()) return true
|
||||
if (logIndex % 3 == 0) {
|
||||
AccessibilityUtil.performScrollUp(getRoot(), 0)
|
||||
|
||||
@@ -47,7 +47,7 @@ object WeworkOperationImpl {
|
||||
*/
|
||||
fun replyMessage(
|
||||
titleList: List<String>,
|
||||
receivedName: String,
|
||||
receivedName: String?,
|
||||
originalContent: String,
|
||||
textType: Int,
|
||||
receivedContent: String
|
||||
@@ -70,7 +70,11 @@ object WeworkOperationImpl {
|
||||
} else {
|
||||
LogUtils.d("$title: 回复失败 直接发送答案")
|
||||
error("$title: 回复失败 直接发送答案 $receivedContent")
|
||||
sendChatMessage(receivedContent, "[自动回复]【$originalContent】@$receivedName\n")
|
||||
if (receivedName == null) {
|
||||
sendChatMessage(receivedContent, "[自动回复]【$originalContent】\n")
|
||||
} else {
|
||||
sendChatMessage(receivedContent, "[自动回复]【$originalContent】@$receivedName\n")
|
||||
}
|
||||
WeworkLoopImpl.getChatMessageList()
|
||||
}
|
||||
} else {
|
||||
@@ -432,8 +436,7 @@ object WeworkOperationImpl {
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
val listViewList = AccessibilityUtil.findAllByClazz(getRoot(), Views.ListView)
|
||||
if (!listViewList.isNullOrEmpty()) {
|
||||
// if (AccessibilityUtil.findTextAndClick(listViewList.last(), "添加客户")) {
|
||||
if (AccessibilityUtil.findTextAndClick(listViewList.last(), "添加")) {
|
||||
if (AccessibilityUtil.findTextAndClick(listViewList.last(), "添加客户", "添加居民", "加微信")) {
|
||||
AccessibilityUtil.findTextAndClick(getRoot(), "搜索手机号添加")
|
||||
AccessibilityUtil.findTextInput(getRoot(), friend.phone.trim())
|
||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "网络查找手机")) {
|
||||
@@ -500,7 +503,7 @@ object WeworkOperationImpl {
|
||||
}
|
||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "添加为联系人")) {
|
||||
LogUtils.d("添加好友成功: " + friend.phone)
|
||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "发送添加邀请")) {
|
||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "发送添加邀请", "发送申请")) {
|
||||
LogUtils.d("发送添加邀请成功: " + friend.phone)
|
||||
}
|
||||
} else {
|
||||
@@ -565,38 +568,33 @@ object WeworkOperationImpl {
|
||||
private fun relaySelectTarget(selectList: List<String>, extraText: String? = null): Boolean {
|
||||
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
|
||||
if (list != null) {
|
||||
val frontNode = AccessibilityUtil.findFrontNode(list)
|
||||
val frontNode = AccessibilityUtil.findFrontNode(list, 2)
|
||||
val textViewList = AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView)
|
||||
if (textViewList.size >= 2) {
|
||||
val searchButton: AccessibilityNodeInfo = textViewList[textViewList.size - 2]
|
||||
val multiButton: AccessibilityNodeInfo = textViewList[textViewList.size - 1]
|
||||
AccessibilityUtil.performClick(multiButton)
|
||||
sleep(1000)
|
||||
AccessibilityUtil.performClick(searchButton)
|
||||
//todo 搜索需要在循环内
|
||||
sleep(1000)
|
||||
for (select in selectList) {
|
||||
AccessibilityUtil.findTextInput(getRoot(), select)
|
||||
sleep(2000)
|
||||
AccessibilityUtil.findTextInput(getRoot(), select.replace("…", "").replace("-.*$".toRegex(), ""))
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL * 2)
|
||||
val selectListView = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
|
||||
val imageView =
|
||||
AccessibilityUtil.findOnceByClazz(selectListView, Views.ImageView)
|
||||
val imageView = AccessibilityUtil.findOneByClazz(selectListView, Views.ImageView)
|
||||
if (imageView != null) {
|
||||
AccessibilityUtil.performClick(imageView)
|
||||
}
|
||||
sleep(1000)
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL)
|
||||
}
|
||||
val confirmButton =
|
||||
AccessibilityUtil.findOneByText(getRoot(), "确定(${selectList.size})")
|
||||
if (confirmButton != null) {
|
||||
AccessibilityUtil.performClick(confirmButton)
|
||||
sleep(1000)
|
||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||
if (!extraText.isNullOrBlank()) {
|
||||
LogUtils.d("extraText: $extraText")
|
||||
AccessibilityUtil.findTextInput(getRoot(), extraText)
|
||||
sleep(1000)
|
||||
}
|
||||
val sendButtonList = AccessibilityUtil.findAllByText(getRoot(), "发送", timeout = 0)
|
||||
val sendButtonList = AccessibilityUtil.findAllByText(getRoot(), "发送")
|
||||
for (sendButton in sendButtonList.filter { it.text != null }) {
|
||||
if (sendButton.text == "发送" || sendButton.text == "发送(${selectList.size})") {
|
||||
AccessibilityUtil.performClick(sendButton)
|
||||
@@ -623,10 +621,10 @@ object WeworkOperationImpl {
|
||||
*/
|
||||
private fun createGroup(): Boolean {
|
||||
goHomeTab("工作台")
|
||||
val textViewGroup = AccessibilityUtil.scrollAndFindByText(getRoot(), "客户群")
|
||||
val textViewGroup = AccessibilityUtil.scrollAndFindByText(getRoot(), "客户群", "居民群")
|
||||
if (AccessibilityUtil.performClick(textViewGroup)) {
|
||||
LogUtils.d("进入客户群应用")
|
||||
val textView = AccessibilityUtil.findOneByText(getRoot(), "创建一个客户群")
|
||||
val textView = AccessibilityUtil.findOneByText(getRoot(), "创建一个客户群", "创建一个居民群")
|
||||
AccessibilityUtil.performClick(textView)
|
||||
return true
|
||||
} else {
|
||||
@@ -681,15 +679,18 @@ object WeworkOperationImpl {
|
||||
}
|
||||
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
|
||||
if (list != null) {
|
||||
val frontNode = AccessibilityUtil.findFrontNode(list)
|
||||
val frontNode = AccessibilityUtil.findFrontNode(list, 2)
|
||||
val textViewList = AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView)
|
||||
if (textViewList.size >= 2) {
|
||||
val multiButton = textViewList.lastOrNull()
|
||||
for (select in selectList) {
|
||||
AccessibilityUtil.performClick(multiButton)
|
||||
AccessibilityUtil.findTextInput(getRoot(), select)
|
||||
val selectListView =
|
||||
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)
|
||||
@@ -740,7 +741,7 @@ object WeworkOperationImpl {
|
||||
}
|
||||
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
|
||||
if (list != null) {
|
||||
val frontNode = AccessibilityUtil.findFrontNode(list)
|
||||
val frontNode = AccessibilityUtil.findFrontNode(list, 2)
|
||||
val textViewList = AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView)
|
||||
if (textViewList.size >= 2) {
|
||||
val multiButton = textViewList.lastOrNull()
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.lang.Exception
|
||||
* event.source则不需要验证包名获取窗口并可获得事件详情
|
||||
*/
|
||||
class WeworkService : AccessibilityService() {
|
||||
private val TAG = "WeworkService"
|
||||
lateinit var webSocketManager: WebSocketManager
|
||||
|
||||
override fun onServiceConnected() {
|
||||
@@ -85,10 +86,15 @@ class WeworkService : AccessibilityService() {
|
||||
}
|
||||
|
||||
class EchoWebSocketListener() : WebSocketListener() {
|
||||
private val TAG = "WeworkService.EchoWebSocketListener"
|
||||
private lateinit var socket: WebSocket
|
||||
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||
socket = webSocket
|
||||
Log.e("ChatMaskActivityListener", "链接建立")
|
||||
Log.e(TAG, "链接建立")
|
||||
val robotId = SPUtils.getInstance().getString(WebConfig.LISTEN_CHANNEL_ID, "")
|
||||
val appVersion = SPUtils.getInstance().getString("appVersion", "")
|
||||
val workVersion= SPUtils.getInstance().getString("workVersion", "")
|
||||
log("链接建立: $robotId appVersion: $appVersion workVersion: $workVersion")
|
||||
}
|
||||
|
||||
override fun onMessage(webSocket: WebSocket, text: String) {
|
||||
@@ -104,19 +110,19 @@ class WeworkService : AccessibilityService() {
|
||||
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
||||
super.onClosed(webSocket, code, reason)
|
||||
//服务器关闭后
|
||||
Log.e("ChatMaskActivityListener", "链接关闭 $reason")
|
||||
Log.e(TAG, "链接关闭 $reason")
|
||||
}
|
||||
|
||||
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
|
||||
super.onClosing(webSocket, code, reason)
|
||||
socket.close(code, reason)
|
||||
Log.e("ChatMaskActivityListener", "服务端关闭连接 $code: $reason")
|
||||
Log.e(TAG, "服务端关闭连接 $code: $reason")
|
||||
}
|
||||
|
||||
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
||||
//服务器中断
|
||||
|
||||
Log.e("ChatMaskActivityListener", "链接错误: " + t.toString() + response.toString())
|
||||
Log.e(TAG, "链接错误: " + t.toString() + response.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,8 +70,8 @@ object AccessibilityUtil {
|
||||
}
|
||||
|
||||
//寻找第一个文本匹配(关键词)并点击
|
||||
fun findTextAndClick(nodeInfo: AccessibilityNodeInfo?, text: String): Boolean {
|
||||
val textView = findOneByText(nodeInfo, text) ?: return false
|
||||
fun findTextAndClick(nodeInfo: AccessibilityNodeInfo?, vararg textList: String): Boolean {
|
||||
val textView = findOneByText(nodeInfo, *textList) ?: return false
|
||||
return performClick(textView)
|
||||
}
|
||||
|
||||
@@ -113,20 +113,20 @@ object AccessibilityUtil {
|
||||
//滚动并按文本寻找第一个控件
|
||||
fun scrollAndFindByText(
|
||||
nodeInfo: AccessibilityNodeInfo,
|
||||
text: String,
|
||||
vararg textList: String,
|
||||
maxRetry: Int = 3
|
||||
): AccessibilityNodeInfo? {
|
||||
var index = 0
|
||||
while (index++ < maxRetry) {
|
||||
performScrollUp(nodeInfo, 0)
|
||||
val node = findOnceByText(nodeInfo, text)
|
||||
val node = findOnceByText(nodeInfo, *textList)
|
||||
if (node != null) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
while (index++ < maxRetry * 2) {
|
||||
performScrollDown(nodeInfo, 0)
|
||||
val node = findOnceByText(nodeInfo, text)
|
||||
val node = findOnceByText(nodeInfo, *textList)
|
||||
if (node != null) {
|
||||
return node
|
||||
}
|
||||
@@ -369,12 +369,12 @@ object AccessibilityUtil {
|
||||
/**
|
||||
* 按文本(关键词)寻找节点和子节点内的一个匹配项
|
||||
* @param node 节点
|
||||
* @param text 关键词
|
||||
* @param textList 关键词
|
||||
* @param timeout 检查超时时间
|
||||
*/
|
||||
fun findOneByText(
|
||||
node: AccessibilityNodeInfo?,
|
||||
text: String,
|
||||
vararg textList: String,
|
||||
exact: Boolean = false,
|
||||
timeout: Long = 5000,
|
||||
root: Boolean = true
|
||||
@@ -383,18 +383,9 @@ object AccessibilityUtil {
|
||||
val startTime = System.currentTimeMillis()
|
||||
var currentTime = startTime
|
||||
while (currentTime - startTime <= timeout) {
|
||||
val textViewList = node.findAccessibilityNodeInfosByText(text)
|
||||
LogUtils.v("text: $text count: " + textViewList.size)
|
||||
if (textViewList != null && textViewList.size > 0) {
|
||||
for (textView in textViewList) {
|
||||
if (textView.text == text) {
|
||||
return textView
|
||||
}
|
||||
}
|
||||
if (!exact) {
|
||||
return textViewList[0]
|
||||
}
|
||||
}
|
||||
val result = findOnceByText(node, *textList, exact = exact)
|
||||
LogUtils.v("text: $textList result == null: ${result == null}")
|
||||
if (result != null) return result
|
||||
sleep(SHORT_INTERVAL)
|
||||
if (root) {
|
||||
node = getRoot(true)
|
||||
@@ -403,43 +394,53 @@ object AccessibilityUtil {
|
||||
}
|
||||
currentTime = System.currentTimeMillis()
|
||||
}
|
||||
Log.e(tag, "findOneByText: not found: $text")
|
||||
Log.e(tag, "findOneByText: not found: $textList")
|
||||
return null
|
||||
}
|
||||
|
||||
fun findOnceByText(
|
||||
node: AccessibilityNodeInfo?,
|
||||
text: String,
|
||||
vararg textList: String,
|
||||
exact: Boolean = false
|
||||
): AccessibilityNodeInfo? {
|
||||
return findOneByText(node, text, exact, 0)
|
||||
if (node == null) return null
|
||||
val textNodeList = findAllOnceByText(node, *textList, exact = exact)
|
||||
LogUtils.v("text: $textList count: " + textNodeList.size)
|
||||
if (exact) return textNodeList[0]
|
||||
else if (textNodeList.size > 0) {
|
||||
for (textNode in textNodeList) {
|
||||
for (text in textList) {
|
||||
if (textNode.text == text) {
|
||||
return textNode
|
||||
}
|
||||
}
|
||||
}
|
||||
return textNodeList[0]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 按文本(关键词)寻找节点和子节点内的所有匹配项
|
||||
* @param node 节点
|
||||
* @param text 关键词
|
||||
* @param textList 关键词
|
||||
* @param timeout 检查超时时间
|
||||
*/
|
||||
fun findAllByText(
|
||||
node: AccessibilityNodeInfo?,
|
||||
text: String,
|
||||
vararg textList: String,
|
||||
exact: Boolean = false,
|
||||
timeout: Long = 5000,
|
||||
root: Boolean = true
|
||||
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 tvList = node.findAccessibilityNodeInfosByText(text)
|
||||
if (tvList != null && tvList.size > 0) {
|
||||
if (!exact) {
|
||||
return tvList
|
||||
} else if (tvList.count { it.text == text } > 0) {
|
||||
return tvList.filter { it.text == text }
|
||||
}
|
||||
}
|
||||
val result = findAllOnceByText(node, *textList, exact = exact)
|
||||
LogUtils.v("text: $textList count: " + result.size)
|
||||
if (result.size >= minSize) return result
|
||||
sleep(SHORT_INTERVAL)
|
||||
if (root) {
|
||||
node = getRoot(true)
|
||||
@@ -448,10 +449,39 @@ object AccessibilityUtil {
|
||||
}
|
||||
currentTime = System.currentTimeMillis()
|
||||
}
|
||||
Log.e(tag, "findAllByText: not found: $text")
|
||||
Log.e(tag, "findAllByText: not found: $textList")
|
||||
return arrayListOf()
|
||||
}
|
||||
|
||||
/**
|
||||
* 按文本(关键词)寻找节点和子节点内的所有匹配项
|
||||
* node 节点
|
||||
* clazz 类名
|
||||
* limitDepth 深度 限制深度搜索深度必须匹配提供值且类名相同才返回 不填默认不限制
|
||||
*/
|
||||
fun findAllOnceByText(
|
||||
node: AccessibilityNodeInfo?,
|
||||
vararg textList: String,
|
||||
exact: Boolean = false,
|
||||
list: ArrayList<AccessibilityNodeInfo> = ArrayList()
|
||||
): ArrayList<AccessibilityNodeInfo> {
|
||||
if (node == null) return list
|
||||
val nodeText = node.text
|
||||
if (nodeText != null) {
|
||||
for (text in textList) {
|
||||
if (exact && nodeText == text) {
|
||||
list.add(node)
|
||||
} else if (!exact && nodeText.contains(text)) {
|
||||
list.add(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i in 0 until node.childCount) {
|
||||
findAllOnceByText(node.getChild(i), *textList, exact = exact, list = list)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 按类名寻找节点和子节点内的一个匹配项
|
||||
* node 节点
|
||||
@@ -468,10 +498,6 @@ object AccessibilityUtil {
|
||||
root: Boolean = true
|
||||
): AccessibilityNodeInfo? {
|
||||
var node = node ?: return null
|
||||
if (node.className == clazz) {
|
||||
if (limitDepth == null || limitDepth == depth)
|
||||
return node
|
||||
}
|
||||
val startTime = System.currentTimeMillis()
|
||||
var currentTime = startTime
|
||||
while (currentTime - startTime <= timeout) {
|
||||
@@ -524,12 +550,11 @@ object AccessibilityUtil {
|
||||
fun findAllByClazz(
|
||||
node: AccessibilityNodeInfo?,
|
||||
clazz: String,
|
||||
list: ArrayList<AccessibilityNodeInfo> = ArrayList(),
|
||||
timeout: Long = 5000,
|
||||
root: Boolean = true,
|
||||
minSize: Int = 1
|
||||
): ArrayList<AccessibilityNodeInfo> {
|
||||
var node = node ?: return list
|
||||
var node = node ?: return arrayListOf()
|
||||
val startTime = System.currentTimeMillis()
|
||||
var currentTime = startTime
|
||||
while (currentTime - startTime <= timeout) {
|
||||
@@ -546,7 +571,7 @@ object AccessibilityUtil {
|
||||
}
|
||||
LogUtils.e("findAllByClazz Exception()")
|
||||
Exception().printStackTrace()
|
||||
return list
|
||||
return arrayListOf()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -568,11 +593,23 @@ object AccessibilityUtil {
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找节点的前兄弟节点 直到该节点满足子节点数
|
||||
* node 节点
|
||||
*/
|
||||
fun findFrontNode(node: AccessibilityNodeInfo?, minChildCount: Int = 0): AccessibilityNodeInfo? {
|
||||
var findFrontNode = findFrontNode(node) ?: return null
|
||||
while (findFrontNode.childCount < minChildCount) {
|
||||
findFrontNode = findFrontNode(findFrontNode) ?: return null
|
||||
}
|
||||
return findFrontNode
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找节点的前兄弟节点
|
||||
* node 节点
|
||||
*/
|
||||
fun findFrontNode(node: AccessibilityNodeInfo?): AccessibilityNodeInfo? {
|
||||
private fun findFrontNode(node: AccessibilityNodeInfo?): AccessibilityNodeInfo? {
|
||||
if (node == null) return null
|
||||
var parent: AccessibilityNodeInfo? = node.parent
|
||||
var son: AccessibilityNodeInfo? = node
|
||||
@@ -593,11 +630,23 @@ object AccessibilityUtil {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找节点的后兄弟节点 直到该节点满足子节点数
|
||||
* node 节点
|
||||
*/
|
||||
fun findBackNode(node: AccessibilityNodeInfo?, minChildCount: Int = 0): AccessibilityNodeInfo? {
|
||||
var findBackNode = findBackNode(node) ?: return null
|
||||
while (findBackNode.childCount < minChildCount) {
|
||||
findBackNode = findFrontNode(findBackNode) ?: return null
|
||||
}
|
||||
return findBackNode
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找节点的后兄弟节点
|
||||
* node 节点
|
||||
*/
|
||||
fun findBackNode(node: AccessibilityNodeInfo?): AccessibilityNodeInfo? {
|
||||
private fun findBackNode(node: AccessibilityNodeInfo?): AccessibilityNodeInfo? {
|
||||
if (node == null) return null
|
||||
var parent: AccessibilityNodeInfo? = node.parent
|
||||
var son: AccessibilityNodeInfo? = node
|
||||
|
||||
@@ -16,12 +16,6 @@ import update.UpdateAppUtils
|
||||
object UpdateUtil {
|
||||
|
||||
fun checkUpdate() {
|
||||
// val remoteVersionCode = 10
|
||||
// val remoteVersionName = "1.0.1"
|
||||
// val forceUpdate = false
|
||||
// val updateLog = "修复Bug\n优化用户体验"
|
||||
// val downloadUrl = "https://down.qq.com/qqweb/QQ_1/android_apk/Android_8.5.0.5025_537066738.apk"
|
||||
// val fileMD5 = "560017dc94e8f9b65f4ca997c7feb326"
|
||||
OkGo.get<String>(Constant.URL_CHECK_UPDATE)
|
||||
.execute(object : StringCallback() {
|
||||
override fun onSuccess(response: Response<String>) {
|
||||
|
||||
@@ -21,22 +21,22 @@ object WeworkRoomUtil {
|
||||
* 房间类型 ROOM_TYPE
|
||||
* @see WeworkMessageBean.ROOM_TYPE
|
||||
*/
|
||||
fun getRoomType(root: AccessibilityNodeInfo, print: Boolean = true): Int {
|
||||
fun getRoomType(print: Boolean = true): Int {
|
||||
val roomTitle = getRoomTitle()
|
||||
when {
|
||||
isExternalSingleChat(root) -> {
|
||||
isExternalSingleChat(roomTitle) -> {
|
||||
LogUtils.d("ROOM_TYPE: ROOM_TYPE_EXTERNAL_CONTACT")
|
||||
return WeworkMessageBean.ROOM_TYPE_EXTERNAL_CONTACT
|
||||
}
|
||||
isGroupChat(root) -> {
|
||||
return if (isExternalGroup(root)) {
|
||||
LogUtils.d("ROOM_TYPE: ROOM_TYPE_EXTERNAL_GROUP")
|
||||
WeworkMessageBean.ROOM_TYPE_EXTERNAL_GROUP
|
||||
} else {
|
||||
LogUtils.d("ROOM_TYPE: ROOM_TYPE_INTERNAL_GROUP")
|
||||
WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP
|
||||
}
|
||||
isExternalGroup() -> {
|
||||
LogUtils.d("ROOM_TYPE: ROOM_TYPE_EXTERNAL_GROUP")
|
||||
return WeworkMessageBean.ROOM_TYPE_EXTERNAL_GROUP
|
||||
}
|
||||
isSingleChat(root) -> {
|
||||
isGroupChat(roomTitle) -> {
|
||||
LogUtils.d("ROOM_TYPE: ROOM_TYPE_INTERNAL_GROUP")
|
||||
return WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP
|
||||
}
|
||||
isSingleChat() -> {
|
||||
LogUtils.d("ROOM_TYPE: ROOM_TYPE_INTERNAL_CONTACT")
|
||||
return WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT
|
||||
}
|
||||
@@ -55,19 +55,23 @@ object WeworkRoomUtil {
|
||||
* @see WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP
|
||||
* @see WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT
|
||||
*/
|
||||
fun getRoomTitle(root: AccessibilityNodeInfo): ArrayList<String> {
|
||||
fun getRoomTitle(print: Boolean = true): ArrayList<String> {
|
||||
val titleList = arrayListOf<String>()
|
||||
val list = AccessibilityUtil.findOnceByClazz(root, Views.ListView)
|
||||
val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView)
|
||||
if (list != null) {
|
||||
val frontNode = findFrontNode(list.parent.parent)
|
||||
val textViewList = findAllOnceByClazz(frontNode, Views.TextView)
|
||||
for (textView in textViewList) {
|
||||
if (!textView.text.isNullOrBlank()) {
|
||||
titleList.add(textView.text.toString().replace("\\(\\d+\\)$".toRegex(), ""))
|
||||
val text = textView.text.toString()
|
||||
titleList.add(text.replace("\\(\\d+\\)$".toRegex(), ""))
|
||||
if (text.contains("\\(\\d+\\)$".toRegex())) {
|
||||
titleList.add(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtils.v("getRoomTitle: ", titleList)
|
||||
if (print) LogUtils.v("getRoomTitle: ", titleList)
|
||||
return titleList
|
||||
}
|
||||
|
||||
@@ -76,8 +80,8 @@ object WeworkRoomUtil {
|
||||
*/
|
||||
fun intoRoom(title: String): Boolean {
|
||||
LogUtils.d("intoRoom(): $title")
|
||||
val titleList = getRoomTitle(getRoot())
|
||||
val roomType = getRoomType(getRoot())
|
||||
val titleList = getRoomTitle(false)
|
||||
val roomType = getRoomType()
|
||||
if (roomType != WeworkMessageBean.ROOM_TYPE_UNKNOWN
|
||||
&& titleList.count {
|
||||
it.replace("…", "").replace("\\(.*?\\)".toRegex(), "") == title.replace("…", "")
|
||||
@@ -96,7 +100,7 @@ object WeworkRoomUtil {
|
||||
val searchButton: AccessibilityNodeInfo = textViewList[textViewList.size - 2]
|
||||
val multiButton: AccessibilityNodeInfo = textViewList[textViewList.size - 1]
|
||||
AccessibilityUtil.performClick(searchButton)
|
||||
AccessibilityUtil.findTextInput(getRoot(), title.replace("…", ""))
|
||||
AccessibilityUtil.findTextInput(getRoot(), title.replace("…", "").replace("-.*$".toRegex(), ""))
|
||||
sleep(Constant.CHANGE_PAGE_INTERVAL)
|
||||
val selectListView = findOneByClazz(getRoot(), Views.ListView)
|
||||
val imageView = AccessibilityUtil.findOnceByClazz(selectListView, Views.ImageView)
|
||||
@@ -195,35 +199,22 @@ object WeworkRoomUtil {
|
||||
|
||||
/**
|
||||
* 是否是群聊
|
||||
* 群右上角有两个按钮(快速会议按钮、更多按钮)
|
||||
* 群名最后有(\d)显示群人数
|
||||
*/
|
||||
private fun isGroupChat(root: AccessibilityNodeInfo): Boolean {
|
||||
val list = AccessibilityUtil.findOnceByClazz(root, Views.ListView)
|
||||
if (list != null) {
|
||||
val frontNode = findFrontNode(list.parent.parent)
|
||||
val textViewList = findAllOnceByClazz(frontNode, Views.TextView)
|
||||
if (textViewList.size >= 2) {
|
||||
val buttonList = findAllOnceByClazz(textViewList.last().parent.parent, Views.TextView)
|
||||
return buttonList.size == 2
|
||||
} else {
|
||||
LogUtils.v("未找到群管理按钮")
|
||||
}
|
||||
} else {
|
||||
LogUtils.d("未找到消息列表")
|
||||
}
|
||||
return false
|
||||
private fun isGroupChat(roomTitle: ArrayList<String>): Boolean {
|
||||
return roomTitle.size > 1 && roomTitle[1].contains("\\(\\d+\\)$".toRegex())
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是外部群
|
||||
* listview前兄弟控件 && text包含外部群
|
||||
*/
|
||||
private fun isExternalGroup(root: AccessibilityNodeInfo): Boolean {
|
||||
val listView = AccessibilityUtil.findOnceByClazz(root, Views.ListView, null, 0)
|
||||
private fun isExternalGroup(): Boolean {
|
||||
val listView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView, null, 0)
|
||||
if (listView != null) {
|
||||
val frontNode = findFrontNode(listView)
|
||||
if (frontNode != null) {
|
||||
val nodeList = AccessibilityUtil.findAllByText(frontNode, "外部群", timeout = 0)
|
||||
val nodeList = AccessibilityUtil.findAllOnceByText(frontNode, "外部群")
|
||||
return nodeList.isNotEmpty()
|
||||
}
|
||||
}
|
||||
@@ -234,9 +225,9 @@ object WeworkRoomUtil {
|
||||
* 是否是单聊
|
||||
* 有列表和输入框
|
||||
*/
|
||||
private fun isSingleChat(root: AccessibilityNodeInfo): Boolean {
|
||||
val list = AccessibilityUtil.findOnceByClazz(root, Views.ListView)
|
||||
val editText = AccessibilityUtil.findOnceByClazz(root, Views.EditText)
|
||||
private fun isSingleChat(): Boolean {
|
||||
val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView)
|
||||
val editText = AccessibilityUtil.findOnceByClazz(getRoot(), Views.EditText)
|
||||
if (list != null && editText != null) {
|
||||
return true
|
||||
}
|
||||
@@ -247,8 +238,7 @@ object WeworkRoomUtil {
|
||||
* 是否是外部单聊
|
||||
* 姓名下面有@xx
|
||||
*/
|
||||
private fun isExternalSingleChat(root: AccessibilityNodeInfo): Boolean {
|
||||
val roomTitle = getRoomTitle(root)
|
||||
private fun isExternalSingleChat(roomTitle: ArrayList<String>): Boolean {
|
||||
return roomTitle.size > 1 && roomTitle.count { it.matches("^[@@].*?".toRegex()) } > 0
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ object WeworkTextUtil {
|
||||
fun longClickMessageItem(
|
||||
node: AccessibilityNodeInfo?,
|
||||
replyTextType: Int,
|
||||
replyNick: String,
|
||||
replyNick: String?,
|
||||
replyContent: String,
|
||||
key: String
|
||||
): Boolean {
|
||||
@@ -290,14 +290,24 @@ object WeworkTextUtil {
|
||||
for (i in 0 until node.childCount) {
|
||||
val item = node.getChild(node.childCount - 1 - i) ?: continue
|
||||
val nameList = getNameList(item)
|
||||
if (nameList.isEmpty()) {
|
||||
val backNode = getMessageListNode(item, WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT)
|
||||
if (backNode != null) {
|
||||
val textNode = AccessibilityUtil.findOnceByText(backNode, replyContent)
|
||||
if (textNode != null) {
|
||||
LogUtils.d("nameList: $nameList\nreplyContent: $replyContent")
|
||||
return longClickMessageItem(item, WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (name in nameList) {
|
||||
if (name == replyNick) {
|
||||
val backNode = getMessageListNode(item)
|
||||
val backNode = getMessageListNode(item, WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP)
|
||||
if (backNode != null) {
|
||||
val textNode = AccessibilityUtil.findOnceByText(backNode, replyContent)
|
||||
if (textNode != null) {
|
||||
LogUtils.d("nameList: $nameList\nreplyContent: $replyContent")
|
||||
return longClickMessageItem(item, key)
|
||||
return longClickMessageItem(item, WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,8 +316,8 @@ object WeworkTextUtil {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun longClickMessageItem(item: AccessibilityNodeInfo, key: String): Boolean {
|
||||
val backNode = getMessageListNode(item)
|
||||
private fun longClickMessageItem(item: AccessibilityNodeInfo, roomType: Int, key: String): Boolean {
|
||||
val backNode = getMessageListNode(item, roomType)
|
||||
AccessibilityUtil.performLongClickWithSon(backNode)
|
||||
val optionRvList = findAllByClazz(getRoot(), Views.RecyclerView)
|
||||
for (optionRv in optionRvList) {
|
||||
@@ -327,10 +337,17 @@ object WeworkTextUtil {
|
||||
* 适用于左侧发言者
|
||||
* @param item 消息item节点
|
||||
*/
|
||||
private fun getMessageListNode(item: AccessibilityNodeInfo): AccessibilityNodeInfo? {
|
||||
val node = AccessibilityUtil.findOnceByClazz(item, Views.ViewGroup)
|
||||
if (node != null) {
|
||||
return AccessibilityUtil.findBackNode(node)
|
||||
private fun getMessageListNode(item: AccessibilityNodeInfo, roomType: Int): AccessibilityNodeInfo? {
|
||||
if (roomType in arrayOf(WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT, WeworkMessageBean.ROOM_TYPE_EXTERNAL_CONTACT)) {
|
||||
val node = AccessibilityUtil.findOnceByClazz(item, Views.ImageView)
|
||||
if (node != null) {
|
||||
return AccessibilityUtil.findBackNode(node)
|
||||
}
|
||||
} else if (roomType in arrayOf(WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP, WeworkMessageBean.ROOM_TYPE_EXTERNAL_GROUP)) {
|
||||
val node = AccessibilityUtil.findOnceByClazz(item, Views.ViewGroup)
|
||||
if (node != null) {
|
||||
return AccessibilityUtil.findBackNode(node)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -150,6 +150,40 @@
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="@dimen/setting_start_padding"
|
||||
android:paddingTop="@dimen/setting_vertical_padding"
|
||||
android:paddingEnd="@dimen/setting_end_padding"
|
||||
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="@dimen/setting_start_padding"
|
||||
android:layout_marginEnd="@dimen/setting_end_padding"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="企业微信版本"
|
||||
android:textColor="@color/color_333333"
|
||||
android:textSize="@dimen/setting_start_font_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_work_version"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="4.0.2"
|
||||
android:textColor="@color/color_999999"
|
||||
android:textSize="@dimen/setting_end_font_size" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -232,6 +266,41 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="@dimen/setting_start_padding"
|
||||
android:paddingTop="@dimen/setting_vertical_padding"
|
||||
android:paddingEnd="@dimen/setting_end_start_padding"
|
||||
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||
|
||||
<Switch
|
||||
android:id="@+id/sw_auto_reply"
|
||||
android:layout_width="@dimen/setting_end_font_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="@dimen/setting_end_start_padding" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="@dimen/setting_start_padding"
|
||||
android:layout_toStartOf="@id/sw_auto_reply"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="开启自动回复"
|
||||
android:textColor="@color/color_333333"
|
||||
android:textSize="@dimen/setting_start_font_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -273,13 +342,13 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/bt_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="50dp"
|
||||
android:paddingEnd="50dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/comment_red_btn"
|
||||
android:id="@+id/bt_save"
|
||||
android:paddingStart="50dp"
|
||||
android:paddingEnd="50dp"
|
||||
android:text="保存" />
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user