update 封装base库;集成flowwindow库;悬浮窗功能;赞助和分享;集成企微sdk;界面更新;添加待办修复;滚动手势优化;建群达到上限检查;兼容减号和括号搜索;应用保活;其他已知缺陷修复
@@ -31,35 +31,12 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
implementation project(':baselibrary')
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation project(':floatwindow')
|
||||||
implementation 'androidx.core:core-ktx:1.3.2'
|
implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
|
||||||
implementation 'com.google.android.material:material:1.4.0'
|
|
||||||
|
|
||||||
//工具集
|
|
||||||
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'
|
|
||||||
//网络
|
|
||||||
implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0'
|
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
||||||
implementation 'androidx.core:core-ktx:1.3.2'
|
|
||||||
|
|
||||||
//友盟统计SDK
|
//友盟统计SDK
|
||||||
implementation 'com.umeng.umsdk:common:9.4.7'// 必选
|
implementation 'com.umeng.umsdk:common:9.4.7'// 必选
|
||||||
implementation 'com.umeng.umsdk:asms:1.4.1'// 必选
|
implementation 'com.umeng.umsdk:asms:1.4.1'// 必选
|
||||||
implementation 'com.umeng.umsdk:apm:1.5.2' // 错误分析升级为独立SDK,看crash数据请一定集成,可选
|
implementation 'com.umeng.umsdk:apm:1.5.2' // 错误分析升级为独立SDK,看crash数据请一定集成,可选
|
||||||
|
|
||||||
//自动更新
|
|
||||||
implementation 'com.teprinciple:updateapputilsx:2.3.0'
|
|
||||||
//ok
|
|
||||||
implementation 'com.lzy.net:okgo:3.0.4'
|
|
||||||
//qrcode
|
|
||||||
implementation 'com.github.yoojia:next-qrcode:2.0-2'
|
|
||||||
//QMUI
|
|
||||||
implementation 'com.qmuiteam:qmui:2.0.0-alpha10'
|
|
||||||
}
|
}
|
||||||
BIN
app/libs/lib_wwapi-2.0.12.11.aar
Normal file
@@ -24,6 +24,7 @@
|
|||||||
<application
|
<application
|
||||||
android:name="org.yameida.worktool.MyApplication"
|
android:name="org.yameida.worktool.MyApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
tools:replace="android:allowBackup"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name="org.yameida.worktool.activity.ListenActivity"
|
android:name="org.yameida.worktool.activity.ListenActivity"
|
||||||
android:windowSoftInputMode="adjustUnspecified|stateHidden"
|
android:windowSoftInputMode="adjustUnspecified|stateHidden"
|
||||||
|
android:launchMode="singleTask"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@@ -44,7 +46,24 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="org.yameida.worktool.activity.LoginActivity"
|
android:name="org.yameida.worktool.activity.LoginActivity"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="org.yameida.worktool.activity.SettingsActivity"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="org.yameida.worktool.activity.BrowserActivity"
|
||||||
android:windowSoftInputMode="adjustUnspecified|stateHidden"
|
android:windowSoftInputMode="adjustUnspecified|stateHidden"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="org.yameida.worktool.activity.FloatViewGuideActivity"
|
||||||
|
android:windowSoftInputMode="adjustUnspecified|stateHidden"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
</activity>
|
</activity>
|
||||||
<service
|
<service
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ import com.blankj.utilcode.util.SPUtils
|
|||||||
|
|
||||||
object Constant {
|
object Constant {
|
||||||
|
|
||||||
val AVAILABLE_VERSION = arrayListOf("4.0.2", "4.0.6", "4.0.8", "4.0.10", "4.0.12", "4.0.16", "4.0.18", "4.0.19")
|
val AVAILABLE_VERSION = arrayListOf("4.0.2", "4.0.6", "4.0.8", "4.0.10", "4.0.12", "4.0.16", "4.0.18", "4.0.19", "4.0.20")
|
||||||
const val PACKAGE_NAMES = "com.tencent.wework"
|
const val PACKAGE_NAMES = "com.tencent.wework"
|
||||||
const val LISTEN_CHANNEL_ID = "LISTEN_CHANNEL_ID"
|
|
||||||
const val WEWORK_NOTIFY = "wework_notify"
|
const val WEWORK_NOTIFY = "wework_notify"
|
||||||
const val CHANGE_PAGE_INTERVAL = 1000L
|
const val CHANGE_PAGE_INTERVAL = 1000L
|
||||||
const val POP_WINDOW_INTERVAL = 500L
|
const val POP_WINDOW_INTERVAL = 500L
|
||||||
private const val DEFAULT_HOST = "wss://worktool.asrtts.cn"
|
private const val DEFAULT_HOST = "wss://worktool.asrtts.cn"
|
||||||
|
|
||||||
var myName = ""
|
var myName = ""
|
||||||
var regTrimTitle = "(…$)|(-.*$)|(\\(.*?\\)$)".toRegex()
|
// var regTrimTitle = "(…$)|(-.*$)|(\\(.*?\\)$)".toRegex()
|
||||||
|
var regTrimTitle = "(…$)".toRegex()
|
||||||
var key = "9876543210abcdef".toByteArray()
|
var key = "9876543210abcdef".toByteArray()
|
||||||
var iv = "0123456789abcdef".toByteArray()
|
var iv = "0123456789abcdef".toByteArray()
|
||||||
val transformation = "AES/CBC/PKCS7Padding"
|
val transformation = "AES/CBC/PKCS7Padding"
|
||||||
@@ -21,16 +21,33 @@ object Constant {
|
|||||||
var autoReply = SPUtils.getInstance().getInt("autoReply", 1)
|
var autoReply = SPUtils.getInstance().getInt("autoReply", 1)
|
||||||
var groupStrict = false
|
var groupStrict = false
|
||||||
var friendRemarkStrict = false
|
var friendRemarkStrict = false
|
||||||
|
var robotId: String
|
||||||
|
get() = SPUtils.getInstance().getString("robotId", SPUtils.getInstance().getString("LISTEN_CHANNEL_ID", ""))
|
||||||
|
set(value) {
|
||||||
|
SPUtils.getInstance().put("robotId", value)
|
||||||
|
}
|
||||||
|
var replyStrategy: Int
|
||||||
|
get() = SPUtils.getInstance().getInt("replyStrategy", 1)
|
||||||
|
set(value) {
|
||||||
|
SPUtils.getInstance().put("replyStrategy", value)
|
||||||
|
}
|
||||||
|
var qaUrl: String
|
||||||
|
get() = SPUtils.getInstance().getString("qaUrl", "")
|
||||||
|
set(value) {
|
||||||
|
SPUtils.getInstance().put("qaUrl", value)
|
||||||
|
}
|
||||||
var host: String
|
var host: String
|
||||||
get() = SPUtils.getInstance().getString("host", DEFAULT_HOST)
|
get() = SPUtils.getInstance().getString("host", DEFAULT_HOST)
|
||||||
set(value) {
|
set(value) {
|
||||||
SPUtils.getInstance().put("host", value)
|
SPUtils.getInstance().put("host", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWsUrl() = "$host/webserver/wework/" + SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID)
|
fun getWsUrl() = "$host/webserver/wework/$robotId"
|
||||||
|
|
||||||
fun getCheckUpdateUrl() = "${getBaseUrl()}/appUpdate/checkUpdate"
|
fun getCheckUpdateUrl() = "${getBaseUrl()}/appUpdate/checkUpdate"
|
||||||
|
|
||||||
|
fun getRobotUpdateUrl() = "${getBaseUrl()}/robot/robotInfo/update"
|
||||||
|
|
||||||
fun getTestUrl() = "${getBaseUrl()}/test"
|
fun getTestUrl() = "${getBaseUrl()}/test"
|
||||||
|
|
||||||
private fun getBaseUrl() = host.replace("wss", "https").replace("ws", "http")
|
private fun getBaseUrl() = host.replace("wss", "https").replace("ws", "http")
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ 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
|
||||||
|
import org.yameida.worktool.utils.IWWAPIUtil
|
||||||
import update.UpdateAppUtils
|
import update.UpdateAppUtils
|
||||||
|
|
||||||
class MyApplication : Application() {
|
class MyApplication : Application() {
|
||||||
@@ -46,7 +47,9 @@ class MyApplication : Application() {
|
|||||||
if (SPUtils.getInstance().getString("uminit", "1") == "1") {
|
if (SPUtils.getInstance().getString("uminit", "1") == "1") {
|
||||||
UMConfigure.init(this, key, 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", Constant.robotId);
|
||||||
|
//初始化企业微信sdk
|
||||||
|
IWWAPIUtil.init(this)
|
||||||
//初始化自动更新
|
//初始化自动更新
|
||||||
UpdateAppUtils.init(this)
|
UpdateAppUtils.init(this)
|
||||||
//设置全局异常捕获重启
|
//设置全局异常捕获重启
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.yameida.worktool.activity
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import kotlinx.android.synthetic.main.activity_browser.*
|
||||||
|
import org.yameida.worktool.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 浏览器页
|
||||||
|
*/
|
||||||
|
class BrowserActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
setContentView(R.layout.activity_browser)
|
||||||
|
|
||||||
|
initView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
qmwv.loadUrl("https://wt.asrtts.cn")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package org.yameida.worktool.activity
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.view.View
|
||||||
|
import android.view.animation.AlphaAnimation
|
||||||
|
import android.view.animation.Animation
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.blankj.utilcode.util.LogUtils
|
||||||
|
import com.blankj.utilcode.util.SPUtils
|
||||||
|
import com.blankj.utilcode.util.Utils
|
||||||
|
import kotlinx.android.synthetic.main.activity_float_guide.*
|
||||||
|
import org.yameida.worktool.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gallon on 2019/7/20.
|
||||||
|
* 提示开启悬浮窗权限
|
||||||
|
*/
|
||||||
|
class FloatViewGuideActivity: AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_float_guide)
|
||||||
|
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or
|
||||||
|
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
||||||
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||||
|
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
|
||||||
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||||
|
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
|
|
||||||
|
tv_float_allow.setOnClickListener {
|
||||||
|
try {
|
||||||
|
if (!Settings.canDrawOverlays(Utils.getApp())) {
|
||||||
|
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply {
|
||||||
|
data = Uri.parse("package:$packageName")
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {}
|
||||||
|
}
|
||||||
|
tv_float_reject.setOnClickListener {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
cb_guide_not.isChecked = SPUtils.getInstance().getBoolean("not_show_float_guide", false)
|
||||||
|
cb_guide_not.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
SPUtils.getInstance().put("not_show_float_guide", isChecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
val alphaAnimation = AlphaAnimation(0.2F, 1F).apply {
|
||||||
|
duration = 800
|
||||||
|
repeatCount = Animation.INFINITE
|
||||||
|
repeatMode = Animation.REVERSE
|
||||||
|
}
|
||||||
|
iv_over_finger.startAnimation(alphaAnimation)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
val canDrawOverlays = Settings.canDrawOverlays(Utils.getApp())
|
||||||
|
LogUtils.d("Settings.canDrawOverlays: $canDrawOverlays")
|
||||||
|
if (canDrawOverlays) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,14 +4,12 @@ import android.os.Bundle
|
|||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.CompoundButton
|
import android.widget.CompoundButton
|
||||||
import android.widget.Switch
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.blankj.utilcode.util.*
|
import com.blankj.utilcode.util.*
|
||||||
import com.umeng.analytics.MobclickAgent
|
import com.umeng.analytics.MobclickAgent
|
||||||
import kotlinx.android.synthetic.main.activity_listen.*
|
import kotlinx.android.synthetic.main.activity_listen.*
|
||||||
import org.yameida.worktool.*
|
import org.yameida.worktool.*
|
||||||
import org.yameida.worktool.service.WeworkService
|
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@@ -28,7 +26,9 @@ class ListenActivity : AppCompatActivity() {
|
|||||||
* @param type 0=游客登录
|
* @param type 0=游客登录
|
||||||
*/
|
*/
|
||||||
fun enterActivity(context: Context, type: Int) {
|
fun enterActivity(context: Context, type: Int) {
|
||||||
|
LogUtils.d("ListenActivity.enterActivity type: $type")
|
||||||
context.startActivity(Intent(context, ListenActivity::class.java).apply {
|
context.startActivity(Intent(context, ListenActivity::class.java).apply {
|
||||||
|
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
putExtra("type", type)
|
putExtra("type", type)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -56,10 +56,7 @@ class ListenActivity : AppCompatActivity() {
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
sw_overlay.isChecked = PermissionUtils.isGrantedDrawOverlays()
|
sw_overlay.isChecked = PermissionUtils.isGrantedDrawOverlays()
|
||||||
freshOpenServiceSwitch(
|
freshOpenServiceSwitch()
|
||||||
WeworkService::class.java,
|
|
||||||
sw_accessibility
|
|
||||||
)
|
|
||||||
if (needToWork) {
|
if (needToWork) {
|
||||||
needToWork = false
|
needToWork = false
|
||||||
goToWork()
|
goToWork()
|
||||||
@@ -67,28 +64,19 @@ class ListenActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
et_channel.setText(SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID))
|
iv_settings.setOnClickListener {
|
||||||
|
SettingsActivity.enterActivity(this)
|
||||||
|
}
|
||||||
|
et_channel.setText(Constant.robotId)
|
||||||
bt_save.setOnClickListener {
|
bt_save.setOnClickListener {
|
||||||
val channel = et_channel.text.toString().trim()
|
val channel = et_channel.text.toString().trim()
|
||||||
SPUtils.getInstance().put(Constant.LISTEN_CHANNEL_ID, channel)
|
Constant.robotId = channel
|
||||||
ToastUtils.showLong("保存成功")
|
ToastUtils.showLong("保存成功")
|
||||||
sendBroadcast(Intent(Constant.WEWORK_NOTIFY).apply {
|
sendBroadcast(Intent(Constant.WEWORK_NOTIFY).apply {
|
||||||
putExtra("type", "modify_channel")
|
putExtra("type", "modify_channel")
|
||||||
})
|
})
|
||||||
MobclickAgent.onProfileSignIn(channel)
|
MobclickAgent.onProfileSignIn(channel)
|
||||||
}
|
}
|
||||||
sw_encrypt.isChecked = Constant.encryptType == 1
|
|
||||||
sw_encrypt.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
|
||||||
LogUtils.i("sw_encrypt onCheckedChanged: $isChecked")
|
|
||||||
Constant.encryptType = if (isChecked) 1 else 0
|
|
||||||
SPUtils.getInstance().put("encryptType", Constant.encryptType)
|
|
||||||
})
|
|
||||||
sw_auto_reply.isChecked = Constant.autoReply == 1
|
|
||||||
sw_auto_reply.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
|
||||||
LogUtils.i("sw_auto_reply onCheckedChanged: $isChecked")
|
|
||||||
Constant.autoReply = if (isChecked) 1 else 0
|
|
||||||
SPUtils.getInstance().put("autoReply", Constant.autoReply)
|
|
||||||
})
|
|
||||||
tv_host.text = Constant.host
|
tv_host.text = Constant.host
|
||||||
tv_host.setOnClickListener {
|
tv_host.setOnClickListener {
|
||||||
showSelectHostDialog()
|
showSelectHostDialog()
|
||||||
@@ -134,7 +122,7 @@ class ListenActivity : AppCompatActivity() {
|
|||||||
sw_accessibility.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
sw_accessibility.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||||
LogUtils.i("sw_accessibility onCheckedChanged: $isChecked")
|
LogUtils.i("sw_accessibility onCheckedChanged: $isChecked")
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
if (SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID).isNullOrBlank()) {
|
if (Constant.robotId.isBlank()) {
|
||||||
sw_accessibility.isChecked = false
|
sw_accessibility.isChecked = false
|
||||||
ToastUtils.showLong("请先填写并保存链接号~")
|
ToastUtils.showLong("请先填写并保存链接号~")
|
||||||
} else if (!PermissionHelper.isAccessibilitySettingOn()) {
|
} else if (!PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
@@ -183,24 +171,15 @@ class ListenActivity : AppCompatActivity() {
|
|||||||
private fun openAccessibility() {
|
private fun openAccessibility() {
|
||||||
val clickListener =
|
val clickListener =
|
||||||
DialogInterface.OnClickListener { dialog, which ->
|
DialogInterface.OnClickListener { dialog, which ->
|
||||||
freshOpenServiceSwitch(
|
freshOpenServiceSwitch()
|
||||||
WeworkService::class.java,
|
|
||||||
sw_accessibility
|
|
||||||
)
|
|
||||||
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
val cancel = DialogInterface.OnCancelListener {
|
val cancel = DialogInterface.OnCancelListener {
|
||||||
freshOpenServiceSwitch(
|
freshOpenServiceSwitch()
|
||||||
WeworkService::class.java,
|
|
||||||
sw_accessibility
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val cancelListener = DialogInterface.OnClickListener { dialog, which ->
|
val cancelListener = DialogInterface.OnClickListener { dialog, which ->
|
||||||
freshOpenServiceSwitch(
|
freshOpenServiceSwitch()
|
||||||
WeworkService::class.java,
|
|
||||||
sw_accessibility
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val dialog: AlertDialog = AlertDialog.Builder(this)
|
val dialog: AlertDialog = AlertDialog.Builder(this)
|
||||||
.setMessage(R.string.tips)
|
.setMessage(R.string.tips)
|
||||||
@@ -211,20 +190,8 @@ class ListenActivity : AppCompatActivity() {
|
|||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun freshOpenServiceSwitch(clazz: Class<*>, s: Switch) {
|
private fun freshOpenServiceSwitch() {
|
||||||
if (PermissionHelper.isAccessibilitySettingOn()) {
|
sw_accessibility.isChecked = PermissionHelper.isAccessibilitySettingOn()
|
||||||
s.isChecked = true
|
|
||||||
when (s.id) {
|
|
||||||
R.id.sw_accessibility -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.isChecked = false
|
|
||||||
when (s.id) {
|
|
||||||
R.id.sw_accessibility -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSelectHostDialog() {
|
private fun showSelectHostDialog() {
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
package org.yameida.worktool.activity
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.text.InputType
|
||||||
|
import android.view.WindowManager
|
||||||
|
import android.widget.CompoundButton
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.blankj.utilcode.util.*
|
||||||
|
import com.lzy.okgo.OkGo
|
||||||
|
import com.lzy.okgo.callback.StringCallback
|
||||||
|
import com.lzy.okgo.model.Response
|
||||||
|
import com.qmuiteam.qmui.widget.dialog.QMUIDialog
|
||||||
|
import kotlinx.android.synthetic.main.activity_settings.*
|
||||||
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.yameida.worktool.Constant
|
||||||
|
import org.yameida.worktool.R
|
||||||
|
import org.yameida.worktool.utils.*
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录页
|
||||||
|
*/
|
||||||
|
class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun enterActivity(context: Context) {
|
||||||
|
LogUtils.d("SettingsActivity.enterActivity")
|
||||||
|
context.startActivity(Intent(context, SettingsActivity::class.java).apply {
|
||||||
|
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
setContentView(R.layout.activity_settings)
|
||||||
|
|
||||||
|
initView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
freshOpenFlow()
|
||||||
|
freshOpenMain()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
iv_back_left.setOnClickListener { finish() }
|
||||||
|
sw_encrypt.isChecked = Constant.encryptType == 1
|
||||||
|
sw_encrypt.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
LogUtils.i("sw_encrypt onCheckedChanged: $isChecked")
|
||||||
|
Constant.encryptType = if (isChecked) 1 else 0
|
||||||
|
SPUtils.getInstance().put("encryptType", Constant.encryptType)
|
||||||
|
})
|
||||||
|
sw_receive.isChecked = Constant.autoReply == 1
|
||||||
|
sw_receive.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
LogUtils.i("sw_receive onCheckedChanged: $isChecked")
|
||||||
|
Constant.autoReply = if (isChecked) 1 else 0
|
||||||
|
SPUtils.getInstance().put("autoReply", Constant.autoReply)
|
||||||
|
})
|
||||||
|
rl_reply_strategy.setOnClickListener { showReplyStrategyDialog() }
|
||||||
|
rl_qa_url.setOnClickListener { showQaUrlDialog() }
|
||||||
|
rl_donate.setOnClickListener { showDonateDialog() }
|
||||||
|
rl_share.setOnClickListener { showShareDialog() }
|
||||||
|
freshOpenFlow()
|
||||||
|
bt_open_flow.setOnClickListener {
|
||||||
|
freshOpenFlow()
|
||||||
|
if (Settings.canDrawOverlays(Utils.getApp())) {
|
||||||
|
if (!FlowPermissionHelper.canBackgroundStart(Utils.getApp())) {
|
||||||
|
ToastUtils.showLong("请同时打开后台弹出界面权限~")
|
||||||
|
PermissionPageManagement.goToSetting(this)
|
||||||
|
}
|
||||||
|
FloatWindowHelper.showWindow()
|
||||||
|
} else {
|
||||||
|
startActivityForResult(Intent(this, FloatViewGuideActivity::class.java), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freshOpenMain()
|
||||||
|
bt_open_main.setOnClickListener {
|
||||||
|
freshOpenMain()
|
||||||
|
if (PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
|
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||||
|
startActivity(intent)
|
||||||
|
} else {
|
||||||
|
if (Constant.robotId.isBlank()) {
|
||||||
|
ToastUtils.showLong("请先填写并保存链接号~")
|
||||||
|
} else if (!PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
|
openAccessibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
freshOpenFlow()
|
||||||
|
if (Settings.canDrawOverlays(Utils.getApp())) {
|
||||||
|
if (!FlowPermissionHelper.canBackgroundStart(Utils.getApp())) {
|
||||||
|
ToastUtils.showLong("请同时打开后台弹出界面权限~")
|
||||||
|
PermissionPageManagement.goToSetting(this)
|
||||||
|
}
|
||||||
|
FloatWindowHelper.showWindow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showReplyStrategyDialog() {
|
||||||
|
val strategyArray = arrayOf("只读消息不回调", "仅私聊和群聊@机器人回调", "私聊群聊全部回调")
|
||||||
|
QMUIDialog.CheckableDialogBuilder(this)
|
||||||
|
.setTitle("回复策略")
|
||||||
|
.addItems(strategyArray) { dialog, which ->
|
||||||
|
dialog.dismiss()
|
||||||
|
updateRobotReplyStrategy(which)
|
||||||
|
}
|
||||||
|
.setCheckedIndex(Constant.replyStrategy)
|
||||||
|
.create(R.style.QMUI_Dialog)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showQaUrlDialog() {
|
||||||
|
val builder = QMUIDialog.EditTextDialogBuilder(this)
|
||||||
|
builder.setTitle("消息回调地址")
|
||||||
|
.setPlaceholder("请输入回调接口地址")
|
||||||
|
.setDefaultText(Constant.qaUrl)
|
||||||
|
.setInputType(InputType.TYPE_CLASS_TEXT)
|
||||||
|
.addAction(getString(R.string.delete)) { dialog, index ->
|
||||||
|
dialog.dismiss()
|
||||||
|
updateRobotQaUrl("")
|
||||||
|
}
|
||||||
|
.addAction(getString(R.string.cancel)) { dialog, index -> dialog.dismiss() }
|
||||||
|
.addAction(getString(R.string.add)) { dialog, index ->
|
||||||
|
val text = builder.editText.text
|
||||||
|
if (text != null) {
|
||||||
|
if (text.matches("https?://[^/]+.*".toRegex())) {
|
||||||
|
dialog.dismiss()
|
||||||
|
updateRobotQaUrl(text.toString().trim())
|
||||||
|
} else {
|
||||||
|
ToastUtils.showLong("格式异常!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ToastUtils.showLong("请勿为空!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.create(R.style.QMUI_Dialog).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showDonateDialog() {
|
||||||
|
DonateUtil.zfbDonate(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showShareDialog() {
|
||||||
|
startActivity(Intent.createChooser(Intent().apply {
|
||||||
|
action = Intent.ACTION_SEND
|
||||||
|
type = ShareUtil.TEXT
|
||||||
|
putExtra(Intent.EXTRA_TEXT, "我发现一个非常好用的企业微信机器人程序,文档地址: https://worktool.apifox.cn/ APP下载地址是: https://cdn.asrtts.cn/uploads/worktool/apk/worktool-latest.apk")
|
||||||
|
}, "分享"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun freshOpenFlow() {
|
||||||
|
if (Settings.canDrawOverlays(Utils.getApp())) {
|
||||||
|
if (FlowPermissionHelper.canBackgroundStart(Utils.getApp())) {
|
||||||
|
bt_open_flow.setBackgroundResource(R.drawable.comment_gray_btn)
|
||||||
|
bt_open_flow.text = "悬浮窗权限已开启"
|
||||||
|
} else {
|
||||||
|
bt_open_flow.setBackgroundResource(R.drawable.comment_red_btn)
|
||||||
|
bt_open_flow.text = "开启后台弹出界面"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bt_open_flow.setBackgroundResource(R.drawable.comment_red_btn)
|
||||||
|
bt_open_flow.text = "开启悬浮窗权限"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun freshOpenMain() {
|
||||||
|
if (PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
|
bt_open_main.setBackgroundResource(R.drawable.comment_gray_btn)
|
||||||
|
bt_open_main.text = "主功能已开启"
|
||||||
|
} else {
|
||||||
|
bt_open_main.setBackgroundResource(R.drawable.comment_red_btn)
|
||||||
|
bt_open_main.text = "开启主功能"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开辅助
|
||||||
|
*/
|
||||||
|
private fun openAccessibility() {
|
||||||
|
val clickListener =
|
||||||
|
DialogInterface.OnClickListener { dialog, which ->
|
||||||
|
freshOpenMain()
|
||||||
|
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
val cancel = DialogInterface.OnCancelListener {
|
||||||
|
freshOpenMain()
|
||||||
|
}
|
||||||
|
val cancelListener = DialogInterface.OnClickListener { dialog, which ->
|
||||||
|
freshOpenMain()
|
||||||
|
}
|
||||||
|
val dialog: AlertDialog = AlertDialog.Builder(this)
|
||||||
|
.setMessage(R.string.tips)
|
||||||
|
.setOnCancelListener(cancel)
|
||||||
|
.setNegativeButton("取消", cancelListener)
|
||||||
|
.setPositiveButton("确定", clickListener)
|
||||||
|
.create()
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateRobotQaUrl(callbackUrl: String) {
|
||||||
|
try {
|
||||||
|
val json = hashMapOf<String, Any>()
|
||||||
|
json["robotId"] = Constant.robotId
|
||||||
|
if (callbackUrl.isEmpty()) {
|
||||||
|
json["openCallback"] = 0
|
||||||
|
} else {
|
||||||
|
json["openCallback"] = 1
|
||||||
|
json["callbackUrl"] = callbackUrl
|
||||||
|
}
|
||||||
|
val requestBody = RequestBody.create(
|
||||||
|
MediaType.parse("application/json;charset=UTF-8"),
|
||||||
|
GsonUtils.toJson(json)
|
||||||
|
)
|
||||||
|
val call = object : StringCallback() {
|
||||||
|
override fun onSuccess(response: Response<String>?) {
|
||||||
|
if (response != null && JSONObject(response.body()).getInt("code") == 200) {
|
||||||
|
Constant.qaUrl = callbackUrl
|
||||||
|
ToastUtils.showLong(if (callbackUrl.isEmpty()) "关闭成功" else "更新成功")
|
||||||
|
} else {
|
||||||
|
onError(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(response: Response<String>?) {
|
||||||
|
ToastUtils.showLong(if (callbackUrl.isEmpty()) "关闭失败,请稍后再试~" else "更新失败,请稍后再试~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OkGo.post<String>(Constant.getRobotUpdateUrl()).upRequestBody(requestBody).execute(call)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateRobotReplyStrategy(type: Int) {
|
||||||
|
try {
|
||||||
|
val json = hashMapOf<String, Any>()
|
||||||
|
json["robotId"] = Constant.robotId
|
||||||
|
json["replyAll"] = type
|
||||||
|
val requestBody = RequestBody.create(
|
||||||
|
MediaType.parse("application/json;charset=UTF-8"),
|
||||||
|
GsonUtils.toJson(json)
|
||||||
|
)
|
||||||
|
val call = object : StringCallback() {
|
||||||
|
override fun onSuccess(response: Response<String>?) {
|
||||||
|
if (response != null && JSONObject(response.body()).getInt("code") == 200) {
|
||||||
|
Constant.replyStrategy = type
|
||||||
|
ToastUtils.showLong("更新成功")
|
||||||
|
} else {
|
||||||
|
onError(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(response: Response<String>?) {
|
||||||
|
ToastUtils.showLong("更新失败,请稍后再试~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OkGo.post<String>(Constant.getRobotUpdateUrl()).upRequestBody(requestBody).execute(call)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@ public class WeworkMessageBean {
|
|||||||
* 获取群信息 GET_GROUP_INFO
|
* 获取群信息 GET_GROUP_INFO
|
||||||
* 获取好友信息 GET_FRIEND_INFO
|
* 获取好友信息 GET_FRIEND_INFO
|
||||||
* 获取我的信息 GET_MY_INFO
|
* 获取我的信息 GET_MY_INFO
|
||||||
|
* 获取最近聊天列表 GET_RECENT_LIST
|
||||||
*/
|
*/
|
||||||
public static final int HEART_BEAT = 11;
|
public static final int HEART_BEAT = 11;
|
||||||
public static final int TYPE_RECEIVE_MESSAGE_LIST = 101;
|
public static final int TYPE_RECEIVE_MESSAGE_LIST = 101;
|
||||||
@@ -82,6 +83,7 @@ public class WeworkMessageBean {
|
|||||||
public static final int GET_FRIEND_INFO = 502;
|
public static final int GET_FRIEND_INFO = 502;
|
||||||
public static final int GET_MY_INFO = 503;
|
public static final int GET_MY_INFO = 503;
|
||||||
public static final int GET_GROUP_QRCODE = 504;
|
public static final int GET_GROUP_QRCODE = 504;
|
||||||
|
public static final int GET_RECENT_LIST = 505;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* roomType
|
* roomType
|
||||||
@@ -165,7 +167,7 @@ public class WeworkMessageBean {
|
|||||||
//转发附加留言
|
//转发附加留言
|
||||||
public String extraText;
|
public String extraText;
|
||||||
//接收消息类型
|
//接收消息类型
|
||||||
public int textType;
|
public Integer textType;
|
||||||
|
|
||||||
//群名
|
//群名
|
||||||
public String groupName;
|
public String groupName;
|
||||||
@@ -206,7 +208,7 @@ public class WeworkMessageBean {
|
|||||||
|
|
||||||
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, Integer type, Integer roomType, List<String> titleList, List<SubMessageBean> messageList, String log) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.roomType = roomType;
|
this.roomType = roomType;
|
||||||
this.titleList = titleList;
|
this.titleList = titleList;
|
||||||
@@ -217,36 +219,62 @@ public class WeworkMessageBean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//消息类型
|
//消息类型
|
||||||
public int type = 0;
|
public Integer type = 0;
|
||||||
|
|
||||||
//消息列表的每条消息
|
//消息列表的每条消息
|
||||||
public static class SubMessageBean {
|
public static class SubMessageBean {
|
||||||
//0其他人 1机器人自己 2unknown(如系统消息)
|
//0其他人 1机器人自己 2unknown(如系统消息)
|
||||||
public int sender = 0;
|
public Integer sender;
|
||||||
//消息类型判断 仅针对sender=0
|
//消息类型判断 仅针对sender=0
|
||||||
public int textType;
|
public Integer textType;
|
||||||
public List<ItemMessageBean> itemMessageList;
|
public List<ItemMessageBean> itemMessageList;
|
||||||
public List<String> nameList;
|
public List<String> nameList;
|
||||||
|
|
||||||
public SubMessageBean(int sender, int textType, List<ItemMessageBean> itemMessageList, List<String> nameList) {
|
public SubMessageBean(Integer sender, Integer textType, List<ItemMessageBean> itemMessageList, List<String> nameList) {
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.textType = textType;
|
this.textType = textType;
|
||||||
this.itemMessageList = itemMessageList;
|
this.itemMessageList = itemMessageList;
|
||||||
this.nameList = nameList;
|
this.nameList = nameList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
SubMessageBean that = (SubMessageBean) o;
|
||||||
|
return Objects.equals(sender, that.sender) && Objects.equals(textType, that.textType) && Objects.equals(itemMessageList, that.itemMessageList) && Objects.equals(nameList, that.nameList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(sender, textType, itemMessageList, nameList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//消息列表每条消息的text推断
|
//消息列表每条消息的text推断
|
||||||
public static class ItemMessageBean {
|
public static class ItemMessageBean {
|
||||||
//0消息主体上方信息 如日期等 系统消息(拉人/撤回/外部群等居中的提示语)
|
//0消息主体上方信息 如日期等 系统消息(拉人/撤回/外部群等居中的提示语)
|
||||||
//2消息内容
|
//2消息内容
|
||||||
public int feature = 0;
|
public Integer feature;
|
||||||
public String text;
|
public String text;
|
||||||
|
|
||||||
public ItemMessageBean(int feature, String text) {
|
public ItemMessageBean(Integer feature, String text) {
|
||||||
this.feature = feature;
|
this.feature = feature;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ItemMessageBean that = (ItemMessageBean) o;
|
||||||
|
return Objects.equals(feature, that.feature) && Objects.equals(text, that.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(feature, text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//我的信息
|
//我的信息
|
||||||
@@ -315,7 +343,7 @@ 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(messageId, that.messageId) && 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(fileBase64, that.fileBase64) && Objects.equals(fileUrl, that.fileUrl) && Objects.equals(fileType, that.fileType);
|
return Objects.equals(messageId, that.messageId) && 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(textType, that.textType) && 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(showMessageHistory, that.showMessageHistory) && Objects.equals(myInfo, that.myInfo) && Objects.equals(objectName, that.objectName) && Objects.equals(qrcode, that.qrcode) && Objects.equals(friend, that.friend) && Objects.equals(fileBase64, that.fileBase64) && Objects.equals(fileUrl, that.fileUrl) && Objects.equals(fileType, that.fileType) && Objects.equals(type, that.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -143,6 +143,11 @@ fun backPress() {
|
|||||||
if (confirm != null) {
|
if (confirm != null) {
|
||||||
LogUtils.d("尝试点击确定/我知道了/暂不进入")
|
LogUtils.d("尝试点击确定/我知道了/暂不进入")
|
||||||
AccessibilityUtil.performClick(confirm)
|
AccessibilityUtil.performClick(confirm)
|
||||||
|
} else {
|
||||||
|
val stayButton = AccessibilityUtil.findOnceByText(getRoot(true), "关闭应用", "等待", exact = true)
|
||||||
|
if (stayButton != null) {
|
||||||
|
LogUtils.d("疑似ANR 尝试点击等待")
|
||||||
|
AccessibilityUtil.performClick(stayButton)
|
||||||
} else {
|
} else {
|
||||||
LogUtils.d("未找到对话框 点击bar中心")
|
LogUtils.d("未找到对话框 点击bar中心")
|
||||||
AccessibilityUtil.performXYClick(WeworkController.weworkService, ScreenUtils.getScreenWidth() / 2F, BarUtils.getStatusBarHeight() * 2F)
|
AccessibilityUtil.performXYClick(WeworkController.weworkService, ScreenUtils.getScreenWidth() / 2F, BarUtils.getStatusBarHeight() * 2F)
|
||||||
@@ -155,6 +160,7 @@ fun backPress() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
sleep(Constant.POP_WINDOW_INTERVAL)
|
sleep(Constant.POP_WINDOW_INTERVAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import android.os.Message
|
|||||||
import com.blankj.utilcode.util.EncryptUtils
|
import com.blankj.utilcode.util.EncryptUtils
|
||||||
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.SPUtils
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import okhttp3.WebSocket
|
import okhttp3.WebSocket
|
||||||
import org.yameida.worktool.Constant
|
import org.yameida.worktool.Constant
|
||||||
import org.yameida.worktool.model.ExecCallbackBean
|
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.FloatWindowHelper
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.util.LinkedHashSet
|
import java.util.LinkedHashSet
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
@@ -21,12 +23,16 @@ object MyLooper {
|
|||||||
private var threadHandler: Handler? = null
|
private var threadHandler: Handler? = null
|
||||||
|
|
||||||
val looper = thread {
|
val looper = thread {
|
||||||
LogUtils.e("myLooper starting...")
|
LogUtils.i("myLooper starting...")
|
||||||
Looper.prepare()
|
Looper.prepare()
|
||||||
val myLooper = Looper.myLooper()
|
val myLooper = Looper.myLooper()
|
||||||
if (myLooper != null) {
|
if (myLooper != null) {
|
||||||
threadHandler = object : Handler(myLooper) {
|
threadHandler = object : Handler(myLooper) {
|
||||||
override fun handleMessage(msg: Message) {
|
override fun handleMessage(msg: Message) {
|
||||||
|
while (FloatWindowHelper.isPause) {
|
||||||
|
LogUtils.i("主功能暂停...")
|
||||||
|
sleep(Constant.CHANGE_PAGE_INTERVAL)
|
||||||
|
}
|
||||||
LogUtils.d("handle message: " + Thread.currentThread().name, msg)
|
LogUtils.d("handle message: " + Thread.currentThread().name, msg)
|
||||||
try {
|
try {
|
||||||
dealWithMessage(msg.obj as WeworkMessageBean)
|
dealWithMessage(msg.obj as WeworkMessageBean)
|
||||||
@@ -42,7 +48,11 @@ object MyLooper {
|
|||||||
Looper.loop()
|
Looper.loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun init() {}
|
fun init() {
|
||||||
|
LogUtils.i("init myLooper...")
|
||||||
|
SPUtils.getInstance("noTipMessage").clear()
|
||||||
|
SPUtils.getInstance("limit").clear()
|
||||||
|
}
|
||||||
|
|
||||||
fun getInstance(): Handler {
|
fun getInstance(): Handler {
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -168,6 +178,9 @@ object MyLooper {
|
|||||||
WeworkMessageBean.GET_MY_INFO -> {
|
WeworkMessageBean.GET_MY_INFO -> {
|
||||||
WeworkController.getMyInfo(message)
|
WeworkController.getMyInfo(message)
|
||||||
}
|
}
|
||||||
|
WeworkMessageBean.GET_RECENT_LIST -> {
|
||||||
|
WeworkController.getRecentList(message)
|
||||||
|
}
|
||||||
WeworkMessageBean.ROBOT_CONTROLLER_TEST -> {
|
WeworkMessageBean.ROBOT_CONTROLLER_TEST -> {
|
||||||
WeworkController.test(message)
|
WeworkController.test(message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,4 +390,14 @@ object WeworkController {
|
|||||||
return WeworkGetImpl.getMyInfo(message)
|
return WeworkGetImpl.getMyInfo(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最近聊天列表
|
||||||
|
* @see WeworkMessageBean.GET_RECENT_LIST
|
||||||
|
*/
|
||||||
|
@RequestMapping
|
||||||
|
fun getRecentList(message: WeworkMessageBean): Boolean {
|
||||||
|
LogUtils.d("getRecentList():")
|
||||||
|
return WeworkGetImpl.getRecentList(message)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -197,4 +197,45 @@ object WeworkGetImpl {
|
|||||||
backPress()
|
backPress()
|
||||||
return weworkMessageBean
|
return weworkMessageBean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最近聊天列表
|
||||||
|
*/
|
||||||
|
fun getRecentList(message: WeworkMessageBean): Boolean {
|
||||||
|
goHome()
|
||||||
|
AccessibilityUtil.scrollToTop(WeworkController.weworkService, getRoot())
|
||||||
|
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup)
|
||||||
|
if (list != null && list.childCount >= 2) {
|
||||||
|
val listBriefList = LinkedHashSet<WeworkMessageBean.SubMessageBean>()
|
||||||
|
val onScrollListener = object : AccessibilityUtil.OnScrollListener() {
|
||||||
|
override fun onScroll(): Boolean {
|
||||||
|
list.refresh()
|
||||||
|
for (i in 0 until list.childCount) {
|
||||||
|
val item = list.getChild(i)
|
||||||
|
val tempList = arrayListOf<WeworkMessageBean.ItemMessageBean>()
|
||||||
|
val tvList = AccessibilityUtil.findAllOnceByClazz(item, Views.TextView).mapNotNull { it.text }
|
||||||
|
tvList.forEach { tempList.add(WeworkMessageBean.ItemMessageBean(null, it.toString())) }
|
||||||
|
listBriefList.add(WeworkMessageBean.SubMessageBean(null, null, tempList, null))
|
||||||
|
//tvList title/time/content
|
||||||
|
if (tvList.size == 3) {
|
||||||
|
//只查看最近一周内的消息
|
||||||
|
if (tvList[1].isNotBlank() && !tvList[1].contains("(刚刚)|(分钟前)|(上午)|(下午)|(昨天)|(星期)|(日程)|(会议)".toRegex())) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//滚动前先获取一次
|
||||||
|
onScrollListener.onScroll()
|
||||||
|
AccessibilityUtil.scrollToBottom(WeworkController.weworkService, getRoot(), listener = onScrollListener)
|
||||||
|
LogUtils.d("最近聊天列表", GsonUtils.toJson(listBriefList))
|
||||||
|
val weworkMessageBean = WeworkMessageBean()
|
||||||
|
weworkMessageBean.type = WeworkMessageBean.GET_RECENT_LIST
|
||||||
|
weworkMessageBean.messageList = listBriefList.toList()
|
||||||
|
WeworkController.weworkService.webSocketManager.send(weworkMessageBean)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,8 @@ package org.yameida.worktool.service
|
|||||||
import android.view.accessibility.AccessibilityNodeInfo
|
import android.view.accessibility.AccessibilityNodeInfo
|
||||||
import androidx.core.text.isDigitsOnly
|
import androidx.core.text.isDigitsOnly
|
||||||
import com.blankj.utilcode.util.LogUtils
|
import com.blankj.utilcode.util.LogUtils
|
||||||
|
import com.blankj.utilcode.util.SPUtils
|
||||||
import org.yameida.worktool.Constant
|
import org.yameida.worktool.Constant
|
||||||
import org.yameida.worktool.Demo
|
|
||||||
import org.yameida.worktool.model.WeworkMessageBean
|
import org.yameida.worktool.model.WeworkMessageBean
|
||||||
import org.yameida.worktool.service.WeworkController.mainLoopRunning
|
import org.yameida.worktool.service.WeworkController.mainLoopRunning
|
||||||
import org.yameida.worktool.utils.*
|
import org.yameida.worktool.utils.*
|
||||||
@@ -141,9 +141,7 @@ object WeworkLoopImpl {
|
|||||||
if (lastMessage != null) {
|
if (lastMessage != null) {
|
||||||
var tempContent = ""
|
var tempContent = ""
|
||||||
for (itemMessage in lastMessage.itemMessageList) {
|
for (itemMessage in lastMessage.itemMessageList) {
|
||||||
if (itemMessage.text.contains("@" + Constant.myName)
|
if (itemMessage.text.contains("@" + Constant.myName)) {
|
||||||
|| itemMessage.text.isDigitsOnly()
|
|
||||||
) {
|
|
||||||
tempContent = itemMessage.text
|
tempContent = itemMessage.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,8 +233,24 @@ object WeworkLoopImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (logIndex % 120 == 0) {
|
if (logIndex % 120 == 0) {
|
||||||
|
//让企微切换页面使APP保持活跃
|
||||||
goHomeTab("通讯录")
|
goHomeTab("通讯录")
|
||||||
goHomeTab("消息")
|
goHomeTab("消息")
|
||||||
|
//滚动到顶端查看是否有无提示消息
|
||||||
|
AccessibilityUtil.scrollToTop(WeworkController.weworkService, getRoot())
|
||||||
|
val listview = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup)
|
||||||
|
if (listview != null && listview.childCount >= 2) {
|
||||||
|
if (checkNoTipMessage(listview) != 1) {
|
||||||
|
AccessibilityUtil.scrollToBottom(WeworkController.weworkService, getRoot(), listener = object : AccessibilityUtil.OnScrollListener() {
|
||||||
|
override fun onScroll(): Boolean {
|
||||||
|
if (checkNoTipMessage(listview) != 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!isAtHome()) return true
|
if (!isAtHome()) return true
|
||||||
if (logIndex++ % 30 == 0) {
|
if (logIndex++ % 30 == 0) {
|
||||||
@@ -244,15 +258,15 @@ object WeworkLoopImpl {
|
|||||||
if (logIndex % 120 == 0) log("读取首页聊天列表")
|
if (logIndex % 120 == 0) log("读取首页聊天列表")
|
||||||
}
|
}
|
||||||
val listview = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup)
|
val listview = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup)
|
||||||
if (listview != null) {
|
if (listview != null && listview.childCount >= 2) {
|
||||||
if (listview.childCount >= 2) {
|
|
||||||
if (checkUnreadChatRoom(listview)) {
|
if (checkUnreadChatRoom(listview)) {
|
||||||
//进入聊天页
|
//如果有红点 点击进入聊天页
|
||||||
|
return true
|
||||||
|
} else if (checkNoTipMessage(listview) == 1) {
|
||||||
|
//如果发现拉入群聊/修改群名/移出群聊 点击进入聊天页
|
||||||
return true
|
return true
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LogUtils.e("读取聊天列表失败")
|
LogUtils.v("未发现新消息或无提示消息")
|
||||||
error("读取聊天列表失败")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LogUtils.e("读取聊天列表失败")
|
LogUtils.e("读取聊天列表失败")
|
||||||
@@ -263,7 +277,6 @@ object WeworkLoopImpl {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查首页-聊天列表是否有未读红点并点击进入
|
* 检查首页-聊天列表是否有未读红点并点击进入
|
||||||
* 获取红点
|
|
||||||
*/
|
*/
|
||||||
private fun checkUnreadChatRoom(list: AccessibilityNodeInfo): Boolean {
|
private fun checkUnreadChatRoom(list: AccessibilityNodeInfo): Boolean {
|
||||||
val spotNodeList = arrayListOf<AccessibilityNodeInfo>()
|
val spotNodeList = arrayListOf<AccessibilityNodeInfo>()
|
||||||
@@ -296,6 +309,45 @@ object WeworkLoopImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查首页-聊天列表是否有拉入群聊/修改群名/移出群聊等无提示消息
|
||||||
|
* @return -1当前列表不存在一周内消息 0未发现无提示消息 1发现无提示消息
|
||||||
|
*/
|
||||||
|
private fun checkNoTipMessage(list: AccessibilityNodeInfo): Int {
|
||||||
|
list.refresh()
|
||||||
|
val listBriefList = arrayListOf<List<CharSequence>>()
|
||||||
|
for (i in 0 until list.childCount) {
|
||||||
|
val item = list.getChild(i)
|
||||||
|
val tvList = AccessibilityUtil.findAllOnceByClazz(item, Views.TextView).mapNotNull { it.text }
|
||||||
|
listBriefList.add(tvList)
|
||||||
|
//tvList title/time/content
|
||||||
|
if (tvList.size == 3) {
|
||||||
|
//只查看最近一周内的消息
|
||||||
|
if (tvList[1].isBlank() || tvList[1].contains("(刚刚)|(分钟前)|(上午)|(下午)|(昨天)|(星期)|(日程)|(会议)".toRegex())) {
|
||||||
|
if (tvList[2].contains("(移出了群聊)|(邀请你加入了)|(修改群名为)|(此群为外部群)|(加入了外部群)".toRegex())) {
|
||||||
|
val interval = System.currentTimeMillis() / 1000 - SPUtils.getInstance("noTipMessage").getLong(tvList[0].toString(), 0)
|
||||||
|
if (interval > 3600) {
|
||||||
|
LogUtils.i("发现无提示消息: $tvList")
|
||||||
|
log("发现无提示消息: $tvList")
|
||||||
|
if (AccessibilityUtil.performClick(item)) {
|
||||||
|
//进入聊天页 下一步 getChatMessageList
|
||||||
|
} else {
|
||||||
|
AccessibilityUtil.clickByNode(WeworkController.weworkService, item)
|
||||||
|
}
|
||||||
|
SPUtils.getInstance("noTipMessage").put(tvList[0].toString(), System.currentTimeMillis() / 1000)
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
LogUtils.v("发现无提示消息: $tvList 消息在 $interval 秒前已被查看")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析消息列表里的一条消息
|
* 解析消息列表里的一条消息
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -215,6 +215,10 @@ object WeworkOperationImpl {
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
if (!WeworkRoomUtil.isGroupExists(groupName)) {
|
if (!WeworkRoomUtil.isGroupExists(groupName)) {
|
||||||
|
if (!beforeCreateGroupCheck()) {
|
||||||
|
uploadCommandResult(message, ExecCallbackBean.ERROR_CREATE_GROUP_LIMIT, "建群达到上限", startTime)
|
||||||
|
return false
|
||||||
|
}
|
||||||
if (!createGroup()) {
|
if (!createGroup()) {
|
||||||
uploadCommandResult(message, ExecCallbackBean.ERROR_CREATE_GROUP, "创建群失败", startTime)
|
uploadCommandResult(message, ExecCallbackBean.ERROR_CREATE_GROUP, "创建群失败", startTime)
|
||||||
return false
|
return false
|
||||||
@@ -720,9 +724,13 @@ object WeworkOperationImpl {
|
|||||||
Views.ImageView
|
Views.ImageView
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
} else if (AccessibilityUtil.findOnceByText(getRoot(), "该用户不存在") != null) {
|
||||||
|
LogUtils.e("该用户不存在: ${friend.phone}")
|
||||||
|
uploadCommandResult(message, ExecCallbackBean.ERROR_TARGET, "该用户不存在: ${friend.phone}", startTime)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
if (modifyFriendInfo(friend)) {
|
if (modifyFriendInfo(friend)) {
|
||||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "添加为联系人")) {
|
if (AccessibilityUtil.findTextAndClick(getRoot(), "添加为联系人", timeout = 2000)) {
|
||||||
LogUtils.d("准备发送好友邀请: ${friend.phone}")
|
LogUtils.d("准备发送好友邀请: ${friend.phone}")
|
||||||
if (!friend.leavingMsg.isNullOrEmpty()) {
|
if (!friend.leavingMsg.isNullOrEmpty()) {
|
||||||
AccessibilityUtil.findTextInput(getRoot(), friend.leavingMsg)
|
AccessibilityUtil.findTextInput(getRoot(), friend.leavingMsg)
|
||||||
@@ -833,7 +841,7 @@ object WeworkOperationImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (modifyFriendInfo(friend)) {
|
if (modifyFriendInfo(friend)) {
|
||||||
if (AccessibilityUtil.findTextAndClick(getRoot(), "添加为联系人")) {
|
if (AccessibilityUtil.findTextAndClick(getRoot(), "添加为联系人", timeout = 2000)) {
|
||||||
LogUtils.d("准备发送好友邀请: ${friend.name}")
|
LogUtils.d("准备发送好友邀请: ${friend.name}")
|
||||||
if (!friend.leavingMsg.isNullOrEmpty()) {
|
if (!friend.leavingMsg.isNullOrEmpty()) {
|
||||||
AccessibilityUtil.findTextInput(getRoot(), friend.leavingMsg)
|
AccessibilityUtil.findTextInput(getRoot(), friend.leavingMsg)
|
||||||
@@ -906,6 +914,9 @@ object WeworkOperationImpl {
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
goHome()
|
goHome()
|
||||||
|
if (AccessibilityUtil.findOnceByText(getRoot(), "日程", exact = true) == null) {
|
||||||
|
AccessibilityUtil.scrollToTop(WeworkController.weworkService, getRoot())
|
||||||
|
}
|
||||||
val tvDiaryFlag = AccessibilityUtil.findOneByText(getRoot(), "日程", exact = true)
|
val tvDiaryFlag = AccessibilityUtil.findOneByText(getRoot(), "日程", exact = true)
|
||||||
if (tvDiaryFlag != null && (tvDiaryFlag.parent?.childCount == 2 || tvDiaryFlag.parent?.childCount == 3)) {
|
if (tvDiaryFlag != null && (tvDiaryFlag.parent?.childCount == 2 || tvDiaryFlag.parent?.childCount == 3)) {
|
||||||
AccessibilityUtil.performClick(tvDiaryFlag)
|
AccessibilityUtil.performClick(tvDiaryFlag)
|
||||||
@@ -1141,11 +1152,34 @@ object WeworkOperationImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查是否达到当日建群上限
|
* 建群前检查是否达到当日建群上限
|
||||||
|
* @return true允许建群 false不允许建群
|
||||||
|
*/
|
||||||
|
private fun beforeCreateGroupCheck(): Boolean {
|
||||||
|
//有建群权限且最近300秒内发现限制建群
|
||||||
|
if (SPUtils.getInstance("limit").getBoolean("canCreateGroup", false)) {
|
||||||
|
val interval = System.currentTimeMillis() / 1000 - SPUtils.getInstance("limit").getLong("createGroupLimit", 0)
|
||||||
|
if (interval < 300) {
|
||||||
|
LogUtils.e("发现达到当日建群上限 请等待${300 - interval}秒后再试!")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建群后检查是否达到当日建群上限
|
||||||
|
* @return true达到上限 false为达到上限
|
||||||
*/
|
*/
|
||||||
private fun createGroupLimit(): Boolean {
|
private fun createGroupLimit(): Boolean {
|
||||||
val hasLimit =
|
val hasLimit =
|
||||||
AccessibilityUtil.findOneByText(getRoot(), "新建群聊功能暂时被限制", "未验证企业", timeout = 2000)
|
AccessibilityUtil.findOneByText(getRoot(), "新建群聊功能暂时被限制", "未验证企业", timeout = 2000)
|
||||||
|
if (hasLimit == null) {
|
||||||
|
SPUtils.getInstance("limit").put("canCreateGroup", true)
|
||||||
|
} else if (SPUtils.getInstance("limit").getBoolean("canCreateGroup", false)) {
|
||||||
|
SPUtils.getInstance("limit").put("createGroupLimit", System.currentTimeMillis() / 1000)
|
||||||
|
LogUtils.e("发现达到当日建群上限")
|
||||||
|
}
|
||||||
return hasLimit != null
|
return hasLimit != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.yameida.worktool.Constant
|
|||||||
import org.yameida.worktool.Demo
|
import org.yameida.worktool.Demo
|
||||||
import org.yameida.worktool.utils.*
|
import org.yameida.worktool.utils.*
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 企业微信辅助服务
|
* 企业微信辅助服务
|
||||||
@@ -24,6 +25,8 @@ import java.lang.Exception
|
|||||||
class WeworkService : AccessibilityService() {
|
class WeworkService : AccessibilityService() {
|
||||||
private val TAG = "WeworkService"
|
private val TAG = "WeworkService"
|
||||||
lateinit var webSocketManager: WebSocketManager
|
lateinit var webSocketManager: WebSocketManager
|
||||||
|
var currentPackage = ""
|
||||||
|
var currentClass = ""
|
||||||
|
|
||||||
override fun onServiceConnected() {
|
override fun onServiceConnected() {
|
||||||
LogUtils.i("初始化成功")
|
LogUtils.i("初始化成功")
|
||||||
@@ -35,7 +38,7 @@ class WeworkService : AccessibilityService() {
|
|||||||
//初始化消息处理器
|
//初始化消息处理器
|
||||||
MyLooper.init()
|
MyLooper.init()
|
||||||
//开发者可以在这里添加测试代码 启动时调用一次
|
//开发者可以在这里添加测试代码 启动时调用一次
|
||||||
Demo.test(AppUtils.isAppDebug())
|
thread { Demo.test(AppUtils.isAppDebug()) }
|
||||||
|
|
||||||
//监听是否修改链接号并重新长连接
|
//监听是否修改链接号并重新长连接
|
||||||
registerReceiver(object : BroadcastReceiver() {
|
registerReceiver(object : BroadcastReceiver() {
|
||||||
@@ -62,6 +65,11 @@ class WeworkService : AccessibilityService() {
|
|||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
override fun onAccessibilityEvent(event: AccessibilityEvent) {
|
override fun onAccessibilityEvent(event: AccessibilityEvent) {
|
||||||
|
currentPackage = event.packageName?.toString() ?: ""
|
||||||
|
val className = event.className?.toString() ?: ""
|
||||||
|
if (className.contains(currentPackage)) {
|
||||||
|
currentClass = className
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInterrupt() {
|
override fun onInterrupt() {
|
||||||
@@ -83,13 +91,13 @@ class WeworkService : AccessibilityService() {
|
|||||||
private lateinit var socket: WebSocket
|
private lateinit var socket: WebSocket
|
||||||
override fun onOpen(webSocket: WebSocket, response: Response) {
|
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||||
socket = webSocket
|
socket = webSocket
|
||||||
Log.e(TAG, "链接建立")
|
Log.e(TAG, "连接建立")
|
||||||
val robotId = SPUtils.getInstance().getString(Constant.LISTEN_CHANNEL_ID, "")
|
val robotId = Constant.robotId
|
||||||
val appVersion = SPUtils.getInstance().getString("appVersion", "")
|
val appVersion = SPUtils.getInstance().getString("appVersion", "")
|
||||||
val workVersion = SPUtils.getInstance().getString("workVersion", "")
|
val workVersion = SPUtils.getInstance().getString("workVersion", "")
|
||||||
val deviceRooted = SPUtils.getInstance().getBoolean("deviceRooted", false)
|
val deviceRooted = SPUtils.getInstance().getBoolean("deviceRooted", false)
|
||||||
val hook = SPUtils.getInstance().getBoolean("hook", false)
|
val hook = SPUtils.getInstance().getBoolean("hook", false)
|
||||||
log("链接建立: $robotId appVersion: $appVersion workVersion: $workVersion deviceRooted: $deviceRooted hook: $hook")
|
log("连接建立: $robotId appVersion: $appVersion workVersion: $workVersion deviceRooted: $deviceRooted hook: $hook")
|
||||||
LogUtils.i("设置自动跳转企业微信")
|
LogUtils.i("设置自动跳转企业微信")
|
||||||
sendBroadcast(true)
|
sendBroadcast(true)
|
||||||
}
|
}
|
||||||
@@ -107,7 +115,7 @@ class WeworkService : AccessibilityService() {
|
|||||||
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
||||||
super.onClosed(webSocket, code, reason)
|
super.onClosed(webSocket, code, reason)
|
||||||
//服务器关闭后
|
//服务器关闭后
|
||||||
Log.e(TAG, "链接关闭 $reason")
|
Log.e(TAG, "连接关闭 $reason")
|
||||||
sendBroadcast(false)
|
sendBroadcast(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +128,7 @@ class WeworkService : AccessibilityService() {
|
|||||||
|
|
||||||
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)
|
sendBroadcast(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.yameida.worktool.service.WeworkController
|
|||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import java.lang.StringBuilder
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,11 +55,21 @@ import android.content.Context
|
|||||||
* performLongClick 对某个节点或父节点进行长按
|
* performLongClick 对某个节点或父节点进行长按
|
||||||
* performLongClickWithSon 对某个节点或子节点进行长按
|
* performLongClickWithSon 对某个节点或子节点进行长按
|
||||||
*
|
*
|
||||||
|
* 注意:操作均为阻塞式,原则上本工具类所有操作都应在子线程执行
|
||||||
*/
|
*/
|
||||||
object AccessibilityUtil {
|
object AccessibilityUtil {
|
||||||
private const val tag = "AccessibilityUtil"
|
private const val tag = "AccessibilityUtil"
|
||||||
private const val SHORT_INTERVAL = 150L
|
private const val SHORT_INTERVAL = 150L
|
||||||
private const val SCROLL_INTERVAL = 500L
|
private const val SCROLL_INTERVAL_NATIVE = 500L
|
||||||
|
private const val SCROLL_INTERVAL = 800L
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动监听
|
||||||
|
* 如果期望停止滚动则在onScroll回调中返回true 否则返回false
|
||||||
|
*/
|
||||||
|
abstract class OnScrollListener {
|
||||||
|
abstract fun onScroll(): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
//编辑EditView(粘贴 不推荐)
|
//编辑EditView(粘贴 不推荐)
|
||||||
fun sendTextForEditText(context: Context, nodeInfo: AccessibilityNodeInfo?, text: String): Boolean {
|
fun sendTextForEditText(context: Context, nodeInfo: AccessibilityNodeInfo?, text: String): Boolean {
|
||||||
@@ -84,8 +95,13 @@ object AccessibilityUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//寻找第一个文本匹配(关键词)并点击
|
//寻找第一个文本匹配(关键词)并点击
|
||||||
fun findTextAndClick(nodeInfo: AccessibilityNodeInfo?, vararg textList: String): Boolean {
|
fun findTextAndClick(nodeInfo: AccessibilityNodeInfo?,
|
||||||
val textView = findOneByText(nodeInfo, *textList) ?: return false
|
vararg textList: String,
|
||||||
|
exact: Boolean = false,
|
||||||
|
timeout: Long = 5000,
|
||||||
|
root: Boolean = true
|
||||||
|
): Boolean {
|
||||||
|
val textView = findOneByText(nodeInfo, *textList, exact = exact, timeout = timeout, root = root) ?: return false
|
||||||
return performClick(textView)
|
return performClick(textView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +133,106 @@ object AccessibilityUtil {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//滚动到顶部
|
||||||
|
fun scrollToTop(
|
||||||
|
service: AccessibilityService,
|
||||||
|
nodeInfo: AccessibilityNodeInfo,
|
||||||
|
scrollNodeIndex: Int = 0,
|
||||||
|
tryUseGesture: Boolean = true,
|
||||||
|
listener: OnScrollListener? = null,
|
||||||
|
maxRetry: Int = 10
|
||||||
|
): Boolean {
|
||||||
|
var textChanged = false
|
||||||
|
var index = 0
|
||||||
|
while (index++ < maxRetry) {
|
||||||
|
val scrollBefore = findAllOnceByClazz(getRoot(), Views.TextView)
|
||||||
|
performScrollUp(nodeInfo, scrollNodeIndex)
|
||||||
|
if (scrollBefore == findAllOnceByClazz(getRoot(), Views.TextView)) {
|
||||||
|
LogUtils.d("已经滚动到顶部")
|
||||||
|
if (textChanged) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textChanged = true
|
||||||
|
LogUtils.v("未滚动到顶部 $index")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tryUseGesture) {
|
||||||
|
LogUtils.d("未找到可滚动列表 使用手势滚动")
|
||||||
|
val width = ScreenUtils.getScreenWidth()
|
||||||
|
val height = ScreenUtils.getScreenHeight()
|
||||||
|
index = 0
|
||||||
|
while (index++ < maxRetry) {
|
||||||
|
val scrollBefore = findAllOnceByClazz(getRoot(), Views.TextView)
|
||||||
|
scrollByXY(service, width / 2, (height / 2.2).toInt(), 0, height / 3)
|
||||||
|
if (scrollBefore == findAllOnceByClazz(getRoot(), Views.TextView)) {
|
||||||
|
LogUtils.d("已经滚动到顶部")
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
LogUtils.v("未滚动到顶部 $index")
|
||||||
|
if (listener != null && listener.onScroll()) {
|
||||||
|
LogUtils.d("提前终止滚动")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//滚动到顶部
|
||||||
|
fun scrollToBottom(
|
||||||
|
service: AccessibilityService,
|
||||||
|
nodeInfo: AccessibilityNodeInfo,
|
||||||
|
scrollNodeIndex: Int = 0,
|
||||||
|
tryUseGesture: Boolean = true,
|
||||||
|
listener: OnScrollListener? = null,
|
||||||
|
maxRetry: Int = 10
|
||||||
|
): Boolean {
|
||||||
|
var textChanged = false
|
||||||
|
var index = 0
|
||||||
|
while (index++ < maxRetry) {
|
||||||
|
val scrollBefore = findAllOnceByClazz(getRoot(), Views.TextView)
|
||||||
|
performScrollDown(nodeInfo, scrollNodeIndex)
|
||||||
|
if (scrollBefore == findAllOnceByClazz(getRoot(), Views.TextView)) {
|
||||||
|
LogUtils.d("已经滚动到底部")
|
||||||
|
if (textChanged) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textChanged = true
|
||||||
|
LogUtils.v("未滚动到底部 $index")
|
||||||
|
if (listener != null && listener.onScroll()) {
|
||||||
|
LogUtils.d("提前终止滚动")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tryUseGesture) {
|
||||||
|
LogUtils.d("未找到可滚动列表 使用手势滚动")
|
||||||
|
val width = ScreenUtils.getScreenWidth()
|
||||||
|
val height = ScreenUtils.getScreenHeight()
|
||||||
|
index = 0
|
||||||
|
while (index++ < maxRetry) {
|
||||||
|
val scrollBefore = findAllOnceByClazz(getRoot(), Views.TextView)
|
||||||
|
scrollByXY(service, width / 2, (height / 2.2).toInt(), 0, -height / 3)
|
||||||
|
if (scrollBefore == findAllOnceByClazz(getRoot(), Views.TextView)) {
|
||||||
|
LogUtils.d("已经滚动到底部")
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
LogUtils.v("未滚动到底部 $index")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
//滚动并按文本寻找第一个控件
|
//滚动并按文本寻找第一个控件
|
||||||
fun scrollAndFindByText(
|
fun scrollAndFindByText(
|
||||||
service: AccessibilityService,
|
service: AccessibilityService,
|
||||||
@@ -124,6 +240,10 @@ object AccessibilityUtil {
|
|||||||
vararg textList: String,
|
vararg textList: String,
|
||||||
maxRetry: Int = 3
|
maxRetry: Int = 3
|
||||||
): AccessibilityNodeInfo? {
|
): AccessibilityNodeInfo? {
|
||||||
|
val node = findOnceByText(nodeInfo, *textList)
|
||||||
|
if (node != null) {
|
||||||
|
return node
|
||||||
|
}
|
||||||
var index = 0
|
var index = 0
|
||||||
while (index++ < maxRetry) {
|
while (index++ < maxRetry) {
|
||||||
performScrollDown(nodeInfo, 0)
|
performScrollDown(nodeInfo, 0)
|
||||||
@@ -146,8 +266,7 @@ object AccessibilityUtil {
|
|||||||
val height = ScreenUtils.getScreenHeight()
|
val height = ScreenUtils.getScreenHeight()
|
||||||
index = 0
|
index = 0
|
||||||
while (index++ < maxRetry * 2) {
|
while (index++ < maxRetry * 2) {
|
||||||
scrollByXY(service, width / 2, height / 2, 0, -height / 2)
|
scrollByXY(service, width / 2, (height / 2.2).toInt(), 0, -height / 3)
|
||||||
sleep(SCROLL_INTERVAL)
|
|
||||||
val node = findOnceByText(nodeInfo, *textList)
|
val node = findOnceByText(nodeInfo, *textList)
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
return node
|
return node
|
||||||
@@ -155,8 +274,7 @@ object AccessibilityUtil {
|
|||||||
}
|
}
|
||||||
index = 0
|
index = 0
|
||||||
while (index++ < maxRetry * 3) {
|
while (index++ < maxRetry * 3) {
|
||||||
scrollByXY(service, width / 2, height / 2, 0, height / 2)
|
scrollByXY(service, width / 2, (height / 2.2).toInt(), 0, height / 3)
|
||||||
sleep(SCROLL_INTERVAL)
|
|
||||||
val node = findOnceByText(nodeInfo, *textList)
|
val node = findOnceByText(nodeInfo, *textList)
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
return node
|
return node
|
||||||
@@ -299,7 +417,7 @@ object AccessibilityUtil {
|
|||||||
val canScrollNodeList = findCanScrollNode(node)
|
val canScrollNodeList = findCanScrollNode(node)
|
||||||
if (canScrollNodeList.size > index) {
|
if (canScrollNodeList.size > index) {
|
||||||
canScrollNodeList[index].performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD)
|
canScrollNodeList[index].performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD)
|
||||||
sleep(SCROLL_INTERVAL)
|
sleep(SCROLL_INTERVAL_NATIVE)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -311,7 +429,7 @@ object AccessibilityUtil {
|
|||||||
val canScrollNodeList = findCanScrollNode(node)
|
val canScrollNodeList = findCanScrollNode(node)
|
||||||
if (canScrollNodeList.size > index) {
|
if (canScrollNodeList.size > index) {
|
||||||
canScrollNodeList[index].performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
|
canScrollNodeList[index].performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
|
||||||
sleep(SCROLL_INTERVAL)
|
sleep(SCROLL_INTERVAL_NATIVE)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -814,22 +932,31 @@ object AccessibilityUtil {
|
|||||||
node: AccessibilityNodeInfo?,
|
node: AccessibilityNodeInfo?,
|
||||||
printText: Boolean = true,
|
printText: Boolean = true,
|
||||||
depth: Int = 0
|
depth: Int = 0
|
||||||
) {
|
): StringBuilder {
|
||||||
if (node == null) return
|
val sb = StringBuilder()
|
||||||
|
if (node == null) return sb
|
||||||
var s = ""
|
var s = ""
|
||||||
for (i in 0 until depth) {
|
for (i in 0 until depth) {
|
||||||
s += "---"
|
s += "---"
|
||||||
}
|
}
|
||||||
Log.d(tag, "$s depth: $depth className: " + node.className + " isClickable: " + node.isClickable)
|
val temp = "$s depth: $depth className: " + node.className + " isClickable: " + node.isClickable
|
||||||
|
Log.d(tag, temp)
|
||||||
|
sb.append(temp).append("\n")
|
||||||
|
var text = ""
|
||||||
if (printText && node.text != null) {
|
if (printText && node.text != null) {
|
||||||
Log.d(tag, "$s depth: $depth text: " + node.text)
|
text = "$s depth: $depth text: " + node.text
|
||||||
|
Log.d(tag, text)
|
||||||
|
sb.append(text).append("\n")
|
||||||
}
|
}
|
||||||
if (printText && node.contentDescription != null) {
|
if (printText && node.contentDescription != null) {
|
||||||
Log.d(tag, "$s depth: $depth desc: " + node.contentDescription)
|
val desc = "$s depth: $depth desc: " + node.contentDescription
|
||||||
|
Log.d(tag, desc)
|
||||||
|
sb.append(desc).append("\n")
|
||||||
}
|
}
|
||||||
for (i in 0 until node.childCount) {
|
for (i in 0 until node.childCount) {
|
||||||
printNodeClazzTree(node.getChild(i), printText, depth + 1)
|
sb.append(printNodeClazzTree(node.getChild(i), printText, depth + 1))
|
||||||
}
|
}
|
||||||
|
return sb
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -946,7 +1073,7 @@ object AccessibilityUtil {
|
|||||||
path.lineTo(x.toFloat() + distanceX, y.toFloat() + distanceY)
|
path.lineTo(x.toFloat() + distanceX, y.toFloat() + distanceY)
|
||||||
builder.addStroke(StrokeDescription(path, 0L, 300L))
|
builder.addStroke(StrokeDescription(path, 0L, 300L))
|
||||||
val gesture = builder.build()
|
val gesture = builder.build()
|
||||||
return service.dispatchGesture(gesture, object : GestureResultCallback() {
|
val dispatchGesture = service.dispatchGesture(gesture, object : GestureResultCallback() {
|
||||||
override fun onCompleted(gestureDescription: GestureDescription) {
|
override fun onCompleted(gestureDescription: GestureDescription) {
|
||||||
LogUtils.v("scroll ok onCompleted")
|
LogUtils.v("scroll ok onCompleted")
|
||||||
}
|
}
|
||||||
@@ -955,5 +1082,7 @@ object AccessibilityUtil {
|
|||||||
LogUtils.v("scroll ok onCancelled")
|
LogUtils.v("scroll ok onCancelled")
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
|
sleep(SCROLL_INTERVAL)
|
||||||
|
return dispatchGesture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
33
app/src/main/java/org/yameida/worktool/utils/DonateUtil.kt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package org.yameida.worktool.utils
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import org.yameida.worktool.R
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import com.blankj.utilcode.util.ToastUtils
|
||||||
|
import com.blankj.utilcode.util.Utils
|
||||||
|
import com.qmuiteam.qmui.widget.dialog.QMUIDialog
|
||||||
|
|
||||||
|
object DonateUtil {
|
||||||
|
|
||||||
|
fun zfbDonate(context: Context) {
|
||||||
|
try {
|
||||||
|
QMUIDialog.MessageDialogBuilder(context)
|
||||||
|
.setTitle(context.getString(R.string.host_list))
|
||||||
|
.setTitle("捐赠")
|
||||||
|
.setMessage("如果你觉得${context.getString(R.string.app_name)}很棒,可否愿意花一点点钱请作者喝杯咖啡")
|
||||||
|
.addAction("支付宝") {
|
||||||
|
dialog, index -> dialog.dismiss()
|
||||||
|
ToastUtils.showLong(Utils.getApp().getString(R.string.app_name) + " 因为有你的支持而能够不断更新、完善,非常感谢支持!")
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
|
intent.data = Uri.parse("alipays://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode=https%3A%2F%2Fqr.alipay.com%2Ffkx15436xnv3mzpuufhvn52%3F_s%3Dweb-other")
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
.create(R.style.QMUI_Dialog)
|
||||||
|
.show()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
ToastUtils.showShort("打开支付宝失败,你可能还没有安装支付宝客户端")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,145 @@
|
|||||||
package org.yameida.worktool.utils
|
package org.yameida.worktool.utils
|
||||||
|
|
||||||
|
import android.accessibilityservice.AccessibilityService
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.os.Message
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import com.blankj.utilcode.util.FileUtils
|
||||||
import com.blankj.utilcode.util.LogUtils
|
import com.blankj.utilcode.util.LogUtils
|
||||||
|
import com.blankj.utilcode.util.ToastUtils
|
||||||
|
import com.blankj.utilcode.util.Utils
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import org.yameida.floatwindow.FloatWindowManager
|
||||||
|
import org.yameida.floatwindow.DefaultFloatService
|
||||||
|
import org.yameida.floatwindow.listener.OnClickListener
|
||||||
|
import org.yameida.worktool.R
|
||||||
|
import org.yameida.worktool.activity.ListenActivity
|
||||||
|
import org.yameida.worktool.activity.SettingsActivity
|
||||||
|
import org.yameida.worktool.model.WeworkMessageBean
|
||||||
|
import org.yameida.worktool.service.*
|
||||||
|
import java.io.File
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
object FloatWindowHelper {
|
object FloatWindowHelper {
|
||||||
|
|
||||||
|
var isPause = false
|
||||||
|
|
||||||
fun showWindow() {
|
fun showWindow() {
|
||||||
LogUtils.d("FloatWindowHelper.showWindow()")
|
LogUtils.d("FloatWindowHelper.showWindow()")
|
||||||
|
|
||||||
|
FloatWindowManager.show(DefaultFloatService::class.java)
|
||||||
|
|
||||||
|
val app = Utils.getApp()
|
||||||
|
val intent = Intent(app, DefaultFloatService::class.java)
|
||||||
|
app.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主功能继续
|
||||||
|
*/
|
||||||
|
private fun accessibilityServiceResume() {
|
||||||
|
if (PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
|
LogUtils.i("主功能继续")
|
||||||
|
ToastUtils.showShort("主功能继续~")
|
||||||
|
//隐藏软键盘模式
|
||||||
|
WeworkController.weworkService.softKeyboardController.showMode = AccessibilityService.SHOW_MODE_HIDDEN
|
||||||
|
isPause = false
|
||||||
|
MyLooper.getInstance().removeMessages(WeworkMessageBean.LOOP_RECEIVE_NEW_MESSAGE)
|
||||||
|
MyLooper.getInstance().sendMessage(Message.obtain().apply {
|
||||||
|
what = WeworkMessageBean.LOOP_RECEIVE_NEW_MESSAGE
|
||||||
|
obj = WeworkMessageBean().apply { type = WeworkMessageBean.LOOP_RECEIVE_NEW_MESSAGE }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
LogUtils.e("请先打开WorkTool主功能~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主功能暂停
|
||||||
|
*/
|
||||||
|
private fun accessibilityServicePause() {
|
||||||
|
if (PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
|
LogUtils.i("主功能暂停")
|
||||||
|
ToastUtils.showShort("主功能暂停~")
|
||||||
|
//显示软键盘模式
|
||||||
|
WeworkController.weworkService.softKeyboardController.showMode = AccessibilityService.SHOW_MODE_AUTO
|
||||||
|
isPause = true
|
||||||
|
WeworkController.mainLoopRunning = false
|
||||||
|
} else {
|
||||||
|
LogUtils.e("请先打开WorkTool主功能~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val serviceConnection = object : ServiceConnection {
|
||||||
|
override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) {
|
||||||
|
LogUtils.i("DefaultFloatService 服务连接")
|
||||||
|
val service = (iBinder as DefaultFloatService.DefaultFloatServiceBinder).getService()
|
||||||
|
service.onClickListener = object : OnClickListener {
|
||||||
|
override fun onClick(v: View, event: Int) {
|
||||||
|
when (event) {
|
||||||
|
1 -> {
|
||||||
|
if (PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
|
if (!isPause) {
|
||||||
|
ToastUtils.showShort("请先暂停WorkTool主功能~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
thread {
|
||||||
|
val printNodeClazzTree =
|
||||||
|
AccessibilityUtil.printNodeClazzTree(getRoot(true))
|
||||||
|
val df = SimpleDateFormat("MMdd_HHmmss")
|
||||||
|
val filePath = "${
|
||||||
|
Utils.getApp().getExternalFilesDir("share")
|
||||||
|
}/${df.format(Date())}/${df.format(Date())}_printNode.txt"
|
||||||
|
val newFile = File(filePath)
|
||||||
|
val create = FileUtils.createFileByDeleteOldFile(newFile)
|
||||||
|
if (create && newFile.canWrite()) {
|
||||||
|
printNodeClazzTree.append("\n")
|
||||||
|
.append(WeworkController.weworkService.currentPackage)
|
||||||
|
.append("\n")
|
||||||
|
.append(WeworkController.weworkService.currentClass)
|
||||||
|
newFile.writeBytes(printNodeClazzTree.toString().toByteArray())
|
||||||
|
LogUtils.i("打印节点文件存储本地成功 $filePath")
|
||||||
|
}
|
||||||
|
ShareUtil.share("*", newFile)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ToastUtils.showShort("请先打开WorkTool主功能~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
if (PermissionHelper.isAccessibilitySettingOn()) {
|
||||||
|
if (isPause) {
|
||||||
|
Glide.with(Utils.getApp()).load(R.drawable.float_icon_pause).into(v as ImageView)
|
||||||
|
accessibilityServiceResume()
|
||||||
|
} else {
|
||||||
|
Glide.with(Utils.getApp()).load(R.drawable.float_icon_play).into(v as ImageView)
|
||||||
|
accessibilityServicePause()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ToastUtils.showShort("请先打开WorkTool主功能~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
3 -> {
|
||||||
|
ListenActivity.enterActivity(Utils.getApp(), 0)
|
||||||
|
}
|
||||||
|
4 -> {
|
||||||
|
SettingsActivity.enterActivity(Utils.getApp())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
|
LogUtils.i("DefaultFloatService 服务断开")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package org.yameida.worktool.utils
|
||||||
|
|
||||||
|
import android.app.AppOpsManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.Settings
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
|
object FlowPermissionHelper {
|
||||||
|
|
||||||
|
fun isXiaoMi(): Boolean {
|
||||||
|
return checkManufacturer("xiaomi")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOppo(): Boolean {
|
||||||
|
return checkManufacturer("oppo")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isVivo(): Boolean {
|
||||||
|
return checkManufacturer("vivo")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkManufacturer(manufacturer: String): Boolean {
|
||||||
|
return manufacturer.equals(Build.MANUFACTURER, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun canBackgroundStart(context: Context): Boolean {
|
||||||
|
if (isXiaoMi()) {
|
||||||
|
return isXiaomiBgStartPermissionAllowed(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVivo()) {
|
||||||
|
return isVivoBgStartPermissionAllowed(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOppo() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
return Settings.canDrawOverlays(context)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun isXiaomiBgStartPermissionAllowed(context: Context): Boolean {
|
||||||
|
val ops = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
|
||||||
|
try {
|
||||||
|
val op = 10021
|
||||||
|
val method: Method = ops.javaClass.getMethod("checkOpNoThrow", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType, String::class.java)
|
||||||
|
val result = method.invoke(ops, op, android.os.Process.myUid(), context.packageName) as Int
|
||||||
|
return result == AppOpsManager.MODE_ALLOWED
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isVivoBgStartPermissionAllowed(context: Context): Boolean {
|
||||||
|
return getVivoBgStartPermissionStatus(context) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断Vivo后台弹出界面状态, 1无权限,0有权限
|
||||||
|
* @param context context
|
||||||
|
*/
|
||||||
|
private fun getVivoBgStartPermissionStatus(context: Context): Int {
|
||||||
|
val uri: Uri = Uri.parse("content://com.vivo.permissionmanager.provider.permission/start_bg_activity")
|
||||||
|
val selection = "pkgname = ?"
|
||||||
|
val selectionArgs = arrayOf(context.packageName)
|
||||||
|
var state = 1
|
||||||
|
try {
|
||||||
|
context.contentResolver.query(uri, null, selection, selectionArgs, null)?.use {
|
||||||
|
if (it.moveToFirst()) {
|
||||||
|
state = it.getInt(it.getColumnIndex("currentstate"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
74
app/src/main/java/org/yameida/worktool/utils/IWWAPIUtil.kt
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package org.yameida.worktool.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.blankj.utilcode.util.AppUtils
|
||||||
|
import com.blankj.utilcode.util.Utils
|
||||||
|
import com.tencent.wework.api.IWWAPI
|
||||||
|
import com.tencent.wework.api.WWAPIFactory
|
||||||
|
import com.tencent.wework.api.model.WWMediaLink
|
||||||
|
import com.tencent.wework.api.model.WWMediaMiniProgram
|
||||||
|
import com.tencent.wework.api.model.WWSimpleRespMessage
|
||||||
|
|
||||||
|
|
||||||
|
object IWWAPIUtil {
|
||||||
|
|
||||||
|
private var iwwapi: IWWAPI? = null
|
||||||
|
|
||||||
|
var appid = "wwe51e5ed82702b49b" //企业唯一标识。创建企业后显示在,我的企业 CorpID字段
|
||||||
|
var agentid = "1000002" //应用唯一标识。显示在具体应用下的 AgentId字段
|
||||||
|
var schema = "wwauthe51e5ed82702b49b000002"
|
||||||
|
|
||||||
|
fun init(context: Context, schema: String = this.schema) {
|
||||||
|
this.schema = schema
|
||||||
|
iwwapi = WWAPIFactory.createWWAPI(context)
|
||||||
|
iwwapi?.registerApp(schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendLink(thumbUrl: String?, webpageUrl: String?, title: String?, description: String?) {
|
||||||
|
val link = WWMediaLink()
|
||||||
|
link.thumbUrl = thumbUrl
|
||||||
|
link.webpageUrl = webpageUrl
|
||||||
|
link.title = title
|
||||||
|
link.description = description
|
||||||
|
link.appPkg = AppUtils.getAppPackageName()
|
||||||
|
link.appName = AppUtils.getAppName()
|
||||||
|
link.appId = appid
|
||||||
|
link.agentId = agentid
|
||||||
|
iwwapi?.sendMessage(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMicroProgram() {
|
||||||
|
val miniProgram = WWMediaMiniProgram()
|
||||||
|
miniProgram.appPkg = AppUtils.getAppPackageName()
|
||||||
|
miniProgram.appName = AppUtils.getAppName()
|
||||||
|
miniProgram.appId = appid
|
||||||
|
miniProgram.agentId = agentid
|
||||||
|
miniProgram.schema = schema
|
||||||
|
miniProgram.username = "gh_dde54cb88ce7@app" //必须是应用关联的小程序,注意要有@app后缀
|
||||||
|
miniProgram.description = "dddddd"
|
||||||
|
miniProgram.path = "/pages/plugin/index.html?plugid=1cbd3b7c8674e61769436b5e354ddb2f"
|
||||||
|
// val bitmap = (getDrawable(R.drawable.test) as BitmapDrawable).bitmap
|
||||||
|
// val stream = ByteArrayOutputStream()
|
||||||
|
// bitmap.compress(Bitmap.CompressFormat.JPEG, 0, stream)
|
||||||
|
// val byteArray: ByteArray = stream.toByteArray()
|
||||||
|
|
||||||
|
// miniProgram.hdImageData = byteArray
|
||||||
|
miniProgram.title = "测试_MaHow"
|
||||||
|
iwwapi!!.sendMessage(miniProgram) { resp ->
|
||||||
|
if (resp is WWSimpleRespMessage) {
|
||||||
|
val rsp = resp as WWSimpleRespMessage
|
||||||
|
var t: String? = ""
|
||||||
|
Toast.makeText(
|
||||||
|
Utils.getApp(),
|
||||||
|
"发小程序," + rsp.errCode + "," + rsp.errMsg.also {
|
||||||
|
t = it
|
||||||
|
},
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,6 @@ object PermissionHelper {
|
|||||||
val canonicalName = WeworkService::class.java.canonicalName ?: ""
|
val canonicalName = WeworkService::class.java.canonicalName ?: ""
|
||||||
val serviceName = context.packageName + "/" + canonicalName
|
val serviceName = context.packageName + "/" + canonicalName
|
||||||
val serviceShortName = context.packageName + "/" + canonicalName.replace(context.packageName, "")
|
val serviceShortName = context.packageName + "/" + canonicalName.replace(context.packageName, "")
|
||||||
LogUtils.i("isAccessibilitySettingOn: $serviceName $serviceShortName")
|
|
||||||
try {
|
try {
|
||||||
enable = Settings.Secure.getInt(
|
enable = Settings.Secure.getInt(
|
||||||
context.contentResolver,
|
context.contentResolver,
|
||||||
@@ -27,6 +26,7 @@ object PermissionHelper {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
var flag = false
|
||||||
if (enable == 1) {
|
if (enable == 1) {
|
||||||
val stringSplitter = TextUtils.SimpleStringSplitter(':')
|
val stringSplitter = TextUtils.SimpleStringSplitter(':')
|
||||||
val settingVal = Settings.Secure.getString(
|
val settingVal = Settings.Secure.getString(
|
||||||
@@ -38,14 +38,14 @@ object PermissionHelper {
|
|||||||
while (stringSplitter.hasNext()) {
|
while (stringSplitter.hasNext()) {
|
||||||
val accessibilityService = stringSplitter.next()
|
val accessibilityService = stringSplitter.next()
|
||||||
if (accessibilityService == serviceName || accessibilityService == serviceShortName) {
|
if (accessibilityService == serviceName || accessibilityService == serviceShortName) {
|
||||||
LogUtils.i("isAccessibilitySettingOn: true")
|
flag = true
|
||||||
return true
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogUtils.i("isAccessibilitySettingOn: false")
|
LogUtils.v("isAccessibilitySettingOn: $serviceName $serviceShortName $flag")
|
||||||
return false
|
return flag
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,9 +15,10 @@ object RegexHelper {
|
|||||||
.replace("{", "\\{")
|
.replace("{", "\\{")
|
||||||
.replace("}", "\\}")
|
.replace("}", "\\}")
|
||||||
.replace("|", "\\|")
|
.replace("|", "\\|")
|
||||||
// .replace("-", "\\-") //企微自身限制
|
//企微自身存在限制
|
||||||
// .replace("(", "\\(") //企微自身限制
|
.replace("-", "\\-")
|
||||||
// .replace(")", "\\)") //企微自身限制
|
.replace("(", "\\(")
|
||||||
|
.replace(")", "\\)")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.yameida.worktool.utils;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import com.blankj.utilcode.util.ToastUtils;
|
||||||
|
|
||||||
|
import org.yameida.worktool.R;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ShareCommentsUtil {
|
||||||
|
private static boolean checkInstallation(Context context, String packageName) {
|
||||||
|
try {
|
||||||
|
context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
|
||||||
|
return true;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void shareToWeChat(Context context) {
|
||||||
|
try {
|
||||||
|
if (!checkInstallation(context, "com.tencent.mm")) {
|
||||||
|
ToastUtils.showShort("未发现微信");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(); //分享精确到微信的页面,朋友圈页面,或者选择好友分享页面
|
||||||
|
ComponentName comp = new ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareToTimeLineUI");
|
||||||
|
intent.setComponent(comp);
|
||||||
|
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
|
||||||
|
intent.setType("image/*"); // intent.setType("text/plain");添加Uri图片地址
|
||||||
|
String msg = "我想分享";
|
||||||
|
intent.putExtra("Kdescription", msg);
|
||||||
|
ArrayList<Uri> imageUris = new ArrayList<Uri>();
|
||||||
|
File dir = context.getExternalFilesDir(null);
|
||||||
|
if (dir == null || dir.getAbsolutePath().equals("")) {
|
||||||
|
dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||||
|
}
|
||||||
|
File pic = new File(dir, "bigbang.jpg");
|
||||||
|
pic.deleteOnExit();
|
||||||
|
BitmapDrawable bitmapDrawable;
|
||||||
|
bitmapDrawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_launcher);
|
||||||
|
try {
|
||||||
|
bitmapDrawable.getBitmap().compress(Bitmap.CompressFormat.JPEG, 75, new FileOutputStream(pic));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Uri uri = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(context.getContentResolver(), pic.getAbsolutePath(), "bigbang.jpg", null));
|
||||||
|
imageUris.add(uri);
|
||||||
|
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
|
||||||
|
((Activity) context).startActivityForResult(intent, 1000);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
ToastUtils.showShort("分享到微信失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ public class WebSocketManager {
|
|||||||
private String url;
|
private String url;
|
||||||
private WebSocketListener listener;
|
private WebSocketListener listener;
|
||||||
private boolean connecting = false;
|
private boolean connecting = false;
|
||||||
|
private long lastConnectedTime = 0L;
|
||||||
|
|
||||||
public WebSocketManager(String url, WebSocketListener listener) {
|
public WebSocketManager(String url, WebSocketListener listener) {
|
||||||
Log.e(url, "新建链接");
|
Log.e(url, "新建链接");
|
||||||
@@ -113,18 +114,25 @@ public class WebSocketManager {
|
|||||||
Log.e(url, "重连");
|
Log.e(url, "重连");
|
||||||
boolean isConnect = false;
|
boolean isConnect = false;
|
||||||
int interval = reconnectInt;
|
int interval = reconnectInt;
|
||||||
while (!isConnect) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
isConnect = connect();
|
isConnect = connect();
|
||||||
Thread.sleep(interval);
|
if (isConnect) {
|
||||||
if (interval < 600000) {
|
connecting = false;
|
||||||
interval *= 2;
|
break;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(interval);
|
||||||
|
if (interval < 600000) {
|
||||||
|
interval *= 2;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
connecting = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean connect() {
|
private boolean connect() {
|
||||||
@@ -137,6 +145,7 @@ public class WebSocketManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledFuture heartCheckStart() {
|
private ScheduledFuture heartCheckStart() {
|
||||||
|
lastConnectedTime = System.currentTimeMillis();
|
||||||
Runnable r = () -> {
|
Runnable r = () -> {
|
||||||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
|
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
|
||||||
Log.e(url, "心跳检测" + df.format(new Date()));// new Date()为获取当前系统时间
|
Log.e(url, "心跳检测" + df.format(new Date()));// new Date()为获取当前系统时间
|
||||||
@@ -145,8 +154,12 @@ public class WebSocketManager {
|
|||||||
WeworkController.INSTANCE.setEnableLoopRunning(false);
|
WeworkController.INSTANCE.setEnableLoopRunning(false);
|
||||||
//断开链接后进入重连
|
//断开链接后进入重连
|
||||||
reConnect();
|
reConnect();
|
||||||
|
//重连后刷新连接时间
|
||||||
|
lastConnectedTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
if (System.currentTimeMillis() - lastConnectedTime > heartBeatRate * 2000 && !FloatWindowHelper.INSTANCE.isPause()) {
|
||||||
|
ToastUtils.show("机器人运行中 请勿人工操作手机~");
|
||||||
}
|
}
|
||||||
// ToastUtils.show("机器人运行中 请勿人工操作手机~");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//每heartBeatRate秒发一次心跳包
|
//每heartBeatRate秒发一次心跳包
|
||||||
|
|||||||
@@ -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(noCut = true)
|
val roomTitle = getRoomTitle(noCut = true, print = false)
|
||||||
when {
|
when {
|
||||||
isExternalSingleChat(roomTitle) -> {
|
isExternalSingleChat(roomTitle) -> {
|
||||||
LogUtils.d("ROOM_TYPE: ROOM_TYPE_EXTERNAL_CONTACT")
|
LogUtils.d("ROOM_TYPE: ROOM_TYPE_EXTERNAL_CONTACT")
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public class CheckRoot {
|
|||||||
fullResponse.add(line);
|
fullResponse.add(line);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Log.i(LOG_TAG, "Unexpected error - Here is what I know: " + e.getMessage());
|
||||||
}
|
}
|
||||||
Log.i(LOG_TAG, "–> Full response was: " + fullResponse);
|
Log.i(LOG_TAG, "–> Full response was: " + fullResponse);
|
||||||
return fullResponse;
|
return fullResponse;
|
||||||
@@ -137,7 +137,7 @@ public class CheckRoot {
|
|||||||
}
|
}
|
||||||
process.destroy();
|
process.destroy();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Log.i(LOG_TAG, "Unexpected error - Here is what I know: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,8 +181,7 @@ public class CheckRoot {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
|
Log.i(LOG_TAG, "Unexpected error - Here is what I know: " + e.getMessage());
|
||||||
+ e.getMessage());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +194,7 @@ public class CheckRoot {
|
|||||||
fout.close();
|
fout.close();
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Log.i(LOG_TAG, "Unexpected error - Here is what I know: " + e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,7 +213,7 @@ public class CheckRoot {
|
|||||||
Log.i(LOG_TAG, result);
|
Log.i(LOG_TAG, result);
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Log.i(LOG_TAG, "Unexpected error - Here is what I know: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
app/src/main/res/layout/activity_browser.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:focusableInTouchMode="true" >
|
||||||
|
|
||||||
|
<com.qmuiteam.qmui.widget.webview.QMUIWebView
|
||||||
|
android:id="@+id/qmwv"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
>
|
||||||
|
|
||||||
|
</com.qmuiteam.qmui.widget.webview.QMUIWebView>
|
||||||
|
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
234
app/src/main/res/layout/activity_float_guide.xml
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:text="允许弹出悬浮窗口"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="22sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="18dp"
|
||||||
|
android:layout_marginStart="18dp"
|
||||||
|
android:layout_marginEnd="18dp"
|
||||||
|
android:text="请允许弹窗权限,以使用悬浮窗按钮和其他完整功能"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:background="@drawable/bg_float_guide">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_guide_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_guide_icon"
|
||||||
|
android:layout_width="75dp"
|
||||||
|
android:layout_height="75dp"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="18dp"
|
||||||
|
android:src="@mipmap/ic_launcher" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_guide_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="18dp"
|
||||||
|
android:layout_toEndOf="@id/iv_guide_icon"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textColor="#000"
|
||||||
|
android:textSize="22sp" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_guide_permit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/rl_guide_title"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/bar_gray">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:scaleX="0.9"
|
||||||
|
android:scaleY="0.9"
|
||||||
|
android:src="@drawable/ic_arrow_back"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="65dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:textSize="21sp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:text="应用权限"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:src="@drawable/abc_ic_menu_moreoverflow_mtrl_alpha"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:background="@color/color_b2000000"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/bar_gray">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="65dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:textSize="21sp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/while_bg">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textColor="@color/qmui_config_color_black"
|
||||||
|
android:text="允许覆盖其他应用程序"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:src="@drawable/widget_tip_button"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_over_finger"
|
||||||
|
android:layout_width="55dp"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_below="@id/ll_guide_permit"
|
||||||
|
android:layout_marginEnd="23dp"
|
||||||
|
android:layout_marginTop="-15dp"
|
||||||
|
android:src="@drawable/widget_guide_finger"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_float_allow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:background="@drawable/comment_red_btn"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="7dp"
|
||||||
|
android:paddingTop="7dp"
|
||||||
|
android:text="允许"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_float_reject"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:background="@drawable/comment_gray_btn"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="7dp"
|
||||||
|
android:paddingTop="7dp"
|
||||||
|
android:text="暂不使用"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="15dp">
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/cb_guide_not"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="2dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toEndOf="@id/cb_guide_not"
|
||||||
|
android:text="不再询问"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -5,9 +5,46 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/background">
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/color_dashen"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_settings"
|
||||||
|
android:layout_width="25dp"
|
||||||
|
android:layout_height="25dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:src="@drawable/tab_settings_check" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:background="@color/list_divider_line"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@id/rl_bar">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -231,76 +268,6 @@
|
|||||||
|
|
||||||
</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_encrypt"
|
|
||||||
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_encrypt"
|
|
||||||
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"
|
|
||||||
android:paddingStart="@dimen/setting_start_padding"
|
|
||||||
android:paddingTop="@dimen/setting_vertical_padding"
|
|
||||||
android:paddingEnd="@dimen/setting_end_start_padding"
|
|
||||||
android:paddingBottom="@dimen/setting_vertical_padding">
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
android:id="@+id/sw_auto_reply"
|
|
||||||
android:layout_width="@dimen/setting_end_font_width"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginStart="@dimen/setting_end_start_padding" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginStart="@dimen/setting_start_padding"
|
|
||||||
android:layout_toStartOf="@id/sw_auto_reply"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="开启新消息接收"
|
|
||||||
android:textColor="@color/color_333333"
|
|
||||||
android:textSize="@dimen/setting_start_font_size" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -384,6 +351,9 @@
|
|||||||
android:background="@drawable/comment_red_btn"
|
android:background="@drawable/comment_red_btn"
|
||||||
android:paddingStart="50dp"
|
android:paddingStart="50dp"
|
||||||
android:paddingEnd="50dp"
|
android:paddingEnd="50dp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/white"
|
||||||
android:text="保存" />
|
android:text="保存" />
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
612
app/src/main/res/layout/activity_settings.xml
Normal file
@@ -0,0 +1,612 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/color_dashen"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_back_left"
|
||||||
|
android:layout_width="25dp"
|
||||||
|
android:layout_height="25dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:src="@drawable/back_icon" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:background="@color/list_divider_line"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@id/rl_bar">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 视频 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
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"
|
||||||
|
android:text="配置"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_reply_strategy"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/setting_start_padding"
|
||||||
|
android:paddingTop="@dimen/setting_vertical_padding"
|
||||||
|
android:paddingEnd="@dimen/setting_end_padding"
|
||||||
|
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_rec_reply_strategy_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_hq" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_reply_strategy"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_reply_strategy"
|
||||||
|
android:layout_toEndOf="@id/iv_rec_reply_strategy_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="回复策略"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="设置新消息回复的策略"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_qa_url"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/setting_start_padding"
|
||||||
|
android:paddingTop="@dimen/setting_vertical_padding"
|
||||||
|
android:paddingEnd="@dimen/setting_end_padding"
|
||||||
|
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_qa_url_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_fps" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_fps"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_fps"
|
||||||
|
android:layout_toEndOf="@id/iv_qa_url_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="消息回调"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="设置回调地址来接收和处理新消息"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_rec_orientation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:paddingStart="@dimen/setting_start_padding"
|
||||||
|
android:paddingTop="@dimen/setting_vertical_padding"
|
||||||
|
android:paddingEnd="@dimen/setting_end_padding"
|
||||||
|
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_rec_orientation_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_orientation" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_orientation"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_orientation"
|
||||||
|
android:layout_toEndOf="@id/iv_rec_orientation_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="方向"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_rec_location"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:paddingStart="@dimen/setting_start_padding"
|
||||||
|
android:paddingTop="@dimen/setting_vertical_padding"
|
||||||
|
android:paddingEnd="@dimen/setting_end_padding"
|
||||||
|
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_rec_location_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_directory" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_location"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_location"
|
||||||
|
android:layout_toEndOf="@id/iv_rec_location_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="save_location"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_save_location_tip"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="video_default_path"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<!-- 控制台 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
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"
|
||||||
|
android:text="控制台"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_encrypt"
|
||||||
|
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">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_encrypt"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_no_pop" />
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/sw_encrypt"
|
||||||
|
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_encrypt"
|
||||||
|
android:layout_toEndOf="@id/iv_encrypt"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="开启通讯加密"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="阻止网络抓包截取数据"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_rec_resolution"
|
||||||
|
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">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_rec_resolution_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_hd" />
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/sw_receive"
|
||||||
|
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" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_resolution"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_resolution"
|
||||||
|
android:layout_toEndOf="@id/iv_rec_resolution_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="开启新消息接收"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="查看会话列表的所有未读消息"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<!-- 其他 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
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"
|
||||||
|
android:text="其他"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_language"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:paddingStart="@dimen/setting_start_padding"
|
||||||
|
android:paddingTop="@dimen/setting_vertical_padding"
|
||||||
|
android:paddingEnd="@dimen/setting_end_padding"
|
||||||
|
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_rec_language_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_language" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_language"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_language"
|
||||||
|
android:layout_toEndOf="@id/iv_rec_language_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="language"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="reply_strategy_tips"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_donate"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/setting_start_padding"
|
||||||
|
android:paddingTop="@dimen/setting_vertical_padding"
|
||||||
|
android:paddingEnd="@dimen/setting_end_padding"
|
||||||
|
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_rec_donate_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/settings_rate_us" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_donate"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_donate"
|
||||||
|
android:layout_toEndOf="@id/iv_rec_donate_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="赞助我们"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="还有机会成为我们的内测用户体验新功能"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_share"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/setting_start_padding"
|
||||||
|
android:paddingTop="@dimen/setting_vertical_padding"
|
||||||
|
android:paddingEnd="@dimen/setting_end_padding"
|
||||||
|
android:paddingBottom="@dimen/setting_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_rec_share_"
|
||||||
|
android:layout_width="@dimen/setting_start_image_width"
|
||||||
|
android:layout_height="@dimen/setting_start_image_width"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:scaleX="1.1"
|
||||||
|
android:scaleY="1.1"
|
||||||
|
android:src="@drawable/settings_share" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_select_share"
|
||||||
|
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"
|
||||||
|
android:textColor="@color/float_time_color"
|
||||||
|
android:textSize="@dimen/setting_end_font_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<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/tv_select_share"
|
||||||
|
android:layout_toEndOf="@id/iv_rec_share_"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="分享应用"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:textSize="@dimen/setting_start_font_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="把本应用分享给其他人"
|
||||||
|
android:textColor="@color/color_999999"
|
||||||
|
android:textSize="@dimen/setting_end_font_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bt_open_main"
|
||||||
|
style="@style/rec_top_btn"
|
||||||
|
android:background="@drawable/comment_red_btn"
|
||||||
|
android:text="开启主功能"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bt_open_flow"
|
||||||
|
style="@style/rec_top_btn"
|
||||||
|
android:background="@drawable/comment_red_btn"
|
||||||
|
android:text="开启悬浮窗" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="#fff"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/body"
|
|
||||||
android:layout_width="300dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:hint="wss://"
|
|
||||||
android:lines="3"
|
|
||||||
android:textColor="#000000" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/ok"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="#169BD5"
|
|
||||||
android:text="确定" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/cancel"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="#F4F4F4"
|
|
||||||
android:text="@android:string/cancel" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -7,17 +7,8 @@
|
|||||||
<!-- 升级对话框 -->
|
<!-- 升级对话框 -->
|
||||||
<string name="update_title" translatable="false">发现新版本</string>
|
<string name="update_title" translatable="false">发现新版本</string>
|
||||||
<string name="update_content" translatable="false">更新内容</string>
|
<string name="update_content" translatable="false">更新内容</string>
|
||||||
<string name="update_no" translatable="false">下次再说</string>
|
|
||||||
<string name="update_yes" translatable="false">立即更新</string>
|
|
||||||
<string name="update_permission_hint" translatable="false">必须先要授予权限才能正常下载更新哦</string>
|
|
||||||
<string name="update_status_start" translatable="false">正在下载</string>
|
|
||||||
<string name="update_status_running" translatable="false">下载中 %d%%</string>
|
|
||||||
<string name="update_status_successful" translatable="false">下载完成,点击安装</string>
|
|
||||||
<string name="update_status_failed" translatable="false">下载失败,点击重试</string>
|
|
||||||
<string name="update_failed" translatable="false">自动更新失败</string>
|
<string name="update_failed" translatable="false">自动更新失败</string>
|
||||||
<string name="update_no_update" translatable="false">当前已是最新版本</string>
|
<string name="update_no_update" translatable="false">当前已是最新版本</string>
|
||||||
<string name="update_notification_channel_id" translatable="false">update</string>
|
|
||||||
<string name="update_notification_channel_name" translatable="false">升级通知</string>
|
|
||||||
|
|
||||||
<!-- UI -->
|
<!-- UI -->
|
||||||
<string name="tip">提示</string>
|
<string name="tip">提示</string>
|
||||||
|
|||||||
@@ -21,4 +21,44 @@
|
|||||||
<item name="android:textColorHint">@color/textInputLayout</item>
|
<item name="android:textColorHint">@color/textInputLayout</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="ds_rec_btn">
|
||||||
|
<item name="android:textSize">
|
||||||
|
@dimen/size_button
|
||||||
|
</item>
|
||||||
|
<item name="android:textColor">
|
||||||
|
@android:color/white
|
||||||
|
</item>
|
||||||
|
<item name="android:gravity">
|
||||||
|
center
|
||||||
|
</item>
|
||||||
|
<item name="android:background">@drawable/comment_red_btn</item>
|
||||||
|
<item name="android:paddingTop">
|
||||||
|
@dimen/btn_top_bottom_padding
|
||||||
|
</item>
|
||||||
|
<item name="android:paddingBottom">
|
||||||
|
@dimen/btn_top_bottom_padding
|
||||||
|
</item>
|
||||||
|
<item name="android:layout_width">
|
||||||
|
match_parent
|
||||||
|
</item>
|
||||||
|
<item name="android:layout_height">
|
||||||
|
@dimen/btn_height
|
||||||
|
</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="rec_top_btn" parent="@style/ds_rec_btn">
|
||||||
|
<item name="android:layout_marginStart">
|
||||||
|
25dp
|
||||||
|
</item>
|
||||||
|
<item name="android:layout_marginTop">
|
||||||
|
17dp
|
||||||
|
</item>
|
||||||
|
<item name="android:layout_marginEnd">
|
||||||
|
25.0dp
|
||||||
|
</item>
|
||||||
|
<item name="android:layout_marginBottom">
|
||||||
|
8dp
|
||||||
|
</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
1
baselibrary/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
67
baselibrary/build.gradle
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 30
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 24
|
||||||
|
targetSdkVersion 30
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
api 'androidx.core:core-ktx:1.3.2'
|
||||||
|
api 'androidx.appcompat:appcompat:1.3.1'
|
||||||
|
api 'com.google.android.material:material:1.4.0'
|
||||||
|
|
||||||
|
//工具集
|
||||||
|
api 'com.blankj:utilcodex:1.31.0'
|
||||||
|
//toast
|
||||||
|
api 'com.github.getActivity:ToastUtils:10.5'
|
||||||
|
//Gson
|
||||||
|
api 'com.google.code.gson:gson:2.8.5'
|
||||||
|
//网络
|
||||||
|
api 'com.github.bumptech.glide:okhttp3-integration:4.9.0'
|
||||||
|
//自动更新
|
||||||
|
api 'com.teprinciple:updateapputilsx:2.3.0'
|
||||||
|
//okgo
|
||||||
|
api 'com.lzy.net:okgo:3.0.4'
|
||||||
|
//qrcode
|
||||||
|
api 'com.github.yoojia:next-qrcode:2.0-2'
|
||||||
|
//QMUI
|
||||||
|
api 'com.qmuiteam:qmui:2.0.0-alpha10'
|
||||||
|
//recyclerview
|
||||||
|
api 'androidx.recyclerview:recyclerview:1.2.0-alpha05'
|
||||||
|
//glide
|
||||||
|
api 'com.github.bumptech.glide:glide:4.9.0'
|
||||||
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
|
||||||
|
//photoview
|
||||||
|
api 'com.github.chrisbanes:PhotoView:2.1.3'
|
||||||
|
//悬浮窗框架
|
||||||
|
api 'com.github.princekin-f:EasyFloat:1.3.4'
|
||||||
|
|
||||||
|
//leak
|
||||||
|
// debugApi 'com.squareup.leakcanary:leakcanary-android:1.5.4'
|
||||||
|
// releaseApi 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
|
||||||
|
// testApi 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
21
baselibrary/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
2
baselibrary/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="base" />
|
||||||
95
baselibrary/src/main/java/base/adapter/RvSimpleAdapter.java
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package base.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gallon on 2019/7/26.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class RvSimpleAdapter<T> extends RecyclerView.Adapter<RvViewHolder> {
|
||||||
|
|
||||||
|
protected LayoutInflater mInflater;
|
||||||
|
public List<T> mData;
|
||||||
|
public int mHeaderCount = 0;
|
||||||
|
public Context mContext;
|
||||||
|
protected int mLayoutId;
|
||||||
|
|
||||||
|
public static abstract class OnItemClickListener {
|
||||||
|
public abstract void onItemClick(View view, int position, RvViewHolder holder);
|
||||||
|
|
||||||
|
public void onItemLongClick(View view, int position, RvViewHolder holder) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private OnItemClickListener onItemClickListener;
|
||||||
|
|
||||||
|
public void setOnItemClickListener(OnItemClickListener listener) {
|
||||||
|
this.onItemClickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvSimpleAdapter(Context context, List<T> data, int layoutId) {
|
||||||
|
this.mContext = context;
|
||||||
|
this.mData = data;
|
||||||
|
this.mLayoutId = layoutId;
|
||||||
|
mInflater = LayoutInflater.from(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return null == mData ? 0 : mData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(final RvViewHolder holder, final int position) {
|
||||||
|
convert(holder, mData.get(holder.getLayoutPosition() - mHeaderCount), position);
|
||||||
|
setUpItemEvent(holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void convert(RvViewHolder holder, T bean, int position);
|
||||||
|
|
||||||
|
public void setUpItemEvent(final RvViewHolder holder) {
|
||||||
|
if (onItemClickListener != null) {
|
||||||
|
holder.itemView.setOnClickListener(v -> {
|
||||||
|
//这个获取位置的方法,防止添加删除导致位置不变
|
||||||
|
int layoutPosition = holder.getAdapterPosition() - mHeaderCount;
|
||||||
|
onItemClickListener.onItemClick(holder.itemView, layoutPosition, holder);
|
||||||
|
});
|
||||||
|
holder.itemView.setOnLongClickListener(v -> {
|
||||||
|
int layoutPosition = holder.getAdapterPosition() - mHeaderCount;
|
||||||
|
onItemClickListener.onItemLongClick(holder.itemView, layoutPosition, holder);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RvViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
RvViewHolder viewHolder = onCreateDefViewHolder(parent, viewType);
|
||||||
|
return viewHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RvViewHolder onCreateDefViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
return new RvViewHolder(mInflater.inflate(mLayoutId, parent, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addData(T datas) {
|
||||||
|
mData.add(mData.size(), datas);
|
||||||
|
notifyItemInserted(mData.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addData(int pos, T datas) {
|
||||||
|
mData.add(pos, datas);
|
||||||
|
notifyItemInserted(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void deleteData(int pos) {
|
||||||
|
mData.remove(pos);
|
||||||
|
notifyItemRemoved(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
59
baselibrary/src/main/java/base/adapter/RvViewHolder.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package base.adapter;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gallon on 2019/7/26.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class RvViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
private SparseArray<View> mViews;
|
||||||
|
|
||||||
|
public RvViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
mViews = new SparseArray<View>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过viewId获取控件
|
||||||
|
public <T extends View> T getView(int viewId) {
|
||||||
|
View view = mViews.get(viewId);
|
||||||
|
if (view == null) {
|
||||||
|
view = itemView.findViewById(viewId);
|
||||||
|
mViews.put(viewId, view);
|
||||||
|
}
|
||||||
|
return (T) view;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置TextView的值
|
||||||
|
*/
|
||||||
|
public RvViewHolder setText(int viewId, String text) {
|
||||||
|
TextView tv = getView(viewId);
|
||||||
|
tv.setText(text);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvViewHolder setImageResource(int viewId, int resId) {
|
||||||
|
ImageView view = getView(viewId);
|
||||||
|
view.setImageResource(resId);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvViewHolder setImageBitamp(int viewId, Bitmap bitmap) {
|
||||||
|
ImageView view = getView(viewId);
|
||||||
|
view.setImageBitmap(bitmap);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RvViewHolder setImageURI(int viewId, String uri) {
|
||||||
|
ImageView view = getView(viewId);
|
||||||
|
// Imageloader.getInstance().loadImg(view,uri);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
baselibrary/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<resources>
|
||||||
|
</resources>
|
||||||
2
baselibrary/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<resources>
|
||||||
|
</resources>
|
||||||
1
floatwindow/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
38
floatwindow/build.gradle
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 30
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 24
|
||||||
|
targetSdkVersion 30
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '1.8'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
api 'androidx.core:core-ktx:1.3.2'
|
||||||
|
api 'androidx.appcompat:appcompat:1.3.1'
|
||||||
|
api 'com.google.android.material:material:1.4.0'
|
||||||
|
|
||||||
|
//工具集
|
||||||
|
api 'com.blankj:utilcodex:1.31.0'
|
||||||
|
}
|
||||||
21
floatwindow/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
13
floatwindow/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.yameida.floatwindow">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
|
<application android:label="@string/app_name">
|
||||||
|
<service android:name=".DefaultFloatService" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,706 @@
|
|||||||
|
package org.yameida.floatwindow;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.CountDownTimer;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
import android.view.animation.LinearInterpolator;
|
||||||
|
|
||||||
|
import com.blankj.utilcode.util.BarUtils;
|
||||||
|
import com.blankj.utilcode.util.ScreenUtils;
|
||||||
|
import com.blankj.utilcode.util.Utils;
|
||||||
|
import org.yameida.floatwindow.view.HiderView;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class BaseFloatWindow extends Service {
|
||||||
|
protected final String TAG = this.getClass().getSimpleName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 悬浮球 坐落 左 右 标记
|
||||||
|
*/
|
||||||
|
public static final int LEFT = 0;
|
||||||
|
public static final int RIGHT = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录 logo 停放的位置,以备下次恢复
|
||||||
|
*/
|
||||||
|
protected final String LOCATION_X = TAG + "_x";
|
||||||
|
protected final String LOCATION_Y = TAG + "_y";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停靠默认位置
|
||||||
|
*/
|
||||||
|
protected int mDefaultLocation = RIGHT;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 悬浮窗 坐落 位置
|
||||||
|
*/
|
||||||
|
protected int mHintLocation = mDefaultLocation;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录当前手指位置在屏幕上的横坐标值
|
||||||
|
*/
|
||||||
|
private float mXInScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录当前手指位置在屏幕上的纵坐标值
|
||||||
|
*/
|
||||||
|
private float mYInScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录手指按下时在屏幕上的横坐标的值
|
||||||
|
*/
|
||||||
|
private float mXDownInScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录手指按下时在屏幕上的纵坐标的值
|
||||||
|
*/
|
||||||
|
private float mYDownInScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录手指按下时在小悬浮窗的View上的横坐标的值
|
||||||
|
*/
|
||||||
|
private float mXInView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录手指按下时在小悬浮窗的View上的纵坐标的值
|
||||||
|
*/
|
||||||
|
private float mYinview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录屏幕的宽度
|
||||||
|
*/
|
||||||
|
private int mScreenWidth;
|
||||||
|
|
||||||
|
protected WindowManager mWindowManager;
|
||||||
|
protected WindowManager.LayoutParams params;
|
||||||
|
|
||||||
|
private Context context = Utils.getApp();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出悬浮窗区域
|
||||||
|
*/
|
||||||
|
private HiderView mHiderView = new HiderView(context);
|
||||||
|
private boolean showHider = true;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于 定时 隐藏 logo的定时器
|
||||||
|
*/
|
||||||
|
private CountDownTimer mHideTimer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* float menu的高度
|
||||||
|
*/
|
||||||
|
private Handler mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 悬浮窗左右移动到默认位置 动画的 加速器
|
||||||
|
*/
|
||||||
|
private Interpolator mLinearInterpolator = new LinearInterpolator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记是否拖动中
|
||||||
|
*/
|
||||||
|
private boolean isDrag = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于恢复悬浮球的location的属性动画值
|
||||||
|
*/
|
||||||
|
private int mResetLocationValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限制拖动的y轴坐标
|
||||||
|
*/
|
||||||
|
protected int minY = 0;
|
||||||
|
protected int maxY = ScreenUtils.getScreenHeight();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个事件用于处理移动、自定义点击或者其它事情,return true可以保证onclick事件失效
|
||||||
|
*/
|
||||||
|
private View.OnTouchListener touchListener = new View.OnTouchListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
switch (event.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
floatEventDown(event);
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
floatEventMove(event);
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
floatEventUp();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ValueAnimator valueAnimator = null;
|
||||||
|
protected boolean isExtended = false;
|
||||||
|
|
||||||
|
protected View logoView;
|
||||||
|
protected View rightView;
|
||||||
|
protected View leftView;
|
||||||
|
|
||||||
|
private GetViewCallback mGetViewCallback;
|
||||||
|
|
||||||
|
protected BaseFloatWindow() {
|
||||||
|
initFloatWindow();
|
||||||
|
initTimer();
|
||||||
|
initFloatView();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFloatView() {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(context);
|
||||||
|
logoView = mGetViewCallback == null ? getLogoView(inflater) : mGetViewCallback.getLogoView(inflater);
|
||||||
|
leftView = mGetViewCallback == null ? getLeftView(inflater) : mGetViewCallback.getLeftView(inflater);
|
||||||
|
rightView = mGetViewCallback == null ? getRightView(inflater) : mGetViewCallback.getRightView(inflater);
|
||||||
|
|
||||||
|
if (logoView == null) {
|
||||||
|
throw new IllegalArgumentException("Must impl GetViewCallback or impl " + this.getClass().getSimpleName() + "and make getLogoView() not return null !");
|
||||||
|
}
|
||||||
|
|
||||||
|
logoView.setOnTouchListener(touchListener);//恢复touch事件
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 隐藏悬浮球的定时器
|
||||||
|
*/
|
||||||
|
private void initTimer() {
|
||||||
|
mHideTimer = new CountDownTimer(2000, 10) { //悬浮窗超过5秒没有操作的话会自动隐藏
|
||||||
|
@Override
|
||||||
|
public void onTick(long millisUntilFinished) {
|
||||||
|
if (isExtended) {
|
||||||
|
mHideTimer.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish() {
|
||||||
|
if (isExtended) {
|
||||||
|
mHideTimer.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isDrag) {
|
||||||
|
if (mHintLocation == LEFT) {
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
shrinkLeftLogoView(logoView);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.shrinkLeftLogoView(logoView);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
shrinkRightLogoView(logoView);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.shrinkRightLogoView(logoView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化悬浮球 window
|
||||||
|
*/
|
||||||
|
private void initFloatWindow() {
|
||||||
|
params = new WindowManager.LayoutParams();
|
||||||
|
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
if (!Settings.canDrawOverlays(context)) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||||
|
} else {
|
||||||
|
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||||
|
} else {
|
||||||
|
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
|
||||||
|
int screenHeigth = mWindowManager.getDefaultDisplay().getHeight();
|
||||||
|
params.format = PixelFormat.RGBA_8888;
|
||||||
|
params.gravity = Gravity.LEFT | Gravity.TOP;
|
||||||
|
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
|
||||||
|
mHintLocation = getSetting(LOCATION_X, mDefaultLocation);
|
||||||
|
int defaultY = ((screenHeigth) / 2) / 3;
|
||||||
|
int y = getSetting(LOCATION_Y, defaultY);
|
||||||
|
if (mHintLocation == LEFT) {
|
||||||
|
params.x = 0;
|
||||||
|
} else {
|
||||||
|
params.x = mScreenWidth;
|
||||||
|
}
|
||||||
|
if (y != 0 && y != defaultY) {
|
||||||
|
params.y = y;
|
||||||
|
} else {
|
||||||
|
params.y = defaultY;
|
||||||
|
}
|
||||||
|
params.alpha = 1;
|
||||||
|
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 悬浮窗touch事件的 down 事件
|
||||||
|
*/
|
||||||
|
private void floatEventDown(MotionEvent event) {
|
||||||
|
isDrag = false;
|
||||||
|
mHideTimer.cancel();
|
||||||
|
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
resetLogoViewSize(mHintLocation, logoView);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.resetLogoViewSize(mHintLocation, logoView);
|
||||||
|
}
|
||||||
|
|
||||||
|
mXInView = event.getX();
|
||||||
|
mYinview = event.getY();
|
||||||
|
mXDownInScreen = event.getRawX();
|
||||||
|
mYDownInScreen = event.getRawY();
|
||||||
|
mXInScreen = event.getRawX();
|
||||||
|
mYInScreen = event.getRawY();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 悬浮窗touch事件的 move 事件
|
||||||
|
*/
|
||||||
|
private void floatEventMove(MotionEvent event) {
|
||||||
|
mXInScreen = event.getRawX();
|
||||||
|
mYInScreen = event.getRawY();
|
||||||
|
|
||||||
|
//连续移动的距离超过3则更新一次视图位置
|
||||||
|
if (Math.abs(mXInScreen - mXDownInScreen) > logoView.getWidth() / 4 || Math.abs(mYInScreen - mYDownInScreen) > logoView.getWidth() / 4) {
|
||||||
|
params.x = (int) (mXInScreen - mXInView);
|
||||||
|
params.y = (int) (mYInScreen - mYinview) - logoView.getHeight() / 2;
|
||||||
|
updateViewPosition(); // 手指移动的时候更新小悬浮窗的位置
|
||||||
|
// double a = mScreenWidth / 2;
|
||||||
|
// float offset = (float) ((a - (Math.abs(params.x - a))) / a);
|
||||||
|
// if (mGetViewCallback == null) {
|
||||||
|
// dragLogoViewOffset(logoView, isDrag, false, offset);
|
||||||
|
// } else {
|
||||||
|
// mGetViewCallback.dragLogoViewOffset(logoView, isDrag, false, offset);
|
||||||
|
// }
|
||||||
|
mHiderView.attachToWindow();
|
||||||
|
} else {
|
||||||
|
// isDrag = false;
|
||||||
|
//// logoView.setDrag(false, 0, true);
|
||||||
|
// if (mGetViewCallback == null) {
|
||||||
|
// dragLogoViewOffset(logoView, false, true, 0);
|
||||||
|
// } else {
|
||||||
|
// mGetViewCallback.dragLogoViewOffset(logoView, false, true, 0);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 悬浮窗touch事件的 up 事件
|
||||||
|
*/
|
||||||
|
private void floatEventUp() {
|
||||||
|
if (mXInScreen < mScreenWidth / 2) { //在左边
|
||||||
|
mHintLocation = LEFT;
|
||||||
|
} else { //在右边
|
||||||
|
mHintLocation = RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
valueAnimator = ValueAnimator.ofInt(64);
|
||||||
|
valueAnimator.setInterpolator(mLinearInterpolator);
|
||||||
|
valueAnimator.setDuration(1000);
|
||||||
|
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationUpdate(ValueAnimator animation) {
|
||||||
|
mResetLocationValue = (int) animation.getAnimatedValue();
|
||||||
|
mHandler.post(updatePositionRunnable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
valueAnimator.addListener(new Animator.AnimatorListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
if (Math.abs(params.x) < 0) {
|
||||||
|
params.x = 0;
|
||||||
|
} else if (Math.abs(params.x) > mScreenWidth) {
|
||||||
|
params.x = mScreenWidth;
|
||||||
|
}
|
||||||
|
updateViewPosition();
|
||||||
|
isDrag = false;
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
dragLogoViewOffset(logoView, false, true, 0);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.dragLogoViewOffset(logoView, false, true, 0);
|
||||||
|
}
|
||||||
|
mHideTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
if (Math.abs(params.x) < 0) {
|
||||||
|
params.x = 0;
|
||||||
|
} else if (Math.abs(params.x) > mScreenWidth) {
|
||||||
|
params.x = mScreenWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateViewPosition();
|
||||||
|
isDrag = false;
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
dragLogoViewOffset(logoView, false, true, 0);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.dragLogoViewOffset(logoView, false, true, 0);
|
||||||
|
}
|
||||||
|
mHideTimer.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!valueAnimator.isRunning()) {
|
||||||
|
valueAnimator.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
//这里需要判断如果如果手指所在位置和logo所在位置在一个宽度内则不移动,
|
||||||
|
if (Math.abs(mXInScreen - mXDownInScreen) > logoView.getWidth() / 5F || Math.abs(mYInScreen - mYDownInScreen) > logoView.getHeight() / 5F) {
|
||||||
|
isDrag = false;
|
||||||
|
} else {
|
||||||
|
openMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
mHiderView.release();
|
||||||
|
if (mHiderView.mLp != null) {
|
||||||
|
int lx = mScreenWidth / 2 - mHiderView.getWidth() / 2;
|
||||||
|
int ly = mHiderView.mLp.y + BarUtils.getStatusBarHeight();
|
||||||
|
int rx = lx + mHiderView.getWidth() + logoView.getWidth();
|
||||||
|
int ry = ly + mHiderView.getHeight() + logoView.getHeight();
|
||||||
|
if (mXInScreen >= lx && mXInScreen <= rx
|
||||||
|
&& mYInScreen >= ly && mYInScreen <= ry) {
|
||||||
|
valueAnimator.cancel();
|
||||||
|
// 复原X
|
||||||
|
if (mXDownInScreen < mScreenWidth / 2) { //在左边
|
||||||
|
mHintLocation = LEFT;
|
||||||
|
params.x = 0;
|
||||||
|
} else { //在右边
|
||||||
|
mHintLocation = RIGHT;
|
||||||
|
params.x = mScreenWidth;
|
||||||
|
}
|
||||||
|
// 复原Y
|
||||||
|
params.y = (int) mYDownInScreen;
|
||||||
|
// 滑动的位置在隐藏视图内
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手指离开屏幕后 用于恢复 悬浮球的 logo 的左右位置
|
||||||
|
*/
|
||||||
|
private Runnable updatePositionRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
isDrag = true;
|
||||||
|
checkPosition();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于检查并更新悬浮球的位置
|
||||||
|
*/
|
||||||
|
private void checkPosition() {
|
||||||
|
if (params.x > 0 && params.x < mScreenWidth) {
|
||||||
|
if (mHintLocation == LEFT) {
|
||||||
|
params.x = params.x - mResetLocationValue;
|
||||||
|
} else {
|
||||||
|
params.x = params.x + mResetLocationValue;
|
||||||
|
}
|
||||||
|
updateViewPosition();
|
||||||
|
double a = mScreenWidth / 2;
|
||||||
|
float offset = (float) ((a - (Math.abs(params.x - a))) / a);
|
||||||
|
// logoView.setDrag(isDrag, offset, true);
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
dragLogoViewOffset(logoView, false, true, 0);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.dragLogoViewOffset(logoView, isDrag, true, offset);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(params.x) < 0) {
|
||||||
|
params.x = 0;
|
||||||
|
} else if (Math.abs(params.x) > mScreenWidth) {
|
||||||
|
params.x = mScreenWidth;
|
||||||
|
}
|
||||||
|
if (valueAnimator.isRunning()) {
|
||||||
|
valueAnimator.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateViewPosition();
|
||||||
|
isDrag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
try {
|
||||||
|
dismiss();
|
||||||
|
if (mWindowManager != null && params != null && logoView != null) {
|
||||||
|
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
mWindowManager.addView(logoView, params);
|
||||||
|
}
|
||||||
|
if (mHideTimer != null) {
|
||||||
|
mHideTimer.start();
|
||||||
|
} else {
|
||||||
|
initTimer();
|
||||||
|
mHideTimer.start();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开菜单/关闭菜单
|
||||||
|
*/
|
||||||
|
protected void openMenu() {
|
||||||
|
if (isDrag) return;
|
||||||
|
|
||||||
|
if (!isExtended) {
|
||||||
|
// logoView.setDrawDarkBg(false);
|
||||||
|
try {
|
||||||
|
mWindowManager.removeViewImmediate(logoView);
|
||||||
|
params.width = WindowManager.LayoutParams.MATCH_PARENT;
|
||||||
|
params.height = WindowManager.LayoutParams.MATCH_PARENT;
|
||||||
|
if (mHintLocation == RIGHT) {
|
||||||
|
mWindowManager.addView(rightView, params);
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
rightViewOpened(rightView);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.rightViewOpened(rightView);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mWindowManager.addView(leftView, params);
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
leftViewOpened(leftView);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.leftViewOpened(leftView);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
isExtended = true;
|
||||||
|
mHideTimer.cancel();
|
||||||
|
} else {
|
||||||
|
// logoView.setDrawDarkBg(true);
|
||||||
|
try {
|
||||||
|
mWindowManager.removeViewImmediate(mHintLocation == LEFT ? leftView : rightView);
|
||||||
|
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
mWindowManager.addView(logoView, params);
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
leftOrRightViewClosed(logoView);
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.leftOrRightViewClosed(logoView);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
isExtended = false;
|
||||||
|
mHideTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新悬浮窗在屏幕中的位置。
|
||||||
|
*/
|
||||||
|
private void updateViewPosition() {
|
||||||
|
isDrag = true;
|
||||||
|
try {
|
||||||
|
if (!isExtended) {
|
||||||
|
if (minY == 0) minY = logoView.getHeight();
|
||||||
|
if (maxY == ScreenUtils.getScreenHeight()) maxY -= logoView.getHeight();
|
||||||
|
if (params.y < minY) params.y = minY;
|
||||||
|
if (params.y > maxY) params.y = maxY;
|
||||||
|
mWindowManager.updateViewLayout(logoView, params);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除所有悬浮窗 释放资源
|
||||||
|
*/
|
||||||
|
public void dismiss() {
|
||||||
|
//记录上次的位置logo的停放位置,以备下次恢复
|
||||||
|
saveSetting(LOCATION_X, mHintLocation);
|
||||||
|
saveSetting(LOCATION_Y, params.y);
|
||||||
|
logoView.clearAnimation();
|
||||||
|
try {
|
||||||
|
mHideTimer.cancel();
|
||||||
|
if (isExtended) {
|
||||||
|
mWindowManager.removeViewImmediate(mHintLocation == LEFT ? leftView : rightView);
|
||||||
|
} else {
|
||||||
|
if (logoView.getParent() != null) {
|
||||||
|
mWindowManager.removeViewImmediate(logoView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isExtended = false;
|
||||||
|
isDrag = false;
|
||||||
|
if (mGetViewCallback == null) {
|
||||||
|
onDestroyed();
|
||||||
|
} else {
|
||||||
|
mGetViewCallback.onDestroyed();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract View getLeftView(LayoutInflater inflater);
|
||||||
|
|
||||||
|
protected abstract View getRightView(LayoutInflater inflater);
|
||||||
|
|
||||||
|
protected abstract View getLogoView(LayoutInflater inflater);
|
||||||
|
|
||||||
|
protected abstract void resetLogoViewSize(int hintLocation, View logoView);//logo恢复原始大小
|
||||||
|
|
||||||
|
protected abstract void dragLogoViewOffset(View logoView, boolean isDrag, boolean isResetPosition, float offset);
|
||||||
|
|
||||||
|
protected abstract void shrinkLeftLogoView(View logoView);//logo左边收缩
|
||||||
|
|
||||||
|
protected abstract void shrinkRightLogoView(View logoView);//logo右边收缩
|
||||||
|
|
||||||
|
protected abstract void leftViewOpened(View leftView);//左菜单打开
|
||||||
|
|
||||||
|
protected abstract void rightViewOpened(View rightView);//右菜单打开
|
||||||
|
|
||||||
|
protected abstract void leftOrRightViewClosed(View logoView);
|
||||||
|
|
||||||
|
protected abstract void onDestroyed();
|
||||||
|
|
||||||
|
public interface GetViewCallback {
|
||||||
|
View getLeftView(LayoutInflater inflater);
|
||||||
|
|
||||||
|
View getRightView(LayoutInflater inflater);
|
||||||
|
|
||||||
|
View getLogoView(LayoutInflater inflater);
|
||||||
|
|
||||||
|
|
||||||
|
void resetLogoViewSize(int hintLocation, View logoView);//logo恢复原始大小
|
||||||
|
|
||||||
|
void dragLogoViewOffset(View logoView, boolean isDrag, boolean isResetPosition, float offset);//logo正被拖动,或真在恢复原位
|
||||||
|
|
||||||
|
void shrinkLeftLogoView(View logoView);//logo左边收缩
|
||||||
|
|
||||||
|
void shrinkRightLogoView(View logoView);//logo右边收缩
|
||||||
|
|
||||||
|
void leftViewOpened(View leftView);//左菜单打开
|
||||||
|
|
||||||
|
void rightViewOpened(View rightView);//右菜单打开
|
||||||
|
|
||||||
|
void leftOrRightViewClosed(View logoView);
|
||||||
|
|
||||||
|
void onDestroyed();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于保存悬浮球的位置记录
|
||||||
|
*
|
||||||
|
* @param key String
|
||||||
|
* @param defaultValue int
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private int getSetting(String key, int defaultValue) {
|
||||||
|
try {
|
||||||
|
SharedPreferences sharedata = context.getSharedPreferences("floatLogo", 0);
|
||||||
|
return sharedata.getInt(key, defaultValue);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于保存悬浮球的位置记录
|
||||||
|
*
|
||||||
|
* @param key String
|
||||||
|
* @param value int
|
||||||
|
*/
|
||||||
|
public void saveSetting(String key, int value) {
|
||||||
|
try {
|
||||||
|
SharedPreferences.Editor sharedata = context.getSharedPreferences("floatLogo", 0).edit();
|
||||||
|
sharedata.putInt(key, value);
|
||||||
|
sharedata.apply();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
|
||||||
|
if (mHintLocation == RIGHT) {
|
||||||
|
params.x = mScreenWidth;
|
||||||
|
}
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
package org.yameida.floatwindow
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Binder
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import com.blankj.utilcode.util.*
|
||||||
|
|
||||||
|
import org.yameida.floatwindow.listener.FloatWindowListener
|
||||||
|
import kotlinx.android.synthetic.main.layout_menu_left.view.*
|
||||||
|
import kotlinx.android.synthetic.main.layout_menu_logo.view.*
|
||||||
|
import kotlinx.android.synthetic.main.layout_menu_right.view.*
|
||||||
|
import org.yameida.floatwindow.listener.OnClickListener
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Gallon on 2019/9/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DefaultFloatService : BaseFloatWindow(), View.OnClickListener {
|
||||||
|
|
||||||
|
// private var currentStatus = RecordStatusManager.PLAY_STATUS_STOP
|
||||||
|
private var active = false
|
||||||
|
private var context = Utils.getApp()
|
||||||
|
private var manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
private val CHANNEL_ID_STRING = "907"
|
||||||
|
var floatWindowListener: FloatWindowListener? = null
|
||||||
|
var onClickListener: OnClickListener? = null
|
||||||
|
|
||||||
|
inner class DefaultFloatServiceBinder : Binder() {
|
||||||
|
fun getService() = this@DefaultFloatService
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
minY = SizeUtils.dp2px(100F)
|
||||||
|
maxY = ScreenUtils.getScreenHeight() - SizeUtils.dp2px(150F)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder? = DefaultFloatServiceBinder()
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val mChannel = NotificationChannel(CHANNEL_ID_STRING, "float", NotificationManager.IMPORTANCE_HIGH)
|
||||||
|
manager.createNotificationChannel(mChannel)
|
||||||
|
val notification = Notification.Builder(context, CHANNEL_ID_STRING).build()
|
||||||
|
startForeground(1, notification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
LogUtils.d(TAG, "onStartCommand: ${intent?.data}")
|
||||||
|
show()
|
||||||
|
return super.onStartCommand(intent, flags, startId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
super.show()
|
||||||
|
// FloatWindowManager.isShow = true
|
||||||
|
floatWindowListener?.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
super.hide()
|
||||||
|
// FloatWindowManager.isShow = false
|
||||||
|
floatWindowListener?.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
LogUtils.v(TAG, "float onClick: ")
|
||||||
|
openMenu()
|
||||||
|
if (v == leftView.fl_window_background_left || v == rightView.fl_window_background_right) {
|
||||||
|
onClickListener?.onClick(v,-1)
|
||||||
|
}
|
||||||
|
if (v == leftView.iv_logo_left || v == rightView.iv_logo_right || v == leftView.iv_logo_left2 || v == rightView.iv_logo_right2) {
|
||||||
|
onClickListener?.onClick(v, 0)
|
||||||
|
}
|
||||||
|
if (v == leftView.iv_start_left || v == rightView.iv_start_right) {
|
||||||
|
onClickListener?.onClick(v,1)
|
||||||
|
}
|
||||||
|
if (v == leftView.iv_shot_left || v == rightView.iv_shot_right) {
|
||||||
|
onClickListener?.onClick(v,2)
|
||||||
|
}
|
||||||
|
if (v == leftView.iv_back_left || v == rightView.iv_back_right) {
|
||||||
|
onClickListener?.onClick(v,3)
|
||||||
|
}
|
||||||
|
if (v == leftView.iv_settings_left || v == rightView.iv_settings_right) {
|
||||||
|
onClickListener?.onClick(v,4)
|
||||||
|
}
|
||||||
|
if (v == leftView.iv_resume_pause_left || v == rightView.iv_resume_pause_right) {
|
||||||
|
onClickListener?.onClick(v,5)
|
||||||
|
}
|
||||||
|
if (v == leftView.iv_stop_left || v == rightView.iv_stop_right) {
|
||||||
|
onClickListener?.onClick(v,6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLeftView(inflater: LayoutInflater): View {
|
||||||
|
leftView = inflater.inflate(R.layout.layout_menu_left, null)
|
||||||
|
leftView.iv_logo_left.setOnClickListener(this)
|
||||||
|
leftView.iv_logo_left2.setOnClickListener(this)
|
||||||
|
leftView.iv_start_left.setOnClickListener(this)
|
||||||
|
leftView.iv_shot_left.setOnClickListener(this)
|
||||||
|
leftView.iv_back_left.setOnClickListener(this)
|
||||||
|
leftView.iv_resume_pause_left.setOnClickListener(this)
|
||||||
|
leftView.iv_stop_left.setOnClickListener(this)
|
||||||
|
leftView.iv_settings_left.setOnClickListener(this)
|
||||||
|
leftView.fl_window_background_left.setOnClickListener(this)
|
||||||
|
return leftView
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRightView(inflater: LayoutInflater): View {
|
||||||
|
rightView = inflater.inflate(R.layout.layout_menu_right, null)
|
||||||
|
rightView.iv_logo_right.setOnClickListener(this)
|
||||||
|
rightView.iv_logo_right2.setOnClickListener(this)
|
||||||
|
rightView.iv_start_right.setOnClickListener(this)
|
||||||
|
rightView.iv_shot_right.setOnClickListener(this)
|
||||||
|
rightView.iv_back_right.setOnClickListener(this)
|
||||||
|
rightView.iv_resume_pause_right.setOnClickListener(this)
|
||||||
|
rightView.iv_stop_right.setOnClickListener(this)
|
||||||
|
rightView.iv_settings_right.setOnClickListener(this)
|
||||||
|
rightView.fl_window_background_right.setOnClickListener(this)
|
||||||
|
return rightView
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLogoView(inflater: LayoutInflater): View {
|
||||||
|
return inflater.inflate(R.layout.layout_menu_logo, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetLogoViewSize(hintLocation: Int, logoView: View) {
|
||||||
|
logoView.clearAnimation()
|
||||||
|
logoView.translationX = 0f
|
||||||
|
logoView.scaleX = 1f
|
||||||
|
logoView.scaleY = 1f
|
||||||
|
logoView.alpha = 1f
|
||||||
|
logoView.tv_float_time.textSize = 10f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dragLogoViewOffset(logoView: View, isDrag: Boolean, isResetPosition: Boolean, offset: Float) {
|
||||||
|
if (isDrag && offset > 0) {
|
||||||
|
logoView.scaleX = 1 + offset
|
||||||
|
logoView.scaleY = 1 + offset
|
||||||
|
} else {
|
||||||
|
logoView.translationX = 0f
|
||||||
|
logoView.scaleX = 1f
|
||||||
|
logoView.scaleY = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
logoView.rotation = offset * 360
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun shrinkLeftLogoView(smallView: View) {
|
||||||
|
smallView.translationX = (-smallView.width / 4).toFloat()
|
||||||
|
smallView.alpha = 0.35f
|
||||||
|
logoView.tv_float_time.textSize = 7f
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun shrinkRightLogoView(smallView: View) {
|
||||||
|
smallView.translationX = (smallView.width / 4).toFloat()
|
||||||
|
smallView.alpha = 0.35f
|
||||||
|
logoView.tv_float_time.textSize = 7f
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun leftViewOpened(leftView: View) {
|
||||||
|
val layoutParams = leftView.fl_window_measure_left.layoutParams as FrameLayout.LayoutParams
|
||||||
|
leftView.fl_window_measure_left.measure(0, 0)
|
||||||
|
layoutParams.topMargin = (params.y - leftView.fl_window_measure_left.measuredHeight / 2 - leftView.iv_logo_left.measuredHeight / 2)
|
||||||
|
leftView.fl_window_measure_left.layoutParams = layoutParams
|
||||||
|
// ToastUtils.showShort("左边的菜单被打开了")
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun rightViewOpened(rightView: View) {
|
||||||
|
val layoutParams = rightView.fl_window_measure_right.layoutParams as FrameLayout.LayoutParams
|
||||||
|
rightView.fl_window_measure_right.measure(0, 0)
|
||||||
|
layoutParams.topMargin = params.y - rightView.fl_window_measure_right.measuredHeight / 2 - rightView.iv_logo_right.measuredHeight / 2
|
||||||
|
layoutParams.leftMargin = ScreenUtils.getScreenWidth() - rightView.fl_window_measure_right.measuredWidth
|
||||||
|
rightView.fl_window_measure_right.layoutParams = layoutParams
|
||||||
|
// ToastUtils.showShort("右边的菜单被打开了")
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun leftOrRightViewClosed(smallView: View) {
|
||||||
|
// Toast.makeText(context, "菜单被关闭了", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyed() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package org.yameida.floatwindow
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import com.blankj.utilcode.util.Utils
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Gallon on 2019/9/5.
|
||||||
|
*/
|
||||||
|
object FloatWindowManager {
|
||||||
|
private val TAG = FloatWindowManager::class.java.simpleName
|
||||||
|
|
||||||
|
private var context = Utils.getApp()
|
||||||
|
|
||||||
|
fun show(service: Class<out BaseFloatWindow>, intent: Intent? = null) {
|
||||||
|
startServiceSafe(Intent(context, service).apply {
|
||||||
|
if (intent != null) {
|
||||||
|
this.putExtras(intent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide(service: Class<out BaseFloatWindow>, intent: Intent? = null) {
|
||||||
|
startServiceSafe(Intent(context, service).apply {
|
||||||
|
if (intent != null) {
|
||||||
|
this.putExtras(intent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startServiceSafe(intent: Intent) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
} else {
|
||||||
|
context.startService(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.yameida.floatwindow.listener
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Gallon on 2019/8/11.
|
||||||
|
*/
|
||||||
|
interface FloatWindowListener {
|
||||||
|
fun show()
|
||||||
|
|
||||||
|
fun hide()
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.yameida.floatwindow.listener
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Gallon on 2019/8/11.
|
||||||
|
*/
|
||||||
|
interface OnClickListener {
|
||||||
|
|
||||||
|
fun onClick(v: View, event: Int)
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package org.yameida.floatwindow.view;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import org.yameida.floatwindow.R;
|
||||||
|
|
||||||
|
|
||||||
|
public class HiderView extends LinearLayout {
|
||||||
|
private Context mContext;
|
||||||
|
private WindowManager mWindowManager;
|
||||||
|
public WindowManager.LayoutParams mLp;
|
||||||
|
private ValueAnimator valueAnimator;
|
||||||
|
private int mResetLocationValue;
|
||||||
|
|
||||||
|
public HiderView(Context context) {
|
||||||
|
super(context);
|
||||||
|
this.mContext = context;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HiderView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
this.mContext = context;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
inflate(mContext, R.layout.widget_hiderview_ll, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attachToWindow() {
|
||||||
|
if (this.getParent() != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mWindowManager = (WindowManager) mContext
|
||||||
|
.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
mLp = new WindowManager.LayoutParams();
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
if (!Settings.canDrawOverlays(getContext())) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
mLp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||||
|
} else {
|
||||||
|
mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
mLp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||||
|
} else {
|
||||||
|
mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||||
|
}
|
||||||
|
// mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||||
|
mLp.format = PixelFormat.RGBA_8888;
|
||||||
|
mLp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||||
|
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||||
|
mLp.gravity = Gravity.CENTER | Gravity.TOP;
|
||||||
|
mLp.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
mLp.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
int y = mWindowManager.getDefaultDisplay().getHeight();
|
||||||
|
mLp.y = y;
|
||||||
|
mWindowManager.addView(this, mLp);
|
||||||
|
|
||||||
|
valueAnimator = ValueAnimator.ofInt(0, y / 4);
|
||||||
|
valueAnimator.setDuration(200);
|
||||||
|
|
||||||
|
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationUpdate(ValueAnimator animation) {
|
||||||
|
mResetLocationValue = (int) animation.getAnimatedValue();
|
||||||
|
mLp.y = y - getHeight() - mResetLocationValue;
|
||||||
|
mWindowManager.updateViewLayout(HiderView.this, mLp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
valueAnimator.addListener(new Animator.AnimatorListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator animation) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
mWindowManager.updateViewLayout(HiderView.this, mLp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
mWindowManager.updateViewLayout(HiderView.this, mLp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator animation) {}
|
||||||
|
});
|
||||||
|
if (!valueAnimator.isRunning()) {
|
||||||
|
valueAnimator.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
if (this.getParent() != null) {
|
||||||
|
if (valueAnimator.isRunning()) {
|
||||||
|
valueAnimator.cancel();
|
||||||
|
}
|
||||||
|
mWindowManager.removeView(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 306 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/back_icon.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/bg_float_guide.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_home.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_pause.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_play.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_record.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_setting.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_stop.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_directory.png
Normal file
|
After Width: | Height: | Size: 322 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_fps.png
Normal file
|
After Width: | Height: | Size: 145 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_hd.png
Normal file
|
After Width: | Height: | Size: 342 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_hq.png
Normal file
|
After Width: | Height: | Size: 368 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_language.png
Normal file
|
After Width: | Height: | Size: 697 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_no_pop.png
Normal file
|
After Width: | Height: | Size: 734 B |
|
After Width: | Height: | Size: 616 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_rate_us.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_share.png
Normal file
|
After Width: | Height: | Size: 663 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/tab_settings_check.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/widget_float_hide.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/widget_guide_finger.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/widget_tip_button.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
22
floatwindow/src/main/res/drawable/comment_gray_btn.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#ddd" />
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_enabled="false">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
<stroke android:width="1dp" android:color="@color/c8c8c8" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#aaa" />
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
22
floatwindow/src/main/res/drawable/comment_red_btn.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/color_dashen_passed" />
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_enabled="false">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
<stroke android:width="1dp" android:color="@color/c8c8c8" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/color_dashen" />
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
9
floatwindow/src/main/res/drawable/ic_arrow_back.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||||
|
</vector>
|
||||||
99
floatwindow/src/main/res/layout/layout_menu_left.xml
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/fl_window_background_left"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#66333333">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fl_window_measure_left"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="190dp"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_start_left"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_marginEnd="@dimen/float_margin_start"
|
||||||
|
android:src="@drawable/float_icon_record" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_shot_left"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_marginStart="@dimen/float_margin_start"
|
||||||
|
android:layout_marginTop="29dp"
|
||||||
|
android:src="@drawable/float_icon_pause" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_back_left"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_below="@id/iv_shot_left"
|
||||||
|
android:layout_marginStart="@dimen/float_margin_start"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:src="@drawable/float_icon_home" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_logo_left"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_below="@id/iv_start_left"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="55dp"
|
||||||
|
android:src="@mipmap/ic_launcher_round" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_settings_left"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_below="@id/iv_logo_left"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="@dimen/float_margin_start"
|
||||||
|
android:scaleX="1.05"
|
||||||
|
android:scaleY="1.05"
|
||||||
|
android:src="@drawable/float_icon_setting" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="190dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_logo_left2"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:src="@mipmap/ic_launcher_round" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_resume_pause_left"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:src="@drawable/float_icon_pause" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_stop_left"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_marginStart="-5dp"
|
||||||
|
android:src="@drawable/float_icon_stop" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
22
floatwindow/src/main/res/layout/layout_menu_logo.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/float_stand_size"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="@dimen/float_stand_size"
|
||||||
|
android:layout_height="@dimen/float_stand_size"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
android:src="@mipmap/ic_launcher_round" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_float_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
94
floatwindow/src/main/res/layout/layout_menu_right.xml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/fl_window_background_right"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#66333333">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fl_window_measure_right"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="190dp"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_start_right"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_marginStart="@dimen/float_margin_start"
|
||||||
|
android:src="@drawable/float_icon_record" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_shot_right"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_marginTop="29dp"
|
||||||
|
android:src="@drawable/float_icon_pause" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_back_right"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_below="@id/iv_shot_right"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:src="@drawable/float_icon_home" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_logo_right"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_below="@id/iv_start_right"
|
||||||
|
android:layout_marginStart="55dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:src="@mipmap/ic_launcher_round" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_settings_right"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_below="@id/iv_logo_right"
|
||||||
|
android:layout_marginStart="@dimen/float_margin_start"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:scaleX="1.05"
|
||||||
|
android:scaleY="1.05"
|
||||||
|
android:src="@drawable/float_icon_setting" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="190dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_stop_right"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:src="@drawable/float_icon_stop" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_resume_pause_right"
|
||||||
|
android:layout_width="@dimen/float_size"
|
||||||
|
android:layout_height="@dimen/float_size"
|
||||||
|
android:layout_marginStart="-5dp"
|
||||||
|
android:src="@drawable/float_icon_pause" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_logo_right2"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:src="@mipmap/ic_launcher_round" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
15
floatwindow/src/main/res/layout/widget_hiderview_ll.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
>
|
||||||
|
<!-- android:background="@color/balloonperformer_translucent"-->
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/widget_float_hide" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
BIN
floatwindow/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
floatwindow/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
16
floatwindow/src/main/res/values/colors-rec.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="background">@color/color_f5f5f5</color>
|
||||||
|
<color name="list_divider_line">@color/color_e5e5e5</color>
|
||||||
|
<color name="white">#fff</color>
|
||||||
|
<color name="color_333333">#333333</color>
|
||||||
|
<color name="color_999999">#999999</color>
|
||||||
|
<color name="color_b2000000">#b2000000</color>
|
||||||
|
<color name="color_dashen">#ff5215</color>
|
||||||
|
<color name="color_dashen_passed">#e54b12</color>
|
||||||
|
<color name="float_time_color">#f58220</color>
|
||||||
|
|
||||||
|
<color name="color_e5e5e5">#e5e5e5</color>
|
||||||
|
<color name="color_f5f5f5">#f5f5f5</color>
|
||||||
|
<color name="c8c8c8">#c8c8c8</color>
|
||||||
|
</resources>
|
||||||
10
floatwindow/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#008577</color>
|
||||||
|
<color name="colorPrimaryDark">#00574B</color>
|
||||||
|
<color name="colorAccent">#D81B60</color>
|
||||||
|
|
||||||
|
<color name="bar_gray">#37474F</color>
|
||||||
|
<color name="while_bg">#F7F7F7</color>
|
||||||
|
|
||||||
|
</resources>
|
||||||
19
floatwindow/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<dimen name="setting_start_padding">22dp</dimen>
|
||||||
|
<dimen name="setting_end_start_padding">25dp</dimen>
|
||||||
|
<dimen name="setting_end_padding">10dp</dimen>
|
||||||
|
<dimen name="setting_vertical_padding">10dp</dimen>
|
||||||
|
<dimen name="setting_end_font_width">60dp</dimen>
|
||||||
|
<dimen name="setting_start_image_width">20dp</dimen>
|
||||||
|
<dimen name="size_button">18sp</dimen>
|
||||||
|
<dimen name="btn_top_bottom_padding">10dp</dimen>
|
||||||
|
<dimen name="btn_height">50dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="float_size">60dp</dimen>
|
||||||
|
<dimen name="float_margin_start">50dp</dimen>
|
||||||
|
<dimen name="float_stand_size">36dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="setting_start_font_size">15sp</dimen>
|
||||||
|
<dimen name="setting_end_font_size">13sp</dimen>
|
||||||
|
</resources>
|
||||||
3
floatwindow/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">floatwindow</string>
|
||||||
|
</resources>
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
include ':app'
|
include ':app', ':baselibrary'
|
||||||
|
include ':floatwindow'
|
||||||
rootProject.name = "WorkTool"
|
rootProject.name = "WorkTool"
|
||||||