refactor: ###
优化代码并更新文件中的UI元素 - 重构了MainViewModel.kt中的代码,去除了未使用的导入项和不必要的初始化 - 更新了floating_window.xml布局中的样式 - 在AndroidManifest.xml中添加了PACKAGE_USAGE_STATS权限
This commit is contained in:
parent
5dcda8829d
commit
054e86ec13
@ -9,6 +9,7 @@
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
@ -6,8 +6,6 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.delay
|
||||
@ -15,7 +13,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
@ -26,9 +23,6 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
// region 依赖项
|
||||
private val gaidHelper by lazy { GAIDHelper(application) }
|
||||
private val windowManager by lazy {
|
||||
getApplication<Application>().getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region 公共API
|
||||
@ -58,9 +52,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
delay(1000) // 延迟 1000 毫秒,确保桌面已经显示
|
||||
try {
|
||||
MyAccessibilityService.getInstance()?.findAndLaunchApp(
|
||||
"breakingnews",
|
||||
"io.sixminutes.breakingnews",
|
||||
"Test"
|
||||
"breakingnews", "io.sixminutes.breakingnews", "Test"
|
||||
//"Show Inter Ad 1: 3689d2816239b64e"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
|
@ -50,7 +50,7 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
private var targetAppName: String? = null
|
||||
private var targetAppPackageName: String? = null
|
||||
private var currentAppPackageName: String? = null
|
||||
private var currentClassName: String? = null
|
||||
private var currentActivityName: String? = null
|
||||
private var launcherButtonText: String? = null
|
||||
private val mainHandler by lazy { Handler(Looper.getMainLooper()) }
|
||||
private var running = false
|
||||
@ -119,13 +119,13 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
// **显示指示器**
|
||||
tapIndicatorView.showTapIndicator(x, y)
|
||||
|
||||
if (RootHelper.runRootCommand(command)) {
|
||||
Toast.makeText(this, "点击 ($x, $y) 成功", Toast.LENGTH_SHORT).show()
|
||||
Log.d(TAG, "Executed: $command")
|
||||
} else {
|
||||
Toast.makeText(this, "点击 ($x, $y) 失败", Toast.LENGTH_SHORT).show()
|
||||
Log.e(TAG, "Failed to execute: $command")
|
||||
}
|
||||
// if (RootHelper.runRootCommand(command)) {
|
||||
// Toast.makeText(this, "点击 ($x, $y) 成功", Toast.LENGTH_SHORT).show()
|
||||
// Log.d(TAG, "Executed: $command")
|
||||
// } else {
|
||||
// Toast.makeText(this, "点击 ($x, $y) 失败", Toast.LENGTH_SHORT).show()
|
||||
// Log.e(TAG, "Failed to execute: $command")
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,6 +140,8 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
buttonText: String? = null,
|
||||
): Boolean {
|
||||
var success = false
|
||||
// 显示悬浮窗
|
||||
createFloatingWindow()
|
||||
safeRootOperation { root ->
|
||||
findNodesByCondition(root) { node ->
|
||||
node.textMatches(appName) || node.contentDescriptionMatches(appName)
|
||||
@ -150,32 +152,18 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
launcherButtonText = buttonText
|
||||
targetAppName = appName
|
||||
success = true
|
||||
|
||||
// 显示悬浮窗
|
||||
createFloatingWindow()
|
||||
} else {
|
||||
Log.w(TAG, "Failed to click app: $appName")
|
||||
showToast("Failed to click app: $appName")
|
||||
updateFloatingText("Failed to click app: $appName", true)
|
||||
}
|
||||
} ?: {
|
||||
Log.w(TAG, "App not found: $appName")
|
||||
showToast("App not found: $appName")
|
||||
updateFloatingText("App not found: $appName", true)
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
private fun isTargetAppRunning(): Boolean {
|
||||
val currentRoot = rootInActiveWindow
|
||||
return if (currentRoot != null) {
|
||||
currentAppPackageName = currentRoot.packageName?.toString()
|
||||
currentAppPackageName == targetAppPackageName
|
||||
} else {
|
||||
Log.e(TAG, "isTargetAppRunning: rootInActiveWindow is null")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// region 点击逻辑优化
|
||||
/**
|
||||
* 智能点击方案(综合节点属性/父容器/坐标点击)
|
||||
@ -290,6 +278,7 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
retryInterval: Long = DEFAULT_RETRY_INTERVAL
|
||||
): Boolean {
|
||||
Log.d(TAG, "Attempting to click button: '$buttonText'")
|
||||
updateFloatingText("Attempting to click button: '$buttonText'")
|
||||
var success = false
|
||||
|
||||
safeRootOperation { root ->
|
||||
@ -338,8 +327,7 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
var retryCount = 0
|
||||
|
||||
fun attempt() {
|
||||
if (!running)
|
||||
return
|
||||
if (!running) return
|
||||
when {
|
||||
checkCondition() -> onSuccess()
|
||||
retryCount < maxRetries -> {
|
||||
@ -454,75 +442,95 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
}
|
||||
}
|
||||
|
||||
// 检查当前窗口是哪个
|
||||
private fun isTargetAppRunning(): Boolean {
|
||||
val currentRoot = rootInActiveWindow
|
||||
return if (currentRoot != null) {
|
||||
currentAppPackageName = currentRoot.packageName?.toString()
|
||||
currentAppPackageName == targetAppPackageName
|
||||
|
||||
} else {
|
||||
Log.e(TAG, "isTargetAppRunning: rootInActiveWindow is null")
|
||||
updateFloatingText("rootInActiveWindow is null", true)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleWindowChange(event: AccessibilityEvent) {
|
||||
if (!running) return
|
||||
if (targetAppPackageName == null) return
|
||||
|
||||
currentAppPackageName = event.packageName?.toString() ?: return
|
||||
currentClassName = event.className?.toString() ?: return
|
||||
val packageName = event.packageName?.toString() ?: "unknownPackageName"
|
||||
val activity = event.className?.toString() ?: "unknownActivity"
|
||||
|
||||
if (packageName == "io.sixminutes.ridicule" && activity == "android.widget.LinearLayout") {
|
||||
Log.w(TAG, "Detected current app is floating window")
|
||||
return
|
||||
}
|
||||
|
||||
// 增强日志输出
|
||||
Log.d(
|
||||
TAG, """
|
||||
Window Changed:
|
||||
├─ Current Package : $currentAppPackageName
|
||||
├─ Current Package : $packageName
|
||||
├─ Target Package : $targetAppPackageName
|
||||
├─ Class Name : ${currentClassName?.substringAfterLast('.')}
|
||||
└─ Full Class Name : $currentClassName
|
||||
├─ Class Name : ${activity.substringAfterLast('.')}
|
||||
└─ Full Class Name : $activity
|
||||
""".trimIndent()
|
||||
)
|
||||
if (targetAppPackageName == null) return
|
||||
|
||||
currentAppPackageName = packageName
|
||||
// 当检测到切换到其他应用时
|
||||
if (currentAppPackageName != targetAppPackageName) {
|
||||
|
||||
// 先检查 isCheckAppPackageName,如果为 true 则不重复启动
|
||||
if (!isCheckAppPackageName) {
|
||||
isCheckAppPackageName = true
|
||||
mainHandler.postDelayed(::checkAppPackageName, DEFAULT_RETRY_INTERVAL)
|
||||
checkAppPackageName()
|
||||
} else {
|
||||
Log.w(TAG, "CheckAppPackageName operation is already running, skipping...")
|
||||
currentActivityName = activity
|
||||
checkActivity()
|
||||
}
|
||||
} else {
|
||||
// 先检查 isCheckActivity,如果为 true 则不重复启动
|
||||
|
||||
if (!isCheckActivity) {
|
||||
isCheckActivity = true
|
||||
mainHandler.postDelayed(::checkActivity, DEFAULT_RETRY_INTERVAL)
|
||||
} else {
|
||||
Log.w(TAG, "CheckActivity operation is already running, skipping...")
|
||||
}
|
||||
}
|
||||
Log.d(
|
||||
TAG,
|
||||
"Current App Package: $currentAppPackageName; Current App Class: $currentClassName; targetAppPackageName: $targetAppPackageName"
|
||||
)
|
||||
}
|
||||
|
||||
// 检查前端应用
|
||||
private fun checkAppPackageName() {
|
||||
if (isCheckAppPackageName) {
|
||||
Log.w(TAG, "CheckAppPackageName operation is already running, skipping...")
|
||||
updateFloatingText("CheckAppPackageName operation is already running, skipping...")
|
||||
return
|
||||
}
|
||||
|
||||
isCheckAppPackageName = true
|
||||
Log.w(TAG, "Detected switch to non-target app: $currentAppPackageName")
|
||||
try {
|
||||
updateFloatingText("Detected switch to non-target app: $currentAppPackageName")
|
||||
|
||||
retryOperation(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_INTERVAL, checkCondition = {
|
||||
val ok = isTargetAppRunning()
|
||||
ok || performReturnGlobalAction()
|
||||
Log.d(TAG, "Check $targetAppPackageName is activated: $ok")
|
||||
ok
|
||||
}, onSuccess = {
|
||||
isCheckAppPackageName = false // 任务结束后重置
|
||||
updateFloatingText("Successfully returned to target app")
|
||||
Log.i(TAG, "Successfully returned to target app")
|
||||
// 返回后再次检查 Activity
|
||||
mainHandler.postDelayed(::checkActivity, DEFAULT_RETRY_INTERVAL)
|
||||
}, onFailure = {
|
||||
isCheckAppPackageName = false // 任务结束后重置
|
||||
updateFloatingText("Failed to return after $DEFAULT_MAX_RETRIES attempts", true)
|
||||
Log.e(TAG, "Failed to return after $DEFAULT_MAX_RETRIES attempts")
|
||||
returnToHomeAndRestart()
|
||||
})
|
||||
} finally {
|
||||
isCheckAppPackageName = false // 任务结束后重置
|
||||
}
|
||||
}
|
||||
|
||||
// 检查当前 Activity
|
||||
private fun checkActivity() {
|
||||
Log.w(TAG, "Current class name is : $currentClassName")
|
||||
if (isCheckActivity) {
|
||||
Log.w(TAG, "CheckActivity operation is already running, skipping...")
|
||||
updateFloatingText("CheckActivity operation is already running, skipping...")
|
||||
return
|
||||
}
|
||||
isCheckActivity = true
|
||||
Log.w(TAG, "Current class name is : $currentActivityName")
|
||||
try {
|
||||
when (currentClassName) {
|
||||
when (currentActivityName) {
|
||||
"io.sixminutes.breakingnews.MainActivity" -> launcherButtonText?.let {
|
||||
findAndClickButton(it)
|
||||
}
|
||||
@ -538,6 +546,13 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
)
|
||||
|
||||
"com.applovin.adview.AppLovinFullscreenActivity" -> simulateTap(648, 62)
|
||||
else -> {
|
||||
Log.d(TAG, "current Activity is unknown")
|
||||
updateFloatingText("current Activity is unknown")
|
||||
mainHandler.postDelayed({
|
||||
checkActivity()
|
||||
}, DEFAULT_RETRY_INTERVAL)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isCheckActivity = false
|
||||
@ -564,8 +579,9 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
*/
|
||||
private fun returnToHomeAndRestart(): Boolean {
|
||||
Log.d(TAG, "Used home+restart strategy")
|
||||
updateFloatingText("used home+restart strategy")
|
||||
return performGlobalAction(GLOBAL_ACTION_HOME) && targetAppName != null && targetAppPackageName != null && findAndLaunchApp(
|
||||
targetAppName!!, targetAppPackageName!!
|
||||
targetAppName!!, targetAppPackageName!!, launcherButtonText
|
||||
)
|
||||
}
|
||||
|
||||
@ -602,7 +618,7 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
// 设置悬浮窗口显示在屏幕的左上角,x,y 为偏移量
|
||||
layoutParams.gravity = android.view.Gravity.BOTTOM or android.view.Gravity.END
|
||||
layoutParams.x = 0
|
||||
layoutParams.y = 100
|
||||
layoutParams.y = 150
|
||||
|
||||
// 将悬浮窗口添加到 WindowManager 中显示
|
||||
windowManager?.addView(floatingView, layoutParams)
|
||||
@ -636,10 +652,17 @@ class MyAccessibilityService : AccessibilityService() {
|
||||
* 更新悬浮窗口中显示的文本
|
||||
* @param text 要显示的文本内容
|
||||
*/
|
||||
private fun updateFloatingText(text: String) {
|
||||
private fun updateFloatingText(text: String, isError: Boolean = false) {
|
||||
// 在悬浮窗口中找到 TextView 并设置新文本
|
||||
val textView = floatingView?.findViewById<TextView>(R.id.first_message)
|
||||
textView?.text = text
|
||||
if (isError) {
|
||||
val errorView = floatingView?.findViewById<TextView>(R.id.error_message)
|
||||
errorView?.text = text
|
||||
} else {
|
||||
val info1 = floatingView?.findViewById<TextView>(R.id.info_message_1)
|
||||
val info2 = floatingView?.findViewById<TextView>(R.id.info_message_2)
|
||||
info2?.text = info1?.text
|
||||
info1?.text = text
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,49 +1,36 @@
|
||||
<!-- res/layout/floating_window.xml -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/frameLayout2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:background="#22000000">
|
||||
android:background="#22000080"
|
||||
android:padding="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/first_message"
|
||||
android:layout_width="240ddp"
|
||||
android:id="@+id/info_message_2"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:text="2"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:text=""
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/first_second"
|
||||
android:layout_width="240pdp"
|
||||
android:id="@+id/info_message_1"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:text="1"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
android:text=""
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/main_message"
|
||||
android:layout_width="240pdp"
|
||||
android:id="@+id/error_message"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:text="xxxx"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/first_message"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:text=""
|
||||
android:textColor="#ff0000"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
Loading…
x
Reference in New Issue
Block a user