update 消息at多人;发送任意文件;修改群备注;优化交互提醒

update ws断开重连时间优化;未登录提示;返回增加关闭关键词
This commit is contained in:
尹甲仑
2022-10-13 17:03:01 +08:00
parent 3273e50399
commit 89752ae328
25 changed files with 842 additions and 206 deletions

View File

@@ -45,6 +45,8 @@ dependencies {
//工具集 //工具集
implementation 'com.blankj:utilcodex:1.31.0' implementation 'com.blankj:utilcodex:1.31.0'
//toast
implementation 'com.github.getActivity:ToastUtils:10.5'
//Gson //Gson
implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.code.gson:gson:2.8.5'
//网络 //网络

View File

@@ -60,6 +60,16 @@
android:resource="@xml/accessibility_service_config" /> android:resource="@xml/accessibility_service_config" />
</service> </service>
<provider
android:name=".utils.GenericFileProvider"
android:authorities="org.yameida.worktool.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<meta-data android:name="TD_APP_ID" android:value="80E9C84E39904DAFB28562910FF7C86C" /> <meta-data android:name="TD_APP_ID" android:value="80E9C84E39904DAFB28562910FF7C86C" />
<meta-data android:name="TD_CHANNEL_ID" android:value="worktool_master" /> <meta-data android:name="TD_CHANNEL_ID" android:value="worktool_master" />
</application> </application>

View File

@@ -22,77 +22,6 @@ object Demo {
//打印当前视图树 //打印当前视图树
// AccessibilityUtil.printNodeClazzTree(getRoot()) // AccessibilityUtil.printNodeClazzTree(getRoot())
//获取群二维码
// WeworkOperationImpl.getGroupQrcode("测试群01")
//手机号添加好友
// WeworkOperationImpl.addFriendByPhone(WeworkMessageBean.Friend().apply {
// this.phone = "13010001000"
// this.markName = "hhh"
// this.markCorp = "corp"
// this.markExtra = "ex"
// this.tagList = arrayListOf("tag1", "tag2")
// })
//自动通过好友
// WeworkLoopImpl.getFriendRequest()
//自动通过好友(后台可配置开关)
// WeworkLoopImpl.mainLoop()
//创建群信息
// WeworkController.initGroup(WeworkMessageBean().apply {
// groupName = "新建外部群 " + UUID.randomUUID().toString().substring(0, 5)
// selectList = arrayListOf("冯燕", "尹甲仑")
// groupAnnouncement = "本群为雨花台区法院诉前调解官方微信群"
// })
//修改群信息
// WeworkController.intoGroupAndConfig(WeworkMessageBean().apply {
// groupName = "新建外部群 " + UUID.randomUUID().toString().substring(0, 5)
// selectList = arrayListOf("冯燕", "尹甲仑")
// groupAnnouncement = "本群为雨花台区法院诉前调解官方微信群"
// })
//获取群信息
// WeworkController.getGroupInfo(WeworkMessageBean().apply {
// selectList = arrayListOf("企微RPA机器人自测1")
// })
//在房间内发送消息
// WeworkController.sendMessage(WeworkMessageBean().apply {
// titleList = arrayListOf("下级群1", "上级群1")
// receivedContent = "aaa"
// })
//获取我的信息
// WeworkController.getMyInfo()
//推送任意小程序
// WeworkController.pushMicroprogram(WeworkMessageBean().apply {
// titleList = arrayListOf("尹甲仑")
// objectName = "小法名律"
// extraText = "123"
// })
//推送微盘图片
// WeworkController.pushMicroDiskImage(WeworkMessageBean().apply {
// titleList = arrayListOf("尹甲仑")
// objectName = "雨水.jpg"
// })
//推送微盘文件
// WeworkController.pushMicroDiskFile(WeworkMessageBean().apply {
// titleList = arrayListOf("尹甲仑")
// objectName = "雨水.jpg"
// })
//推送腾讯文档
// WeworkController.pushOffice(WeworkMessageBean().apply {
// titleList = arrayListOf("尹甲仑")
// objectName = "机器人中台"
// extraText = "附加留言"
// })
} }
fun test2(name: String) { fun test2(name: String) {

View File

@@ -1,8 +1,12 @@
package org.yameida.worktool package org.yameida.worktool
import android.app.Application import android.app.Application
import android.content.Intent
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.SPUtils import com.blankj.utilcode.util.SPUtils
import com.blankj.utilcode.util.Utils import com.blankj.utilcode.util.Utils
import com.efs.sdk.base.core.util.PackageUtil
import com.hjq.toast.ToastUtils
import com.tendcloud.tenddata.TalkingDataSDK import com.tendcloud.tenddata.TalkingDataSDK
import com.umeng.commonsdk.UMConfigure import com.umeng.commonsdk.UMConfigure
import org.yameida.worktool.config.GlobalException import org.yameida.worktool.config.GlobalException
@@ -10,15 +14,34 @@ import update.UpdateAppUtils
class MyApplication : Application() { class MyApplication : Application() {
companion object {
/**
* 回到WorkTool首页 需要先授权显示悬浮窗
*/
fun launchIntent() {
LogUtils.e("进入WorkTool APP~")
val app = Utils.getApp()
app.packageManager.getLaunchIntentForPackage(PackageUtil.getPackageName(app))?.apply {
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK
app.startActivity(this)
}
}
}
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
//初始化工具类 //初始化工具类
Utils.init(this) Utils.init(this)
//初始化 Toast 框架
ToastUtils.init(this)
//初始化友盟统计 //初始化友盟统计
UMConfigure.preInit(this, "6284a3a3d024421570f97c3c", "main_channel") val key = "6284a3a3d024421570f97c3c"
val channel = "main_channel"
UMConfigure.preInit(this, key, channel)
//判断是否同意隐私协议uminit为1时为已经同意直接初始化umsdk //判断是否同意隐私协议uminit为1时为已经同意直接初始化umsdk
if (SPUtils.getInstance().getString("uminit", "1") == "1") { if (SPUtils.getInstance().getString("uminit", "1") == "1") {
UMConfigure.init(this, "6284a3a3d024421570f97c3c", "main_channel", UMConfigure.DEVICE_TYPE_PHONE, "") UMConfigure.init(this, key, channel, UMConfigure.DEVICE_TYPE_PHONE, "")
} }
TalkingDataSDK.init(this, "80E9C84E39904DAFB28562910FF7C86C", "worktool_master", SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID)); TalkingDataSDK.init(this, "80E9C84E39904DAFB28562910FF7C86C", "worktool_master", SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID));
//初始化自动更新 //初始化自动更新

View File

@@ -1,10 +1,7 @@
package org.yameida.worktool.activity package org.yameida.worktool.activity
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import android.text.TextUtils.SimpleStringSplitter
import android.view.WindowManager import android.view.WindowManager
import android.widget.CompoundButton import android.widget.CompoundButton
import android.widget.Switch import android.widget.Switch
@@ -17,8 +14,12 @@ import org.yameida.worktool.*
import org.yameida.worktool.service.WeworkService import org.yameida.worktool.service.WeworkService
import org.yameida.worktool.utils.UpdateUtil import org.yameida.worktool.utils.UpdateUtil
import android.app.Dialog import android.app.Dialog
import android.content.*
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yameida.worktool.utils.PermissionHelper
import org.yameida.worktool.utils.PermissionPageManagement
class ListenActivity : AppCompatActivity() { class ListenActivity : AppCompatActivity() {
@@ -32,16 +33,28 @@ class ListenActivity : AppCompatActivity() {
initView() initView()
initAccessibility() initAccessibility()
initOverlays()
UpdateUtil.checkUpdate() UpdateUtil.checkUpdate()
PermissionUtils.permission("android.permission.READ_EXTERNAL_STORAGE").request() PermissionUtils.permission("android.permission.READ_EXTERNAL_STORAGE").request()
registerReceiver(openWsReceiver, IntentFilter(Constant.WEWORK_NOTIFY))
} }
override fun onStart() { override fun onDestroy() {
super.onStart() super.onDestroy()
unregisterReceiver(openWsReceiver)
}
override fun onResume() {
super.onResume()
sw_overlay.isChecked = PermissionUtils.isGrantedDrawOverlays()
freshOpenServiceSwitch( freshOpenServiceSwitch(
WeworkService::class.java, WeworkService::class.java,
sw_accessibility sw_accessibility
) )
if (needToWork) {
needToWork = false
goToWork()
}
} }
private fun initView() { private fun initView() {
@@ -102,11 +115,11 @@ class ListenActivity : AppCompatActivity() {
if (SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID).isNullOrBlank()) { if (SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID).isNullOrBlank()) {
sw_accessibility.isChecked = false sw_accessibility.isChecked = false
ToastUtils.showLong("请先填写并保存链接号~") ToastUtils.showLong("请先填写并保存链接号~")
} else if (!isAccessibilitySettingOn()) { } else if (!PermissionHelper.isAccessibilitySettingOn()) {
openAccessibility() openAccessibility()
} }
} else { } else {
if (isAccessibilitySettingOn()) { if (PermissionHelper.isAccessibilitySettingOn()) {
sw_accessibility.isChecked = true sw_accessibility.isChecked = true
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
startActivity(intent) startActivity(intent)
@@ -115,39 +128,27 @@ class ListenActivity : AppCompatActivity() {
}) })
} }
private fun isAccessibilitySettingOn(): Boolean { private fun initOverlays() {
val context = Utils.getApp() sw_overlay.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
var enable = 0 LogUtils.i("sw_overlay onCheckedChanged: $isChecked")
val serviceName = context.packageName + "/" + WeworkService::class.java.canonicalName if (isChecked) {
LogUtils.i("isAccessibilitySettingOn: $serviceName") if (!PermissionUtils.isGrantedDrawOverlays()) {
try { PermissionUtils.requestDrawOverlays(object : PermissionUtils.SimpleCallback {
enable = Settings.Secure.getInt( override fun onGranted() {
context.contentResolver, ToastUtils.showLong("请同时打开后台弹出界面权限~")
Settings.Secure.ACCESSIBILITY_ENABLED, PermissionPageManagement.goToSetting(this@ListenActivity)
0 }
)
} catch (e: Exception) { override fun onDenied() { sw_accessibility.isChecked = false }
e.printStackTrace() })
} }
if (enable == 1) { } else {
val stringSplitter = SimpleStringSplitter(':') if (PermissionUtils.isGrantedDrawOverlays()) {
val settingVal = Settings.Secure.getString( sw_overlay.isChecked = true
context.contentResolver, PermissionPageManagement.goToSetting(this)
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
)
if (settingVal != null) {
stringSplitter.setString(settingVal)
while (stringSplitter.hasNext()) {
val accessibilityService = stringSplitter.next()
if (accessibilityService == serviceName) {
LogUtils.i("isAccessibilitySettingOn: true")
return true
}
} }
} }
} })
LogUtils.i("isAccessibilitySettingOn: false")
return false
} }
/** /**
@@ -185,7 +186,7 @@ class ListenActivity : AppCompatActivity() {
} }
private fun freshOpenServiceSwitch(clazz: Class<*>, s: Switch) { private fun freshOpenServiceSwitch(clazz: Class<*>, s: Switch) {
if (isAccessibilitySettingOn()) { if (PermissionHelper.isAccessibilitySettingOn()) {
s.isChecked = true s.isChecked = true
when (s.id) { when (s.id) {
R.id.sw_accessibility -> { R.id.sw_accessibility -> {
@@ -205,6 +206,7 @@ class ListenActivity : AppCompatActivity() {
val commentDialog = Dialog(this) val commentDialog = Dialog(this)
commentDialog.setContentView(R.layout.dialog_input) commentDialog.setContentView(R.layout.dialog_input)
val et: EditText = commentDialog.findViewById(R.id.body) as EditText val et: EditText = commentDialog.findViewById(R.id.body) as EditText
et.setText(tv_host.text)
val okBtn: Button = commentDialog.findViewById(R.id.ok) as Button val okBtn: Button = commentDialog.findViewById(R.id.ok) as Button
okBtn.setOnClickListener { okBtn.setOnClickListener {
val text = et.text.toString() val text = et.text.toString()
@@ -228,4 +230,32 @@ class ListenActivity : AppCompatActivity() {
commentDialog.show() commentDialog.show()
} }
private var needToWork = false
private fun goToWork() {
val positiveButton =
MaterialAlertDialogBuilder(this, R.style.Theme_MaterialComponents_DayNight_Dialog)
.setTitle("设置成功")
.setMessage("请勿人工操作手机 \n5秒后自动跳转")
.setNegativeButton("", null)
.setPositiveButton("", null)
val show = positiveButton.show()
bt_save.postDelayed({ show.dismiss() }, 5000)
bt_save.postDelayed({
packageManager.getLaunchIntentForPackage(Constant.PACKAGE_NAMES)?.apply {
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(this)
}
com.hjq.toast.ToastUtils.show("机器人运行中 请勿人工操作手机~")
}, 5000)
}
private val openWsReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.getStringExtra("type") == "openWs") {
needToWork = intent.getBooleanExtra("switch", false)
}
}
}
} }

View File

@@ -0,0 +1,18 @@
package org.yameida.worktool.model
import java.util.*
data class ExecCallbackBean(
//原生消息指令
var rawMsg: String? = null,
//1成功 0失败
var rawSuccess: Int = 0,
//失败原因
var errorReason: String = "",
//执行时间
var runTime: Date = Date()
) : WeworkMessageBean()

View File

@@ -30,6 +30,7 @@ public class WeworkMessageBean {
* 通过当前所有好友请求 PASS_ALL_FRIEND_REQUEST * 通过当前所有好友请求 PASS_ALL_FRIEND_REQUEST
* 按手机号添加好友 ADD_FRIEND_BY_PHONE * 按手机号添加好友 ADD_FRIEND_BY_PHONE
* 展示群信息 SHOW_GROUP_INFO * 展示群信息 SHOW_GROUP_INFO
* 推送文件(网络图片视频和文件等) PUSH_FILE
* <p> * <p>
* 非操作类型 300 * 非操作类型 300
* 机器人普通日志记录 ROBOT_LOG * 机器人普通日志记录 ROBOT_LOG
@@ -61,6 +62,7 @@ public class WeworkMessageBean {
public static final int INIT_ANTI_HARASSMENT_RULE = 215; public static final int INIT_ANTI_HARASSMENT_RULE = 215;
public static final int UPDATE_ANTI_HARASSMENT_RULE = 216; public static final int UPDATE_ANTI_HARASSMENT_RULE = 216;
public static final int DELETED_ANTI_HARASSMENT_RULE = 217; public static final int DELETED_ANTI_HARASSMENT_RULE = 217;
public static final int PUSH_FILE = 218;
public static final int ROBOT_LOG = 301; public static final int ROBOT_LOG = 301;
public static final int ROBOT_ERROR_LOG = 302; public static final int ROBOT_ERROR_LOG = 302;
@@ -126,6 +128,9 @@ public class WeworkMessageBean {
public static final int TEXT_TYPE_COLLECTION = 14; public static final int TEXT_TYPE_COLLECTION = 14;
public static final int TEXT_TYPE_REPLY = 15; public static final int TEXT_TYPE_REPLY = 15;
//消息id(解析指令时同步)
public String messageId;
//标题 通常是群名或联系人 //标题 通常是群名或联系人
public List<String> titleList; public List<String> titleList;
//上传聊天列表 //上传聊天列表
@@ -141,6 +146,8 @@ public class WeworkMessageBean {
public String receivedContent; public String receivedContent;
//想要at的昵称 //想要at的昵称
public String at; public String at;
//想要at的昵称列表
public List<String> atList;
//原始内容text //原始内容text
public String originalContent; public String originalContent;
//多选(转发等) //多选(转发等)
@@ -160,6 +167,10 @@ public class WeworkMessageBean {
public Integer groupNumber; public Integer groupNumber;
//群公告 //群公告
public String groupAnnouncement; public String groupAnnouncement;
//群备注
public String groupRemark;
//群模板
public String groupTemplate;
//新群名 //新群名
public String newGroupName; public String newGroupName;
//新群公告 //新群公告
@@ -178,6 +189,10 @@ public class WeworkMessageBean {
//添加好友 //添加好友
public Friend friend; public Friend friend;
//网络文件
public String fileUrl;
public String fileType;
public WeworkMessageBean() {} public WeworkMessageBean() {}
public WeworkMessageBean(String receivedName, String receivedContent, int type, Integer roomType, List<String> titleList, List<SubMessageBean> messageList, String log) { public WeworkMessageBean(String receivedName, String receivedContent, int type, Integer roomType, List<String> titleList, List<SubMessageBean> messageList, String log) {
@@ -190,6 +205,7 @@ public class WeworkMessageBean {
this.receivedName = receivedName; this.receivedName = receivedName;
} }
//消息类型
public int type = 0; public int type = 0;
//消息列表的每条消息 //消息列表的每条消息
@@ -254,6 +270,19 @@ public class WeworkMessageBean {
public Boolean newFriend; public Boolean newFriend;
//留言 //留言
public String leavingMsg; public String leavingMsg;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Friend friend = (Friend) o;
return Objects.equals(phone, friend.phone) && Objects.equals(name, friend.name) && Objects.equals(markName, friend.markName) && Objects.equals(markCorp, friend.markCorp) && Objects.equals(markExtra, friend.markExtra) && Objects.equals(tagList, friend.tagList) && Objects.equals(newFriend, friend.newFriend) && Objects.equals(leavingMsg, friend.leavingMsg);
}
@Override
public int hashCode() {
return Objects.hash(phone, name, markName, markCorp, markExtra, tagList, newFriend, leavingMsg);
}
} }
@Override @Override
@@ -261,12 +290,12 @@ public class WeworkMessageBean {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
WeworkMessageBean that = (WeworkMessageBean) o; WeworkMessageBean that = (WeworkMessageBean) o;
return textType == that.textType && showMessageHistory == that.showMessageHistory && type == that.type && Objects.equals(titleList, that.titleList) && Objects.equals(messageList, that.messageList) && Objects.equals(log, that.log) && Objects.equals(roomType, that.roomType) && Objects.equals(receivedName, that.receivedName) && Objects.equals(receivedContent, that.receivedContent) && Objects.equals(originalContent, that.originalContent) && Objects.equals(nameList, that.nameList) && Objects.equals(extraText, that.extraText) && Objects.equals(groupName, that.groupName) && Objects.equals(groupOwner, that.groupOwner) && Objects.equals(selectList, that.selectList) && Objects.equals(groupNumber, that.groupNumber) && Objects.equals(groupAnnouncement, that.groupAnnouncement) && Objects.equals(newGroupName, that.newGroupName) && Objects.equals(newGroupAnnouncement, that.newGroupAnnouncement) && Objects.equals(removeList, that.removeList) && Objects.equals(myInfo, that.myInfo) && Objects.equals(objectName, that.objectName); return textType == that.textType && showMessageHistory == that.showMessageHistory && type == that.type && Objects.equals(titleList, that.titleList) && Objects.equals(messageList, that.messageList) && Objects.equals(log, that.log) && Objects.equals(roomType, that.roomType) && Objects.equals(receivedName, that.receivedName) && Objects.equals(receivedContent, that.receivedContent) && Objects.equals(at, that.at) && Objects.equals(atList, that.atList) && Objects.equals(originalContent, that.originalContent) && Objects.equals(nameList, that.nameList) && Objects.equals(extraText, that.extraText) && Objects.equals(groupName, that.groupName) && Objects.equals(groupOwner, that.groupOwner) && Objects.equals(selectList, that.selectList) && Objects.equals(groupNumber, that.groupNumber) && Objects.equals(groupAnnouncement, that.groupAnnouncement) && Objects.equals(groupRemark, that.groupRemark) && Objects.equals(groupTemplate, that.groupTemplate) && Objects.equals(newGroupName, that.newGroupName) && Objects.equals(newGroupAnnouncement, that.newGroupAnnouncement) && Objects.equals(removeList, that.removeList) && Objects.equals(myInfo, that.myInfo) && Objects.equals(objectName, that.objectName) && Objects.equals(qrcode, that.qrcode) && Objects.equals(friend, that.friend) && Objects.equals(fileUrl, that.fileUrl) && Objects.equals(fileType, that.fileType);
} }
@Override @Override
public int hashCode() { 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, friend); return Objects.hash(titleList, messageList, log, roomType, receivedName, receivedContent, at, atList, originalContent, nameList, extraText, textType, groupName, groupOwner, selectList, groupNumber, groupAnnouncement, groupRemark, groupTemplate, newGroupName, newGroupAnnouncement, removeList, showMessageHistory, myInfo, objectName, qrcode, friend, fileUrl, fileType, type);
} }
@Override @Override
@@ -278,6 +307,8 @@ public class WeworkMessageBean {
", roomType=" + roomType + ", roomType=" + roomType +
", receivedName='" + receivedName + '\'' + ", receivedName='" + receivedName + '\'' +
", receivedContent='" + receivedContent + '\'' + ", receivedContent='" + receivedContent + '\'' +
", at='" + at + '\'' +
", atList=" + atList +
", originalContent='" + originalContent + '\'' + ", originalContent='" + originalContent + '\'' +
", nameList=" + nameList + ", nameList=" + nameList +
", extraText='" + extraText + '\'' + ", extraText='" + extraText + '\'' +
@@ -287,12 +318,18 @@ public class WeworkMessageBean {
", selectList=" + selectList + ", selectList=" + selectList +
", groupNumber=" + groupNumber + ", groupNumber=" + groupNumber +
", groupAnnouncement='" + groupAnnouncement + '\'' + ", groupAnnouncement='" + groupAnnouncement + '\'' +
", groupRemark='" + groupRemark + '\'' +
", groupTemplate='" + groupTemplate + '\'' +
", newGroupName='" + newGroupName + '\'' + ", newGroupName='" + newGroupName + '\'' +
", newGroupAnnouncement='" + newGroupAnnouncement + '\'' + ", newGroupAnnouncement='" + newGroupAnnouncement + '\'' +
", removeList=" + removeList + ", removeList=" + removeList +
", showMessageHistory=" + showMessageHistory + ", showMessageHistory=" + showMessageHistory +
", myInfo=" + myInfo + ", myInfo=" + myInfo +
", objectName='" + objectName + '\'' + ", objectName='" + objectName + '\'' +
", qrcode='" + qrcode + '\'' +
", friend=" + friend +
", fileUrl='" + fileUrl + '\'' +
", fileType='" + fileType + '\'' +
", type=" + type + ", type=" + type +
'}'; '}';
} }

View File

@@ -7,12 +7,13 @@ import org.yameida.worktool.Constant
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class WeworkMessageListBean { class WeworkMessageListBean<T> {
companion object { companion object {
const val SOCKET_TYPE_HEARTBEAT = 0 const val SOCKET_TYPE_HEARTBEAT = 0
const val SOCKET_TYPE_MESSAGE_CONFIRM = 1 const val SOCKET_TYPE_MESSAGE_CONFIRM = 1
const val SOCKET_TYPE_MESSAGE_LIST = 2 const val SOCKET_TYPE_MESSAGE_LIST = 2
const val SOCKET_TYPE_RAW_CONFIRM = 3
} }
/** /**
@@ -20,6 +21,7 @@ class WeworkMessageListBean {
* TYPE_HEARTBEAT 心跳检测 * TYPE_HEARTBEAT 心跳检测
* TYPE_MESSAGE_CONFIRM 消息确认 * TYPE_MESSAGE_CONFIRM 消息确认
* TYPE_MESSAGE_LIST 消息列表 * TYPE_MESSAGE_LIST 消息列表
* SOCKET_TYPE_RAW_CONFIRM 执行指令结果确认
*/ */
var socketType = SOCKET_TYPE_HEARTBEAT var socketType = SOCKET_TYPE_HEARTBEAT
@@ -27,7 +29,7 @@ class WeworkMessageListBean {
var messageId = TimeUtils.date2String(Date()).replace(" ", "#") + "#" + UUID.randomUUID() var messageId = TimeUtils.date2String(Date()).replace(" ", "#") + "#" + UUID.randomUUID()
//消息列表 //消息列表
var list: ArrayList<WeworkMessageBean> = arrayListOf() var list: ArrayList<T> = arrayListOf()
//加密消息列表 //加密消息列表
var encryptedList: String = "" var encryptedList: String = ""
@@ -35,7 +37,7 @@ class WeworkMessageListBean {
//消息加密 0不加密 1AES //消息加密 0不加密 1AES
var encryptType = Constant.encryptType var encryptType = Constant.encryptType
constructor(weworkMessageBean: WeworkMessageBean, type: Int) { constructor(weworkMessageBean: T, type: Int, messageId: String? = null) {
if (encryptType == 0) { if (encryptType == 0) {
list.add(weworkMessageBean) list.add(weworkMessageBean)
} else if (encryptType == 1) { } else if (encryptType == 1) {
@@ -47,6 +49,7 @@ class WeworkMessageListBean {
) )
} }
this.socketType = type this.socketType = type
if (messageId != null) this.messageId = messageId
} }
constructor(messageId: String, type: Int) { constructor(messageId: String, type: Int) {
@@ -54,17 +57,4 @@ class WeworkMessageListBean {
this.socketType = type this.socketType = type
} }
constructor(weworkMessageBeanList: List<WeworkMessageBean>, type: Int) {
if (encryptType == 0) {
list.addAll(weworkMessageBeanList)
} else if (encryptType == 1) {
encryptedList = EncryptUtils.encryptAES2HexString(
GsonUtils.toJson(weworkMessageBeanList).toByteArray(),
Constant.key,
Constant.transformation,
Constant.iv
)
}
this.socketType = type
}
} }

View File

@@ -5,7 +5,10 @@ import android.view.accessibility.AccessibilityNodeInfo
import com.blankj.utilcode.util.GsonUtils import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ScreenUtils import com.blankj.utilcode.util.ScreenUtils
import com.hjq.toast.ToastUtils
import org.yameida.worktool.Constant import org.yameida.worktool.Constant
import org.yameida.worktool.MyApplication
import org.yameida.worktool.model.ExecCallbackBean
import org.yameida.worktool.model.WeworkMessageBean import org.yameida.worktool.model.WeworkMessageBean
import org.yameida.worktool.model.WeworkMessageListBean import org.yameida.worktool.model.WeworkMessageListBean
import org.yameida.worktool.utils.AccessibilityUtil import org.yameida.worktool.utils.AccessibilityUtil
@@ -54,6 +57,13 @@ fun goHomeTab(title: String): Boolean {
} }
if (!atHome) { if (!atHome) {
backPress() backPress()
//如果在登录页面就提示关闭worktool主功能
if (AccessibilityUtil.findOnceByText(getRoot(), "手机号登录", exact = true) != null) {
LogUtils.e("登录前请先关闭WorkTool主功能")
ToastUtils.show("登录前请先关闭WorkTool主功能")
MyApplication.launchIntent()
sleep(5000)
}
} }
} }
LogUtils.v("进入首页-${title}") LogUtils.v("进入首页-${title}")
@@ -135,7 +145,20 @@ fun backPress() {
} }
/** /**
* 上传运行日志 简单封装 info log * 上传执行指令结果
*/
fun uploadCommandResult(message: WeworkMessageBean, success: Boolean, reason: String) {
WeworkController.weworkService.webSocketManager.send(
WeworkMessageListBean(
ExecCallbackBean(GsonUtils.toJson(message), if (success) 1 else 0, reason),
WeworkMessageListBean.SOCKET_TYPE_RAW_CONFIRM,
messageId = message.messageId
), true
)
}
/**
* 上传运行日志
*/ */
fun log(message: Any?, type: Int = WeworkMessageBean.ROBOT_LOG) { fun log(message: Any?, type: Int = WeworkMessageBean.ROBOT_LOG) {
WeworkController.weworkService.webSocketManager.send( WeworkController.weworkService.webSocketManager.send(
@@ -154,7 +177,7 @@ fun log(message: Any?, type: Int = WeworkMessageBean.ROBOT_LOG) {
} }
/** /**
* 上传运行日志 简单封装 error log * 上传运行日志
*/ */
fun error(message: Any?) { fun error(message: Any?) {
log(message, WeworkMessageBean.ROBOT_ERROR_LOG) log(message, WeworkMessageBean.ROBOT_ERROR_LOG)

View File

@@ -46,12 +46,13 @@ object MyLooper {
while (true) { while (true) {
threadHandler?.let { return it } threadHandler?.let { return it }
LogUtils.e("threadHandler is not ready...") LogUtils.e("threadHandler is not ready...")
sleep(Constant.POP_WINDOW_INTERVAL / 5)
} }
} }
fun onMessage(webSocket: WebSocket?, text: String) { fun onMessage(webSocket: WebSocket?, text: String) {
val messageList = val messageList: WeworkMessageListBean<WeworkMessageBean> =
GsonUtils.fromJson<WeworkMessageListBean>(text, WeworkMessageListBean::class.java) GsonUtils.fromJson<WeworkMessageListBean<WeworkMessageBean>>(text, object : TypeToken<WeworkMessageListBean<WeworkMessageBean>>(){}.type)
if (messageList.socketType == WeworkMessageListBean.SOCKET_TYPE_HEARTBEAT) { if (messageList.socketType == WeworkMessageListBean.SOCKET_TYPE_HEARTBEAT) {
return return
} }
@@ -82,7 +83,7 @@ object MyLooper {
WeworkController.mainLoopRunning = false WeworkController.mainLoopRunning = false
getInstance().sendMessage(Message.obtain().apply { getInstance().sendMessage(Message.obtain().apply {
what = message.type * message.hashCode() what = message.type * message.hashCode()
obj = message obj = message.apply { messageId = messageList.messageId }
}) })
} }
getInstance().removeMessages(WeworkMessageBean.LOOP_RECEIVE_NEW_MESSAGE) getInstance().removeMessages(WeworkMessageBean.LOOP_RECEIVE_NEW_MESSAGE)
@@ -129,6 +130,9 @@ object MyLooper {
WeworkMessageBean.PUSH_OFFICE -> { WeworkMessageBean.PUSH_OFFICE -> {
WeworkController.pushOffice(message) WeworkController.pushOffice(message)
} }
WeworkMessageBean.PUSH_FILE -> {
WeworkController.pushFile(message)
}
WeworkMessageBean.PASS_ALL_FRIEND_REQUEST -> { WeworkMessageBean.PASS_ALL_FRIEND_REQUEST -> {
} }
WeworkMessageBean.ADD_FRIEND_BY_PHONE -> { WeworkMessageBean.ADD_FRIEND_BY_PHONE -> {

View File

@@ -47,8 +47,8 @@ object WeworkController {
*/ */
@RequestMapping @RequestMapping
fun sendMessage(message: WeworkMessageBean): Boolean { fun sendMessage(message: WeworkMessageBean): Boolean {
LogUtils.d("sendMessage(): ${message.titleList} ${message.receivedContent} ${message.at}") LogUtils.d("sendMessage(): ${message.titleList} ${message.receivedContent} ${message.at} ${message.atList?.joinToString()}")
return WeworkOperationImpl.sendMessage(message.titleList, message.receivedContent, message.at) return WeworkOperationImpl.sendMessage(message.titleList, message.receivedContent, message.at, message.atList)
} }
/** /**
@@ -103,14 +103,16 @@ object WeworkController {
* @param message#groupName 修改群名称 * @param message#groupName 修改群名称
* @param message#selectList 添加群成员名称列表 选填 * @param message#selectList 添加群成员名称列表 选填
* @param message#groupAnnouncement 修改群公告 选填 * @param message#groupAnnouncement 修改群公告 选填
* @param message#groupRemark 修改群备注 选填
*/ */
@RequestMapping @RequestMapping
fun initGroup(message: WeworkMessageBean): Boolean { fun initGroup(message: WeworkMessageBean): Boolean {
LogUtils.d("initGroup(): ${message.groupName} ${message.selectList} ${message.groupAnnouncement}") LogUtils.d("initGroup(): ${message.groupName} ${message.selectList} ${message.groupAnnouncement} ${message.groupRemark}")
return WeworkOperationImpl.initGroup( return WeworkOperationImpl.initGroup(
message.groupName, message.groupName,
message.selectList, message.selectList,
message.groupAnnouncement message.groupAnnouncement,
message.groupRemark
) )
} }
@@ -131,17 +133,19 @@ object WeworkController {
* @param message#groupName 待修改的群 * @param message#groupName 待修改的群
* @param message#newGroupName 修改群名 选填 * @param message#newGroupName 修改群名 选填
* @param message#newGroupAnnouncement 修改群公告 选填 * @param message#newGroupAnnouncement 修改群公告 选填
* @param message#groupRemark 修改群备注 选填
* @param message#selectList 添加群成员名称列表/拉人 选填 * @param message#selectList 添加群成员名称列表/拉人 选填
* @param message#showMessageHistory 拉人是否附带历史记录 选填 * @param message#showMessageHistory 拉人是否附带历史记录 选填
* @param message#removeList 移除群成员名称列表/踢人 选填 * @param message#removeList 移除群成员名称列表/踢人 选填
*/ */
@RequestMapping @RequestMapping
fun intoGroupAndConfig(message: WeworkMessageBean): Boolean { fun intoGroupAndConfig(message: WeworkMessageBean): Boolean {
LogUtils.d("intoGroupAndConfig(): ${message.groupName} ${message.newGroupName} ${message.newGroupAnnouncement} ${message.selectList} ${message.showMessageHistory} ${message.removeList}") LogUtils.d("intoGroupAndConfig(): ${message.groupName} ${message.newGroupName} ${message.newGroupAnnouncement} ${message.selectList} ${message.showMessageHistory} ${message.removeList} ${message.groupRemark}")
return WeworkOperationImpl.intoGroupAndConfig( return WeworkOperationImpl.intoGroupAndConfig(
message.groupName, message.groupName,
message.newGroupName, message.newGroupName,
message.newGroupAnnouncement, message.newGroupAnnouncement,
message.groupRemark,
message.selectList, message.selectList,
message.showMessageHistory, message.showMessageHistory,
message.removeList message.removeList
@@ -217,6 +221,27 @@ object WeworkController {
) )
} }
/**
* 推送文件(网络图片视频和文件等)
* @see WeworkMessageBean.PUSH_FILE
* @param message#titleList 待发送姓名列表
* @param message#objectName 文件名称
* @param message#fileUrl 文件网络地址
* @param message#fileType 文件类型
* @param message#extraText 附加留言 可选
*/
@RequestMapping
fun pushFile(message: WeworkMessageBean): Boolean {
LogUtils.d("pushFile(): ${message.titleList} ${message.objectName} ${message.fileUrl} ${message.fileType} ${message.extraText}")
return WeworkOperationImpl.pushFile(
message.titleList,
message.objectName,
message.fileUrl,
message.fileType,
message.extraText
)
}
/** /**
* 按手机号添加好友 * 按手机号添加好友
* @see WeworkMessageBean.ADD_FRIEND_BY_PHONE * @see WeworkMessageBean.ADD_FRIEND_BY_PHONE

View File

@@ -139,7 +139,7 @@ object WeworkGetImpl {
} }
/** /**
* 获取群名、群主、群成员数、群公告 * 获取群名、群主、群成员数、群公告、群备注
*/ */
fun getGroupInfoDetail(): WeworkMessageBean { fun getGroupInfoDetail(): WeworkMessageBean {
val weworkMessageBean = WeworkMessageBean() val weworkMessageBean = WeworkMessageBean()
@@ -188,6 +188,12 @@ object WeworkGetImpl {
LogUtils.d("群公告: " + tvAnnouncement.text) LogUtils.d("群公告: " + tvAnnouncement.text)
weworkMessageBean.groupAnnouncement = tvAnnouncement.text.toString() weworkMessageBean.groupAnnouncement = tvAnnouncement.text.toString()
} }
val tvRemarkFlag = AccessibilityUtil.findOnceByText(getRoot(), "备注", exact = true)
val tvRemark = AccessibilityUtil.findOnceByClazz(AccessibilityUtil.findBackNode(tvRemarkFlag), Views.TextView)
if (tvRemark != null && tvRemark.text != null) {
LogUtils.d("群备注: " + tvRemark.text)
weworkMessageBean.groupRemark = tvRemark.text.toString()
}
backPress() backPress()
return weworkMessageBean return weworkMessageBean
} }

View File

@@ -73,7 +73,7 @@ object WeworkLoopImpl {
if (nameList.isEmpty()) if (nameList.isEmpty())
break break
//todo 可自定义执行任务 //todo 可自定义执行任务
Demo.test2(nameList[0]) // Demo.test2(nameList[0])
} }
} }
return true return true

View File

@@ -3,13 +3,14 @@ package org.yameida.worktool.service
import android.view.accessibility.AccessibilityNodeInfo import android.view.accessibility.AccessibilityNodeInfo
import org.yameida.worktool.Constant import org.yameida.worktool.Constant
import org.yameida.worktool.model.WeworkMessageBean import org.yameida.worktool.model.WeworkMessageBean
import org.yameida.worktool.utils.AccessibilityUtil
import org.yameida.worktool.utils.Views
import org.yameida.worktool.utils.WeworkRoomUtil
import org.yameida.worktool.utils.WeworkTextUtil
import com.github.yoojia.qrcode.qrcode.QRCodeDecoder import com.github.yoojia.qrcode.qrcode.QRCodeDecoder
import com.blankj.utilcode.util.* import com.blankj.utilcode.util.*
import com.lzy.okgo.OkGo
import org.yameida.worktool.utils.*
import java.io.File
import java.lang.Exception import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
/** /**
@@ -24,21 +25,30 @@ object WeworkOperationImpl {
* @param at 要at的昵称 * @param at 要at的昵称
* @see WeworkMessageBean.TEXT_TYPE * @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,
atList: List<String>? = null
): Boolean {
if (receivedContent.isNullOrEmpty()) { if (receivedContent.isNullOrEmpty()) {
LogUtils.d("未发现发送内容") LogUtils.d("未发现发送内容")
return false return false
} }
for (title in titleList) { for (title in titleList) {
if (WeworkRoomUtil.intoRoom(title)) { if (WeworkRoomUtil.intoRoom(title)) {
sendChatMessage(receivedContent, at = at) if (sendChatMessage(receivedContent, at = at, atList = atList)) {
LogUtils.d("$title: 发送成功") LogUtils.d("$title: 发送成功")
return true
} else {
LogUtils.d("$title: 发送失败")
}
} else { } else {
LogUtils.d("$title: 发送失败") LogUtils.d("$title: 发送失败")
error("$title: 发送失败 $receivedContent") error("$title: 发送失败 $receivedContent")
} }
} }
return true return false
} }
/** /**
@@ -134,11 +144,15 @@ object WeworkOperationImpl {
) { ) {
LogUtils.d("开始转发") LogUtils.d("开始转发")
sleep(1000) sleep(1000)
relaySelectTarget(nameList, extraText) if (relaySelectTarget(nameList, extraText)) {
LogUtils.d("$title: 转发成功")
} else {
LogUtils.d("$title: 转发失败")
error("$title: 转发失败 $originalContent")
}
} }
LogUtils.d("$title: 转发成功")
} else { } else {
LogUtils.d("$title: 转发失败") LogUtils.d("$title: 转发失败 未找到房间")
error("$title: 转发失败 $originalContent") error("$title: 转发失败 $originalContent")
} }
} }
@@ -165,11 +179,13 @@ object WeworkOperationImpl {
* @param groupName 修改群名称 * @param groupName 修改群名称
* @param selectList 添加群成员名称列表 选填 * @param selectList 添加群成员名称列表 选填
* @param groupAnnouncement 修改群公告 选填 * @param groupAnnouncement 修改群公告 选填
* @param groupRemark 修改群备注 选填
*/ */
fun initGroup( fun initGroup(
groupName: String, groupName: String,
selectList: List<String>?, selectList: List<String>?,
groupAnnouncement: String? groupAnnouncement: String?,
groupRemark: String?
): Boolean { ): Boolean {
if (!WeworkRoomUtil.isGroupExists(groupName)) { if (!WeworkRoomUtil.isGroupExists(groupName)) {
if (!createGroup() || !groupRename(groupName) || !groupAddMember(selectList) if (!createGroup() || !groupRename(groupName) || !groupAddMember(selectList)
@@ -180,8 +196,10 @@ object WeworkOperationImpl {
|| !groupChangeAnnouncement(groupAnnouncement) || !groupChangeAnnouncement(groupAnnouncement)
) return false ) return false
} }
//TODO 暂移除获取群二维码 if (groupRemark != null) {
// getGroupQrcode(groupName) groupChangeRemark(groupRemark)
}
// getGroupQrcode(groupName, groupRemark)
return true return true
} }
@@ -191,6 +209,7 @@ object WeworkOperationImpl {
* @param groupName 待修改的群 * @param groupName 待修改的群
* @param newGroupName 修改群名 选填 * @param newGroupName 修改群名 选填
* @param newGroupAnnouncement 修改群公告 选填 * @param newGroupAnnouncement 修改群公告 选填
* @param groupRemark 修改群备注 选填
* @param selectList 添加群成员名称列表/拉人 选填 * @param selectList 添加群成员名称列表/拉人 选填
* @param showMessageHistory 拉人是否附带历史记录 选填 * @param showMessageHistory 拉人是否附带历史记录 选填
* @param removeList 移除群成员名称列表/踢人 选填 * @param removeList 移除群成员名称列表/踢人 选填
@@ -199,6 +218,7 @@ object WeworkOperationImpl {
groupName: String, groupName: String,
newGroupName: String?, newGroupName: String?,
newGroupAnnouncement: String?, newGroupAnnouncement: String?,
groupRemark: String?,
selectList: List<String>?, selectList: List<String>?,
showMessageHistory: Boolean = false, showMessageHistory: Boolean = false,
removeList: List<String>? removeList: List<String>?
@@ -216,6 +236,9 @@ object WeworkOperationImpl {
if (newGroupAnnouncement != null) { if (newGroupAnnouncement != null) {
groupChangeAnnouncement(newGroupAnnouncement) groupChangeAnnouncement(newGroupAnnouncement)
} }
if (groupRemark != null) {
groupChangeRemark(groupRemark)
}
backPress() backPress()
return true return true
} }
@@ -249,10 +272,13 @@ object WeworkOperationImpl {
AccessibilityUtil.performClick(shareFileButton) AccessibilityUtil.performClick(shareFileButton)
val shareToWorkButton = AccessibilityUtil.findOneByText(getRoot(true), "发送给同事") val shareToWorkButton = AccessibilityUtil.findOneByText(getRoot(true), "发送给同事")
AccessibilityUtil.performClick(shareToWorkButton) AccessibilityUtil.performClick(shareToWorkButton)
relaySelectTarget(titleList, extraText) if (relaySelectTarget(titleList, extraText)) {
val stayButton = AccessibilityUtil.findOneByText(getRoot(), "留在企业微信") val stayButton = AccessibilityUtil.findOneByText(getRoot(), "留在企业微信")
AccessibilityUtil.performClick(stayButton) AccessibilityUtil.performClick(stayButton)
return true return true
} else {
LogUtils.e("微盘文件转发失败: $objectName")
}
} else { } else {
LogUtils.e("微盘未搜索到相关图片: $objectName") LogUtils.e("微盘未搜索到相关图片: $objectName")
} }
@@ -290,8 +316,11 @@ object WeworkOperationImpl {
AccessibilityUtil.performClick(imageViewList[1]) AccessibilityUtil.performClick(imageViewList[1])
val shareFileButton = AccessibilityUtil.findOneByDesc(getRoot(), "转发") val shareFileButton = AccessibilityUtil.findOneByDesc(getRoot(), "转发")
AccessibilityUtil.performClick(shareFileButton) AccessibilityUtil.performClick(shareFileButton)
relaySelectTarget(titleList, extraText) if (relaySelectTarget(titleList, extraText)) {
return true return true
} else {
LogUtils.e("微盘文件转发失败: $objectName")
}
} else { } else {
LogUtils.e("微盘未搜索到相关文件: $objectName") LogUtils.e("微盘未搜索到相关文件: $objectName")
} }
@@ -370,8 +399,11 @@ object WeworkOperationImpl {
AccessibilityUtil.performClick(imageViewList[1]) AccessibilityUtil.performClick(imageViewList[1])
val shareFileButton = AccessibilityUtil.findOneByDesc(getRoot(), "转发") val shareFileButton = AccessibilityUtil.findOneByDesc(getRoot(), "转发")
AccessibilityUtil.performClick(shareFileButton) AccessibilityUtil.performClick(shareFileButton)
relaySelectTarget(titleList, extraText) if (relaySelectTarget(titleList, extraText)) {
return true return true
} else {
LogUtils.e("微盘文件转发失败: $objectName")
}
} else { } else {
LogUtils.e("文档未搜索到相关文件: $objectName") LogUtils.e("文档未搜索到相关文件: $objectName")
} }
@@ -381,6 +413,52 @@ object WeworkOperationImpl {
return false return false
} }
/**
* 推送文件(网络图片视频和文件等)
* @see WeworkMessageBean.PUSH_FILE
* @param titleList 待发送姓名列表
* @param objectName 文件名称
* @param fileUrl 文件网络地址
* @param fileType 文件类型
* @param extraText 附加留言 可选
*/
fun pushFile(
titleList: List<String>,
objectName: String,
fileUrl: String,
fileType: String,
extraText: String? = null
): Boolean {
LogUtils.i("下载开始 $fileUrl")
val execute = OkGo.get<File>(fileUrl).execute()
LogUtils.i("下载成功 $fileUrl")
val body = execute.body()
if (body != null) {
val df = SimpleDateFormat("yyyy-MM-dd")
val filePath = "${Utils.getApp().getExternalFilesDir("share")}/${df.format(Date())}/$objectName"
val newFile = File(filePath)
val create = FileUtils.createFileByDeleteOldFile(newFile)
if (create && newFile.canWrite()) {
newFile.writeBytes(body.bytes())
LogUtils.i("文件存储本地成功 $filePath")
ShareUtil.share("${if (fileType.isBlank()) "*" else fileType}/*", newFile)
val shareToWorkButton = AccessibilityUtil.findOneByText(getRoot(true), "发送给同事")
AccessibilityUtil.performClick(shareToWorkButton)
if (relaySelectTarget(titleList, extraText)) {
val stayButton = AccessibilityUtil.findOneByText(getRoot(), "留在企业微信")
AccessibilityUtil.performClick(stayButton)
return true
} else {
LogUtils.e("文件转发失败: $objectName")
}
} else {
LogUtils.e("文件存储本地失败 $filePath")
error("文件存储本地失败 $filePath")
}
}
return false
}
/** /**
* 手机号添加好友 * 手机号添加好友
* @see WeworkMessageBean.ADD_FRIEND_BY_PHONE * @see WeworkMessageBean.ADD_FRIEND_BY_PHONE
@@ -888,39 +966,62 @@ object WeworkOperationImpl {
return true return true
} }
/**
* 修改群备注
* 注:首次为发布 后续为编辑
* 注2外部群为edittext 内部群为webview(只能追加文本)
*/
private fun groupChangeRemark(groupRemark: String? = null): Boolean {
if (groupRemark == null) return true
if (WeworkRoomUtil.intoGroupManager()) {
val textView = AccessibilityUtil.findOneByText(getRoot(), "备注", exact = true)
if (textView != null) {
AccessibilityUtil.performClick(textView)
if (AccessibilityUtil.findTextInput(getRoot(), groupRemark)) {
LogUtils.d("群备注修改: $groupRemark")
if (AccessibilityUtil.findTextAndClick(getRoot(), "确定")) {
return true
} else {
LogUtils.e("无法进行群备注发布: ")
}
} else {
LogUtils.e("无法进行群备注修改: ")
}
} else {
LogUtils.e("未找到群公告按钮")
}
} else {
LogUtils.e("进入群管理页失败")
}
return false
}
/** /**
* 发送消息+@at * 发送消息+@at
*/ */
private fun sendChatMessage(text: String, at: String? = null, reply: Boolean? = false) { private fun sendChatMessage(text: String, at: String? = null, atList: List<String>? = null, reply: Boolean? = false): Boolean {
val voiceFlag = AccessibilityUtil.findOnceByText(getRoot(), "按住 说话", "按住说话", exact = true) val voiceFlag = AccessibilityUtil.findOnceByText(getRoot(), "按住 说话", "按住说话", exact = true)
if (voiceFlag != null) { if (voiceFlag != null) {
AccessibilityUtil.performClickWithSon(AccessibilityUtil.findFrontNode(voiceFlag)) AccessibilityUtil.performClickWithSon(AccessibilityUtil.findFrontNode(voiceFlag))
} }
var atFailed = false var atFailed = false
if (!at.isNullOrEmpty()) { val atList = if (!at.isNullOrEmpty()) listOf(at) else atList
AccessibilityUtil.findTextInput(getRoot(), "@") if (!atList.isNullOrEmpty()) {
val atFlag = AccessibilityUtil.findOneByText(getRoot(), "选择提醒的人", timeout = 2000, exact = true) atList.forEachIndexed { index, at ->
if (atFlag != null) { if (index == 0) {
val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView) AccessibilityUtil.findTextInput(getRoot(), "@")
if (rv != null) {
AccessibilityUtil.findTextInput(getRoot(), at)
val atNode =
AccessibilityUtil.findOneByText(rv, at, root = false, timeout = 2000)
if (atNode != null) {
AccessibilityUtil.performClick(atNode)
} else {
LogUtils.e("未找到at人: $at")
atFailed = true
backPress()
}
sleep(Constant.POP_WINDOW_INTERVAL)
} else { } else {
val searchFlag = AccessibilityUtil.findOnceByText(getRoot(), "搜索", exact = true) AccessibilityUtil.sendTextForEditText(Utils.getApp(),
val list = AccessibilityUtil.findBackNode(searchFlag, minChildCount = 2) AccessibilityUtil.findOnceByClazz(getRoot(), Views.EditText), "@"
if (list != null) { )
}
val atFlag = AccessibilityUtil.findOneByText(getRoot(), "选择提醒的人", timeout = 2000, exact = true)
if (atFlag != null) {
val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView)
if (rv != null) {
AccessibilityUtil.findTextInput(getRoot(), at) AccessibilityUtil.findTextInput(getRoot(), at)
val atNode = val atNode =
AccessibilityUtil.findOneByText(list, at, root = false, timeout = 2000) AccessibilityUtil.findOneByText(rv, at, root = false, timeout = 2000)
if (atNode != null) { if (atNode != null) {
AccessibilityUtil.performClick(atNode) AccessibilityUtil.performClick(atNode)
} else { } else {
@@ -929,19 +1030,37 @@ object WeworkOperationImpl {
backPress() backPress()
} }
sleep(Constant.POP_WINDOW_INTERVAL) sleep(Constant.POP_WINDOW_INTERVAL)
} else {
val searchFlag = AccessibilityUtil.findOnceByText(getRoot(), "搜索", exact = true)
val list = AccessibilityUtil.findBackNode(searchFlag, minChildCount = 2)
if (list != null) {
AccessibilityUtil.findTextInput(getRoot(), at)
val atNode =
AccessibilityUtil.findOneByText(list, at, root = false, timeout = 2000)
if (atNode != null) {
AccessibilityUtil.performClick(atNode)
} else {
LogUtils.e("未找到at人: $at")
atFailed = true
backPress()
}
sleep(Constant.POP_WINDOW_INTERVAL)
}
} }
} }
} }
} }
val content = if (atFailed) "@$at $text" else "$text" val content = if (atFailed) "@${atList?.joinToString()} $text" else text
val append = (reply == true) || (!at.isNullOrEmpty() && !atFailed) val append = (reply == true) || (!atList.isNullOrEmpty() && !atFailed)
if (AccessibilityUtil.findTextInput(getRoot(), content, append = append)) { if (AccessibilityUtil.findTextInput(getRoot(), content, append = append)) {
AccessibilityUtil.findOneByText(getRoot(), "发送", exact = true, timeout = 2000)
val sendButton = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button) val sendButton = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button)
.firstOrNull { it.text == "发送" } .firstOrNull { it.text == "发送" }
if (sendButton != null) { if (sendButton != null) {
LogUtils.d("发送消息: \n$content") LogUtils.d("发送消息: \n$content")
log("发送消息: \n$content") log("发送消息: \n$content")
AccessibilityUtil.performClick(sendButton) AccessibilityUtil.performClick(sendButton)
return true
} else { } else {
LogUtils.e("未找到发送按钮") LogUtils.e("未找到发送按钮")
error("未找到发送按钮") error("未找到发送按钮")
@@ -950,6 +1069,7 @@ object WeworkOperationImpl {
LogUtils.e("未找到输入框") LogUtils.e("未找到输入框")
error("未找到输入框") error("未找到输入框")
} }
return false
} }
/** /**
@@ -1015,8 +1135,9 @@ object WeworkOperationImpl {
/** /**
* 获取群二维码并上传后台 * 获取群二维码并上传后台
*/ */
fun getGroupQrcode(groupName: String): Boolean { fun getGroupQrcode(groupName: String, groupRemark: String?): Boolean {
if (WeworkRoomUtil.intoRoom(groupName) && WeworkRoomUtil.intoGroupManager()) { if (AccessibilityUtil.findOneByText(getRoot(), "全部群成员", "微信用户创建", timeout = Constant.CHANGE_PAGE_INTERVAL) != null ||
(WeworkRoomUtil.intoRoom(groupName) && WeworkRoomUtil.intoGroupManager())) {
val tvList = AccessibilityUtil.findAllOnceByClazz(getRoot(), Views.TextView) val tvList = AccessibilityUtil.findAllOnceByClazz(getRoot(), Views.TextView)
tvList.forEachIndexed { index, tv -> tvList.forEachIndexed { index, tv ->
if (tv.text != null && tv.text.contains("微信用户创建")) { if (tv.text != null && tv.text.contains("微信用户创建")) {
@@ -1054,6 +1175,7 @@ object WeworkOperationImpl {
val weworkMessageBean = WeworkMessageBean() val weworkMessageBean = WeworkMessageBean()
weworkMessageBean.type = WeworkMessageBean.GET_GROUP_QRCODE weworkMessageBean.type = WeworkMessageBean.GET_GROUP_QRCODE
weworkMessageBean.groupName = groupName weworkMessageBean.groupName = groupName
weworkMessageBean.groupRemark = groupRemark
weworkMessageBean.qrcode = qrcode weworkMessageBean.qrcode = qrcode
WeworkController.weworkService.webSocketManager.send( WeworkController.weworkService.webSocketManager.send(
weworkMessageBean weworkMessageBean

View File

@@ -71,12 +71,14 @@ class WeworkService : AccessibilityService() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
LogUtils.i("onDestroy") LogUtils.i("onDestroy")
//关闭自动回复
WeworkController.enableLoopRunning = false
//隐藏软键盘模式 //隐藏软键盘模式
softKeyboardController.showMode = SHOW_MODE_AUTO softKeyboardController.showMode = SHOW_MODE_AUTO
webSocketManager.close(1000, "service Destroy") webSocketManager.close(1000, "service Destroy")
} }
class EchoWebSocketListener() : WebSocketListener() { inner class EchoWebSocketListener : WebSocketListener() {
private val TAG = "WeworkService.EchoWebSocketListener" private val TAG = "WeworkService.EchoWebSocketListener"
private lateinit var socket: WebSocket private lateinit var socket: WebSocket
override fun onOpen(webSocket: WebSocket, response: Response) { override fun onOpen(webSocket: WebSocket, response: Response) {
@@ -86,6 +88,8 @@ class WeworkService : AccessibilityService() {
val appVersion = SPUtils.getInstance().getString("appVersion", "") val appVersion = SPUtils.getInstance().getString("appVersion", "")
val workVersion= SPUtils.getInstance().getString("workVersion", "") val workVersion= SPUtils.getInstance().getString("workVersion", "")
log("链接建立: $robotId appVersion: $appVersion workVersion: $workVersion") log("链接建立: $robotId appVersion: $appVersion workVersion: $workVersion")
LogUtils.i("设置自动跳转企业微信")
sendBroadcast(true)
} }
override fun onMessage(webSocket: WebSocket, text: String) { override fun onMessage(webSocket: WebSocket, text: String) {
@@ -102,18 +106,27 @@ class WeworkService : AccessibilityService() {
super.onClosed(webSocket, code, reason) super.onClosed(webSocket, code, reason)
//服务器关闭后 //服务器关闭后
Log.e(TAG, "链接关闭 $reason") Log.e(TAG, "链接关闭 $reason")
sendBroadcast(false)
} }
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
super.onClosing(webSocket, code, reason) super.onClosing(webSocket, code, reason)
socket.close(code, reason) socket.close(code, reason)
Log.e(TAG, "服务端关闭连接 $code: $reason") Log.e(TAG, "服务端关闭连接 $code: $reason")
sendBroadcast(false)
} }
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
//服务器中断 //服务器中断
Log.e(TAG, "链接错误: " + t.toString() + response.toString()) Log.e(TAG, "链接错误: " + t.toString() + response.toString())
sendBroadcast(false)
}
private fun sendBroadcast(switch: Boolean) {
sendBroadcast(Intent(Constant.WEWORK_NOTIFY).apply {
putExtra("type", "openWs")
putExtra("switch", switch)
})
} }
} }
} }

View File

@@ -19,6 +19,10 @@ import java.lang.Exception
import java.lang.Thread.sleep import java.lang.Thread.sleep
import com.blankj.utilcode.util.ScreenUtils import com.blankj.utilcode.util.ScreenUtils
import org.yameida.worktool.service.WeworkController import org.yameida.worktool.service.WeworkController
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
/** /**
* 1.查询类 * 1.查询类
@@ -56,6 +60,17 @@ object AccessibilityUtil {
private const val SHORT_INTERVAL = 150L private const val SHORT_INTERVAL = 150L
private const val SCROLL_INTERVAL = 500L private const val SCROLL_INTERVAL = 500L
//编辑EditView(粘贴 不推荐)
fun sendTextForEditText(context: Context, nodeInfo: AccessibilityNodeInfo?, text: String): Boolean {
val nodeInfo: AccessibilityNodeInfo = nodeInfo ?: return false
val clipboard: ClipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("text", text)
clipboard.setPrimaryClip(clip)
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS)
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE)
return true
}
//编辑EditView(非粘贴 推荐) //编辑EditView(非粘贴 推荐)
fun editTextInput(nodeInfo: AccessibilityNodeInfo?, text: String): Boolean { fun editTextInput(nodeInfo: AccessibilityNodeInfo?, text: String): Boolean {
val nodeInfo: AccessibilityNodeInfo = nodeInfo ?: return false val nodeInfo: AccessibilityNodeInfo = nodeInfo ?: return false

View File

@@ -0,0 +1,8 @@
package org.yameida.worktool.utils
import androidx.core.content.FileProvider
/**
* Created by Gallon on 2019/7/8.
*/
class GenericFileProvider: FileProvider()

View File

@@ -0,0 +1,51 @@
package org.yameida.worktool.utils
import android.provider.Settings
import android.text.TextUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.Utils
import org.yameida.worktool.service.WeworkService
/**
* 无障碍服务开启辅助类
*/
object PermissionHelper {
fun isAccessibilitySettingOn(): Boolean {
val context = Utils.getApp()
var enable = 0
val canonicalName = WeworkService::class.java.canonicalName ?: ""
val serviceName = context.packageName + "/" + canonicalName
val serviceShortName = context.packageName + "/" + canonicalName.replace(context.packageName, "")
LogUtils.i("isAccessibilitySettingOn: $serviceName $serviceShortName")
try {
enable = Settings.Secure.getInt(
context.contentResolver,
Settings.Secure.ACCESSIBILITY_ENABLED,
0
)
} catch (e: Exception) {
e.printStackTrace()
}
if (enable == 1) {
val stringSplitter = TextUtils.SimpleStringSplitter(':')
val settingVal = Settings.Secure.getString(
context.contentResolver,
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
)
if (settingVal != null) {
stringSplitter.setString(settingVal)
while (stringSplitter.hasNext()) {
val accessibilityService = stringSplitter.next()
if (accessibilityService == serviceName || accessibilityService == serviceShortName) {
LogUtils.i("isAccessibilitySettingOn: true")
return true
}
}
}
}
LogUtils.i("isAccessibilitySettingOn: false")
return false
}
}

View File

@@ -0,0 +1,220 @@
package org.yameida.worktool.utils;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
/**
* 跳转到APP的权限配置页
*/
public class PermissionPageManagement {
private static final String TAG = "JumpPermissionManagement";
/**
* Build.MANUFACTURER
*/
private static final String MANUFACTURER_HUAWEI = "HUAWEI";//华为
private static final String MANUFACTURER_MEIZU = "Meizu";//魅族
private static final String MANUFACTURER_XIAOMI = "Xiaomi";//小米
private static final String MANUFACTURER_SONY = "Sony";//索尼
private static final String MANUFACTURER_OPPO = "OPPO";//oppo
private static final String MANUFACTURER_LG = "LG";
private static final String MANUFACTURER_VIVO = "vivo";//vivo
private static final String MANUFACTURER_SAMSUNG = "samsung";//三星
private static final String MANUFACTURER_ZTE = "ZTE";//中兴
private static final String MANUFACTURER_YULONG = "YuLong";//酷派
private static final String MANUFACTURER_LENOVO = "LENOVO";//联想
/**
* 此函数可以自己定义
* @param activity
*/
public static void goToSetting(Activity activity){
switch (Build.MANUFACTURER){
case MANUFACTURER_HUAWEI:
Huawei(activity);
break;
case MANUFACTURER_MEIZU:
Meizu(activity);
break;
case MANUFACTURER_XIAOMI:
Xiaomi(activity);
break;
case MANUFACTURER_SONY:
Sony(activity);
break;
case MANUFACTURER_OPPO:
OPPO(activity);
break;
case MANUFACTURER_VIVO:
VIVO(activity);
break;
case MANUFACTURER_LG:
LG(activity);
break;
default:
ApplicationInfo(activity);
Log.e("goToSetting", "目前暂不支持此系统");
break;
}
}
public static void Huawei(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", activity.getApplicationInfo().packageName);
ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");
intent.setComponent(comp);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
goIntentSetting(activity);
}
}
public static void Meizu(Activity activity) {
try {
Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra("packageName", activity.getPackageName());
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
goIntentSetting(activity);
}
}
public static void Xiaomi(Activity activity) {
try {
Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.putExtra("extra_pkgname", activity.getPackageName());
ComponentName componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
intent.setComponent(componentName);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
goIntentSetting(activity);
}
}
public static void Sony(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", activity.getPackageName());
ComponentName comp = new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity");
intent.setComponent(comp);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
goIntentSetting(activity);
}
}
public static void OPPO(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", activity.getPackageName());
// ComponentName comp = new ComponentName("com.color.safecenter", "com.color.safecenter.permission.PermissionManagerActivity");
ComponentName comp = new ComponentName("com.coloros.securitypermission", "com.coloros.securitypermission.permission.PermissionAppAllPermissionActivity");//R11t 7.1.1 os-v3.2
intent.setComponent(comp);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
goIntentSetting(activity);
}
}
public static void VIVO(Activity activity) {
Intent localIntent;
if (((Build.MODEL.contains("Y85")) && (!Build.MODEL.contains("Y85A"))) || (Build.MODEL.contains("vivo Y53L"))) {
localIntent = new Intent();
localIntent.setClassName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.PurviewTabActivity");
localIntent.putExtra("packagename", activity.getPackageName());
localIntent.putExtra("tabId", "1");
activity.startActivity(localIntent);
} else {
localIntent = new Intent();
localIntent.setClassName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.SoftPermissionDetailActivity");
localIntent.setAction("secure.intent.action.softPermissionDetail");
localIntent.putExtra("packagename", activity.getPackageName());
activity.startActivity(localIntent);
}
}
public static void LG(Activity activity) {
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", activity.getPackageName());
ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity");
intent.setComponent(comp);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
goIntentSetting(activity);
}
}
/**
* 只能打开到自带安全软件
* @param activity
*/
public static void _360(Activity activity) {
Intent intent = new Intent("android.intent.action.MAIN");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", activity.getPackageName());
ComponentName comp = new ComponentName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity");
intent.setComponent(comp);
activity.startActivity(intent);
}
/**
* 应用信息界面
* @param activity
*/
public static void ApplicationInfo(Activity activity){
Intent localIntent = new Intent();
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {
localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
localIntent.setData(Uri.fromParts("package", activity.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {
localIntent.setAction(Intent.ACTION_VIEW);
localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
localIntent.putExtra("com.android.settings.ApplicationPkgName", activity.getPackageName());
}
activity.startActivity(localIntent);
}
/**
* 系统设置界面
* @param activity
*/
public static void SystemConfig(Activity activity) {
Intent intent = new Intent(Settings.ACTION_SETTINGS);
activity.startActivity(intent);
}
/**
* 默认打开应用详细页
*/
private static void goIntentSetting(Activity pActivity) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", pActivity.getPackageName(), null);
intent.setData(uri);
try {
pActivity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,68 @@
package org.yameida.worktool.utils
import android.content.Intent
import android.provider.Settings
import androidx.core.content.FileProvider
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.Utils
import java.io.File
/**
* 文件分享工具类
*/
object ShareUtil {
/**
* Share Text
*/
const val TEXT = "text/plain"
/**
* Share Image
*/
const val IMAGE = "image/*"
/**
* Share Audio
*/
const val AUDIO = "audio/*"
/**
* Share Video
*/
const val VIDEO = "video/*"
/**
* Share File
*/
const val File = "*/*"
/**
* 文件分享 需要先授权显示悬浮窗
*/
fun share(type: String, path: String): Boolean {
return share(type, File(path))
}
/**
* 文件分享 需要先授权显示悬浮窗
*/
fun share(type: String, file: File): Boolean {
val app = Utils.getApp()
if (!Settings.canDrawOverlays(app)) {
LogUtils.e("文件分享失败 没有悬浮窗权限~")
return false
}
val intent = Intent().apply {
action = Intent.ACTION_SEND
flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.type = type
val fileURI = FileProvider.getUriForFile(app, app.packageName + ".fileprovider", file)
putExtra(Intent.EXTRA_STREAM, fileURI)
}
app.startActivity(Intent.createChooser(intent, "WorkTool文件分享").apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK })
LogUtils.e("分享了 $type ${file.absolutePath}")
return true
}
}

View File

@@ -4,6 +4,7 @@ import android.util.Log;
import com.blankj.utilcode.util.GsonUtils; import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.LogUtils;
import com.hjq.toast.ToastUtils;
import org.yameida.worktool.model.WeworkMessageBean; import org.yameida.worktool.model.WeworkMessageBean;
import org.yameida.worktool.model.WeworkMessageListBean; import org.yameida.worktool.model.WeworkMessageListBean;
@@ -24,15 +25,11 @@ import okhttp3.WebSocketListener;
public class WebSocketManager { public class WebSocketManager {
public static final String HEARTBEAT = "{" + public static final String HEARTBEAT = "{\"type\":" + WeworkMessageBean.HEART_BEAT + "}";
"\"type\": " + WeworkMessageBean.HEART_BEAT +
",\"hearBeat\": \"心跳检测\"" +
"}";
private static final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
public static Map<String, WebSocketManager> webSocketManager = new ConcurrentHashMap<>(); public static Map<String, WebSocketManager> webSocketManager = new ConcurrentHashMap<>();
private static final int reconnectTimes = 7;
private static final int reconnectInt = 5000; //毫秒 private static final int reconnectInt = 5000; //毫秒
private static final long heartBeatRate = 15; //秒 private static final long heartBeatRate = 10; //秒
private Map<String, Long> messageIdMap = new ConcurrentHashMap<>(); private Map<String, Long> messageIdMap = new ConcurrentHashMap<>();
private ScheduledFuture task; private ScheduledFuture task;
private WebSocket socket; private WebSocket socket;
@@ -52,7 +49,7 @@ public class WebSocketManager {
} }
public void send(WeworkMessageBean msg) { public void send(WeworkMessageBean msg) {
send(new WeworkMessageListBean(msg, WeworkMessageListBean.SOCKET_TYPE_MESSAGE_LIST)); send(new WeworkMessageListBean(msg, WeworkMessageListBean.SOCKET_TYPE_MESSAGE_LIST, null));
} }
/** /**
@@ -101,7 +98,6 @@ public class WebSocketManager {
Log.e(url, "链接关闭"); Log.e(url, "链接关闭");
} }
public static void closeManager() { public static void closeManager() {
Log.e("SocketManager", "关闭Manager:"); Log.e("SocketManager", "关闭Manager:");
for (Map.Entry<String, WebSocketManager> e : webSocketManager.entrySet()) { for (Map.Entry<String, WebSocketManager> e : webSocketManager.entrySet()) {
@@ -115,10 +111,14 @@ public class WebSocketManager {
connecting = true; connecting = true;
Log.e(url, "重连"); Log.e(url, "重连");
boolean isConnect = false; boolean isConnect = false;
int interval = reconnectInt;
while (!isConnect) { while (!isConnect) {
try { try {
isConnect = connect(); isConnect = connect();
Thread.sleep(reconnectInt); Thread.sleep(interval);
if (interval < 600000) {
interval *= 2;
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -142,6 +142,7 @@ public class WebSocketManager {
if (!connecting && (socket == null || !socket.send(HEARTBEAT))) { if (!connecting && (socket == null || !socket.send(HEARTBEAT))) {
reConnect(); reConnect();
} }
ToastUtils.show("机器人运行中 请勿人工操作手机~");
}; };
//每heartBeatRate秒发一次心跳包 //每heartBeatRate秒发一次心跳包

View File

@@ -19,7 +19,7 @@ object WeworkRoomUtil {
* @see WeworkMessageBean.ROOM_TYPE * @see WeworkMessageBean.ROOM_TYPE
*/ */
fun getRoomType(print: Boolean = true): Int { fun getRoomType(print: Boolean = true): Int {
val roomTitle = getRoomTitle() val roomTitle = getRoomTitle(noCut = true)
when { when {
isExternalSingleChat(roomTitle) -> { isExternalSingleChat(roomTitle) -> {
LogUtils.d("ROOM_TYPE: ROOM_TYPE_EXTERNAL_CONTACT") LogUtils.d("ROOM_TYPE: ROOM_TYPE_EXTERNAL_CONTACT")
@@ -52,7 +52,7 @@ object WeworkRoomUtil {
* @see WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP * @see WeworkMessageBean.ROOM_TYPE_INTERNAL_GROUP
* @see WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT * @see WeworkMessageBean.ROOM_TYPE_INTERNAL_CONTACT
*/ */
fun getRoomTitle(print: Boolean = true): ArrayList<String> { fun getRoomTitle(print: Boolean = true, noCut: Boolean = false): ArrayList<String> {
val titleList = arrayListOf<String>() val titleList = arrayListOf<String>()
//聊天消息列表 1ListView 0RecycleView xViewGroup //聊天消息列表 1ListView 0RecycleView xViewGroup
val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView)
@@ -63,8 +63,8 @@ object WeworkRoomUtil {
if (!textView.text.isNullOrBlank()) { if (!textView.text.isNullOrBlank()) {
val text = textView.text.toString() val text = textView.text.toString()
titleList.add(text.replace("\\(\\d+\\)$".toRegex(), "")) titleList.add(text.replace("\\(\\d+\\)$".toRegex(), ""))
if (text.contains("\\(\\d+\\)$".toRegex())) { if (noCut && text.contains("\\(\\d+\\)$".toRegex())) {
titleList.add(text) titleList.add(text)
} }
} }
} }

View File

@@ -301,6 +301,41 @@
</RelativeLayout> </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_overlay"
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_overlay"
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 <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -338,7 +373,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="20dp" android:layout_marginTop="15dp"
android:orientation="vertical"> android:orientation="vertical">
<Button <Button

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>

View File

@@ -6,6 +6,7 @@ buildscript {
jcenter() jcenter()
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
maven { url 'https://repo1.maven.org/maven2/' } maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://jitpack.io' }
} }
dependencies { dependencies {
classpath "com.android.tools.build:gradle:4.0.0" classpath "com.android.tools.build:gradle:4.0.0"
@@ -22,6 +23,7 @@ allprojects {
jcenter() jcenter()
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
maven { url 'https://repo1.maven.org/maven2/' } maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://jitpack.io' }
} }
} }