Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加前台服务,增强免疫力,增加Toast #4

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ android {

applicationVariants.configureEach { variant ->
variant.outputs.configureEach {
outputFileName = "Android自动化_${defaultConfig.versionName}.apk"
outputFileName = "AndroidAuto_${defaultConfig.versionName}.apk"
}
}

Expand Down
14 changes: 11 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools" >

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application
android:name=".App"
Expand All @@ -14,13 +16,14 @@
android:roundIcon="@mipmap/icon_logo"
android:supportsRtl="true"
android:theme="@style/Theme.AndroidAuto"
tools:targetApi="31">
tools:targetApi="31" >


<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.AndroidAuto.NoActionBar">
android:theme="@style/Theme.AndroidAuto.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand All @@ -32,6 +35,11 @@
android:value="" />
</activity>

<service
android:name=".ForegroundService"
android:exported="false" >
</service>

<meta-data
android:name="PGYER_APPID"
android:value="d325bd4eedf71f5222f6734963fb9520" />
Expand Down
89 changes: 89 additions & 0 deletions app/src/main/java/com/lygttpod/android/auto/ForegroundService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.lygttpod.android.auto

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.BitmapFactory
import android.os.IBinder
import android.util.Log
import android.widget.Toast

class ForegroundService : Service() {
companion object {
private const val TAG = "ForegroundService"

private const val CHANNEL_ID = "ForegroundService"
private const val CHANNEL_NAME = "前台服务"

const val ACTION_TOAST = "ACTION_TOAST"
const val KEY_TOAST_TEXT = "KEY_TOAST_TEXT"
}

private val pendingIntent by lazy {
val intent = Intent(this, MainActivity::class.java)
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
}

private val notification by lazy {
Notification.Builder(this, CHANNEL_ID)
.setContentTitle("前台服务")
.setContentText("重要,勿删!")
.setSmallIcon(R.mipmap.icon_logo)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.icon_logo))
.setContentIntent(pendingIntent)
.setOngoing(true)
.build()
}

private var lastToastTime = 0L
private var lastToastText = ""

private val receiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val text = intent?.getStringExtra(KEY_TOAST_TEXT)
?.takeIf { it.isNotBlank() } ?: return
Log.d(TAG, "收到Toast: $text")

if (text == lastToastText && System.currentTimeMillis() - lastToastTime < 5000) {
Log.d(TAG, "文本重复,忽略")
return
}

Toast.makeText(App.instance(), text, Toast.LENGTH_SHORT).show()
lastToastTime = System.currentTimeMillis()
lastToastText = text
}
}
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val nm = getSystemService(NotificationManager::class.java)

nm.createNotificationChannel(
NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)
)

startForeground(1, notification)

registerReceiver(receiver, IntentFilter(ACTION_TOAST), RECEIVER_NOT_EXPORTED)

return super.onStartCommand(intent, flags, startId)
}

override fun onBind(intent: Intent): IBinder {
TODO("Return the communication channel to the service.")
}

override fun onDestroy() {
super.onDestroy()
unregisterReceiver(receiver)
stopForeground(STOP_FOREGROUND_REMOVE)
}
}
22 changes: 22 additions & 0 deletions app/src/main/java/com/lygttpod/android/auto/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.lygttpod.android.auto

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
Expand Down Expand Up @@ -43,6 +47,12 @@ class MainActivity : AppCompatActivity() {
}
}
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 666)
} else {
startForegroundService(Intent(this, ForegroundService::class.java))
}
}

override fun onResume() {
Expand All @@ -54,4 +64,16 @@ class MainActivity : AppCompatActivity() {
val navController = findNavController(R.id.nav_host_fragment_content_main)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 666 && grantResults.getOrNull(0)
== PackageManager.PERMISSION_GRANTED) {
startForegroundService(Intent(this, ForegroundService::class.java))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.lygttpod.android.auto.ad.task

import android.content.Intent
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import androidx.lifecycle.MutableLiveData
Expand Down Expand Up @@ -31,6 +32,9 @@ object FuckADTask {
private const val APP_CONFIG = "appConfig"
private const val FILTER_KEYWORD = "filterKeyword"

private const val ACTION_TOAST = "ACTION_TOAST"
private const val KEY_TOAST_TEXT = "KEY_TOAST_TEXT"

private val mutex = Mutex()

private val fuckADTaskScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
Expand Down Expand Up @@ -159,6 +163,9 @@ object FuckADTask {
if (skipResult) {
withContext(Dispatchers.Main) {
Log.d("FuckADTask", "自动跳过【${adApp.appName}】的广告啦")
AppContext.sendBroadcast(Intent(ACTION_TOAST).apply {
putExtra(KEY_TOAST_TEXT, "自动跳过【${adApp.appName}】")
})
}
}
skipResult
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.lygttpod.android.auto.wx.helper

import android.content.Context
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import com.android.accessibility.ext.toast
import com.lygttpod.android.auto.wx.page.WXDeleteDialogPage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

object DeleteTaskHelper {
private const val TAG = "DeleteTaskHelper"

private var isEnabled = false

private val mutex = Mutex()
private val eventFlow = MutableStateFlow<AccessibilityEvent?>(null)

private var scope: CoroutineScope? = null

fun enable(context: Context, enable: Boolean) {
isEnabled = enable
if (isEnabled) {
Log.d(TAG, "打开任务: DeleteTaskHelper")
context.toast("微信删除任务已开启")
scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope?.launch {
eventFlow.buffer().collect {
mutex.withLock {
WXDeleteDialogPage.handleEvent()
}
}
}
} else {
Log.d(TAG, "关闭任务: DeleteTaskHelper")
context.toast("微信删除任务已关闭")
scope?.cancel("关闭任务:DeleteTaskHelper")
}
}

fun handle(event: AccessibilityEvent) {
if (!isEnabled) return
scope?.launch {
if (mutex.isLocked) return@launch
eventFlow.emit(event)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.lygttpod.android.auto.wx.page

import android.util.Log
import com.android.accessibility.ext.acc.*
import com.android.accessibility.ext.task.retryCheckTaskWithLog
import com.lygttpod.android.auto.wx.data.NodeInfo
import com.lygttpod.android.auto.wx.service.wxAccessibilityService
import com.lygttpod.android.auto.wx.version.nodeProxy

object WXDeleteDialogPage : IPage {

interface Nodes {
val dialogContentNode: NodeInfo
val dialogDeleteNode: NodeInfo

companion object : Nodes by nodeProxy()
}

override fun pageClassName() = ""

override fun pageTitleName() = "微信抢红包"

override fun isMe(): Boolean {
return wxAccessibilityService?.findByIdAndText(
Nodes.dialogContentNode.nodeId,
Nodes.dialogContentNode.nodeText
) != null
}

private suspend fun inPage() = retryCheckTaskWithLog("判断是否在删除聊天弹窗界面") { isMe() }

suspend fun handleEvent() {
val inPage = inPage()
if (!inPage) return
wxAccessibilityService.clickByIdAndText(
Nodes.dialogDeleteNode.nodeId,
Nodes.dialogDeleteNode.nodeText
)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.lygttpod.android.auto.wx.service

import android.accessibilityservice.AccessibilityService
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import androidx.lifecycle.MutableLiveData
import com.android.accessibility.ext.AsyncAccessibilityService
import com.lygttpod.android.auto.wx.helper.DeleteTaskHelper
import com.lygttpod.android.auto.wx.helper.HBTaskHelper
import java.util.concurrent.atomic.AtomicBoolean

Expand All @@ -30,5 +32,6 @@ class WXAccessibility : AsyncAccessibilityService() {

override fun asyncHandleAccessibilityEvent(event: AccessibilityEvent) {
HBTaskHelper.hbTask(event)
DeleteTaskHelper.handle(event)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.android.accessibility.ext.openAccessibilitySetting
import com.lygttpod.android.auto.wx.R
import com.lygttpod.android.auto.wx.adapter.FriendInfoAdapter
import com.lygttpod.android.auto.wx.databinding.FragmentWxMainBinding
import com.lygttpod.android.auto.wx.helper.DeleteTaskHelper
import com.lygttpod.android.auto.wx.helper.FriendStatusHelper
import com.lygttpod.android.auto.wx.helper.HBTaskHelper
import com.lygttpod.android.auto.wx.helper.TaskByGroupHelper
Expand Down Expand Up @@ -78,11 +79,13 @@ class WxMainFragment : Fragment() {
private fun initObserver() {
accServiceLiveData.observe(viewLifecycleOwner) { open ->
binding.chAutoHb.isEnabled = open
checkAutoDeleteWhenDeleteChatStatus(open)
binding.btnGetFriendList.isEnabled = open
binding.btnCheck.isEnabled = open
binding.btnCheckByGroup.isEnabled = open

binding.btnOpenService.text = if (open) "【微信自动化】服务已开启" else "打开【微信自动化】服务"
binding.btnOpenService.text =
if (open) "【微信自动化】服务已开启" else "打开【微信自动化】服务"

}

Expand Down Expand Up @@ -155,6 +158,10 @@ class WxMainFragment : Fragment() {
HBTaskHelper.autoFuckMoney(isChecked)
}

binding.chAutoDeleteWhenDeleteChat.setOnCheckedChangeListener { _, isChecked ->
DeleteTaskHelper.enable(requireContext(), isChecked)
}

binding.btnFilterAll.setOnClickListener {
adapter.setData(FriendStatusHelper.filterAllData())
}
Expand Down Expand Up @@ -194,4 +201,13 @@ class WxMainFragment : Fragment() {
super.onDestroyView()
_binding = null
}

private fun checkAutoDeleteWhenDeleteChatStatus(wxEnabled: Boolean) {
binding.chAutoDeleteWhenDeleteChat.isEnabled = wxEnabled
if (wxEnabled && binding.chAutoDeleteWhenDeleteChat.isChecked) {
DeleteTaskHelper.enable(requireContext(), true)
} else {
DeleteTaskHelper.enable(requireContext(), false)
}
}
}
Loading