diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a55a6d90..749903f0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -80,6 +80,11 @@
android:enabled="true"
android:foregroundServiceType="mediaProjection"
/>
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/android/skip/KeepAliveActivity.kt b/app/src/main/java/com/android/skip/KeepAliveActivity.kt
index 7dd11144..45401a94 100644
--- a/app/src/main/java/com/android/skip/KeepAliveActivity.kt
+++ b/app/src/main/java/com/android/skip/KeepAliveActivity.kt
@@ -16,6 +16,10 @@ import com.android.skip.compose.PictureDialog
import com.android.skip.compose.ResourceIcon
import com.android.skip.compose.RowContent
import com.android.skip.compose.ScaffoldPage
+import com.android.skip.service.MyAccessibilityService
+import com.android.skip.utils.Constants
+import com.android.skip.utils.DataStoreUtils
+import com.blankj.utilcode.util.ServiceUtils.startService
import java.net.URLEncoder
class KeepAliveActivity : BaseActivity() {
@@ -26,68 +30,91 @@ class KeepAliveActivity : BaseActivity() {
finish()
}
}
-}
-@Composable
-fun KeepAliveInterface(onBackClick: () -> Unit) {
- val context = LocalContext.current
- val showPicDialog = remember { mutableStateOf(false) }
- val showBrowserDialog = remember { mutableStateOf(false) }
- ScaffoldPage(stringResource(id = R.string.alive), onBackClick = onBackClick, content = {
- PictureDialog(showPicDialog)
- FlatButton(content = {
- RowContent(
- stringResource(id = R.string.alive_power_saving_title),
- stringResource(id = R.string.alive_power_saving_subtitle),
- { ResourceIcon(iconResource = R.drawable.counter_1) }
- )
- }) {
- val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
- intent.data = Uri.parse("package:${context.packageName}")
- context.startActivity(intent)
- }
- FlatButton(content = {
- RowContent(
- stringResource(id = R.string.alive_self_start_title),
- stringResource(id = R.string.alive_self_start_subtitle),
- { ResourceIcon(iconResource = R.drawable.counter_2) }
- )
- }) {
- val intent = Intent()
- intent.component = ComponentName(
- "com.miui.securitycenter",
- "com.miui.permcenter.autostart.AutoStartManagementActivity"
- )
- context.startActivity(intent)
- }
- FlatButton(content = {
- RowContent(
- stringResource(id = R.string.alive_backstage_title),
- stringResource(id = R.string.alive_backstage_subtitle),
- { ResourceIcon(iconResource = R.drawable.counter_3) }
- )
- }) {
- showPicDialog.value = true
- }
- FlatButton(content = {
- RowContent(
- stringResource(id = R.string.alive_warn_title),
- stringResource(id = R.string.alive_warn_subtitle),
- { ResourceIcon(iconResource = R.drawable.warning) }
+ @Composable
+ fun KeepAliveInterface(onBackClick: () -> Unit) {
+ val context = LocalContext.current
+ val showPicDialog = remember { mutableStateOf(false) }
+ val showBrowserDialog = remember { mutableStateOf(false) }
+ val checkForegroundAccessibility = remember {
+ mutableStateOf(
+ DataStoreUtils.getSyncData(Constants.SKIP_FOREGROUND_ACCESSIBILITY, false),
)
- }) {
- showBrowserDialog.value = true
}
- })
+ ScaffoldPage(stringResource(id = R.string.alive), onBackClick = onBackClick, content = {
+ PictureDialog(showPicDialog)
+ FlatButton(content = {
+ RowContent(
+ stringResource(id = R.string.alive_power_saving_title),
+ stringResource(id = R.string.alive_power_saving_subtitle),
+ { ResourceIcon(iconResource = R.drawable.counter_1) }
+ )
+ }) {
+ val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
+ intent.data = Uri.parse("package:${context.packageName}")
+ context.startActivity(intent)
+ }
+ FlatButton(content = {
+ RowContent(
+ stringResource(id = R.string.alive_self_start_title),
+ stringResource(id = R.string.alive_self_start_subtitle),
+ { ResourceIcon(iconResource = R.drawable.counter_2) }
+ )
+ }) {
+ val intent = Intent()
+ intent.component = ComponentName(
+ "com.miui.securitycenter",
+ "com.miui.permcenter.autostart.AutoStartManagementActivity"
+ )
+ context.startActivity(intent)
+ }
+ FlatButton(content = {
+ RowContent(
+ stringResource(id = R.string.alive_backstage_title),
+ stringResource(id = R.string.alive_backstage_subtitle),
+ { ResourceIcon(iconResource = R.drawable.counter_3) }
+ )
+ }) {
+ showPicDialog.value = true
+ }
+ FlatButton(content = {
+ RowContent(
+ stringResource(id = R.string.alive_warn_title),
+ stringResource(id = R.string.alive_warn_subtitle),
+ { ResourceIcon(iconResource = R.drawable.warning) }
+ )
+ }) {
+ showBrowserDialog.value = true
+ }
+ FlatButton(content = {
+ RowContent(
+ stringResource(id = R.string.alive_foreground_service_title),
+ stringResource(id = R.string.alive_foreground_service_subtitle),
+ { ResourceIcon(iconResource = R.drawable.counter_4) },
+ checkForegroundAccessibility.value,
+ {
+ checkForegroundAccessibility.value = it
+ DataStoreUtils.putSyncData(Constants.SKIP_FOREGROUND_ACCESSIBILITY, it)
+
+ val intent = Intent(Constants.FOREGROUND_ACCESSIBILITY_RECEIVER_ACTION)
+ intent.putExtra(Constants.FOREGROUND_ACCESSIBILITY_RECEIVER_ENABLED, it)
+ intent.setPackage(packageName)
+ sendBroadcast(intent)
+ }
+ )
+ })
+ })
- val searchContent = Build.MANUFACTURER + stringResource(id = R.string.alive_warn_search_content)
- OpenBrowserDialog(
- openName = searchContent,
- openUrl = createBaiduSearchUrl(searchContent),
- showDialog = showBrowserDialog
- )
+ val searchContent = Build.MANUFACTURER + stringResource(id = R.string.alive_warn_search_content)
+ OpenBrowserDialog(
+ openName = searchContent,
+ openUrl = createBaiduSearchUrl(searchContent),
+ showDialog = showBrowserDialog
+ )
+ }
+
+ private fun createBaiduSearchUrl(query: String): String {
+ return "https://www.baidu.com/s?wd=${URLEncoder.encode(query, "UTF-8")}"
+ }
}
-fun createBaiduSearchUrl(query: String): String {
- return "https://www.baidu.com/s?wd=${URLEncoder.encode(query, "UTF-8")}"
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/skip/service/MyAccessibilityService.kt b/app/src/main/java/com/android/skip/service/MyAccessibilityService.kt
index 71d1da5e..f5e4507b 100644
--- a/app/src/main/java/com/android/skip/service/MyAccessibilityService.kt
+++ b/app/src/main/java/com/android/skip/service/MyAccessibilityService.kt
@@ -2,12 +2,17 @@ package com.android.skip.service
import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.GestureDescription
+import android.content.BroadcastReceiver
+import android.content.Context
import android.content.Intent
+import android.content.IntentFilter
import android.graphics.Path
import android.graphics.Rect
+import android.os.Build
import android.view.KeyEvent
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
+import androidx.annotation.RequiresApi
import com.android.skip.SKIP_LAYOUT_INSPECT
import com.android.skip.SKIP_PERMIT_NOTICE
import com.android.skip.handler.BoundsHandler
@@ -16,8 +21,10 @@ import com.android.skip.handler.TextNodeHandler
import com.android.skip.manager.AnalyticsManager
import com.android.skip.manager.ToastManager
import com.android.skip.manager.WhitelistManager
+import com.android.skip.utils.Constants
import com.android.skip.utils.DataStoreUtils
import com.blankj.utilcode.util.LogUtils
+import com.blankj.utilcode.util.ServiceUtils
data class MyNode(val node: AccessibilityNodeInfo, val depth: Int)
@@ -27,6 +34,7 @@ class MyAccessibilityService : AccessibilityService() {
private val boundsHandler = BoundsHandler()
private var isLayoutInspect = false
private var layoutInspectClassName: String? = null
+ private lateinit var foregroundAccessibilityReceiver: ForegroundAccessibilityChangeReceiver
init {
textNodeHandler.setNextHandler(idNodeHandler).setNextHandler(boundsHandler)
@@ -59,7 +67,7 @@ class MyAccessibilityService : AccessibilityService() {
click(this, rect)
}
} catch (e: Exception) {
- LogUtils.e(e)
+// LogUtils.e(e)
} finally {
AnalyticsManager.increaseScanCount()
}
@@ -155,4 +163,45 @@ class MyAccessibilityService : AccessibilityService() {
false
}
}
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+
+ val intentFilter = IntentFilter(Constants.FOREGROUND_ACCESSIBILITY_RECEIVER_ACTION)
+ foregroundAccessibilityReceiver = ForegroundAccessibilityChangeReceiver()
+ registerReceiver(foregroundAccessibilityReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
+
+ if (DataStoreUtils.getSyncData(Constants.SKIP_FOREGROUND_ACCESSIBILITY, false)) {
+ val intent = Intent(this, MyForegroundService::class.java)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(intent);
+ } else {
+ startService(intent);
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ unregisterReceiver(foregroundAccessibilityReceiver)
+ }
+
+ inner class ForegroundAccessibilityChangeReceiver: BroadcastReceiver() {
+ override fun onReceive(p0: Context?, p1: Intent?) {
+ if (p1 != null && p1.action.equals(Constants.FOREGROUND_ACCESSIBILITY_RECEIVER_ACTION)) {
+ val enabled = p1.getBooleanExtra(Constants.FOREGROUND_ACCESSIBILITY_RECEIVER_ENABLED, false)
+ val intent = Intent(this@MyAccessibilityService, MyForegroundService::class.java)
+ if (enabled) { // start foreground service
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(intent);
+ } else {
+ startService(intent);
+ }
+ } else { // stop foreground service
+ stopService(intent)
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/skip/service/MyForegroundService.kt b/app/src/main/java/com/android/skip/service/MyForegroundService.kt
new file mode 100644
index 00000000..9be06b80
--- /dev/null
+++ b/app/src/main/java/com/android/skip/service/MyForegroundService.kt
@@ -0,0 +1,40 @@
+package com.android.skip.service
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.graphics.BitmapFactory
+import android.os.Build
+import android.os.IBinder
+import androidx.core.app.NotificationCompat
+import com.android.skip.NewMainActivity
+import com.android.skip.R
+
+class MyForegroundService: Service() {
+ override fun onBind(p0: Intent?): IBinder? {
+ TODO("Not yet implemented")
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+
+ val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val channel = NotificationChannel("skip_foreground_service", "SKIP 前台服务", NotificationManager.IMPORTANCE_DEFAULT)
+ manager.createNotificationChannel(channel)
+ }
+ val it = Intent(this, NewMainActivity::class.java)
+ val pi = PendingIntent.getActivity(this, 0, it, PendingIntent.FLAG_IMMUTABLE)
+ val notification = NotificationCompat.Builder(this, "skip_foreground_service")
+ .setContentTitle("SKIP 前台服务")
+ .setContentText("SKIP 前台服务运行中")
+ .setSmallIcon(R.drawable.warning)
+ .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.warning))
+ .setContentIntent(pi)
+ .build()
+ startForeground(1, notification)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/skip/utils/Constants.kt b/app/src/main/java/com/android/skip/utils/Constants.kt
new file mode 100644
index 00000000..9cdcfa08
--- /dev/null
+++ b/app/src/main/java/com/android/skip/utils/Constants.kt
@@ -0,0 +1,9 @@
+package com.android.skip.utils
+
+object Constants {
+ const val FOREGROUND_ACCESSIBILITY_RECEIVER_ACTION = "SKIP_FOREGROUND_ACCESSIBILITY_RECEIVER_ACTION"
+
+ const val FOREGROUND_ACCESSIBILITY_RECEIVER_ENABLED = "SKIP_FOREGROUND_ACCESSIBILITY_RECEIVER_ENABLED"
+
+ const val SKIP_FOREGROUND_ACCESSIBILITY = "SKIP_FOREGROUND_ACCESSIBILITY"
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/counter_4.xml b/app/src/main/res/drawable/counter_4.xml
new file mode 100644
index 00000000..2e801eba
--- /dev/null
+++ b/app/src/main/res/drawable/counter_4.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3a1bd048..66ecb942 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -38,6 +38,8 @@
请注意
以上操作方法可能仅适用于MIUI或HyperOS,其他系统手机请自行查询相应的应用保活方法
如何实现应用后台保活
+ 前台服务
+ 是否允许以前台服务方式运行无障碍服务
应用白名单
diff --git a/gui/svg/counter_4_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg b/gui/svg/counter_4_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
new file mode 100644
index 00000000..3c63a01c
--- /dev/null
+++ b/gui/svg/counter_4_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file