mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-15 19:22:26 +08:00
feat: 基础架构
This commit is contained in:
parent
b8f7d503ac
commit
b288cdd120
14
README.md
14
README.md
|
@ -1,8 +1,16 @@
|
|||
# AdCloser
|
||||
# gkd
|
||||
|
||||
基于无障碍和自定义匹配规则的广告关闭app
|
||||
搞快点,顾名思义,做快速点击,一款基于无障碍和自定义匹配规则的快速点击app
|
||||
|
||||
记录递归调用的次数, 根据统计次数考虑是否添加规则长度, 可减少匹配时间
|
||||
## feature
|
||||
|
||||
- 跳过启动页面
|
||||
- 关闭app内部广告
|
||||
- 任意点击操作
|
||||
- 支持导入订阅链接
|
||||
- 支持浏览器直接跳转导入规则至app
|
||||
|
||||
类似 uiautomatorviewer 的路径选取规则创建器
|
||||
|
||||
# Fix Bug
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("kotlin-kapt")
|
||||
}
|
||||
|
||||
val composeVersion = "1.0.5"
|
||||
|
@ -9,7 +10,7 @@ android {
|
|||
buildToolsVersion = "31.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "li.songe.ad_closer"
|
||||
applicationId = "li.songe.gkd"
|
||||
minSdk = 26
|
||||
targetSdk = 31
|
||||
versionCode = 1
|
||||
|
@ -40,9 +41,11 @@ android {
|
|||
)
|
||||
)
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
manifestPlaceholders["appName"] = "搞快点"
|
||||
}
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
manifestPlaceholders["appName"] = "搞快点-dev"
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
|
@ -66,29 +69,50 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation("androidx.core:core-ktx:1.7.0")
|
||||
// normal
|
||||
implementation("androidx.appcompat:appcompat:1.4.0")
|
||||
implementation("com.google.android.material:material:1.4.0")
|
||||
|
||||
// ktx
|
||||
implementation("androidx.core:core-ktx:1.7.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0")
|
||||
|
||||
// compose
|
||||
implementation("androidx.compose.ui:ui:$composeVersion")
|
||||
implementation("androidx.compose.material:material:$composeVersion")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview:$composeVersion")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling:$composeVersion")
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$composeVersion")
|
||||
implementation("androidx.activity:activity-compose:1.4.0")
|
||||
implementation("androidx.navigation:navigation-compose:2.4.0-beta02")
|
||||
|
||||
// test
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.3")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$composeVersion")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling:$composeVersion")
|
||||
|
||||
// https://github.com/RikkaApps/Shizuku-API
|
||||
val shizuku_version = "12.1.0"
|
||||
implementation("dev.rikka.shizuku:api:$shizuku_version")
|
||||
// Add this line if you want to support Shizuku
|
||||
implementation("dev.rikka.shizuku:provider:$shizuku_version")
|
||||
val shizukuVersion = "12.1.0"
|
||||
implementation("dev.rikka.shizuku:api:$shizukuVersion")
|
||||
implementation("dev.rikka.shizuku:provider:$shizukuVersion")
|
||||
|
||||
// 工具集合类
|
||||
// https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/README-CN.md
|
||||
implementation("com.blankj:utilcodex:1.30.6")
|
||||
|
||||
// https://developer.android.com/jetpack/compose/navigation
|
||||
implementation("androidx.navigation:navigation-compose:2.4.0-beta02")
|
||||
|
||||
// https://bugly.qq.com/docs/user-guide/instruction-manual-android/
|
||||
implementation("com.tencent.bugly:crashreport:4.0.0")
|
||||
|
||||
// https://developer.android.google.cn/training/data-storage/room?hl=zh-cn
|
||||
val roomVersion = "2.3.0"
|
||||
implementation("androidx.room:room-runtime:$roomVersion")
|
||||
kapt("androidx.room:room-compiler:$roomVersion")
|
||||
implementation("androidx.room:room-ktx:$roomVersion")
|
||||
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation ("com.google.code.gson:gson:2.8.9")
|
||||
|
||||
}
|
5
app/proguard-rules.pro
vendored
5
app/proguard-rules.pro
vendored
|
@ -18,4 +18,7 @@
|
|||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-dontwarn com.tencent.bugly.**
|
||||
-keep public class com.tencent.bugly.**{*;}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer
|
||||
package li.songe.gkd
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
|
|||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("li.songe.ad_closer", appContext.packageName)
|
||||
assertEquals("li.songe.gkd", appContext.packageName)
|
||||
}
|
||||
}
|
|
@ -1,27 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="li.songe.ad_closer">
|
||||
package="li.songe.gkd">
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:label="${appName}"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:name=".App"
|
||||
android:name="li.songe.gkd.App"
|
||||
android:theme="@style/Theme.AdCloser">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name="li.songe.gkd.MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:excludeFromRecents="true"
|
||||
android:theme="@style/Theme.AdCloser.NoActionBar">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".EntryActivity"
|
||||
android:name="li.songe.gkd.EntryActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:excludeFromRecents="true"
|
||||
android:theme="@style/Entry">
|
||||
<intent-filter>
|
||||
|
@ -30,9 +31,20 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="li.songe.gkd.WebActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data
|
||||
android:host="dev.songe.li"
|
||||
android:path="/detail"
|
||||
android:port="80"
|
||||
android:scheme="adcloser" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".service.AdCloserService"
|
||||
android:name="li.songe.gkd.service.GkdService"
|
||||
android:exported="false"
|
||||
android:label="@string/accessibility_service_label"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// IUserService.aidl
|
||||
package li.songe.ad_closer;
|
||||
package li.songe.gkd;
|
||||
|
||||
interface IUserService {
|
||||
void destroy() = 16777114; // Destroy method defined by Shizuku server
|
|
@ -1,11 +0,0 @@
|
|||
package li.songe.ad_closer
|
||||
|
||||
import android.app.Application
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
|
||||
class App:Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
LogUtils.d("onCreate")
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package li.songe.ad_closer
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import li.songe.ad_closer.ui.theme.AdCloserTheme
|
||||
import rikka.shizuku.Shizuku
|
||||
import rikka.shizuku.Shizuku.OnRequestPermissionResultListener
|
||||
import android.content.pm.PackageManager
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
AdCloserTheme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
Surface(color = MaterialTheme.colors.background) {
|
||||
Greeting("Android2")
|
||||
}
|
||||
}
|
||||
LogUtils.d(this)
|
||||
packageName
|
||||
}
|
||||
// Shizuku.addRequestPermissionResultListener { requestCode, grantResult ->
|
||||
// LogUtils.d(requestCode, grantResult)
|
||||
// }
|
||||
// checkPermission(0)
|
||||
// Shizuku.bindUserService()
|
||||
|
||||
}
|
||||
private fun checkPermission(code: Int): Boolean {
|
||||
if (Shizuku.isPreV11()) {
|
||||
// Pre-v11 is unsupported
|
||||
return false
|
||||
}
|
||||
return when {
|
||||
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED -> {
|
||||
// Granted
|
||||
true
|
||||
}
|
||||
Shizuku.shouldShowRequestPermissionRationale() -> {
|
||||
// Users choose "Deny and don't ask again"
|
||||
false
|
||||
}
|
||||
else -> {
|
||||
// Request the permission
|
||||
Shizuku.requestPermission(code)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Greeting(name: String) {
|
||||
Text(text = "Hello $name 4399")
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun DefaultPreview() {
|
||||
AdCloserTheme {
|
||||
Greeting("React")
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package li.songe.ad_closer.data
|
||||
|
||||
|
||||
data class RuleGroup(
|
||||
val id: Long,
|
||||
val description: String,
|
||||
val packageName: String,
|
||||
val className: String,
|
||||
val ruleList: List<String>
|
||||
)
|
||||
// 从网址导入时, 会显示 规则描述 目标应用 目标活动界面, 此界面可点击打开
|
18
app/src/main/java/li/songe/gkd/App.kt
Normal file
18
app/src/main/java/li/songe/gkd/App.kt
Normal file
|
@ -0,0 +1,18 @@
|
|||
package li.songe.gkd
|
||||
|
||||
import android.app.Application
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import com.tencent.bugly.crashreport.CrashReport
|
||||
|
||||
class App:Application() {
|
||||
companion object{
|
||||
lateinit var context:Application
|
||||
}
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
context = this
|
||||
LogUtils.d("onCreate")
|
||||
LogUtils.getConfig().isLog2FileSwitch = true
|
||||
CrashReport.initCrashReport(applicationContext, "d0ce46b353", false);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer
|
||||
package li.songe.gkd
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
44
app/src/main/java/li/songe/gkd/MainActivity.kt
Normal file
44
app/src/main/java/li/songe/gkd/MainActivity.kt
Normal file
|
@ -0,0 +1,44 @@
|
|||
package li.songe.gkd
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import kotlinx.coroutines.launch
|
||||
import li.songe.gkd.ui.BottomNavigationBar
|
||||
import li.songe.gkd.ui.NavHostContainer
|
||||
import li.songe.gkd.ui.theme.AdCloserTheme
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
AdCloserTheme {
|
||||
Surface(color = MaterialTheme.colors.background) {
|
||||
Surface(color = Color.White) {
|
||||
val navController = rememberNavController()
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
BottomNavigationBar(navController = navController)
|
||||
}, content = { padding ->
|
||||
NavHostContainer(navController = navController, padding = padding)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
app/src/main/java/li/songe/gkd/WebActivity.kt
Normal file
12
app/src/main/java/li/songe/gkd/WebActivity.kt
Normal file
|
@ -0,0 +1,12 @@
|
|||
package li.songe.gkd
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
|
||||
class WebActivity:AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
LogUtils.d(intent.data)
|
||||
}
|
||||
}
|
|
@ -1,17 +1,13 @@
|
|||
package li.songe.ad_closer.data
|
||||
package li.songe.gkd.data
|
||||
|
||||
data class Rule(
|
||||
val packageName: String,
|
||||
val className: String,
|
||||
val selector: String
|
||||
val selector: String,
|
||||
val description: String = "",
|
||||
) {
|
||||
companion object {
|
||||
val defaultRuleList = listOf<Rule>(
|
||||
// Rule(
|
||||
// "com.zhihu.android",
|
||||
// "com.zhihu.android.mix.activity.ContentMixProfileActivity",
|
||||
// "View[text=查看详情] + View[text=×]"
|
||||
// ),
|
||||
Rule(
|
||||
"com.zhihu.android",
|
||||
"com.zhihu.android.mix.activity.ContentMixProfileActivity",
|
||||
|
@ -77,6 +73,11 @@ data class Rule(
|
|||
"com.baidu.tieba.tblauncher.MainTabActivity",
|
||||
"ImageView[id=com.baidu.tieba:id/float_layer_feedback_picture]"
|
||||
),
|
||||
Rule(
|
||||
"com.baidu.tieba",
|
||||
"com.baidu.tieba.pb.pb.main.PbActivity",
|
||||
"ImageView[id=com.baidu.tieba:id/float_layer_feedback_picture]"
|
||||
),
|
||||
Rule(
|
||||
"com.baidu.tieba",
|
||||
"com.baidu.tieba.tblauncher.MainTabActivity",
|
||||
|
@ -125,7 +126,7 @@ data class Rule(
|
|||
Rule(
|
||||
"com.tencent.mm",
|
||||
"com.tencent.mm.plugin.sns.ui.SnsTimeLineUI",
|
||||
"LinearLayout[childCount=2] > LinearLayout[id=com.tencent.mm:id/fzb] > TextView[id=com.tencent.mm:id/fzg] + LinearLayout[id=com.tencent.mm:id/fj][childCount=0]"
|
||||
"LinearLayout > LinearLayout[id=com.tencent.mm:id/fzb][childCount=2] > TextView[id=com.tencent.mm:id/fzg] + LinearLayout[id=com.tencent.mm:id/fj][childCount=0]"
|
||||
),
|
||||
Rule(
|
||||
"com.baidu.tieba",
|
30
app/src/main/java/li/songe/gkd/db/AppDatabase.kt
Normal file
30
app/src/main/java/li/songe/gkd/db/AppDatabase.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
package li.songe.gkd.db
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import li.songe.gkd.App
|
||||
|
||||
@Database(entities = [Rule::class, RuleGroup::class], version = 1)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun ruleDao(): RuleDao
|
||||
abstract fun ruleGroupDao(): RuleGroupDao
|
||||
|
||||
companion object {
|
||||
val db by lazy {
|
||||
var basePath = (App.context.getExternalFilesDir(null)?.absolutePath ?: "")
|
||||
var name = "database.db"
|
||||
if (basePath.isNotEmpty()) {
|
||||
if (!basePath.endsWith("/")) {
|
||||
basePath += "/"
|
||||
}
|
||||
name = basePath + name
|
||||
}
|
||||
Room.databaseBuilder(
|
||||
App.context,
|
||||
AppDatabase::class.java,
|
||||
name
|
||||
).build()
|
||||
}
|
||||
}
|
||||
}
|
40
app/src/main/java/li/songe/gkd/db/Rule.kt
Normal file
40
app/src/main/java/li/songe/gkd/db/Rule.kt
Normal file
|
@ -0,0 +1,40 @@
|
|||
package li.songe.gkd.db
|
||||
|
||||
import androidx.room.*
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
@Entity(tableName = "rule")
|
||||
data class Rule(
|
||||
@PrimaryKey() @ColumnInfo(name = "id") val id: Long = Random.nextLong(
|
||||
-9007199254740991L,
|
||||
9007199254740991L
|
||||
),
|
||||
@ColumnInfo(name = "package_name") var packageName: String,
|
||||
@ColumnInfo(name = "class_name") var className: String,
|
||||
@ColumnInfo(name = "selector") var selector: String,
|
||||
@ColumnInfo(name = "description") var description: String = "",
|
||||
@ColumnInfo(name = "rule_group_id") var ruleGroupUid: Long,
|
||||
@ColumnInfo(name = "ctime") var ctime: Long = System.currentTimeMillis(),
|
||||
@ColumnInfo(name = "mtime") var mtime: Long = System.currentTimeMillis(),
|
||||
@ColumnInfo(name = "disable") var disable: Boolean = false,
|
||||
/**
|
||||
* 规则序列号, 先匹配 seq 最小的规则, 如果序列号相等, 则执行顺序是未知的
|
||||
*/
|
||||
@ColumnInfo(name = "seq") var seq: Int = 0,
|
||||
)
|
||||
|
||||
@Dao
|
||||
interface RuleDao {
|
||||
@Query("SELECT * FROM rule")
|
||||
suspend fun query(): MutableList<Rule>
|
||||
|
||||
@Update
|
||||
suspend fun update(vararg args: Rule)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(vararg args: Rule)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(vararg args: Rule)
|
||||
}
|
48
app/src/main/java/li/songe/gkd/db/RuleGroup.kt
Normal file
48
app/src/main/java/li/songe/gkd/db/RuleGroup.kt
Normal file
|
@ -0,0 +1,48 @@
|
|||
package li.songe.gkd.db
|
||||
|
||||
import androidx.room.*
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
@Entity(tableName = "rule_group")
|
||||
data class RuleGroup(
|
||||
@PrimaryKey() @ColumnInfo(name = "id") val id: Long = Random.nextLong(
|
||||
-9007199254740991L,
|
||||
9007199254740991L
|
||||
),
|
||||
@ColumnInfo(name = "package_name") var packageName: String,
|
||||
@ColumnInfo(name = "class_name") var className: String,
|
||||
@ColumnInfo(name = "description") var description: String = "",
|
||||
@ColumnInfo(name = "ctime") var ctime: Long = System.currentTimeMillis(),
|
||||
@ColumnInfo(name = "mtime") var mtime: Long = System.currentTimeMillis(),
|
||||
@ColumnInfo(name = "disable") var disable: Boolean = false,
|
||||
)
|
||||
|
||||
data class RuleGroupWithRuleList(
|
||||
@Embedded val ruleGroup: RuleGroup,
|
||||
@Relation(
|
||||
parentColumn = "id",
|
||||
entityColumn = "rule_group_id"
|
||||
)
|
||||
val ruleList: MutableList<Rule>
|
||||
)
|
||||
|
||||
@Dao
|
||||
interface RuleGroupDao {
|
||||
@Query("SELECT * FROM rule_group")
|
||||
suspend fun query(): MutableList<RuleGroup>
|
||||
|
||||
@Update
|
||||
suspend fun update(vararg args: RuleGroup)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(vararg args: RuleGroup)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(vararg args: RuleGroup)
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM rule_group")
|
||||
suspend fun queryRuleGroupWithRuleList(): MutableList<RuleGroupWithRuleList>
|
||||
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package li.songe.ad_closer.log
|
||||
package li.songe.gkd.log
|
||||
|
||||
data class OperationRecord(
|
||||
val timestamp: Long,
|
||||
val packageName: String,
|
||||
val classNme: String,
|
||||
val ruleId: String)
|
||||
val ruleId: String
|
||||
)
|
|
@ -1,28 +1,19 @@
|
|||
package li.songe.ad_closer.service
|
||||
package li.songe.gkd.service
|
||||
|
||||
import android.accessibilityservice.AccessibilityService
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import kotlinx.coroutines.*
|
||||
import li.songe.ad_closer.data.Rule
|
||||
import li.songe.ad_closer.util.MatchRule
|
||||
import li.songe.ad_closer.util.findNodeInfo
|
||||
import li.songe.gkd.data.Rule
|
||||
import li.songe.gkd.util.MatchRule
|
||||
import li.songe.gkd.util.findNodeInfo
|
||||
|
||||
|
||||
/**
|
||||
* demo: https://juejin.cn/post/6844903589127651335
|
||||
*/
|
||||
class AdCloserService : AccessibilityService() {
|
||||
|
||||
// private fun getActivityInfo(componentName: ComponentName): ActivityInfo? {
|
||||
// return try {
|
||||
// packageManager.getActivityInfo(componentName, 0)
|
||||
// } catch (e: NameNotFoundException) {
|
||||
// null
|
||||
// }
|
||||
// }
|
||||
|
||||
class GkdService : AccessibilityService() {
|
||||
private val scope = CoroutineScope(Dispatchers.Default + Job())
|
||||
// override fun onDestroy() {
|
||||
// super.onDestroy()
|
||||
|
@ -33,9 +24,11 @@ class AdCloserService : AccessibilityService() {
|
|||
LogUtils.d("onCreate")
|
||||
}
|
||||
|
||||
private var job: Job? = null
|
||||
override fun onServiceConnected() {
|
||||
super.onServiceConnected()
|
||||
scope.launch {
|
||||
LogUtils.d("onServiceConnected")
|
||||
job = scope.launch {
|
||||
while (true) {
|
||||
if (!this.isActive) {
|
||||
break
|
||||
|
@ -50,21 +43,23 @@ class AdCloserService : AccessibilityService() {
|
|||
if (window != null && ruleListMap.containsKey(currentActivityClassName)) {
|
||||
run loop@{
|
||||
ruleListMap[currentActivityClassName]!!.forEachIndexed { _, rule ->
|
||||
var nodeInfo = findNodeInfo(window, rule.matchUnit, listOf(0))
|
||||
var level = 0
|
||||
while (nodeInfo != null && !nodeInfo.isClickable) {
|
||||
nodeInfo = nodeInfo.parent
|
||||
level += 1
|
||||
}
|
||||
val nodeInfo = findNodeInfo(window, rule.matchUnit, listOf(0))
|
||||
if (nodeInfo != null) {
|
||||
nodeInfo.apply {
|
||||
LogUtils.dTag("click", level, rule.rawText)
|
||||
performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
||||
LogUtils.dTag("findNode", nodeInfo)
|
||||
var parentNodeInfo = nodeInfo
|
||||
var level = 0
|
||||
while (parentNodeInfo != null && !parentNodeInfo.isClickable) {
|
||||
parentNodeInfo = parentNodeInfo.parent
|
||||
level += 1
|
||||
}
|
||||
if (parentNodeInfo != null) {
|
||||
parentNodeInfo.apply {
|
||||
LogUtils.dTag("click", level, rule.rawText)
|
||||
performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
||||
}
|
||||
return@loop
|
||||
}
|
||||
} else {
|
||||
LogUtils.dTag("click", "not isClickable", rule.rawText)
|
||||
}
|
||||
return@loop
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -92,18 +87,11 @@ class AdCloserService : AccessibilityService() {
|
|||
}
|
||||
|
||||
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
|
||||
if (event == null) {
|
||||
if (event == null || event.className == null) {
|
||||
return
|
||||
}
|
||||
when (event.eventType) {
|
||||
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
|
||||
// LogUtils.d(rootInActiveWindow?.packageName, event.packageName, event.className)
|
||||
// if (event.packageName == rootInActiveWindow?.packageName && event.className != null && event.className.startsWith(
|
||||
// event.packageName
|
||||
// )
|
||||
// ) {
|
||||
//
|
||||
// }
|
||||
val className = event.className.toString()
|
||||
// val packageName = event.packageName.toString()
|
||||
// 在桌面和应用之间来回切换, 大概率导致识别失败
|
||||
|
@ -120,30 +108,6 @@ class AdCloserService : AccessibilityService() {
|
|||
else -> {
|
||||
}
|
||||
}
|
||||
// val componentName =
|
||||
// ComponentName(
|
||||
// event.packageName?.toString() ?: "",
|
||||
// event.className?.toString() ?: ""
|
||||
// )
|
||||
// val activityInfo = getActivityInfo(componentName)
|
||||
// if (activityInfo != null) {
|
||||
// val newClassName = event.className.toString()
|
||||
// if (currentActivityClassName != newClassName) {
|
||||
// currentActivityClassName = newClassName
|
||||
//// LogUtils.dTag("newClassName", newClassName, rootInActiveWindow?.packageName)
|
||||
// }
|
||||
// }
|
||||
// when (event.eventType) {
|
||||
// AccessibilityEvent.TYPE_WINDOWS_CHANGED -> {
|
||||
// }
|
||||
// AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED -> {
|
||||
// }
|
||||
// AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
|
||||
//
|
||||
// }
|
||||
// else -> {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private var currentActivityClassName = ""
|
||||
|
@ -160,16 +124,15 @@ class AdCloserService : AccessibilityService() {
|
|||
}
|
||||
|
||||
override fun onInterrupt() {
|
||||
scope.cancel()
|
||||
// val invok = {a: Int, b: Int->a+b}
|
||||
job?.cancel()
|
||||
LogUtils.d("onInterrupt")
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
scope.cancel()
|
||||
LogUtils.d("onDestroy")
|
||||
}
|
||||
|
||||
}
|
||||
//typealias Test = (a: Int, b: Int) -> Int
|
||||
//typealias Test = (a: Int, ) -> Int
|
||||
|
||||
//fun invok(a: Int, b: Int = 0){
|
||||
//
|
||||
//}
|
|
@ -1,6 +1,6 @@
|
|||
package li.songe.ad_closer.service
|
||||
package li.songe.gkd.service
|
||||
|
||||
import li.songe.ad_closer.IUserService
|
||||
import li.songe.gkd.IUserService
|
||||
|
||||
class UserService: IUserService.Stub() {
|
||||
override fun destroy() {
|
34
app/src/main/java/li/songe/gkd/ui/BottomNavItem.kt
Normal file
34
app/src/main/java/li/songe/gkd/ui/BottomNavItem.kt
Normal file
|
@ -0,0 +1,34 @@
|
|||
package li.songe.gkd.ui
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import li.songe.gkd.R
|
||||
|
||||
data class BottomNavItem(
|
||||
val label: String,
|
||||
@DrawableRes
|
||||
val icon: Int,
|
||||
val route: String,
|
||||
)
|
||||
|
||||
val BottomNavItems = listOf(
|
||||
BottomNavItem(
|
||||
label = "统计",
|
||||
icon = R.drawable.ic_chart_bar,
|
||||
route = "statistics"
|
||||
),
|
||||
BottomNavItem(
|
||||
label = "本地",
|
||||
icon = R.drawable.ic_database_set,
|
||||
route = "native"
|
||||
),
|
||||
BottomNavItem(
|
||||
label = "订阅",
|
||||
icon = R.drawable.ic_link,
|
||||
route = "subscription"
|
||||
),
|
||||
BottomNavItem(
|
||||
label = "设置",
|
||||
icon = R.drawable.ic_cog,
|
||||
route = "settings"
|
||||
),
|
||||
)
|
81
app/src/main/java/li/songe/gkd/ui/Nav.kt
Normal file
81
app/src/main/java/li/songe/gkd/ui/Nav.kt
Normal file
|
@ -0,0 +1,81 @@
|
|||
package li.songe.gkd.ui
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.BottomNavigation
|
||||
import androidx.compose.material.BottomNavigationItem
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import li.songe.gkd.ui.page.NativePage
|
||||
import li.songe.gkd.ui.page.SettingsPage
|
||||
import li.songe.gkd.ui.page.StatisticsPage
|
||||
import li.songe.gkd.ui.page.SubscriptionPage
|
||||
|
||||
|
||||
@Composable
|
||||
fun NavHostContainer(
|
||||
navController: NavHostController,
|
||||
padding: PaddingValues
|
||||
) {
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = "statistics",
|
||||
modifier = Modifier.padding(paddingValues = padding),
|
||||
builder = {
|
||||
composable("native") {
|
||||
NativePage()
|
||||
}
|
||||
composable("settings") {
|
||||
SettingsPage()
|
||||
}
|
||||
composable("statistics") {
|
||||
StatisticsPage()
|
||||
}
|
||||
composable("subscription") {
|
||||
SubscriptionPage()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BottomNavigationBar(navController: NavController) {
|
||||
BottomNavigation(
|
||||
backgroundColor = Color.White,
|
||||
) {
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentRoute = navBackStackEntry?.destination?.route
|
||||
LaunchedEffect(Unit){
|
||||
navController.navigate(BottomNavItems[1].route)
|
||||
}
|
||||
BottomNavItems.forEach { navItem ->
|
||||
BottomNavigationItem(
|
||||
selected = currentRoute == navItem.route,
|
||||
onClick = {
|
||||
navController.navigate(navItem.route)
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
painter = painterResource(id = navItem.icon),
|
||||
contentDescription = navItem.label,
|
||||
modifier = Modifier.padding(2.dp)
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(text = navItem.label)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
42
app/src/main/java/li/songe/gkd/ui/page/NativePage.kt
Normal file
42
app/src/main/java/li/songe/gkd/ui/page/NativePage.kt
Normal file
|
@ -0,0 +1,42 @@
|
|||
package li.songe.gkd.ui.page
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import li.songe.gkd.R
|
||||
|
||||
@Composable
|
||||
fun NativePage() {
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier.height(40.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_app_2),
|
||||
contentDescription = "",
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.clip(CircleShape)
|
||||
)
|
||||
Column {
|
||||
Text(text = "应用名称")
|
||||
Text(text = "8/10")
|
||||
}
|
||||
val checkedState = remember { mutableStateOf(true) }
|
||||
Switch(checked = checkedState.value,
|
||||
onCheckedChange = {
|
||||
checkedState.value = it
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
62
app/src/main/java/li/songe/gkd/ui/page/SettingsPage.kt
Normal file
62
app/src/main/java/li/songe/gkd/ui/page/SettingsPage.kt
Normal file
|
@ -0,0 +1,62 @@
|
|||
package li.songe.gkd.ui.page
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun SettingsPage() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(
|
||||
state = rememberScrollState()
|
||||
)
|
||||
.padding(20.dp)
|
||||
) {
|
||||
Row {
|
||||
val checkedState = remember { mutableStateOf(true) }
|
||||
val animatedColor = animateColorAsState(
|
||||
Color(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(0xFF * (if (checkedState.value) 1f else .3f)).toInt()
|
||||
)
|
||||
)
|
||||
Text(
|
||||
text = "服务已${(if (checkedState.value) "开启" else "关闭")}",
|
||||
color = animatedColor.value
|
||||
)
|
||||
Switch(checked = checkedState.value,
|
||||
onCheckedChange = {
|
||||
checkedState.value = it
|
||||
}
|
||||
)
|
||||
}
|
||||
Row {
|
||||
val checkedState = remember { mutableStateOf(true) }
|
||||
Text(text = "在[最近任务]界面中隐藏本应用")
|
||||
Switch(checked = checkedState.value,
|
||||
onCheckedChange = { checkedState.value = it }
|
||||
)
|
||||
}
|
||||
Row {
|
||||
val checkedState = remember { mutableStateOf(true) }
|
||||
Text(text = "通知栏显示")
|
||||
Switch(checked = checkedState.value,
|
||||
onCheckedChange = { checkedState.value = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
9
app/src/main/java/li/songe/gkd/ui/page/StatisticsPage.kt
Normal file
9
app/src/main/java/li/songe/gkd/ui/page/StatisticsPage.kt
Normal file
|
@ -0,0 +1,9 @@
|
|||
package li.songe.gkd.ui.page
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
fun StatisticsPage(){
|
||||
Text(text = "Statistics")
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package li.songe.gkd.ui.page
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
fun SubscriptionPage(){
|
||||
Text(text = "Subscription")
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.ui.theme
|
||||
package li.songe.gkd.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.ui.theme
|
||||
package li.songe.gkd.ui.theme
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Shapes
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.ui.theme
|
||||
package li.songe.gkd.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material.MaterialTheme
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.ui.theme
|
||||
package li.songe.gkd.ui.theme
|
||||
|
||||
import androidx.compose.material.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.util
|
||||
package li.songe.gkd.util
|
||||
|
||||
import java.lang.Error
|
||||
import java.util.*
|
||||
|
@ -20,7 +20,6 @@ data class AttributeSelector(val attr: Attribute, val operator: Operator, val va
|
|||
Less -> "<"
|
||||
More -> ">"
|
||||
Start -> "^"
|
||||
else-> TODO()
|
||||
} + "="
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +34,6 @@ data class AttributeSelector(val attr: Attribute, val operator: Operator, val va
|
|||
ChildCount -> "childCount"
|
||||
Id -> "id"
|
||||
Text -> "text"
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +105,7 @@ data class AttributeSelector(val attr: Attribute, val operator: Operator, val va
|
|||
|
||||
fun parseMulti(text: String): List<AttributeSelector> {
|
||||
var startIndex = -1
|
||||
var endIndex = -1
|
||||
var endIndex: Int
|
||||
val attrRawList = mutableListOf<String>()
|
||||
text.forEachIndexed { index, c ->
|
||||
when (c) {
|
||||
|
@ -131,7 +129,6 @@ data class AttributeSelector(val attr: Attribute, val operator: Operator, val va
|
|||
Attribute.ChildCount -> "childCount"
|
||||
Attribute.Id -> "id"
|
||||
Attribute.Text -> "text"
|
||||
else-> TODO()
|
||||
}
|
||||
val operator = (when (selector.operator) {
|
||||
Operator.End -> "$"
|
||||
|
@ -140,7 +137,6 @@ data class AttributeSelector(val attr: Attribute, val operator: Operator, val va
|
|||
Operator.Less -> "<"
|
||||
Operator.More -> ">"
|
||||
Operator.Start -> "^"
|
||||
else-> TODO()
|
||||
})
|
||||
return "[$attr$operator=${selector.value}]"
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package li.songe.ad_closer.util
|
||||
package li.songe.gkd.util
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
|
||||
/**
|
||||
* @param pathIndexList 当前节点在节点树的路径, 最后一项代表节点是父节点第几个元素, 第一项是 0
|
||||
|
@ -49,7 +47,6 @@ private fun match(
|
|||
AttributeSelector.Operator.Less -> childCount < it.value.toInt()
|
||||
AttributeSelector.Operator.More -> childCount > it.value.toInt()
|
||||
AttributeSelector.Operator.Start -> false
|
||||
else -> TODO()
|
||||
}
|
||||
AttributeSelector.Attribute.Id -> {
|
||||
when (it.operator) {
|
||||
|
@ -59,7 +56,6 @@ private fun match(
|
|||
AttributeSelector.Operator.Less -> false
|
||||
AttributeSelector.Operator.More -> false
|
||||
AttributeSelector.Operator.Start -> false
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
AttributeSelector.Attribute.Text -> text != null && when (it.operator) {
|
||||
|
@ -69,9 +65,7 @@ private fun match(
|
|||
AttributeSelector.Operator.Less -> false
|
||||
AttributeSelector.Operator.More -> false
|
||||
AttributeSelector.Operator.Start -> text.startsWith(it.value)
|
||||
else -> TODO()
|
||||
}
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
if (!condition2) {
|
||||
|
@ -147,17 +141,6 @@ fun findNodeInfo(
|
|||
return nodeInfo1
|
||||
}
|
||||
|
||||
//inline fun AccessibilityNodeInfo.forEach(action: (AccessibilityNodeInfo) -> Unit): Unit {
|
||||
// var index = 0
|
||||
// while (index < childCount) {
|
||||
// val child: AccessibilityNodeInfo? = getChild(index)
|
||||
// if (child != null) {
|
||||
// action(child)
|
||||
// }
|
||||
// index += 1
|
||||
// }
|
||||
//}
|
||||
|
||||
inline fun AccessibilityNodeInfo.forEachIndexed(action: (index: Int, AccessibilityNodeInfo) -> Unit) {
|
||||
var index = 0
|
||||
while (index < childCount) {
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.util
|
||||
package li.songe.gkd.util
|
||||
|
||||
data class MatchRule(val matchUnit: MatchUnit, val rawText: String) {
|
||||
companion object {
|
||||
|
@ -29,11 +29,6 @@ data class MatchRule(val matchUnit: MatchUnit, val rawText: String) {
|
|||
return selector.rawText
|
||||
}
|
||||
}
|
||||
|
||||
// sealed class RuleUnit<T>(open val data: T)
|
||||
// class MatchRuleUnit(override val data: MatchUnit) : RuleUnit<MatchUnit>(data)
|
||||
// class RelationRuleUnit(override val data: RelationUnit) : RuleUnit<RelationUnit>(data)
|
||||
|
||||
}
|
||||
|
||||
/**
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.util
|
||||
package li.songe.gkd.util
|
||||
|
||||
data class MatchUnit(
|
||||
val className: String,
|
||||
|
@ -19,9 +19,6 @@ data class MatchUnit(
|
|||
}
|
||||
}
|
||||
}
|
||||
// if (markIndex <= 0) {
|
||||
// throw Error("markIndex: expect it>0, got $markIndex")
|
||||
// }
|
||||
val className = sb.toString()
|
||||
|
||||
return MatchUnit(
|
|
@ -1,4 +1,4 @@
|
|||
package li.songe.ad_closer.util
|
||||
package li.songe.gkd.util
|
||||
|
||||
data class RelationUnit(val to: MatchUnit, val operator: Operator) {
|
||||
sealed class Operator {
|
||||
|
@ -14,6 +14,7 @@ data class RelationUnit(val to: MatchUnit, val operator: Operator) {
|
|||
return offset.toString()
|
||||
}
|
||||
Parent -> ">"
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +58,7 @@ data class RelationUnit(val to: MatchUnit, val operator: Operator) {
|
|||
throw Error("operator.offset: expect no-zero, got 0")
|
||||
}
|
||||
}
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
}
|
||||
}
|
6
app/src/main/res/drawable/ic_app_2.xml
Normal file
6
app/src/main/res/drawable/ic_app_2.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<vector android:autoMirrored="true" android:height="200dp"
|
||||
android:viewportHeight="1024" android:viewportWidth="1024"
|
||||
android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#38C152" android:pathData="M0,3.14h1020.86v1020.86H0z"/>
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M325.87,621.42h-76.61l-14.84,50.07h-62.97l84.05,-257.52h32v0.21l0.17,-0.21h32l84.22,257.52h-62.97l-15.06,-50.07zM263.07,575.48h48.99l-24.04,-79.96h-1.08l-23.87,79.96zM482.06,583.22v88.27h-59.79L422.27,413.97h98.33c30.54,0 54.76,7.83 72.69,23.36 17.89,15.57 26.88,36.05 26.88,61.38 0,25.38 -8.99,45.77 -26.88,61.29 -17.93,15.49 -42.15,23.27 -72.69,23.27h-38.54v-0.04zM482.06,537.25h38.54c12.99,0 22.88,-3.57 29.68,-10.71 6.84,-7.1 10.24,-16.3 10.24,-27.49 0,-11.48 -3.36,-20.82 -10.15,-28.13 -6.75,-7.31 -16.69,-10.97 -29.76,-10.97h-38.54v77.3zM713.04,583.22v88.27h-59.79L653.25,413.97h98.33c30.54,0 54.76,7.83 72.65,23.36 17.98,15.57 26.88,36.05 26.88,61.38 0,25.38 -8.9,45.77 -26.88,61.29 -17.89,15.49 -42.11,23.27 -72.65,23.27L713.04,583.27v-0.04zM713.04,537.25h38.54c12.99,0 22.84,-3.57 29.72,-10.71 6.79,-7.1 10.24,-16.3 10.24,-27.49 0,-11.48 -3.4,-20.82 -10.15,-28.13 -6.8,-7.31 -16.73,-10.97 -29.81,-10.97L713.04,459.95v77.3z"/>
|
||||
</vector>
|
20
app/src/main/res/drawable/ic_apps.xml
Normal file
20
app/src/main/res/drawable/ic_apps.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="200dp"
|
||||
android:height="200dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M387.26,479.68l-192,0c-52.93,0 -96,-43.07 -96,-96l0,-192c0,-52.93 43.07,-96 96,-96l192,0c52.93,0 96,43.07 96,96l0,192C483.26,436.64 440.19,479.68 387.26,479.68zM195.26,159.68c-17.63,0 -32,14.37 -32,32l0,192c0,17.63 14.37,32 32,32l192,0c17.63,0 32,-14.37 32,-32l0,-192c0,-17.63 -14.37,-32 -32,-32L195.26,159.68z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M387.26,927.68l-192,0c-52.93,0 -96,-43.07 -96,-96l0,-192c0,-52.93 43.07,-96 96,-96l192,0c52.93,0 96,43.07 96,96l0,192C483.26,884.64 440.19,927.68 387.26,927.68zM195.26,607.68c-17.63,0 -32,14.34 -32,32l0,192c0,17.66 14.37,32 32,32l192,0c17.63,0 32,-14.34 32,-32l0,-192c0,-17.66 -14.37,-32 -32,-32L195.26,607.68z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M832.13,479.68l-192,0c-52.93,0 -96,-43.07 -96,-96l0,-192c0,-52.93 43.07,-96 96,-96l192,0c52.93,0 96,43.07 96,96l0,192C928.13,436.64 885.06,479.68 832.13,479.68zM640.13,159.68c-17.66,0 -32,14.37 -32,32l0,192c0,17.63 14.34,32 32,32l192,0c17.66,0 32,-14.37 32,-32l0,-192c0,-17.63 -14.34,-32 -32,-32L640.13,159.68z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M832.13,927.68l-192,0c-52.93,0 -96,-43.07 -96,-96l0,-192c0,-52.93 43.07,-96 96,-96l192,0c52.93,0 96,43.07 96,96l0,192C928.13,884.64 885.06,927.68 832.13,927.68zM640.13,607.68c-17.66,0 -32,14.34 -32,32l0,192c0,17.66 14.34,32 32,32l192,0c17.66,0 32,-14.34 32,-32l0,-192c0,-17.66 -14.34,-32 -32,-32L640.13,607.68z" />
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_chart_bar.xml
Normal file
11
app/src/main/res/drawable/ic_chart_bar.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#262626"
|
||||
android:pathData="M85.31,938.69L1024,938.69L1024,1024L0,1024L0,0h85.31v938.69zM256,341.31h85.31L341.31,768L256,768L256,341.31zM512,128h85.31v640L512,768L512,128zM768,341.31h85.31L853.31,768L768,768L768,341.31z" />
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_cog.xml
Normal file
11
app/src/main/res/drawable/ic_cog.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#262626"
|
||||
android:pathData="M903.23,562.18c2.43,-21.82 3.65,-38.59 3.65,-50.18 0,-17.41 -1.6,-33.79 -3.65,-50.18l120.64,-102.66 -113.66,-204.54 -158.08,52.74a387.33,387.33 0,0 0,-88.96 -50.18L633.92,0L396.35,0l-35.33,157.18c-32.06,12.8 -61.57,30.21 -88.96,50.18l-155.84,-52.74L0.19,359.17 120.96,461.82c-2.11,16.38 -3.71,33.28 -3.71,50.18s1.6,33.79 3.71,50.18L12.54,657.09 128,866.82l144,-50.18c27.39,20.48 56.9,37.38 88.96,50.18L394.69,1024h239.23l29.25,-157.18c32.13,-12.8 61.57,-30.21 88.96,-50.18l145.22,50.18 125.12,-209.73 -119.23,-94.91zM798.98,474.62c2.11,15.87 2.62,26.62 2.62,37.38 0,10.75 -1.02,22.02 -2.56,37.38l-7.42,57.86 46.85,35.84 56.83,43.01 -36.86,61.95 -66.82,-26.11 -54.72,-21.5 -47.36,34.82a310.4,310.4 0,0 1,-65.86 37.38l-55.74,22.02 -8.45,57.86 -10.5,69.12L475.26,921.6l-9.98,-69.12 -8.45,-57.86 -55.81,-22.02a300.8,300.8 0,0 1,-64.7 -36.35l-47.94,-35.84 -55.74,22.02 -66.88,26.11 -36.86,-61.95 56.9,-43.01 46.85,-35.84 -7.36,-57.86A400.77,400.77 0,0 1,222.59 512c0,-10.24 1.09,-22.02 2.69,-37.38l7.36,-57.86 -46.85,-35.84 -56.9,-43.01 36.86,-61.95 66.88,26.11 54.72,21.5 47.36,-34.82a310.4,310.4 0,0 1,65.79 -37.38l55.81,-22.02 8.45,-57.86 10.5,-69.12L548.48,102.4l10.05,69.12 8.38,57.86 55.81,22.02a300.8,300.8 0,0 1,64.77 36.35l47.87,35.84 55.81,-22.02 66.82,-26.11 36.86,61.95 -56.32,43.52 -46.85,35.84 7.36,57.86zM512,320a192,192 0,1 0,0 384,192 192,0 1,0 0,-384zM512,608c-52.8,0 -96,-43.2 -96,-96S459.2,416 512,416s96,43.2 96,96S564.8,608 512,608z" />
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_database_set.xml
Normal file
11
app/src/main/res/drawable/ic_database_set.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#262626"
|
||||
android:pathData="M0,311.94l469.63,222.27L469.63,1024L0,800.96L0,311.94zM85.44,743.62l298.75,141.89L384.19,591.68l-298.75,-141.44v293.38zM512.83,0l509.63,223.04L513.28,461.7 0,222.02 512.83,0zM512.7,96.58L215.68,225.09l297.47,138.88 294.78,-138.11 -295.3,-129.28zM1024,311.94v489.02L555.2,1022.72L555.2,534.21L1024,311.94zM640.64,591.62v292.8l297.92,-140.93v-293.12L640.64,591.55z" />
|
||||
</vector>
|
6
app/src/main/res/drawable/ic_link.xml
Normal file
6
app/src/main/res/drawable/ic_link.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector android:autoMirrored="true" android:height="20dp"
|
||||
android:viewportHeight="1024" android:viewportWidth="1024"
|
||||
android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#262626" android:pathData="M593.94,715.65a10.69,10.69 0,0 0,-14.98 0L424.22,870.4c-71.68,71.68 -192.58,79.23 -271.68,0 -79.23,-79.23 -71.62,-200 0,-271.62l154.75,-154.75a10.69,10.69 0,0 0,0 -15.04l-52.99,-52.99a10.69,10.69 0,0 0,-15.04 0L84.5,530.69a287.87,287.87 0,0 0,0 407.49,288 288,0 0,0 407.49,0l154.75,-154.75a10.69,10.69 0,0 0,0 -15.04l-52.74,-52.74zM938.33,84.48a288.26,288.26 0,0 1,0 407.62l-154.75,154.75a10.69,10.69 0,0 1,-15.04 0l-52.99,-52.99a10.69,10.69 0,0 1,0 -15.1l154.75,-154.69c71.68,-71.68 79.23,-192.45 0,-271.68 -79.1,-79.23 -200,-71.68 -271.68,0L443.93,307.2a10.69,10.69 0,0 1,-15.04 0l-52.86,-52.86a10.69,10.69 0,0 1,0 -15.04l154.88,-154.75a287.87,287.87 0,0 1,407.42 0zM642.01,325.38l52.67,52.74a10.69,10.69 0,0 1,0 15.04l-301.5,301.44a10.69,10.69 0,0 1,-15.04 0l-52.74,-52.67a10.69,10.69 0,0 1,0 -15.04l301.63,-301.5a10.69,10.69 0,0 1,15.04 0z"/>
|
||||
</vector>
|
|
@ -1,5 +1,5 @@
|
|||
<resources>
|
||||
<string name="app_name">AdCloser</string>
|
||||
<string name="accessibility_service_label">accessibility_service_label</string>
|
||||
<string name="accessibility_service_description">accessibility_service_description</string>
|
||||
<string name="app_name">搞快点</string>
|
||||
<string name="accessibility_service_label">搞快点</string>
|
||||
<string name="accessibility_service_description">基于规则匹配的无障碍速点服务</string>
|
||||
</resources>
|
|
@ -1,6 +1,6 @@
|
|||
package li.songe.ad_closer
|
||||
package li.songe.gkd
|
||||
|
||||
import li.songe.ad_closer.util.MatchRule
|
||||
import li.songe.gkd.util.MatchRule
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
|
@ -10,7 +10,7 @@ buildscript {
|
|||
}
|
||||
dependencies {
|
||||
val kotlinVersion= "1.5.31"
|
||||
classpath("com.android.tools.build:gradle:7.0.3")
|
||||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
classpath(kotlin("gradle-plugin", version = kotlinVersion))
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
|
@ -5,5 +5,5 @@ dependencyResolutionManagement {
|
|||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "AdCloser"
|
||||
rootProject.name = "gkd"
|
||||
include(":app")
|
||||
|
|
Loading…
Reference in New Issue
Block a user