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'
//toast
implementation 'com.github.getActivity:ToastUtils:10.5'
//Gson
implementation 'com.google.code.gson:gson:2.8.5'
//网络

View File

@@ -60,6 +60,16 @@
android:resource="@xml/accessibility_service_config" />
</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_CHANNEL_ID" android:value="worktool_master" />
</application>

View File

@@ -22,77 +22,6 @@ object Demo {
//打印当前视图树
// 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) {

View File

@@ -1,8 +1,12 @@
package org.yameida.worktool
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.Utils
import com.efs.sdk.base.core.util.PackageUtil
import com.hjq.toast.ToastUtils
import com.tendcloud.tenddata.TalkingDataSDK
import com.umeng.commonsdk.UMConfigure
import org.yameida.worktool.config.GlobalException
@@ -10,15 +14,34 @@ import update.UpdateAppUtils
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() {
super.onCreate()
//初始化工具类
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
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));
//初始化自动更新

View File

@@ -1,10 +1,7 @@
package org.yameida.worktool.activity
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import android.text.TextUtils.SimpleStringSplitter
import android.view.WindowManager
import android.widget.CompoundButton
import android.widget.Switch
@@ -17,8 +14,12 @@ import org.yameida.worktool.*
import org.yameida.worktool.service.WeworkService
import org.yameida.worktool.utils.UpdateUtil
import android.app.Dialog
import android.content.*
import android.widget.Button
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() {
@@ -32,16 +33,28 @@ class ListenActivity : AppCompatActivity() {
initView()
initAccessibility()
initOverlays()
UpdateUtil.checkUpdate()
PermissionUtils.permission("android.permission.READ_EXTERNAL_STORAGE").request()
registerReceiver(openWsReceiver, IntentFilter(Constant.WEWORK_NOTIFY))
}
override fun onStart() {
super.onStart()
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(openWsReceiver)
}
override fun onResume() {
super.onResume()
sw_overlay.isChecked = PermissionUtils.isGrantedDrawOverlays()
freshOpenServiceSwitch(
WeworkService::class.java,
sw_accessibility
)
if (needToWork) {
needToWork = false
goToWork()
}
}
private fun initView() {
@@ -102,11 +115,11 @@ class ListenActivity : AppCompatActivity() {
if (SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID).isNullOrBlank()) {
sw_accessibility.isChecked = false
ToastUtils.showLong("请先填写并保存链接号~")
} else if (!isAccessibilitySettingOn()) {
} else if (!PermissionHelper.isAccessibilitySettingOn()) {
openAccessibility()
}
} else {
if (isAccessibilitySettingOn()) {
if (PermissionHelper.isAccessibilitySettingOn()) {
sw_accessibility.isChecked = true
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
startActivity(intent)
@@ -115,39 +128,27 @@ class ListenActivity : AppCompatActivity() {
})
}
private fun isAccessibilitySettingOn(): Boolean {
val context = Utils.getApp()
var enable = 0
val serviceName = context.packageName + "/" + WeworkService::class.java.canonicalName
LogUtils.i("isAccessibilitySettingOn: $serviceName")
try {
enable = Settings.Secure.getInt(
context.contentResolver,
Settings.Secure.ACCESSIBILITY_ENABLED,
0
)
} catch (e: Exception) {
e.printStackTrace()
private fun initOverlays() {
sw_overlay.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
LogUtils.i("sw_overlay onCheckedChanged: $isChecked")
if (isChecked) {
if (!PermissionUtils.isGrantedDrawOverlays()) {
PermissionUtils.requestDrawOverlays(object : PermissionUtils.SimpleCallback {
override fun onGranted() {
ToastUtils.showLong("请同时打开后台弹出界面权限~")
PermissionPageManagement.goToSetting(this@ListenActivity)
}
if (enable == 1) {
val stringSplitter = 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) {
LogUtils.i("isAccessibilitySettingOn: true")
return true
override fun onDenied() { sw_accessibility.isChecked = false }
})
}
} else {
if (PermissionUtils.isGrantedDrawOverlays()) {
sw_overlay.isChecked = true
PermissionPageManagement.goToSetting(this)
}
}
}
}
LogUtils.i("isAccessibilitySettingOn: false")
return false
})
}
/**
@@ -185,7 +186,7 @@ class ListenActivity : AppCompatActivity() {
}
private fun freshOpenServiceSwitch(clazz: Class<*>, s: Switch) {
if (isAccessibilitySettingOn()) {
if (PermissionHelper.isAccessibilitySettingOn()) {
s.isChecked = true
when (s.id) {
R.id.sw_accessibility -> {
@@ -205,6 +206,7 @@ class ListenActivity : AppCompatActivity() {
val commentDialog = Dialog(this)
commentDialog.setContentView(R.layout.dialog_input)
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
okBtn.setOnClickListener {
val text = et.text.toString()
@@ -228,4 +230,32 @@ class ListenActivity : AppCompatActivity() {
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
* 按手机号添加好友 ADD_FRIEND_BY_PHONE
* 展示群信息 SHOW_GROUP_INFO
* 推送文件(网络图片视频和文件等) PUSH_FILE
* <p>
* 非操作类型 300
* 机器人普通日志记录 ROBOT_LOG
@@ -61,6 +62,7 @@ public class WeworkMessageBean {
public static final int INIT_ANTI_HARASSMENT_RULE = 215;
public static final int UPDATE_ANTI_HARASSMENT_RULE = 216;
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_ERROR_LOG = 302;
@@ -126,6 +128,9 @@ public class WeworkMessageBean {
public static final int TEXT_TYPE_COLLECTION = 14;
public static final int TEXT_TYPE_REPLY = 15;
//消息id(解析指令时同步)
public String messageId;
//标题 通常是群名或联系人
public List<String> titleList;
//上传聊天列表
@@ -141,6 +146,8 @@ public class WeworkMessageBean {
public String receivedContent;
//想要at的昵称
public String at;
//想要at的昵称列表
public List<String> atList;
//原始内容text
public String originalContent;
//多选(转发等)
@@ -160,6 +167,10 @@ public class WeworkMessageBean {
public Integer groupNumber;
//群公告
public String groupAnnouncement;
//群备注
public String groupRemark;
//群模板
public String groupTemplate;
//新群名
public String newGroupName;
//新群公告
@@ -178,6 +189,10 @@ public class WeworkMessageBean {
//添加好友
public Friend friend;
//网络文件
public String fileUrl;
public String fileType;
public WeworkMessageBean() {}
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;
}
//消息类型
public int type = 0;
//消息列表的每条消息
@@ -254,6 +270,19 @@ public class WeworkMessageBean {
public Boolean newFriend;
//留言
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
@@ -261,12 +290,12 @@ public class WeworkMessageBean {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
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
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
@@ -278,6 +307,8 @@ public class WeworkMessageBean {
", roomType=" + roomType +
", receivedName='" + receivedName + '\'' +
", receivedContent='" + receivedContent + '\'' +
", at='" + at + '\'' +
", atList=" + atList +
", originalContent='" + originalContent + '\'' +
", nameList=" + nameList +
", extraText='" + extraText + '\'' +
@@ -287,12 +318,18 @@ public class WeworkMessageBean {
", selectList=" + selectList +
", groupNumber=" + groupNumber +
", groupAnnouncement='" + groupAnnouncement + '\'' +
", groupRemark='" + groupRemark + '\'' +
", groupTemplate='" + groupTemplate + '\'' +
", newGroupName='" + newGroupName + '\'' +
", newGroupAnnouncement='" + newGroupAnnouncement + '\'' +
", removeList=" + removeList +
", showMessageHistory=" + showMessageHistory +
", myInfo=" + myInfo +
", objectName='" + objectName + '\'' +
", qrcode='" + qrcode + '\'' +
", friend=" + friend +
", fileUrl='" + fileUrl + '\'' +
", fileType='" + fileType + '\'' +
", type=" + type +
'}';
}

View File

@@ -7,12 +7,13 @@ import org.yameida.worktool.Constant
import java.util.*
import kotlin.collections.ArrayList
class WeworkMessageListBean {
class WeworkMessageListBean<T> {
companion object {
const val SOCKET_TYPE_HEARTBEAT = 0
const val SOCKET_TYPE_MESSAGE_CONFIRM = 1
const val SOCKET_TYPE_MESSAGE_LIST = 2
const val SOCKET_TYPE_RAW_CONFIRM = 3
}
/**
@@ -20,6 +21,7 @@ class WeworkMessageListBean {
* TYPE_HEARTBEAT 心跳检测
* TYPE_MESSAGE_CONFIRM 消息确认
* TYPE_MESSAGE_LIST 消息列表
* SOCKET_TYPE_RAW_CONFIRM 执行指令结果确认
*/
var socketType = SOCKET_TYPE_HEARTBEAT
@@ -27,7 +29,7 @@ class WeworkMessageListBean {
var messageId = TimeUtils.date2String(Date()).replace(" ", "#") + "#" + UUID.randomUUID()
//消息列表
var list: ArrayList<WeworkMessageBean> = arrayListOf()
var list: ArrayList<T> = arrayListOf()
//加密消息列表
var encryptedList: String = ""
@@ -35,7 +37,7 @@ class WeworkMessageListBean {
//消息加密 0不加密 1AES
var encryptType = Constant.encryptType
constructor(weworkMessageBean: WeworkMessageBean, type: Int) {
constructor(weworkMessageBean: T, type: Int, messageId: String? = null) {
if (encryptType == 0) {
list.add(weworkMessageBean)
} else if (encryptType == 1) {
@@ -47,6 +49,7 @@ class WeworkMessageListBean {
)
}
this.socketType = type
if (messageId != null) this.messageId = messageId
}
constructor(messageId: String, type: Int) {
@@ -54,17 +57,4 @@ class WeworkMessageListBean {
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.LogUtils
import com.blankj.utilcode.util.ScreenUtils
import com.hjq.toast.ToastUtils
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.WeworkMessageListBean
import org.yameida.worktool.utils.AccessibilityUtil
@@ -54,6 +57,13 @@ fun goHomeTab(title: String): Boolean {
}
if (!atHome) {
backPress()
//如果在登录页面就提示关闭worktool主功能
if (AccessibilityUtil.findOnceByText(getRoot(), "手机号登录", exact = true) != null) {
LogUtils.e("登录前请先关闭WorkTool主功能")
ToastUtils.show("登录前请先关闭WorkTool主功能")
MyApplication.launchIntent()
sleep(5000)
}
}
}
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) {
WeworkController.weworkService.webSocketManager.send(
@@ -154,7 +177,7 @@ fun log(message: Any?, type: Int = WeworkMessageBean.ROBOT_LOG) {
}
/**
* 上传运行日志 简单封装 error log
* 上传运行日志
*/
fun error(message: Any?) {
log(message, WeworkMessageBean.ROBOT_ERROR_LOG)

View File

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

View File

@@ -47,8 +47,8 @@ object WeworkController {
*/
@RequestMapping
fun sendMessage(message: WeworkMessageBean): Boolean {
LogUtils.d("sendMessage(): ${message.titleList} ${message.receivedContent} ${message.at}")
return WeworkOperationImpl.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, message.atList)
}
/**
@@ -103,14 +103,16 @@ object WeworkController {
* @param message#groupName 修改群名称
* @param message#selectList 添加群成员名称列表 选填
* @param message#groupAnnouncement 修改群公告 选填
* @param message#groupRemark 修改群备注 选填
*/
@RequestMapping
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(
message.groupName,
message.selectList,
message.groupAnnouncement
message.groupAnnouncement,
message.groupRemark
)
}
@@ -131,17 +133,19 @@ object WeworkController {
* @param message#groupName 待修改的群
* @param message#newGroupName 修改群名 选填
* @param message#newGroupAnnouncement 修改群公告 选填
* @param message#groupRemark 修改群备注 选填
* @param message#selectList 添加群成员名称列表/拉人 选填
* @param message#showMessageHistory 拉人是否附带历史记录 选填
* @param message#removeList 移除群成员名称列表/踢人 选填
*/
@RequestMapping
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(
message.groupName,
message.newGroupName,
message.newGroupAnnouncement,
message.groupRemark,
message.selectList,
message.showMessageHistory,
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

View File

@@ -139,7 +139,7 @@ object WeworkGetImpl {
}
/**
* 获取群名、群主、群成员数、群公告
* 获取群名、群主、群成员数、群公告、群备注
*/
fun getGroupInfoDetail(): WeworkMessageBean {
val weworkMessageBean = WeworkMessageBean()
@@ -188,6 +188,12 @@ object WeworkGetImpl {
LogUtils.d("群公告: " + tvAnnouncement.text)
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()
return weworkMessageBean
}

View File

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

View File

@@ -3,13 +3,14 @@ package org.yameida.worktool.service
import android.view.accessibility.AccessibilityNodeInfo
import org.yameida.worktool.Constant
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.blankj.utilcode.util.*
import com.lzy.okgo.OkGo
import org.yameida.worktool.utils.*
import java.io.File
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
/**
@@ -24,21 +25,30 @@ object WeworkOperationImpl {
* @param at 要at的昵称
* @see WeworkMessageBean.TEXT_TYPE
*/
fun sendMessage(titleList: List<String>, receivedContent: String?, at: String? = null): Boolean {
fun sendMessage(
titleList: List<String>,
receivedContent: String?,
at: String? = null,
atList: List<String>? = null
): Boolean {
if (receivedContent.isNullOrEmpty()) {
LogUtils.d("未发现发送内容")
return false
}
for (title in titleList) {
if (WeworkRoomUtil.intoRoom(title)) {
sendChatMessage(receivedContent, at = at)
if (sendChatMessage(receivedContent, at = at, atList = atList)) {
LogUtils.d("$title: 发送成功")
return true
} else {
LogUtils.d("$title: 发送失败")
}
} else {
LogUtils.d("$title: 发送失败")
error("$title: 发送失败 $receivedContent")
}
}
return true
return false
}
/**
@@ -134,14 +144,18 @@ object WeworkOperationImpl {
) {
LogUtils.d("开始转发")
sleep(1000)
relaySelectTarget(nameList, extraText)
}
if (relaySelectTarget(nameList, extraText)) {
LogUtils.d("$title: 转发成功")
} else {
LogUtils.d("$title: 转发失败")
error("$title: 转发失败 $originalContent")
}
}
} else {
LogUtils.d("$title: 转发失败 未找到房间")
error("$title: 转发失败 $originalContent")
}
}
return true
}
@@ -165,11 +179,13 @@ object WeworkOperationImpl {
* @param groupName 修改群名称
* @param selectList 添加群成员名称列表 选填
* @param groupAnnouncement 修改群公告 选填
* @param groupRemark 修改群备注 选填
*/
fun initGroup(
groupName: String,
selectList: List<String>?,
groupAnnouncement: String?
groupAnnouncement: String?,
groupRemark: String?
): Boolean {
if (!WeworkRoomUtil.isGroupExists(groupName)) {
if (!createGroup() || !groupRename(groupName) || !groupAddMember(selectList)
@@ -180,8 +196,10 @@ object WeworkOperationImpl {
|| !groupChangeAnnouncement(groupAnnouncement)
) return false
}
//TODO 暂移除获取群二维码
// getGroupQrcode(groupName)
if (groupRemark != null) {
groupChangeRemark(groupRemark)
}
// getGroupQrcode(groupName, groupRemark)
return true
}
@@ -191,6 +209,7 @@ object WeworkOperationImpl {
* @param groupName 待修改的群
* @param newGroupName 修改群名 选填
* @param newGroupAnnouncement 修改群公告 选填
* @param groupRemark 修改群备注 选填
* @param selectList 添加群成员名称列表/拉人 选填
* @param showMessageHistory 拉人是否附带历史记录 选填
* @param removeList 移除群成员名称列表/踢人 选填
@@ -199,6 +218,7 @@ object WeworkOperationImpl {
groupName: String,
newGroupName: String?,
newGroupAnnouncement: String?,
groupRemark: String?,
selectList: List<String>?,
showMessageHistory: Boolean = false,
removeList: List<String>?
@@ -216,6 +236,9 @@ object WeworkOperationImpl {
if (newGroupAnnouncement != null) {
groupChangeAnnouncement(newGroupAnnouncement)
}
if (groupRemark != null) {
groupChangeRemark(groupRemark)
}
backPress()
return true
}
@@ -249,10 +272,13 @@ object WeworkOperationImpl {
AccessibilityUtil.performClick(shareFileButton)
val shareToWorkButton = AccessibilityUtil.findOneByText(getRoot(true), "发送给同事")
AccessibilityUtil.performClick(shareToWorkButton)
relaySelectTarget(titleList, extraText)
if (relaySelectTarget(titleList, extraText)) {
val stayButton = AccessibilityUtil.findOneByText(getRoot(), "留在企业微信")
AccessibilityUtil.performClick(stayButton)
return true
} else {
LogUtils.e("微盘文件转发失败: $objectName")
}
} else {
LogUtils.e("微盘未搜索到相关图片: $objectName")
}
@@ -290,8 +316,11 @@ object WeworkOperationImpl {
AccessibilityUtil.performClick(imageViewList[1])
val shareFileButton = AccessibilityUtil.findOneByDesc(getRoot(), "转发")
AccessibilityUtil.performClick(shareFileButton)
relaySelectTarget(titleList, extraText)
if (relaySelectTarget(titleList, extraText)) {
return true
} else {
LogUtils.e("微盘文件转发失败: $objectName")
}
} else {
LogUtils.e("微盘未搜索到相关文件: $objectName")
}
@@ -370,8 +399,11 @@ object WeworkOperationImpl {
AccessibilityUtil.performClick(imageViewList[1])
val shareFileButton = AccessibilityUtil.findOneByDesc(getRoot(), "转发")
AccessibilityUtil.performClick(shareFileButton)
relaySelectTarget(titleList, extraText)
if (relaySelectTarget(titleList, extraText)) {
return true
} else {
LogUtils.e("微盘文件转发失败: $objectName")
}
} else {
LogUtils.e("文档未搜索到相关文件: $objectName")
}
@@ -381,6 +413,52 @@ object WeworkOperationImpl {
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
@@ -888,17 +966,55 @@ object WeworkOperationImpl {
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
*/
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)
if (voiceFlag != null) {
AccessibilityUtil.performClickWithSon(AccessibilityUtil.findFrontNode(voiceFlag))
}
var atFailed = false
if (!at.isNullOrEmpty()) {
val atList = if (!at.isNullOrEmpty()) listOf(at) else atList
if (!atList.isNullOrEmpty()) {
atList.forEachIndexed { index, at ->
if (index == 0) {
AccessibilityUtil.findTextInput(getRoot(), "@")
} else {
AccessibilityUtil.sendTextForEditText(Utils.getApp(),
AccessibilityUtil.findOnceByClazz(getRoot(), Views.EditText), "@"
)
}
val atFlag = AccessibilityUtil.findOneByText(getRoot(), "选择提醒的人", timeout = 2000, exact = true)
if (atFlag != null) {
val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView)
@@ -933,15 +1049,18 @@ object WeworkOperationImpl {
}
}
}
val content = if (atFailed) "@$at $text" else "$text"
val append = (reply == true) || (!at.isNullOrEmpty() && !atFailed)
}
val content = if (atFailed) "@${atList?.joinToString()} $text" else text
val append = (reply == true) || (!atList.isNullOrEmpty() && !atFailed)
if (AccessibilityUtil.findTextInput(getRoot(), content, append = append)) {
AccessibilityUtil.findOneByText(getRoot(), "发送", exact = true, timeout = 2000)
val sendButton = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button)
.firstOrNull { it.text == "发送" }
if (sendButton != null) {
LogUtils.d("发送消息: \n$content")
log("发送消息: \n$content")
AccessibilityUtil.performClick(sendButton)
return true
} else {
LogUtils.e("未找到发送按钮")
error("未找到发送按钮")
@@ -950,6 +1069,7 @@ object WeworkOperationImpl {
LogUtils.e("未找到输入框")
error("未找到输入框")
}
return false
}
/**
@@ -1015,8 +1135,9 @@ object WeworkOperationImpl {
/**
* 获取群二维码并上传后台
*/
fun getGroupQrcode(groupName: String): Boolean {
if (WeworkRoomUtil.intoRoom(groupName) && WeworkRoomUtil.intoGroupManager()) {
fun getGroupQrcode(groupName: String, groupRemark: String?): Boolean {
if (AccessibilityUtil.findOneByText(getRoot(), "全部群成员", "微信用户创建", timeout = Constant.CHANGE_PAGE_INTERVAL) != null ||
(WeworkRoomUtil.intoRoom(groupName) && WeworkRoomUtil.intoGroupManager())) {
val tvList = AccessibilityUtil.findAllOnceByClazz(getRoot(), Views.TextView)
tvList.forEachIndexed { index, tv ->
if (tv.text != null && tv.text.contains("微信用户创建")) {
@@ -1054,6 +1175,7 @@ object WeworkOperationImpl {
val weworkMessageBean = WeworkMessageBean()
weworkMessageBean.type = WeworkMessageBean.GET_GROUP_QRCODE
weworkMessageBean.groupName = groupName
weworkMessageBean.groupRemark = groupRemark
weworkMessageBean.qrcode = qrcode
WeworkController.weworkService.webSocketManager.send(
weworkMessageBean

View File

@@ -71,12 +71,14 @@ class WeworkService : AccessibilityService() {
override fun onDestroy() {
super.onDestroy()
LogUtils.i("onDestroy")
//关闭自动回复
WeworkController.enableLoopRunning = false
//隐藏软键盘模式
softKeyboardController.showMode = SHOW_MODE_AUTO
webSocketManager.close(1000, "service Destroy")
}
class EchoWebSocketListener() : WebSocketListener() {
inner class EchoWebSocketListener : WebSocketListener() {
private val TAG = "WeworkService.EchoWebSocketListener"
private lateinit var socket: WebSocket
override fun onOpen(webSocket: WebSocket, response: Response) {
@@ -86,6 +88,8 @@ class WeworkService : AccessibilityService() {
val appVersion = SPUtils.getInstance().getString("appVersion", "")
val workVersion= SPUtils.getInstance().getString("workVersion", "")
log("链接建立: $robotId appVersion: $appVersion workVersion: $workVersion")
LogUtils.i("设置自动跳转企业微信")
sendBroadcast(true)
}
override fun onMessage(webSocket: WebSocket, text: String) {
@@ -102,18 +106,27 @@ class WeworkService : AccessibilityService() {
super.onClosed(webSocket, code, reason)
//服务器关闭后
Log.e(TAG, "链接关闭 $reason")
sendBroadcast(false)
}
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
super.onClosing(webSocket, code, reason)
socket.close(code, reason)
Log.e(TAG, "服务端关闭连接 $code: $reason")
sendBroadcast(false)
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
//服务器中断
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 com.blankj.utilcode.util.ScreenUtils
import org.yameida.worktool.service.WeworkController
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
/**
* 1.查询类
@@ -56,6 +60,17 @@ object AccessibilityUtil {
private const val SHORT_INTERVAL = 150L
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(非粘贴 推荐)
fun editTextInput(nodeInfo: AccessibilityNodeInfo?, text: String): Boolean {
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.LogUtils;
import com.hjq.toast.ToastUtils;
import org.yameida.worktool.model.WeworkMessageBean;
import org.yameida.worktool.model.WeworkMessageListBean;
@@ -24,15 +25,11 @@ import okhttp3.WebSocketListener;
public class WebSocketManager {
public static final String HEARTBEAT = "{" +
"\"type\": " + WeworkMessageBean.HEART_BEAT +
",\"hearBeat\": \"心跳检测\"" +
"}";
public static final String HEARTBEAT = "{\"type\":" + WeworkMessageBean.HEART_BEAT + "}";
private static final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
public static Map<String, WebSocketManager> webSocketManager = new ConcurrentHashMap<>();
private static final int reconnectTimes = 7;
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 ScheduledFuture task;
private WebSocket socket;
@@ -52,7 +49,7 @@ public class WebSocketManager {
}
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, "链接关闭");
}
public static void closeManager() {
Log.e("SocketManager", "关闭Manager:");
for (Map.Entry<String, WebSocketManager> e : webSocketManager.entrySet()) {
@@ -115,10 +111,14 @@ public class WebSocketManager {
connecting = true;
Log.e(url, "重连");
boolean isConnect = false;
int interval = reconnectInt;
while (!isConnect) {
try {
isConnect = connect();
Thread.sleep(reconnectInt);
Thread.sleep(interval);
if (interval < 600000) {
interval *= 2;
}
} catch (Exception e) {
e.printStackTrace();
}
@@ -142,6 +142,7 @@ public class WebSocketManager {
if (!connecting && (socket == null || !socket.send(HEARTBEAT))) {
reConnect();
}
ToastUtils.show("机器人运行中 请勿人工操作手机~");
};
//每heartBeatRate秒发一次心跳包

View File

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

View File

@@ -301,6 +301,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_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
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -338,7 +373,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:layout_marginTop="15dp"
android:orientation="vertical">
<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()
maven { url 'https://maven.fabric.io/public' }
maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://jitpack.io' }
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.0"
@@ -22,6 +23,7 @@ allprojects {
jcenter()
maven { url 'https://maven.fabric.io/public' }
maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://jitpack.io' }
}
}