├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
└── vcs.xml
├── LICENSE
├── README.md
├── README
└── README_zh_cn.md
├── app
├── .gitignore
├── build.gradle
├── libs
│ ├── api-82-sources.jar
│ └── api-82.jar
├── proguard-rules.pro
├── schemas
│ ├── com.js.deepsleep.data.db.AppDatabase
│ │ ├── 1.json
│ │ └── 2.json
│ └── com.js.deepsleep.db.AppDatabase
│ │ └── 1.json
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── js
│ │ └── deepsleep
│ │ ├── ExampleInstrumentedTest.kt
│ │ └── data
│ │ ├── db
│ │ ├── AppDatabaseTest.kt
│ │ ├── dao
│ │ │ ├── AppStDaoTest.kt
│ │ │ └── ExtendDaoTest.kt
│ │ ├── data
│ │ │ └── TestData.kt
│ │ └── tool
│ │ │ └── LiveDataTestUtil.kt
│ │ └── provider
│ │ └── DSContentProviderTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── xposed_init
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── js
│ │ │ └── deepsleep
│ │ │ ├── BasicApp.kt
│ │ │ ├── KoinDSL.kt
│ │ │ ├── data
│ │ │ ├── db
│ │ │ │ ├── AppDatabase.kt
│ │ │ │ ├── converter
│ │ │ │ │ └── Converters.kt
│ │ │ │ ├── dao
│ │ │ │ │ ├── AppDao.kt
│ │ │ │ │ ├── AppInfoDao.kt
│ │ │ │ │ ├── AppStDao.kt
│ │ │ │ │ ├── BackupDao.kt
│ │ │ │ │ └── ExtendDao.kt
│ │ │ │ └── entity
│ │ │ │ │ ├── App.kt
│ │ │ │ │ ├── AppInfo.kt
│ │ │ │ │ ├── AppSt.kt
│ │ │ │ │ └── Extend.kt
│ │ │ ├── provider
│ │ │ │ ├── DSContentProvider.kt
│ │ │ │ ├── Provider.kt
│ │ │ │ └── ProviderHandler.kt
│ │ │ └── repository
│ │ │ │ ├── app
│ │ │ │ ├── AppAR.kt
│ │ │ │ └── AppRepo.kt
│ │ │ │ ├── backup
│ │ │ │ ├── AppBackup.kt
│ │ │ │ └── BackupRepository.kt
│ │ │ │ ├── extend
│ │ │ │ ├── ER.kt
│ │ │ │ └── ExtendRepo.kt
│ │ │ │ └── syncsp
│ │ │ │ ├── SyncSp.kt
│ │ │ │ └── SyncSpRepo.kt
│ │ │ ├── tools
│ │ │ ├── Enum.kt
│ │ │ ├── LogUtil.kt
│ │ │ ├── SPTools.kt
│ │ │ ├── Util.kt
│ │ │ └── XProvider.kt
│ │ │ ├── ui
│ │ │ ├── about
│ │ │ │ ├── About.kt
│ │ │ │ ├── AboutFragment.kt
│ │ │ │ └── AboutViewModel.kt
│ │ │ ├── app
│ │ │ │ ├── AppFragment.kt
│ │ │ │ ├── AppViewModel.kt
│ │ │ │ ├── HandleApp.kt
│ │ │ │ ├── ItemApp.kt
│ │ │ │ └── SyncStViewModel.kt
│ │ │ ├── databinding
│ │ │ │ ├── DataBind.kt
│ │ │ │ ├── DiffCallback.kt
│ │ │ │ ├── MyLayoutManager.kt
│ │ │ │ ├── RecycleAdapter.kt
│ │ │ │ ├── ViewHolder.kt
│ │ │ │ └── item
│ │ │ │ │ ├── BaseItem.kt
│ │ │ │ │ └── BaseItemHandle.kt
│ │ │ ├── extend
│ │ │ │ ├── AlarmFragment.kt
│ │ │ │ ├── AppAdapter.kt
│ │ │ │ ├── ExtendFragment.kt
│ │ │ │ ├── WakeLockFragment.kt
│ │ │ │ └── fbase
│ │ │ │ │ ├── FBaseFragment.kt
│ │ │ │ │ ├── FBaseViewModel.kt
│ │ │ │ │ └── SyncExViewModel.kt
│ │ │ ├── help
│ │ │ │ ├── Help.kt
│ │ │ │ ├── HelpFragment.kt
│ │ │ │ └── HelpViewModel.kt
│ │ │ ├── mainactivity
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── MainViewModel.kt
│ │ │ └── settings
│ │ │ │ ├── SettingViewModel.kt
│ │ │ │ ├── SettingsFragment.kt
│ │ │ │ └── ThemeHelper.kt
│ │ │ └── xposed
│ │ │ ├── XpUtil.kt
│ │ │ ├── XposedModule.kt
│ │ │ ├── hook
│ │ │ ├── AlarmXp.kt
│ │ │ ├── Application.kt
│ │ │ ├── BroadcastXP.kt
│ │ │ ├── SelfXp.kt
│ │ │ ├── ServiceXp.kt
│ │ │ ├── SettingsProviderXP.kt
│ │ │ ├── SyncXp.kt
│ │ │ └── WakelockXp.kt
│ │ │ └── model
│ │ │ ├── XpAppSt.kt
│ │ │ └── XpNSP.kt
│ └── res
│ │ ├── drawable
│ │ ├── ic_about_24.xml
│ │ ├── ic_baseline_expand_more_24.xml
│ │ ├── ic_filter_list_24dp.xml
│ │ ├── ic_help_24dp.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_other_24dp.xml
│ │ ├── ic_outline_expand_less_24.xml
│ │ ├── ic_search_24dp.xml
│ │ ├── ic_settings_24dp.xml
│ │ ├── ic_settings_backup_restore_24.xml
│ │ └── ic_theme_24dp.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── fragment_about.xml
│ │ ├── fragment_app.xml
│ │ ├── fragment_extend.xml
│ │ ├── fragment_fbase.xml
│ │ ├── fragment_help.xml
│ │ ├── item_app.xml
│ │ └── nav_header.xml
│ │ ├── menu
│ │ ├── nav.xml
│ │ └── toolbar.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values-zh-rCN
│ │ └── strings.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── settings.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ ├── backup_descriptor.xml
│ │ └── settings.xml
│ └── test
│ └── java
│ └── com
│ └── js
│ └── deepsleep
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DeepSleep
2 |
3 | - This is English version(although a lot of google translation😂), for china user [中文版](https://github.com/Jasper-1024/DeepSleep/blob/dev/README/README_zh_cn.md)
4 |
5 | - DeepSleep is a Xposed module. It can limit the background behavior of apps and reduce the power consumption of apps in the background.
6 | - Block acquire [wakelock](https://developer.android.com/training/scheduling/wakelock) and [alarms](https://developer.android.com/training/scheduling/alarms) to prevent redundant wake-ups.
7 | - Block start [services](https://developer.android.com/guide/components/services) to reduce memory consumption.
8 | - Block [sync](https://developer.android.com/training/sync-adapters?hl=zh-cn) to prevent redundant wake-ups.
9 |
10 | - EDxposed/LSPosed scope Select the application to be limited.
11 |
12 | - Serious warning
13 | - Using deepsleep is not recommended if your device has no standby power consumption problems.
14 | - Using deepsleep to limit the application may cause unusual problems with the application.
15 | - IM may experience message delays
16 | - Music player may not play on the lock screen
17 | - Other exceptions caused by restricting the background behavior of the app.
18 |
19 | ## About
20 |
21 | - Due to some persion reason, NoWakeLock is gradually in a state of suspension, and some functions of NoWakeLock are too complicated, so DeepSleep was written.
22 |
23 | ## Features
24 |
25 | - Beta:
26 | - ~~wakelock/alarm/service/sync restriction~~
27 | - ~~Data backup and recovery~~
28 | - ~~help/about fragment~~
29 | - ~~black/white list/regex support~~
30 | - ~~dark/light theme switch~~
31 | - broadcast restriction
32 |
33 | - Release
34 |
35 | -
36 |
37 | ## Compatibility
38 |
39 | - Android N ~
40 | - Edxpoed LSPosed
41 |
42 | ## Compile
43 |
44 | - [master](https://github.com/Jasper-1024/DeepSleep): Released
45 |
46 | - [dev](https://github.com/Jasper-1024/DeepSleep/tree/dev): Bate
47 |
48 | ## Installation
49 |
50 | - [Github releases](https://github.com/Jasper-1024/DeepSleep/releases), alpha/bate/Released.
51 | - [酷安](https://www.coolapk.com/apk/260112), bate/Released
52 | - [Play](https://play.google.com/store/apps/details?id=com.js.deepsleep) bate/Released
53 |
54 | ## Support
55 |
56 | - Only DeepSleep downloaded from the above channels is supported
57 | - Please submit [ISSUE](https://github.com/Jasper-1024/DeepSleep/issues)
58 |
59 | ## Contributing
60 |
61 | - [Jasper Hale](https://github.com/Jasper-1024)
62 |
63 | ## License
64 |
65 | - DeepSleep is released under GNU GPLv3 ([License](https://github.com/Jasper-1024/DeepSleep/blob/master/LICENSE)).
66 |
--------------------------------------------------------------------------------
/README/README_zh_cn.md:
--------------------------------------------------------------------------------
1 | # DeepSleep
2 |
3 | - DeepSleep 是 Xposed 模块.可以限制应用后台行为,节省待机电量消耗.
4 | - 禁止申请 [唤醒锁/wakelock](https://developer.android.com/training/scheduling/wakelock) 和 [闹钟/alarms](https://developer.android.com/training/scheduling/alarms),防止多余唤醒.
5 | - 禁止启动 [后台服务/Service](https://developer.android.com/guide/components/services),减少内存消耗.
6 | - 禁止 [同步/sync](https://developer.android.com/training/sync-adapters?hl=zh-cn),防止多余唤醒.
7 |
8 | - EDxposed/LSPosed 作用域 选择需要限制应用.
9 |
10 | - 严重警告
11 | - 如果您的设备没有待机耗电问题并不推荐使用 deepsleep.
12 | - 使用 deepsleep 限制应用,可能会导致应用出现异常问题.
13 | - 聊天应用 可能出现消息延迟
14 | - 音乐播放器 可能无法锁屏播放
15 | - 其他等因限制应用后台行为导致的异常.
16 |
17 | ## 关于
18 |
19 | - 因为精力有限, NoWakeLock 逐渐处于停更状态,且 NoWakeLock 一些功能过于复杂,因此集中时间编写了 DeepSleep.
20 |
21 | ## 功能
22 |
23 | - ~~Beta~~:
24 | - ~~wakelock/alarm/service/sync 限制~~
25 | - ~~帮助/关于界面~~
26 | - ~~黑白名单/正则支持~~
27 | - ~~深色/浅色主题切换~~
28 | - ~~备份/还原支持~~
29 | - 广播 限制
30 |
31 | - Release:
32 | - 禁用方案加载
33 |
34 | ## 兼容性
35 |
36 | - Android N ~
37 | - Edxpoed LSPosed
38 |
39 | ## 编译
40 |
41 | - [master](https://github.com/Jasper-1024/DeepSleep): 稳定版
42 |
43 | - [dev](https://github.com/Jasper-1024/DeepSleep/tree/dev): 测试版,可能并不稳定.
44 |
45 | ## 安装
46 |
47 | - [Github releases](https://github.com/Jasper-1024/DeepSleep/releases), 包括 alpha/bate/Released 版.
48 | - [酷安](https://www.coolapk.com/apk/260112), bate/Released 版
49 | - [Play](https://play.google.com/store/apps/details?id=com.js.deepsleep) bate/Released
50 |
51 | ## 支持
52 |
53 | - 仅支持在上述渠道下载的 DeepSleep
54 | - 请提交 [ISSUE](https://github.com/Jasper-1024/DeepSleep/issues)
55 |
56 | ## 贡献者
57 |
58 | - [Jasper Hale](https://github.com/Jasper-1024)
59 |
60 | ## 许可证
61 |
62 | - DeepSleep 以 GNU GPLv3 ([许可](https://github.com/Jasper-1024/DeepSleep/blob/master/LICENSE)) 发布.
63 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /debug/app-debug.apk
3 | /debug/output-metadata.json
4 | /release/app-release.apk
5 | /.idea/codeStyles/codeStyleConfig.xml
6 | /.idea/codeStyles/Project.xml
7 | /app/release/output-metadata.json
--------------------------------------------------------------------------------
/app/libs/api-82-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/libs/api-82-sources.jar
--------------------------------------------------------------------------------
/app/libs/api-82.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/libs/api-82.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/schemas/com.js.deepsleep.data.db.AppDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "f69177b7f48bde0eb079915c4fb37293",
6 | "entities": [
7 | {
8 | "tableName": "appInfo",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `uid` INTEGER NOT NULL, `label` TEXT NOT NULL, `icon` INTEGER NOT NULL, `system` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `persistent` INTEGER NOT NULL, `processName` TEXT NOT NULL, PRIMARY KEY(`packageName`))",
10 | "fields": [
11 | {
12 | "fieldPath": "packageName",
13 | "columnName": "packageName",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "uid",
19 | "columnName": "uid",
20 | "affinity": "INTEGER",
21 | "notNull": true
22 | },
23 | {
24 | "fieldPath": "label",
25 | "columnName": "label",
26 | "affinity": "TEXT",
27 | "notNull": true
28 | },
29 | {
30 | "fieldPath": "icon",
31 | "columnName": "icon",
32 | "affinity": "INTEGER",
33 | "notNull": true
34 | },
35 | {
36 | "fieldPath": "system",
37 | "columnName": "system",
38 | "affinity": "INTEGER",
39 | "notNull": true
40 | },
41 | {
42 | "fieldPath": "enabled",
43 | "columnName": "enabled",
44 | "affinity": "INTEGER",
45 | "notNull": true
46 | },
47 | {
48 | "fieldPath": "persistent",
49 | "columnName": "persistent",
50 | "affinity": "INTEGER",
51 | "notNull": true
52 | },
53 | {
54 | "fieldPath": "processName",
55 | "columnName": "processName",
56 | "affinity": "TEXT",
57 | "notNull": true
58 | }
59 | ],
60 | "primaryKey": {
61 | "columnNames": [
62 | "packageName"
63 | ],
64 | "autoGenerate": false
65 | },
66 | "indices": [],
67 | "foreignKeys": []
68 | },
69 | {
70 | "tableName": "appSt",
71 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName_st` TEXT NOT NULL, `flag` INTEGER NOT NULL, `wakelock` INTEGER NOT NULL, `alarm` INTEGER NOT NULL, `service` INTEGER NOT NULL, `sync` INTEGER NOT NULL, PRIMARY KEY(`packageName_st`))",
72 | "fields": [
73 | {
74 | "fieldPath": "packageName",
75 | "columnName": "packageName_st",
76 | "affinity": "TEXT",
77 | "notNull": true
78 | },
79 | {
80 | "fieldPath": "flag",
81 | "columnName": "flag",
82 | "affinity": "INTEGER",
83 | "notNull": true
84 | },
85 | {
86 | "fieldPath": "wakelock",
87 | "columnName": "wakelock",
88 | "affinity": "INTEGER",
89 | "notNull": true
90 | },
91 | {
92 | "fieldPath": "alarm",
93 | "columnName": "alarm",
94 | "affinity": "INTEGER",
95 | "notNull": true
96 | },
97 | {
98 | "fieldPath": "service",
99 | "columnName": "service",
100 | "affinity": "INTEGER",
101 | "notNull": true
102 | },
103 | {
104 | "fieldPath": "sync",
105 | "columnName": "sync",
106 | "affinity": "INTEGER",
107 | "notNull": true
108 | }
109 | ],
110 | "primaryKey": {
111 | "columnNames": [
112 | "packageName_st"
113 | ],
114 | "autoGenerate": false
115 | },
116 | "indices": [],
117 | "foreignKeys": []
118 | },
119 | {
120 | "tableName": "extend",
121 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName_ex` TEXT NOT NULL, `type` TEXT NOT NULL, `allowList` TEXT NOT NULL, `blockList` TEXT NOT NULL, `rE` TEXT NOT NULL, PRIMARY KEY(`packageName_ex`, `type`))",
122 | "fields": [
123 | {
124 | "fieldPath": "packageName",
125 | "columnName": "packageName_ex",
126 | "affinity": "TEXT",
127 | "notNull": true
128 | },
129 | {
130 | "fieldPath": "type",
131 | "columnName": "type",
132 | "affinity": "TEXT",
133 | "notNull": true
134 | },
135 | {
136 | "fieldPath": "allowList",
137 | "columnName": "allowList",
138 | "affinity": "TEXT",
139 | "notNull": true
140 | },
141 | {
142 | "fieldPath": "blockList",
143 | "columnName": "blockList",
144 | "affinity": "TEXT",
145 | "notNull": true
146 | },
147 | {
148 | "fieldPath": "rE",
149 | "columnName": "rE",
150 | "affinity": "TEXT",
151 | "notNull": true
152 | }
153 | ],
154 | "primaryKey": {
155 | "columnNames": [
156 | "packageName_ex",
157 | "type"
158 | ],
159 | "autoGenerate": false
160 | },
161 | "indices": [],
162 | "foreignKeys": []
163 | }
164 | ],
165 | "views": [],
166 | "setupQueries": [
167 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
168 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f69177b7f48bde0eb079915c4fb37293')"
169 | ]
170 | }
171 | }
--------------------------------------------------------------------------------
/app/schemas/com.js.deepsleep.db.AppDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "8e48ca6a3406627ba407289a2dc9af14",
6 | "entities": [
7 | {
8 | "tableName": "appInfo",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `uid` INTEGER NOT NULL, `label` TEXT NOT NULL, `icon` INTEGER NOT NULL, `system` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `persistent` INTEGER NOT NULL, `processName` TEXT NOT NULL, PRIMARY KEY(`packageName`))",
10 | "fields": [
11 | {
12 | "fieldPath": "packageName",
13 | "columnName": "packageName",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "uid",
19 | "columnName": "uid",
20 | "affinity": "INTEGER",
21 | "notNull": true
22 | },
23 | {
24 | "fieldPath": "label",
25 | "columnName": "label",
26 | "affinity": "TEXT",
27 | "notNull": true
28 | },
29 | {
30 | "fieldPath": "icon",
31 | "columnName": "icon",
32 | "affinity": "INTEGER",
33 | "notNull": true
34 | },
35 | {
36 | "fieldPath": "system",
37 | "columnName": "system",
38 | "affinity": "INTEGER",
39 | "notNull": true
40 | },
41 | {
42 | "fieldPath": "enabled",
43 | "columnName": "enabled",
44 | "affinity": "INTEGER",
45 | "notNull": true
46 | },
47 | {
48 | "fieldPath": "persistent",
49 | "columnName": "persistent",
50 | "affinity": "INTEGER",
51 | "notNull": true
52 | },
53 | {
54 | "fieldPath": "processName",
55 | "columnName": "processName",
56 | "affinity": "TEXT",
57 | "notNull": true
58 | }
59 | ],
60 | "primaryKey": {
61 | "columnNames": [
62 | "packageName"
63 | ],
64 | "autoGenerate": false
65 | },
66 | "indices": [],
67 | "foreignKeys": []
68 | },
69 | {
70 | "tableName": "appSt",
71 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName_st` TEXT NOT NULL, `wakelock` INTEGER NOT NULL, `alarm` INTEGER NOT NULL, `server` INTEGER NOT NULL, PRIMARY KEY(`packageName_st`))",
72 | "fields": [
73 | {
74 | "fieldPath": "packageName",
75 | "columnName": "packageName_st",
76 | "affinity": "TEXT",
77 | "notNull": true
78 | },
79 | {
80 | "fieldPath": "wakelock",
81 | "columnName": "wakelock",
82 | "affinity": "INTEGER",
83 | "notNull": true
84 | },
85 | {
86 | "fieldPath": "alarm",
87 | "columnName": "alarm",
88 | "affinity": "INTEGER",
89 | "notNull": true
90 | },
91 | {
92 | "fieldPath": "server",
93 | "columnName": "server",
94 | "affinity": "INTEGER",
95 | "notNull": true
96 | }
97 | ],
98 | "primaryKey": {
99 | "columnNames": [
100 | "packageName_st"
101 | ],
102 | "autoGenerate": false
103 | },
104 | "indices": [],
105 | "foreignKeys": []
106 | },
107 | {
108 | "tableName": "extend",
109 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName_ex` TEXT NOT NULL, `type` TEXT NOT NULL, `allowList` TEXT NOT NULL, `blockList` TEXT NOT NULL, `rE` TEXT NOT NULL, PRIMARY KEY(`packageName_ex`, `type`))",
110 | "fields": [
111 | {
112 | "fieldPath": "packageName",
113 | "columnName": "packageName_ex",
114 | "affinity": "TEXT",
115 | "notNull": true
116 | },
117 | {
118 | "fieldPath": "type",
119 | "columnName": "type",
120 | "affinity": "TEXT",
121 | "notNull": true
122 | },
123 | {
124 | "fieldPath": "allowList",
125 | "columnName": "allowList",
126 | "affinity": "TEXT",
127 | "notNull": true
128 | },
129 | {
130 | "fieldPath": "blockList",
131 | "columnName": "blockList",
132 | "affinity": "TEXT",
133 | "notNull": true
134 | },
135 | {
136 | "fieldPath": "rE",
137 | "columnName": "rE",
138 | "affinity": "TEXT",
139 | "notNull": true
140 | }
141 | ],
142 | "primaryKey": {
143 | "columnNames": [
144 | "packageName_ex",
145 | "type"
146 | ],
147 | "autoGenerate": false
148 | },
149 | "indices": [],
150 | "foreignKeys": []
151 | }
152 | ],
153 | "views": [],
154 | "setupQueries": [
155 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
156 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8e48ca6a3406627ba407289a2dc9af14')"
157 | ]
158 | }
159 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/js/deepsleep/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.js.deepsleep", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/js/deepsleep/data/db/AppDatabaseTest.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db
2 |
3 | import androidx.room.Room
4 | import androidx.room.migration.Migration
5 | import androidx.room.testing.MigrationTestHelper
6 | import androidx.sqlite.db.SupportSQLiteDatabase
7 | import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
8 | import androidx.test.ext.junit.runners.AndroidJUnit4
9 | import androidx.test.platform.app.InstrumentationRegistry
10 | import org.junit.Rule
11 | import org.junit.Test
12 | import org.junit.runner.RunWith
13 | import java.io.IOException
14 |
15 | @RunWith(AndroidJUnit4::class)
16 | class AppDatabaseTest {
17 | private val TEST_DB = "migration-test"
18 |
19 | private val MIGRATION_1_2 = object : Migration(1, 2) {
20 | override fun migrate(database: SupportSQLiteDatabase) {
21 | database.execSQL(
22 | """
23 | CREATE TABLE IF NOT EXISTS appSt_tmp (
24 | `packageName_st` TEXT NOT NULL,
25 | `flag` INTEGER NOT NULL,
26 | `wakelock` INTEGER NOT NULL,
27 | `alarm` INTEGER NOT NULL,
28 | `service` INTEGER NOT NULL,
29 | `sync` INTEGER NOT NULL,
30 | `broadcast` INTEGER NOT NULL DEFAULT 0,
31 | PRIMARY KEY(`packageName_st`))
32 | """.trimMargin()
33 | )
34 | database.execSQL(
35 | """
36 | INSERT INTO appSt_tmp(packageName_st, flag, wakelock, alarm, service, sync)
37 | SELECT packageName_st, flag, wakelock, alarm, service, sync
38 | FROM appSt
39 | """.trimIndent()
40 | )
41 | database.execSQL("DROP TABLE appSt")
42 | database.execSQL("ALTER TABLE appSt_tmp RENAME TO appSt")
43 | }
44 | }
45 |
46 |
47 | private val ALL_MIGRATIONS = arrayOf(
48 | MIGRATION_1_2
49 | )
50 |
51 |
52 | @get:Rule
53 | val helper: MigrationTestHelper = MigrationTestHelper(
54 | InstrumentationRegistry.getInstrumentation(),
55 | AppDatabase::class.java.canonicalName,
56 | FrameworkSQLiteOpenHelperFactory()
57 | )
58 |
59 | @Test
60 | @Throws(IOException::class)
61 | fun migrate1To2() {
62 | var db = helper.createDatabase(TEST_DB, 1).apply {
63 | // db has schema version 1. insert some data using SQL queries.
64 | // You cannot use DAO classes because they expect the latest schema.
65 | // execSQL(...)
66 |
67 |
68 | // Prepare for the next version.
69 | close()
70 | }
71 | //
72 | // db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2)
73 | }
74 |
75 |
76 | @Test
77 | @Throws(IOException::class)
78 | fun migrateAll() {
79 | // Create earliest version of the database.
80 | helper.createDatabase(TEST_DB, 1).apply {
81 | close()
82 | }
83 |
84 | // Open latest version of the database. Room will validate the schema
85 | // once all migrations execute.
86 | Room.databaseBuilder(
87 | InstrumentationRegistry.getInstrumentation().targetContext,
88 | AppDatabase::class.java, TEST_DB
89 | ).addMigrations(*ALL_MIGRATIONS).build().apply {
90 | openHelper.writableDatabase
91 | close()
92 | }
93 | }
94 |
95 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/js/deepsleep/data/db/dao/AppStDaoTest.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.dao
2 |
3 | import android.content.Context
4 | import androidx.room.Room
5 | import androidx.test.core.app.ApplicationProvider
6 | import androidx.test.ext.junit.runners.AndroidJUnit4
7 | import com.js.deepsleep.data.db.AppDatabase
8 | import com.js.deepsleep.data.db.data.TestData
9 | import kotlinx.coroutines.runBlocking
10 | import org.junit.After
11 | import org.junit.Assert
12 | import org.junit.Before
13 | import org.junit.Test
14 | import org.junit.runner.RunWith
15 |
16 | @RunWith(AndroidJUnit4::class)
17 | class AppStDaoTest {
18 |
19 | private lateinit var appStDao: AppStDao
20 | private lateinit var db: AppDatabase
21 |
22 | @Before
23 | fun setUp() {
24 | val context = ApplicationProvider.getApplicationContext()
25 | db = Room.inMemoryDatabaseBuilder(
26 | context, AppDatabase::class.java
27 | ).allowMainThreadQueries()
28 | .build()
29 | appStDao = db.appStDao()
30 | }
31 |
32 | @After
33 | fun tearDown() {
34 | db.close()
35 | }
36 |
37 | @Test
38 | @Throws(Exception::class)
39 | fun testAlarm() {
40 | runBlocking {
41 | appStDao.insert(TestData.appSts)
42 | }
43 |
44 | val tmps = runBlocking { appStDao.appSts() }
45 |
46 | Assert.assertEquals(tmps[0], TestData.appSts[0])
47 | Assert.assertEquals(tmps.size, 3)
48 |
49 | runBlocking { appStDao.insert(TestData.appSt) }
50 | val tmp = runBlocking { appStDao.AppSt(TestData.packageName) }
51 | Assert.assertEquals(tmp, TestData.appSt)
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/js/deepsleep/data/db/dao/ExtendDaoTest.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.dao
2 |
3 | import android.content.Context
4 | import androidx.room.Room
5 | import androidx.test.core.app.ApplicationProvider
6 | import androidx.test.ext.junit.runners.AndroidJUnit4
7 | import com.js.deepsleep.data.db.AppDatabase
8 | import com.js.deepsleep.data.db.data.TestData
9 | import kotlinx.coroutines.runBlocking
10 | import org.junit.After
11 | import org.junit.Assert
12 | import org.junit.Before
13 | import org.junit.Test
14 | import org.junit.runner.RunWith
15 |
16 | @RunWith(AndroidJUnit4::class)
17 | class ExtendDaoTest {
18 | private lateinit var extendDao: ExtendDao
19 | private lateinit var db: AppDatabase
20 |
21 | @Before
22 | fun setUp() {
23 | val context = ApplicationProvider.getApplicationContext()
24 | db = Room.inMemoryDatabaseBuilder(
25 | context, AppDatabase::class.java
26 | ).allowMainThreadQueries()
27 | .build()
28 | extendDao = db.extendDao()
29 | }
30 |
31 | @After
32 | fun tearDown() {
33 | db.close()
34 | }
35 |
36 | @Test
37 | @Throws(Exception::class)
38 | fun test() {
39 |
40 | runBlocking {
41 | extendDao.insert(TestData.extends)
42 | }
43 |
44 | val tmps = runBlocking {
45 | extendDao.Extends()
46 | }
47 |
48 | Assert.assertEquals(tmps.size, 3)
49 | Assert.assertEquals(tmps[0], TestData.extends[0])
50 | Assert.assertEquals(tmps[1].allowList.size, 1)
51 | Assert.assertEquals(tmps[1].blockList.size, 2)
52 | Assert.assertEquals(tmps[1].rE.size, 3)
53 |
54 | runBlocking { extendDao.insert(TestData.extend) }
55 |
56 | val tmp = runBlocking { extendDao.getExtend(TestData.packageName, TestData.wakelock) }
57 |
58 | Assert.assertEquals(tmp, TestData.extend)
59 | // runBlocking {
60 | // appStDao.insert(TestData.appSts)
61 | // }
62 | //
63 | // val tmps = runBlocking { appStDao.AppSts() }
64 | //
65 | // Assert.assertEquals(tmps[0], TestData.appSts[0])
66 | // Assert.assertEquals(tmps.size, 3)
67 | //
68 | // runBlocking { appStDao.insert(TestData.appSt) }
69 | // val tmp = runBlocking { appStDao.AppSt(TestData.packageName) }
70 | // Assert.assertEquals(tmp, TestData.appSt)
71 | }
72 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/js/deepsleep/data/db/data/TestData.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.data
2 |
3 | import com.js.deepsleep.data.db.entity.AppSt
4 | import com.js.deepsleep.data.db.entity.Extend
5 |
6 | class TestData {
7 | companion object {
8 | const val packageName = "test1"
9 | const val wakelock = "wakelock"
10 | const val alarm = "alarm"
11 | const val server = "server"
12 |
13 | val appSt = AppSt(packageName = packageName, wakelock = true, alarm = true, service = true)
14 |
15 | val appSts: List = listOf(
16 | AppSt(packageName = packageName, wakelock = false, alarm = false, service = false),
17 | AppSt(packageName = "test2", wakelock = true, alarm = true, service = true),
18 | AppSt(packageName = "test3", wakelock = true, alarm = true, service = true)
19 | )
20 |
21 | val extend = Extend(
22 | packageName,
23 | wakelock,
24 | setOf("wakelock_allow1", "wakelock_allow2", "wakelock_allow3", "wakelock_allow4"),
25 | setOf("wakelock_block1", "wakelock_block2", "wakelock_block3"),
26 | setOf("wakelock_re1", "wakelock_re2", "wakelock_re3")
27 | )
28 |
29 | val extends: List = listOf(
30 | Extend(
31 | packageName,
32 | wakelock,
33 | setOf("wakelock_allow1", "wakelock_allow2", "wakelock_allow3"),
34 | setOf("wakelock_block1", "wakelock_block2", "wakelock_block3"),
35 | setOf("wakelock_re1", "wakelock_re2", "wakelock_re3")
36 | ),
37 | Extend(
38 | packageName,
39 | alarm,
40 | setOf("wakelock_allow1", "wakelock_allow1", "wakelock_allow1"),
41 | setOf("wakelock_block1", "wakelock_block2", "wakelock_block2"),
42 | setOf("wakelock_re1", "wakelock_re2", "wakelock_re3")
43 | ),
44 | Extend(packageName, server, setOf(), setOf(), setOf())
45 | )
46 |
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/js/deepsleep/data/db/tool/LiveDataTestUtil.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.tool
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.Observer
5 | import java.util.concurrent.CountDownLatch
6 | import java.util.concurrent.TimeUnit
7 |
8 | class LiveDataTestUtil {
9 | /**
10 | * Get the value from a LiveData object. We're waiting for LiveData to emit, for 2 seconds.
11 | * Once we got a notification via onChanged, we stop observing.
12 | */
13 | companion object {
14 | fun getValue(liveData: LiveData): T {
15 | val data = arrayOfNulls(1)
16 | val latch = CountDownLatch(1)
17 | val observer = object : Observer {
18 | override fun onChanged(o: T?) {
19 | data[0] = o
20 | latch.countDown()
21 | liveData.removeObserver(this)
22 | }
23 | }
24 | liveData.observeForever(observer)
25 | latch.await(2, TimeUnit.SECONDS)
26 | return data[0] as T
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/js/deepsleep/data/provider/DSContentProviderTest.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.provider
2 |
3 | import android.content.ContentResolver
4 | import android.content.Context
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import androidx.test.core.app.ApplicationProvider
8 | import junit.framework.Assert.assertEquals
9 | import org.junit.Before
10 | import org.junit.Test
11 |
12 |
13 | class DSContentProviderTest {
14 |
15 | private var mContentResolver: ContentResolver? = null
16 | private val authority = "com.js.deepsleep"
17 |
18 | @Before
19 | fun setUp() {
20 | val context = ApplicationProvider.getApplicationContext()
21 | mContentResolver = context.contentResolver
22 | }
23 |
24 | @Test
25 | fun call() {
26 | val method = "test"
27 | val url = Uri.parse("content://$authority")
28 |
29 | val extras = Bundle()
30 | extras.putString("Test", "Test")
31 |
32 | val bundle = mContentResolver?.call(url, method, null, extras)
33 | //if (bundle != null) {
34 | // LogUtil.d("test1", bundle.toString())
35 | //}
36 | assertEquals(bundle!!.getString("Test"), "Test")
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
33 |
36 |
39 |
42 |
43 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.js.deepsleep.xposed.XposedModule
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/BasicApp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Application
5 | import android.content.Context
6 | import androidx.preference.PreferenceManager
7 | import com.google.gson.Gson
8 | import com.js.deepsleep.ui.settings.ThemeHelper
9 | import org.koin.android.ext.koin.androidContext
10 | import org.koin.core.context.startKoin
11 |
12 | class BasicApp : Application() {
13 | companion object {
14 | @SuppressLint("StaticFieldLeak")
15 | lateinit var context: Context
16 | lateinit var gson: Gson
17 | }
18 |
19 | override fun onCreate() {
20 | super.onCreate()
21 | context = applicationContext
22 | gson = Gson()
23 |
24 | //koin
25 | startKoin {
26 | androidContext(this@BasicApp)
27 | modules(repository, viewModel)
28 | }
29 |
30 | // set Theme
31 | val sharedPreferences =
32 | PreferenceManager.getDefaultSharedPreferences(this)
33 | val themePref =
34 | sharedPreferences.getString("theme_list", ThemeHelper.DEFAULT_MODE)
35 | ThemeHelper.applyTheme(themePref!!)
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/KoinDSL.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("RemoveExplicitTypeArguments")
2 |
3 | package com.js.deepsleep
4 |
5 | import com.js.deepsleep.tools.Type
6 | import com.js.deepsleep.data.db.AppDatabase
7 | import com.js.deepsleep.data.repository.app.AppAR
8 | import com.js.deepsleep.data.repository.app.AppRepo
9 | import com.js.deepsleep.data.repository.backup.BackupRepository
10 | import com.js.deepsleep.data.repository.extend.ER
11 | import com.js.deepsleep.data.repository.extend.ExtendRepo
12 | import com.js.deepsleep.data.repository.syncsp.SyncSp
13 | import com.js.deepsleep.data.repository.syncsp.SyncSpRepo
14 | import com.js.deepsleep.ui.about.AboutViewModel
15 | import com.js.deepsleep.ui.app.AppViewModel
16 | import com.js.deepsleep.ui.app.SyncStViewModel
17 | import com.js.deepsleep.ui.extend.fbase.FBaseViewModel
18 | import com.js.deepsleep.ui.extend.fbase.SyncExViewModel
19 | import com.js.deepsleep.ui.help.HelpViewModel
20 | import com.js.deepsleep.ui.mainactivity.MainViewModel
21 | import com.js.deepsleep.ui.settings.SettingViewModel
22 | import org.koin.androidx.viewmodel.dsl.viewModel
23 | import org.koin.core.qualifier.named
24 | import org.koin.dsl.module
25 |
26 | var repository = module {
27 |
28 | /** AppRepo */
29 | single(named("AppR")) {
30 | AppAR(
31 | AppDatabase.getInstance(BasicApp.context).appDao(),
32 | AppDatabase.getInstance(BasicApp.context).appInfoDao(),
33 | AppDatabase.getInstance(BasicApp.context).appStDao()
34 | )
35 | }
36 |
37 | /** ExtendRepo */
38 | single(named("wakelockER")) {
39 | ER(
40 | AppDatabase.getInstance(BasicApp.context).extendDao(), Type.Wakelock
41 | )
42 | }
43 |
44 | /** ExtendRepo */
45 | single(named("alarmR")) {
46 | ER(
47 | AppDatabase.getInstance(BasicApp.context).extendDao(), Type.Alarm
48 | )
49 | }
50 |
51 | /** BackupRepository */
52 | single(named("backupR")) {
53 | BackupRepository(
54 | AppDatabase.getInstance(BasicApp.context).backupDao()
55 | )
56 | }
57 |
58 | /** SyncSpRepo */
59 | single(named("syncSpR")) {
60 | SyncSp(
61 | AppDatabase.getInstance(BasicApp.context).appStDao(),
62 | AppDatabase.getInstance(BasicApp.context).extendDao()
63 | )
64 | }
65 |
66 | }
67 |
68 | var viewModel = module {
69 |
70 | viewModel(named("AppVm")) {
71 | AppViewModel()
72 | }
73 |
74 | viewModel(named("SyncStVm")) {
75 | SyncStViewModel()
76 | }
77 |
78 | viewModel(named("SyncExVm")) {
79 | SyncExViewModel()
80 | }
81 | // MainViewModel
82 | viewModel(named("MainVm")) {
83 | MainViewModel()
84 | }
85 |
86 | viewModel(named("ExtendVm")) { (packageName: String, type: Type) ->
87 | FBaseViewModel(
88 | packageName,
89 | when (type) {
90 | Type.Wakelock -> get(named("wakelockER"))
91 | Type.Alarm -> get(named("alarmR"))
92 | else -> get(named("wakelockER"))
93 | }
94 | )
95 | }
96 |
97 | viewModel(named("HelpVm")) {
98 | HelpViewModel()
99 | }
100 |
101 | viewModel(named("AboutVm")) {
102 | AboutViewModel()
103 | }
104 |
105 | viewModel(named("SettingVm")) {
106 | SettingViewModel()
107 | }
108 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/AppDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 | import androidx.room.TypeConverters
8 | import androidx.room.migration.Migration
9 | import androidx.sqlite.db.SupportSQLiteDatabase
10 | import com.js.deepsleep.data.db.converter.Converters
11 | import com.js.deepsleep.data.db.dao.*
12 | import com.js.deepsleep.data.db.entity.AppInfo
13 | import com.js.deepsleep.data.db.entity.AppSt
14 | import com.js.deepsleep.data.db.entity.Extend
15 |
16 | @Database(
17 | entities = [AppInfo::class, AppSt::class, Extend::class],
18 | version = 2
19 | )
20 | @TypeConverters(Converters::class)
21 | abstract class AppDatabase : RoomDatabase() {
22 |
23 | abstract fun appDao(): AppDao
24 | abstract fun appInfoDao(): AppInfoDao
25 | abstract fun appStDao(): AppStDao
26 | abstract fun extendDao(): ExtendDao
27 | abstract fun backupDao(): BackupDao
28 |
29 | companion object {
30 | private const val DATABASE_NAME = "deepSleep"
31 |
32 | @Volatile
33 | private var instance: AppDatabase? = null
34 |
35 | fun getInstance(context: Context): AppDatabase =
36 | instance ?: synchronized(this) {
37 | instance ?: buildInstance(context).also {
38 | instance = it
39 | }
40 | }
41 |
42 | private fun buildInstance(context: Context) = Room.databaseBuilder(
43 | context.applicationContext, AppDatabase::class.java, DATABASE_NAME
44 | ).addMigrations(MIGRATION_1_2)
45 | .build()
46 |
47 |
48 | private val MIGRATION_1_2 = object : Migration(1, 2) {
49 | override fun migrate(database: SupportSQLiteDatabase) {
50 | database.execSQL(
51 | """
52 | CREATE TABLE IF NOT EXISTS appSt_tmp (
53 | `packageName_st` TEXT NOT NULL,
54 | `flag` INTEGER NOT NULL,
55 | `wakelock` INTEGER NOT NULL,
56 | `alarm` INTEGER NOT NULL,
57 | `service` INTEGER NOT NULL,
58 | `sync` INTEGER NOT NULL,
59 | `broadcast` INTEGER NOT NULL DEFAULT 0,
60 | PRIMARY KEY(`packageName_st`))
61 | """.trimMargin()
62 | )
63 | database.execSQL(
64 | """
65 | INSERT INTO appSt_tmp (packageName_st, flag, wakelock, alarm, service, sync)
66 | SELECT packageName_st, flag, wakelock, alarm, service, sync
67 | FROM appSt
68 | """.trimIndent()
69 | )
70 | database.execSQL("DROP TABLE appSt")
71 | database.execSQL("ALTER TABLE appSt_tmp RENAME TO appSt")
72 | }
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/converter/Converters.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.converter
2 |
3 | import androidx.room.TypeConverter
4 | import com.google.gson.reflect.TypeToken
5 | import com.js.deepsleep.BasicApp
6 |
7 | class Converters {
8 | @TypeConverter
9 | fun setToString(set: Set): String {
10 | return BasicApp.gson.toJson(set)
11 | }
12 |
13 | @TypeConverter
14 | fun stringToSet(str: String): Set {
15 | val listType = object : TypeToken>() {}.type
16 | return BasicApp.gson.fromJson(str, listType)
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/dao/AppDao.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Query
5 | import androidx.room.Transaction
6 | import com.js.deepsleep.data.db.entity.App
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @Dao
10 | interface AppDao {
11 | // for appFragment
12 | @Transaction
13 | @Query("select * from appInfo")
14 | fun loadApps(): Flow>
15 |
16 | @Transaction
17 | @Query("select * from appInfo where packageName = :packageName")
18 | fun loadApp(packageName: String): Flow
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/dao/AppInfoDao.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.dao
2 |
3 | import androidx.room.*
4 | import com.js.deepsleep.data.db.entity.AppInfo
5 |
6 | @Dao
7 | interface AppInfoDao {
8 | @Query("select * from appInfo")
9 | fun loadAppInfos(): List
10 |
11 | @Query("select * from appInfo where packageName = :packageName")
12 | fun loadAppInfo(packageName: String): AppInfo
13 |
14 | @Insert(onConflict = OnConflictStrategy.REPLACE)
15 | suspend fun insert(appInfos: MutableCollection)
16 |
17 | @Insert(onConflict = OnConflictStrategy.REPLACE)
18 | suspend fun insert(appInfo: AppInfo)
19 |
20 | @Delete
21 | suspend fun deleteAll(appInfos: MutableCollection)
22 |
23 | @Delete
24 | suspend fun delete(appInfo: AppInfo)
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/dao/AppStDao.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.dao
2 |
3 | import androidx.room.*
4 | import com.js.deepsleep.data.db.entity.AppSt
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | @Dao
8 | interface AppStDao {
9 | @Query("select * from appSt")
10 | fun loadAppSts(): Flow>
11 |
12 | @Query("select * from appSt where packageName_st = :packageName")
13 | fun loadAppSt(packageName: String): Flow
14 |
15 | @Insert(onConflict = OnConflictStrategy.REPLACE)
16 | suspend fun insert(appSts: List)
17 |
18 | @Insert(onConflict = OnConflictStrategy.REPLACE)
19 | suspend fun insert(appSt: AppSt)
20 |
21 | @Delete
22 | suspend fun delete(appSts: List)
23 |
24 | @Delete
25 | suspend fun delete(appSt: AppSt)
26 |
27 | // for test
28 | @Query("select * from appSt")
29 | suspend fun appSts(): List
30 |
31 | @Query("select * from appSt where packageName_st = :packageName")
32 | suspend fun AppSt(packageName: String): AppSt
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/dao/BackupDao.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy
6 | import androidx.room.Query
7 | import com.js.deepsleep.data.db.entity.AppSt
8 | import com.js.deepsleep.data.db.entity.Extend
9 |
10 | @Dao
11 | interface BackupDao {
12 | @Query("select * from appSt")
13 | fun backupAppSts(): List
14 |
15 | @Query("select * from extend")
16 | fun backupExtends(): List
17 |
18 | @Insert(onConflict = OnConflictStrategy.REPLACE)
19 | suspend fun restoreAppSts(appSts: List)
20 |
21 | @Insert(onConflict = OnConflictStrategy.REPLACE)
22 | suspend fun restoreExtends(extends1: List)
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/dao/ExtendDao.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.dao
2 |
3 | import androidx.room.*
4 | import com.js.deepsleep.data.db.entity.Extend
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | @Dao
8 | interface ExtendDao {
9 |
10 | // @Query("select * from extend where type = :type")
11 | // fun loadExtends(type: String): Flow
12 | @Query("select * from extend")
13 | fun loadExtends(): Flow>
14 |
15 | @Query("select * from extend where packageName_ex = :packageName and type = :type")
16 | fun loadExtend(packageName: String, type: String): Flow
17 |
18 | @Insert(onConflict = OnConflictStrategy.REPLACE)
19 | suspend fun insert(extend: Extend)
20 |
21 | @Insert(onConflict = OnConflictStrategy.REPLACE)
22 | suspend fun insert(extends1: List)
23 |
24 | @Delete
25 | suspend fun delete(extend: Extend)
26 |
27 | @Delete
28 | suspend fun delete(extends1: List)
29 |
30 | @Query("select * from extend where packageName_ex = :packageName and type = :type")
31 | fun getExtend(packageName: String, type: String): Extend?
32 |
33 | @Query("select * from extend")
34 | suspend fun Extends(): List
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/entity/App.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.entity
2 |
3 | import androidx.room.Embedded
4 | import androidx.room.Relation
5 |
6 | data class App(
7 | @Embedded
8 | var info: AppInfo,
9 | @Relation(
10 | parentColumn = "packageName",
11 | entityColumn = "packageName_st"
12 | )
13 | var st: AppSt?
14 | )
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/entity/AppInfo.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.entity
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 |
6 | // package 信息
7 | @Entity(tableName = "appInfo")
8 | data class AppInfo(
9 | @PrimaryKey
10 | var packageName: String = "",
11 | var uid: Int = 0,
12 | var label: String = "",
13 | var icon: Int = 0,
14 | var system: Boolean = false,
15 | var enabled: Boolean = false,
16 | var persistent: Boolean = false,
17 | var processName: String = ""
18 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/entity/AppSt.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.entity
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import java.io.Serializable
7 |
8 | @Entity(tableName = "appSt")
9 | data class AppSt(
10 | @PrimaryKey
11 | @ColumnInfo(name = "packageName_st")
12 | var packageName: String = "",
13 | var flag: Boolean = false,//标记应用是否有限制
14 | var wakelock: Boolean = false,
15 | var alarm: Boolean = false,
16 | var service: Boolean = false,
17 | var sync: Boolean = false,
18 | var broadcast: Boolean = false
19 | ) : Serializable
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/db/entity/Extend.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.db.entity
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import java.io.Serializable
6 |
7 | @Entity(tableName = "extend", primaryKeys = ["packageName_ex", "type"])
8 | data class Extend(
9 | @ColumnInfo(name = "packageName_ex")
10 | var packageName: String = "",
11 | var type: String = "",
12 | var allowList: Set = mutableSetOf(),
13 | var blockList: Set = mutableSetOf(),
14 | var rE: Set = mutableSetOf()
15 | ) : Serializable
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/provider/DSContentProvider.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.provider
2 |
3 | import android.content.ContentProvider
4 | import android.content.ContentValues
5 | import android.database.Cursor
6 | import android.net.Uri
7 | import android.os.Bundle
8 |
9 | class DSContentProvider : ContentProvider() {
10 | override fun onCreate(): Boolean {
11 | return true
12 | }
13 |
14 | override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
15 | //无序处理
16 | if (extras == null) {
17 | return null
18 | }
19 | return context?.let { ProviderHandler.getInstance(it).getMethod(method, extras) }
20 | }
21 |
22 | override fun query(
23 | uri: Uri, projection: Array?, selection: String?,
24 | selectionArgs: Array?, sortOrder: String?
25 | ): Cursor? {
26 | return null
27 | }
28 |
29 | override fun insert(uri: Uri, values: ContentValues?): Uri {
30 | return uri
31 | }
32 |
33 | override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int {
34 | return 0
35 | }
36 |
37 | override fun getType(uri: Uri): String? {
38 | return null
39 | }
40 |
41 | override fun update(
42 | uri: Uri, values: ContentValues?, selection: String?,
43 | selectionArgs: Array?
44 | ): Int {
45 | return 0
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/provider/Provider.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.provider
2 |
3 | enum class ProviderMethod(var value: String) {
4 | GetAppSt("GetAppSt"),
5 | GetExtends("GetExtends")
6 | }
7 |
8 | object PParameters {
9 | const val packageName: String = "packageName"
10 | const val appSt: String = "appSt"
11 | const val wakelock: String = "wakelock"
12 | const val alarm: String = "alarm"
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/provider/ProviderHandler.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.provider
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import androidx.annotation.VisibleForTesting
6 | import com.js.deepsleep.tools.LogUtil
7 | import com.js.deepsleep.tools.Type
8 | import com.js.deepsleep.data.db.AppDatabase
9 | import com.js.deepsleep.data.db.entity.Extend
10 | import kotlinx.coroutines.runBlocking
11 |
12 | class ProviderHandler(
13 | context: Context
14 | ) {
15 | private val tag = "ProviderHandler"
16 |
17 | private var db: AppDatabase = AppDatabase.getInstance(context)
18 |
19 | companion object {
20 | @Volatile
21 | private var instance: ProviderHandler? = null
22 |
23 | fun getInstance(context: Context): ProviderHandler {
24 | if (instance == null) {
25 | instance = ProviderHandler(context)
26 | }
27 | return instance!!
28 | }
29 | }
30 |
31 | fun getMethod(methodName: String, bundle: Bundle): Bundle? {
32 | return when (methodName) {
33 | ProviderMethod.GetAppSt.value -> getAppSt(bundle)
34 | ProviderMethod.GetExtends.value -> getExtends(bundle)
35 | "test" -> test(bundle)
36 | else -> null
37 | }
38 | }
39 |
40 | @VisibleForTesting
41 | fun test(bundle: Bundle): Bundle {
42 | val test = bundle.get("Test") as String?
43 |
44 | LogUtil.d(tag, "$test")
45 |
46 | val tmp = Bundle()
47 | tmp.putString("Test", "Test")
48 | return tmp
49 | }
50 |
51 | // 获取 appst
52 | private fun getAppSt(bundle: Bundle): Bundle {
53 | val packageName: String = getPackageName(bundle)
54 | val tmp = runBlocking {
55 | try {
56 | db.appStDao().AppSt(packageName)
57 | } catch (e: Exception) {
58 | null
59 | }
60 | }
61 | return Bundle().apply {
62 | this.putSerializable(PParameters.appSt, tmp)
63 | }
64 | }
65 |
66 | private fun getExtends(bundle: Bundle): Bundle {
67 | val packageName: String = getPackageName(bundle)
68 |
69 | val wakelockEx = runBlocking {
70 | getExtend(packageName, Type.Wakelock)
71 | }
72 |
73 | val alarmEx = runBlocking {
74 | getExtend(packageName, Type.Alarm)
75 | }
76 |
77 | return Bundle().apply {
78 | this.putSerializable(PParameters.wakelock, wakelockEx)
79 | this.putSerializable(PParameters.alarm, alarmEx)
80 | }
81 | }
82 |
83 | private fun getPackageName(bundle: Bundle): String {
84 | return bundle.getString(PParameters.packageName, "")
85 | }
86 |
87 | private suspend fun getExtend(packageName: String, type: Type): Extend? {
88 | return try {
89 | db.extendDao().getExtend(packageName, type.value)
90 | } catch (e: Exception) {
91 | null
92 | }
93 | }
94 |
95 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/app/AppAR.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.app
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.pm.ApplicationInfo
5 | import android.content.pm.PackageManager
6 | import androidx.collection.ArrayMap
7 | import com.js.deepsleep.BasicApp
8 | import com.js.deepsleep.data.db.dao.AppDao
9 | import com.js.deepsleep.data.db.dao.AppInfoDao
10 | import com.js.deepsleep.data.db.dao.AppStDao
11 | import com.js.deepsleep.data.db.entity.App
12 | import com.js.deepsleep.data.db.entity.AppInfo
13 | import com.js.deepsleep.data.db.entity.AppSt
14 | import kotlinx.coroutines.Dispatchers
15 | import kotlinx.coroutines.flow.Flow
16 | import kotlinx.coroutines.flow.map
17 | import kotlinx.coroutines.withContext
18 |
19 | class AppAR(
20 | private val appDao: AppDao,
21 | private val appInfoDao: AppInfoDao,
22 | private val appStDao: AppStDao
23 | ) : AppRepo {
24 |
25 | private val pm: PackageManager = BasicApp.context.packageManager
26 |
27 | override fun getApps(): Flow> {
28 | return appDao.loadApps().map { list ->
29 | list.map {
30 | if (it.st == null) {
31 | it.st = AppSt(it.info.packageName)
32 | }
33 | it
34 | }
35 | }
36 | }
37 |
38 | override suspend fun setAppSt(appSt: AppSt) {
39 | appStDao.insert(appSt)
40 | }
41 |
42 | override suspend fun syncAppList() = withContext(Dispatchers.Default) {
43 | val dbAppInfos = getDBAppInfos()//db AppInfos
44 | val sysAppInfos = getSysAppInfos()//system AppInfos
45 |
46 | //取差集更新删除
47 | insertAll(sysAppInfos.keys subtract dbAppInfos.keys, sysAppInfos)
48 | deleteAll(dbAppInfos.keys subtract sysAppInfos.keys, dbAppInfos)
49 | }
50 |
51 | override suspend fun getAppInfo(packageName: String): AppInfo {
52 | return appInfoDao.loadAppInfo(packageName)
53 | }
54 |
55 | /**db 插入新应用*/
56 | private suspend fun insertAll(
57 | packageNames: Set,
58 | sysAppInfos: ArrayMap
59 | ) = withContext(Dispatchers.IO) {
60 | if (packageNames.isNotEmpty()) {
61 | sysAppInfos.filter { it.key in packageNames }.let {
62 | appInfoDao.insert(it.values as MutableCollection)
63 | }
64 | }
65 | }
66 |
67 | /**db 删除卸载应用*/
68 | private suspend fun deleteAll(
69 | packageNames: Set,
70 | dbAppInfos: ArrayMap
71 | ) = withContext(Dispatchers.IO) {
72 | if (packageNames.isNotEmpty()) {
73 | dbAppInfos.filter { it.key in packageNames }.let {
74 | appInfoDao.deleteAll(it.values as MutableCollection)
75 | }
76 | }
77 | }
78 |
79 | // 获取全部 system AppInfos
80 | @SuppressLint("QueryPermissionsNeeded")
81 | private suspend fun getSysAppInfos(): ArrayMap =
82 | withContext(Dispatchers.IO) {
83 | val sysAppInfo = ArrayMap()
84 |
85 | // LogUtil.d("test2", "${pm.getInstalledApplications(0).size}")
86 |
87 | pm.getInstalledApplications(0).forEach {
88 | sysAppInfo[it.packageName] = getSysAppInfo(it)
89 | }
90 |
91 | return@withContext sysAppInfo
92 | }
93 |
94 | // 获取全部数据库 AppInfos
95 | private suspend fun getDBAppInfos(): ArrayMap =
96 | withContext(Dispatchers.IO) {
97 | val dbAppInfos = ArrayMap()
98 | appInfoDao.loadAppInfos().forEach {
99 | dbAppInfos[it.packageName] = it
100 | }
101 | return@withContext dbAppInfos
102 | }
103 |
104 | //获取单个 AppInfo
105 | private fun getSysAppInfo(ai: ApplicationInfo): AppInfo {
106 | val easting = pm.getApplicationEnabledSetting(ai.packageName)
107 | val enabled = ai.enabled &&
108 | (easting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT ||
109 | easting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
110 | val persistent =
111 | ai.flags and ApplicationInfo.FLAG_PERSISTENT != 0 || "android" == ai.packageName
112 | val system = ai.flags and
113 | (ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
114 |
115 | return AppInfo(
116 | ai.packageName,
117 | ai.uid,
118 | pm.getApplicationLabel(ai) as String,
119 | ai.icon,
120 | system,
121 | enabled,
122 | persistent,
123 | ai.processName
124 | )
125 | }
126 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/app/AppRepo.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.app
2 |
3 | import com.js.deepsleep.data.db.entity.App
4 | import com.js.deepsleep.data.db.entity.AppInfo
5 | import com.js.deepsleep.data.db.entity.AppSt
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | interface AppRepo {
9 | fun getApps(): Flow>
10 | suspend fun getAppInfo(packageName: String): AppInfo
11 | suspend fun setAppSt(appSt: AppSt)
12 | suspend fun syncAppList()
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/backup/AppBackup.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.backup
2 |
3 | import com.js.deepsleep.data.db.entity.AppSt
4 | import com.js.deepsleep.data.db.entity.Extend
5 |
6 | data class AppBackup(
7 | var appSts: List = mutableListOf(),
8 | var extends: List = mutableListOf()
9 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/backup/BackupRepository.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.backup
2 |
3 | import com.js.deepsleep.data.db.dao.BackupDao
4 | import kotlinx.coroutines.Dispatchers
5 | import kotlinx.coroutines.withContext
6 |
7 | class BackupRepository(private val backupDao: BackupDao) {
8 | //返回 AppBackup
9 | suspend fun getBackup(extendEnable: Boolean): AppBackup = withContext(Dispatchers.IO) {
10 | AppBackup().apply {
11 | this.appSts = backupDao.backupAppSts()
12 | if (extendEnable) this.extends = backupDao.backupExtends()
13 | }
14 | }
15 |
16 | //恢复 AppBackup
17 | suspend fun restoreBackup(appBackup: AppBackup) = withContext(Dispatchers.IO) {
18 | if (appBackup.appSts.isNotEmpty()) backupDao.restoreAppSts(appBackup.appSts)
19 | if (appBackup.extends.isNotEmpty()) backupDao.restoreExtends(appBackup.extends)
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/extend/ER.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.extend
2 |
3 | import com.js.deepsleep.tools.Type
4 | import com.js.deepsleep.data.db.dao.ExtendDao
5 | import com.js.deepsleep.data.db.entity.Extend
6 | import kotlinx.coroutines.flow.Flow
7 | import kotlinx.coroutines.flow.map
8 |
9 | class ER(private val extendDao: ExtendDao, private val type: Type) : ExtendRepo {
10 |
11 | override fun getExtend(packageName: String): Flow {
12 | // LogUtil.d("test13", "$type")
13 | return extendDao.loadExtend(packageName, type.value).map {
14 | it ?: Extend(packageName, type.value).apply { extendDao.insert(this) }
15 | }
16 | }
17 |
18 | override fun getExtend(packageName: String, type: Type): Extend? {
19 | return extendDao.getExtend(packageName, type.value)
20 | }
21 |
22 | override suspend fun setExtend(extend: Extend) {
23 | // LogUtil.d("test12", "$extend")
24 | extendDao.insert(extend)
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/extend/ExtendRepo.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.extend
2 |
3 | import com.js.deepsleep.data.db.entity.Extend
4 | import com.js.deepsleep.tools.Type
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | interface ExtendRepo {
8 | fun getExtend(packageName: String): Flow
9 | fun getExtend(packageName: String, type: Type): Extend?
10 | suspend fun setExtend(extend: Extend)
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/syncsp/SyncSp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.syncsp
2 |
3 | import com.js.deepsleep.data.db.dao.AppStDao
4 | import com.js.deepsleep.data.db.dao.ExtendDao
5 | import com.js.deepsleep.data.db.entity.AppSt
6 | import com.js.deepsleep.data.db.entity.Extend
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | class SyncSp(private val appStDao: AppStDao, private val extendDao: ExtendDao) : SyncSpRepo {
10 | override suspend fun getAllAppSt(): Flow> {
11 | return appStDao.loadAppSts()
12 | }
13 |
14 | override suspend fun getAllAppStEx(): Flow> {
15 | return extendDao.loadExtends()
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/data/repository/syncsp/SyncSpRepo.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.data.repository.syncsp
2 |
3 | import com.js.deepsleep.data.db.entity.AppSt
4 | import com.js.deepsleep.data.db.entity.Extend
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | interface SyncSpRepo {
8 | suspend fun getAllAppSt(): Flow>
9 | suspend fun getAllAppStEx(): Flow>
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/tools/Enum.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.tools
2 |
3 | enum class Type(var value: String) {
4 | Wakelock("Wakelock"), Alarm("Alarm"), Service("Service"), Sync("Sync"), Broadcast("Broadcast")
5 | }
6 |
7 | enum class AppType(var type: Int) {
8 | All(0), User(1), System(2), Restricted(3), Extend(4)
9 | }
10 |
11 | enum class Sort(var type: Int) {
12 | Name(0), Count(1)
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/tools/LogUtil.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.tools
2 |
3 | import android.util.Log
4 |
5 | class LogUtil {
6 | companion object {
7 | private const val VERBOSE = 1 //啰嗦,等级最低的
8 |
9 | private const val DEBUG = 2 //调试
10 |
11 | private const val INFO = 3 //信息
12 |
13 | private const val WARN = 4 //警告
14 |
15 | private const val ERROR = 5 //错误
16 |
17 | private const val NOTHING = 6 //什么也不打印出来
18 |
19 | private const val level = DEBUG //LEVEL:标准
20 |
21 |
22 | fun v(tag: String, msg: String) {
23 | if (level <= VERBOSE) { //如果大于或者等于定义的标准就打印出来
24 | Log.v(tag, msg)
25 | }
26 | }
27 |
28 | fun d(tag: String, msg: String) {
29 | if (level <= DEBUG) {
30 | Log.d(tag, msg)
31 | }
32 | }
33 |
34 | fun i(tag: String, msg: String) {
35 | if (level <= INFO) {
36 | Log.i(tag, msg)
37 | }
38 | }
39 |
40 | fun w(tag: String, msg: String) {
41 | if (level <= WARN) {
42 | Log.w(tag, msg)
43 | }
44 | }
45 |
46 | fun e(tag: String, msg: String) {
47 | if (level <= ERROR) {
48 | Log.e(tag, msg)
49 | }
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/tools/SPTools.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.tools
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import com.js.deepsleep.BasicApp
6 |
7 |
8 | class SPTools {
9 | companion object {
10 | const val SP_NAME = "DeepSleep"
11 |
12 | private const val default_str = ""
13 | private const val default_bool = true
14 |
15 | @SuppressLint("WorldReadableFiles")
16 | private var prefs = try {
17 | // MODE_WORLD_READABLE, New XSharedPreferences
18 | BasicApp.context.getSharedPreferences(SP_NAME, Context.MODE_WORLD_READABLE)
19 | } catch (e: SecurityException) {
20 | null
21 | }
22 |
23 | fun getString(key: String, defaultValue: String = default_str): String {
24 |
25 | return prefs?.getString(key, defaultValue) ?: defaultValue
26 | }
27 |
28 | fun setString(key: String, value: String) {
29 | with(prefs?.edit() ?: return) {
30 | putString(key, value)
31 | // apply()
32 | commit()
33 | }
34 | }
35 |
36 | fun getBoolean(key: String, defaultValue: Boolean = default_bool): Boolean {
37 | return prefs?.getBoolean(key, defaultValue) ?: defaultValue
38 | }
39 |
40 | fun setBoolean(key: String, value: Boolean) {
41 | with(prefs?.edit() ?: return) {
42 | putBoolean(key, value)
43 | // apply()
44 | commit()
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/tools/Util.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.tools
2 |
3 | import android.view.Menu
4 | import androidx.preference.PreferenceManager
5 | import com.js.deepsleep.BasicApp
6 | import java.util.*
7 |
8 | // filter list
9 | inline fun List.appType(status: (T) -> Boolean): List {
10 | return this.filter { status(it) }
11 | }
12 |
13 | // search list
14 | inline fun List.search(query: String, text: (T) -> String): List {
15 | /*lowerCase and no " " */
16 | val q = query.lowercase(Locale.ROOT).trim { it <= ' ' }
17 | if (q == "") {
18 | return this
19 | }
20 | return this.filter {
21 | text(it).lowercase(Locale.ROOT).contains(q)
22 | }
23 | }
24 |
25 | // sort list
26 | fun List.sort(comparator: Comparator): List {
27 | return this.sortedWith(comparator)
28 | }
29 |
30 | // 设置 menu 不可见
31 | fun menuGone(menu: Menu, set: Set) {
32 | set.forEach {
33 | val filterUser = menu.findItem(it)
34 | filterUser.isVisible = false
35 | }
36 | }
37 |
38 | // 获取setting 状态
39 |
40 | fun getSetting(key: String): Boolean {
41 | val sharedPreferences =
42 | PreferenceManager.getDefaultSharedPreferences(BasicApp.context)
43 | return sharedPreferences.getBoolean(key, false)
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/tools/XProvider.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.tools
2 |
3 | import android.app.ActivityManager
4 | import android.content.Context
5 | import android.net.Uri
6 | import android.os.Binder
7 | import android.os.Bundle
8 | import android.os.RemoteException
9 | import android.os.UserHandle
10 | import android.provider.Settings
11 | import android.widget.Toast
12 | import com.js.deepsleep.BasicApp
13 | import com.js.deepsleep.R
14 | import java.lang.reflect.Method
15 |
16 | private const val TAG = "XProvider"
17 | private const val PER_USER_RANGE = 100000
18 |
19 | class XProvider {
20 | companion object {
21 | @Throws(RemoteException::class, IllegalArgumentException::class)
22 | fun call(context: Context?, method: String?, extras: Bundle?): Bundle? {
23 | return if ((context != null) and (method != null) and (extras != null)) {
24 | handle(context!!, method!!, extras!!)
25 | } else null
26 |
27 | }
28 |
29 | // handle method call
30 | private fun handle(context: Context, method: String, extras: Bundle): Bundle {
31 | return when (method) {
32 | XProviderMethods.forceStop -> xForceStop(context, extras)
33 | else -> Bundle()
34 | }
35 | }
36 | }
37 | }
38 |
39 | // all method's name
40 | object XProviderMethods {
41 | const val forceStop: String = "forceStop"
42 | }
43 |
44 | // XProvider.uri
45 | fun getURI(): Uri {
46 | return Settings.System.CONTENT_URI
47 | }
48 |
49 | private fun getUserId(uid: Int): Int {
50 | return try {
51 | // public static final int getUserId(int uid)
52 | val method =
53 | UserHandle::class.java.getDeclaredMethod("getUserId", Int::class.javaPrimitiveType)
54 | method.invoke(null, uid) as Int
55 | } catch (ex: Throwable) {
56 | return uid / PER_USER_RANGE
57 | }
58 | }
59 |
60 | private fun xForceStop(context: Context, extras: Bundle): Bundle {
61 | val packageName = extras.getString("packageName")
62 | val uid = extras.getInt("uid")
63 | val userid = getUserId(uid)
64 |
65 | forceStop(context, packageName!!, userid)
66 | return forceStop(context, packageName, userid)
67 | }
68 |
69 | // force stop app
70 | @Throws(Throwable::class)
71 | private fun forceStop(context: Context, packageName: String, userid: Int): Bundle {
72 | // Access activity manager as system user
73 | val id = Binder.clearCallingIdentity()
74 | val result = Bundle()
75 | try {
76 | // public void forceStopPackageAsUser(String packageName, int userId)
77 | val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
78 | val mForceStop: Method = am.javaClass.getMethod(
79 | "forceStopPackageAsUser",
80 | String::class.java,
81 | Int::class.javaPrimitiveType
82 | )
83 | mForceStop.invoke(am, packageName, userid)
84 | //if success
85 | result.putString("packageName", packageName)
86 | } finally {
87 | Binder.restoreCallingIdentity(id)
88 | }
89 | return result
90 | }
91 |
92 | fun callStopApp(packageName: String, uid: Int): Boolean {
93 |
94 | val args = Bundle()
95 | args.putString("packageName", packageName)
96 | args.putInt("uid", uid)
97 |
98 | val uri = getURI()
99 | val contentResolver = BasicApp.context.contentResolver
100 |
101 | val result: Bundle? = contentResolver.call(uri, "DeepSleep", XProviderMethods.forceStop, args)
102 |
103 | return result?.getString("packageName") == packageName
104 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/about/About.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.about
2 |
3 | import com.js.deepsleep.BasicApp
4 | import com.js.deepsleep.BuildConfig
5 | import com.js.deepsleep.R
6 |
7 | data class About(
8 | var app_name: String = BasicApp.context.getString(R.string.app_name),
9 | var app_version: String = BuildConfig.VERSION_NAME,
10 | var source: String = BasicApp.context.getString(R.string.SourceCodeUrl),
11 | var license: String = "GNU General Public License version 3",
12 | var contact: String = BasicApp.context.getString(R.string.help_contact)
13 | )
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/about/AboutFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.about
2 |
3 | import android.os.Bundle
4 | import android.text.method.LinkMovementMethod
5 | import android.view.*
6 | import androidx.fragment.app.Fragment
7 | import com.js.deepsleep.R
8 | import com.js.deepsleep.tools.menuGone
9 | import com.js.deepsleep.databinding.FragmentAboutBinding
10 | import org.koin.androidx.viewmodel.ext.android.viewModel
11 | import org.koin.core.qualifier.named
12 |
13 |
14 | class AboutFragment : Fragment() {
15 |
16 | private val viewModel: AboutViewModel by viewModel(named("AboutVm"))
17 |
18 | private lateinit var binding: FragmentAboutBinding
19 |
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | setHasOptionsMenu(true)
23 | super.onCreate(savedInstanceState)
24 | }
25 |
26 | override fun onCreateView(
27 | inflater: LayoutInflater, container: ViewGroup?,
28 | savedInstanceState: Bundle?
29 | ): View {
30 | binding = FragmentAboutBinding.inflate(inflater, container, false)
31 | context ?: return binding.root
32 | binding.vm = viewModel
33 | binding.sourcecode.movementMethod = LinkMovementMethod.getInstance()
34 | return binding.root
35 | }
36 |
37 | // 关闭多余 toolbar 菜单
38 | @Deprecated("Deprecated in Java")
39 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
40 | menuGone(menu, setOf(R.id.menu_filter, R.id.search))
41 | super.onCreateOptionsMenu(menu, inflater)
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/about/AboutViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.about
2 |
3 | import androidx.lifecycle.ViewModel
4 |
5 | class AboutViewModel : ViewModel() {
6 | var about = About()
7 |
8 | // fun aliPay() {
9 | // AliPay(BasicApp.context).jumpAlipay()
10 | // }
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/app/AppFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.app
2 |
3 | import android.graphics.Color
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.LiveData
10 | import androidx.lifecycle.lifecycleScope
11 | import androidx.recyclerview.widget.DividerItemDecoration
12 | import androidx.recyclerview.widget.RecyclerView
13 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
14 | import com.js.deepsleep.databinding.FragmentAppBinding
15 | import com.js.deepsleep.ui.mainactivity.MainViewModel
16 | import kotlinx.coroutines.Dispatchers
17 | import kotlinx.coroutines.launch
18 | import kotlinx.coroutines.runBlocking
19 | import org.koin.androidx.viewmodel.ext.android.sharedViewModel
20 | import org.koin.androidx.viewmodel.ext.android.viewModel
21 | import org.koin.core.qualifier.named
22 |
23 |
24 | class AppFragment : Fragment() {
25 |
26 | private lateinit var binding: FragmentAppBinding
27 |
28 | private val viewModel: AppViewModel by viewModel(named("AppVm"))
29 | private val syncStViewModel: SyncStViewModel by viewModel(named("SyncStVm"))
30 |
31 | private val mainViewModel: MainViewModel by sharedViewModel(named("MainVm"))
32 |
33 | override fun onCreate(savedInstanceState: Bundle?) {
34 | super.onCreate(savedInstanceState)
35 | addSubscription(viewModel.apps)
36 | addSubscription(mainViewModel.type)
37 | addSubscription(mainViewModel.query)
38 | addSubscription(mainViewModel.sort)
39 |
40 | syncStViewModel.syncSp()
41 | }
42 |
43 | override fun onCreateView(
44 | inflater: LayoutInflater, container: ViewGroup?,
45 | savedInstanceState: Bundle?
46 | ): View {
47 |
48 | binding = FragmentAppBinding.inflate(inflater, container, false)
49 | context ?: return binding.root
50 |
51 | //绑定 vm
52 | binding.vm = viewModel
53 | //绑定声明周期
54 | binding.lifecycleOwner = this
55 | //分割线
56 | setItemDecoration(binding.appList)
57 | // 下拉刷新
58 | setSwipeRefreshLayout(binding.refresh)
59 |
60 | return binding.root
61 | }
62 |
63 | override fun onDestroy() {
64 | super.onDestroy()
65 | removeSubscription(viewModel.apps)
66 | removeSubscription(mainViewModel.type)
67 | removeSubscription(mainViewModel.query)
68 | removeSubscription(mainViewModel.sort)
69 | }
70 |
71 | //viewModel.list 添加订阅
72 | private fun addSubscription(liveData: LiveData) {
73 | viewModel.list.addSource(liveData) {
74 | viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
75 | viewModel.list.postValue(list() ?: list())
76 | }
77 | }
78 | }
79 |
80 | //viewModel.list 取消订阅
81 | private fun removeSubscription(liveData: LiveData) {
82 | viewModel.list.removeSource(liveData)
83 | }
84 |
85 | //读取值
86 | private fun list() = viewModel.apps.value?.let { apps ->
87 | mainViewModel.type.value?.let { type ->
88 | mainViewModel.query.value?.let { query ->
89 | mainViewModel.sort.value?.let { sort ->
90 | viewModel.getList(
91 | apps, type, query, sort
92 | )
93 | }
94 | }
95 | }
96 | }
97 |
98 |
99 | //SwipeRefresh
100 | private fun setSwipeRefreshLayout(swipeRefreshLayout: SwipeRefreshLayout) {
101 | swipeRefreshLayout.setDistanceToTriggerSync(600)
102 | //color
103 | swipeRefreshLayout.setColorSchemeColors(Color.BLUE)
104 | // 关闭刷新
105 | swipeRefreshLayout.setOnRefreshListener {
106 | // 同步应用列表
107 | runBlocking {
108 | viewModel.syncApp()
109 | }
110 | swipeRefreshLayout.isRefreshing = false
111 | }
112 | }
113 |
114 | // 分割线
115 | private fun setItemDecoration(recyclerView: RecyclerView) = recyclerView.addItemDecoration(
116 | DividerItemDecoration(
117 | recyclerView.context,
118 | DividerItemDecoration.VERTICAL
119 | )
120 | )
121 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/app/AppViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.app
2 |
3 | import android.os.Bundle
4 | import android.widget.Toast
5 | import androidx.annotation.MainThread
6 | import androidx.lifecycle.MediatorLiveData
7 | import androidx.lifecycle.ViewModel
8 | import androidx.lifecycle.asLiveData
9 | import androidx.lifecycle.viewModelScope
10 | import com.js.deepsleep.BasicApp
11 | import com.js.deepsleep.R
12 | import com.js.deepsleep.data.db.entity.App
13 | import com.js.deepsleep.data.db.entity.AppInfo
14 | import com.js.deepsleep.data.db.entity.AppSt
15 | import com.js.deepsleep.data.repository.app.AppRepo
16 | import com.js.deepsleep.data.repository.extend.ExtendRepo
17 | import com.js.deepsleep.tools.*
18 | import kotlinx.coroutines.Dispatchers
19 | import kotlinx.coroutines.Job
20 | import kotlinx.coroutines.launch
21 | import kotlinx.coroutines.withContext
22 | import org.koin.core.component.KoinComponent
23 | import org.koin.core.component.inject
24 | import org.koin.core.qualifier.named
25 | import java.text.Collator
26 | import java.util.*
27 | import kotlin.collections.set
28 |
29 |
30 | class AppViewModel : ViewModel(), KoinComponent {
31 |
32 |
33 | private val appAR: AppRepo by inject(named("AppR"))
34 |
35 | private val extendR: ExtendRepo by inject(named("wakelockER"))
36 |
37 | private val handleApp = HandleApp(this)
38 |
39 | // 更新应用列表
40 | init {
41 | syncApp()
42 | }
43 |
44 | // 更新应用列表
45 | fun syncApp() {
46 | viewModelScope.launch(Dispatchers.Default) {
47 | appAR.syncAppList()
48 | }
49 | }
50 |
51 | // 保存 appSt
52 | fun saveSt(appSt: AppSt) {
53 | viewModelScope.launch(Dispatchers.Default) {
54 | appSt.let {
55 | it.flag = it.wakelock || it.alarm || it.service || it.sync || it.broadcast
56 | }
57 | appAR.setAppSt(appSt)
58 | }
59 | }
60 |
61 | // call system force stop app
62 | fun stopApp(appInfo: AppInfo) {
63 |
64 | if (appInfo.persistent || appInfo.system) {// if app is system or persistent
65 | return
66 | }
67 | viewModelScope.launch(Dispatchers.Default) {
68 | val result = callStopApp(appInfo.packageName, appInfo.uid)
69 | withContext(Dispatchers.Main) {
70 | isSuccess(result)
71 | }
72 | }
73 | }
74 |
75 | private fun isSuccess(result: Boolean) {
76 | if (!result) {
77 | Toast.makeText(
78 | BasicApp.context,
79 | BasicApp.context.getString(R.string.forcestopEnable),
80 | Toast.LENGTH_SHORT
81 | ).show()
82 | }
83 | }
84 |
85 | val apps = appAR.getApps().asLiveData()
86 |
87 | // recyclerview 的 list
88 | var list = MediatorLiveData>()
89 |
90 | fun getList(apps: List, type: AppType, query: String, sort: Sort): List {
91 | return apps.appType(appType(type))
92 | .search(query, ::search)
93 | .sort(sort(sort))
94 | .toItemApps()
95 | }
96 |
97 | // load 状态
98 | private val map = mutableMapOf()
99 | private fun getLoad(packageName: String): Boolean = map.getOrPut(packageName) { false }
100 | fun setLoad(itemApp: ItemApp) {
101 | itemApp.load.apply { this.set(!this.get()) }
102 | map[itemApp.data.info.packageName] = itemApp.load.get()
103 | }
104 |
105 |
106 | private fun List.toItemApps(): List {
107 | return this.map { app ->
108 | ItemApp(
109 | app,
110 | handleApp,
111 | R.layout.item_app
112 | ).apply { this.load.set(getLoad(this.data.info.packageName)) }
113 | }
114 | }
115 |
116 | //筛选 App 类型
117 | private fun appType(a: AppType): (App) -> Boolean {
118 | return when (a) {
119 | AppType.User -> ::useApp
120 | AppType.System -> ::systemApp
121 | AppType.Restricted -> ::restricted
122 | AppType.All -> ::allApp
123 | AppType.Extend -> ::extendApp
124 | }
125 | }
126 |
127 | private fun useApp(app: App) = !app.info.system
128 | private fun systemApp(app: App) = app.info.system
129 | private fun restricted(app: App) = app.st!!.flag
130 | private fun allApp(app: App) = true
131 |
132 |
133 | private fun extendApp(app: App): Boolean {
134 | val wakelockEX = extendR.getExtend(app.info.packageName, Type.Wakelock)
135 | val alarmEX = extendR.getExtend(app.info.packageName, Type.Alarm)
136 | if (wakelockEX != null && alarmEX != null) {
137 | if (wakelockEX.allowList.isNotEmpty() || alarmEX.allowList.isNotEmpty()
138 | || wakelockEX.blockList.isNotEmpty() || alarmEX.blockList.isNotEmpty()
139 | || wakelockEX.rE.isNotEmpty() || alarmEX.rE.isNotEmpty()
140 | ) {
141 | return true
142 | }
143 | }
144 | return false
145 | }
146 |
147 | // 搜索
148 | private fun search(app: App) = "${app.info.label}${app.info.packageName}"
149 |
150 |
151 | // 排序
152 | private fun sort(sort: Sort): Comparator {
153 | return when (sort) {
154 | Sort.Name -> sortByName()
155 | else -> sortByName()
156 | }
157 | }
158 |
159 | private fun sortByName(): Comparator {
160 | return Comparator { s1, s2 ->
161 | Collator.getInstance(Locale.getDefault()).compare(s1.info.label, s2.info.label)
162 | }
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/app/HandleApp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.app
2 |
3 | import android.view.View
4 | import android.widget.Toast
5 | import androidx.navigation.findNavController
6 | import com.js.deepsleep.BasicApp
7 | import com.js.deepsleep.R
8 | import com.js.deepsleep.data.db.entity.App
9 | import com.js.deepsleep.data.db.entity.AppInfo
10 | import com.js.deepsleep.tools.getSetting
11 | import com.js.deepsleep.ui.databinding.item.BaseItemHandle
12 |
13 | class HandleApp(private val appViewModel: AppViewModel) : BaseItemHandle() {
14 | // 保存 Appst
15 | fun save(app: App) {
16 | app.st?.let { appViewModel.saveSt(it) }
17 | app.info.let {
18 | if (getSetting("ForceStopEnable")) {
19 | appViewModel.stopApp(it)
20 | }
21 | }
22 | }
23 |
24 | // 保存 load
25 | fun load(itemApp: ItemApp) {
26 | appViewModel.setLoad(itemApp)
27 | }
28 |
29 | fun onClick(view: View, appInfo: AppInfo) {
30 |
31 | // 拓展功能是否开启
32 | if (getSetting("ExtendEnable")) {
33 | // 跳转 extend
34 | val direction = AppFragmentDirections.actionAppFragmentToExtendFragment(
35 | appInfo.packageName,
36 | appInfo.label
37 | )
38 | view.findNavController().navigate(direction)
39 | }
40 | }
41 |
42 | fun onLongClick(view: View, appInfo: AppInfo): Boolean {
43 | // 拓展功能是否开启
44 | if (getSetting("ExtendEnable")) {
45 | val direction = AppFragmentDirections.actionAppFragmentToExtendFragment(
46 | appInfo.packageName,
47 | appInfo.label
48 | )
49 | view.findNavController().navigate(direction)
50 | } else {
51 | Toast.makeText(
52 | BasicApp.context,
53 | BasicApp.context.getString(R.string.extendEnable),
54 | Toast.LENGTH_SHORT
55 | ).show()
56 | }
57 | return true
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/app/ItemApp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.app
2 |
3 | import androidx.annotation.LayoutRes
4 | import androidx.databinding.ObservableBoolean
5 | import com.js.deepsleep.data.db.entity.App
6 | import com.js.deepsleep.data.db.entity.AppSt
7 | import com.js.deepsleep.ui.databinding.item.BaseItem
8 |
9 | class ItemApp(
10 | override var data: App,
11 | override val handle: HandleApp,
12 | @LayoutRes override val layoutId: Int
13 | ) : BaseItem(data, handle, layoutId) {
14 |
15 | // 点击状态
16 | var load = ObservableBoolean().apply { this.set(false) }
17 |
18 | override fun getID(): String {
19 | return data.info.packageName
20 | }
21 |
22 | override fun getContent(): Int {
23 | return when (data.st) {
24 | null -> 0
25 | else -> getStContent(data.st!!)
26 | }
27 | }
28 |
29 | // 获取 appSt 的不同
30 | private fun getStContent(appSt: AppSt): Int {
31 | return getFlag(appSt.alarm) +
32 | getFlag(appSt.wakelock) * 2 +
33 | getFlag(appSt.service) * 4 +
34 | getFlag(appSt.sync) * 8
35 | }
36 |
37 | private fun getFlag(boolean: Boolean): Int {
38 | return when (boolean) {
39 | true -> 1
40 | false -> 0
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/app/SyncStViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.app
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.js.deepsleep.tools.SPTools
6 | import com.js.deepsleep.tools.Type
7 | import com.js.deepsleep.data.db.entity.AppSt
8 | import com.js.deepsleep.data.repository.syncsp.SyncSpRepo
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import org.koin.core.component.KoinComponent
12 | import org.koin.core.component.inject
13 | import org.koin.core.qualifier.named
14 |
15 | class SyncStViewModel : ViewModel(), KoinComponent {
16 | private val syncSPR: SyncSpRepo by inject(named("syncSpR"))
17 |
18 | fun syncSp() {
19 | viewModelScope.launch(Dispatchers.IO) {
20 | syncSPR.getAllAppSt().collect { appSts ->
21 | appSts.map { appSt ->
22 | saveSt2SP(appSt)
23 | }
24 | // LogUtil.d("SyncStViewModel", "getSyncSp: ${appSts.size}")
25 | }
26 | }
27 | }
28 |
29 | private fun saveSt2SP(appSt: AppSt) {
30 | // LogUtil.d("SyncSt", "getSyncSp: ${appSt}")
31 |
32 | if (appSt.flag) { // if app has being limited
33 | SPTools.setBoolean("${appSt.packageName}_${Type.Wakelock}", appSt.wakelock)
34 | SPTools.setBoolean("${appSt.packageName}_${Type.Alarm}", appSt.alarm)
35 | SPTools.setBoolean("${appSt.packageName}_${Type.Service}", appSt.service)
36 | SPTools.setBoolean("${appSt.packageName}_${Type.Sync}", appSt.sync)
37 | SPTools.setBoolean("${appSt.packageName}_${Type.Broadcast}", appSt.broadcast)
38 | } else {
39 | if (SPTools.getBoolean("${appSt.packageName}_${Type.Wakelock}")) {
40 | SPTools.setBoolean("${appSt.packageName}_${Type.Wakelock}", appSt.wakelock)
41 | }
42 | if (SPTools.getBoolean("${appSt.packageName}_${Type.Alarm}")) {
43 | SPTools.setBoolean("${appSt.packageName}_${Type.Alarm}", appSt.alarm)
44 | }
45 | if (SPTools.getBoolean("${appSt.packageName}_${Type.Service}")) {
46 | SPTools.setBoolean("${appSt.packageName}_${Type.Service}", appSt.service)
47 | }
48 | if (SPTools.getBoolean("${appSt.packageName}_${Type.Sync}")) {
49 | SPTools.setBoolean("${appSt.packageName}_${Type.Sync}", appSt.sync)
50 | }
51 | if (SPTools.getBoolean("${appSt.packageName}_${Type.Broadcast}")) {
52 | SPTools.setBoolean("${appSt.packageName}_${Type.Broadcast}", appSt.broadcast)
53 | }
54 | }
55 | }
56 |
57 | // private fun setFlag(type: Type) {
58 | // SPTools.setBoolean("${appSt.packageName}_${Type.Wakelock}", appSt.wakelock)
59 | // }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/databinding/DataBind.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.databinding
2 |
3 | import android.R
4 | import android.net.Uri
5 | import android.widget.ImageView
6 | import androidx.databinding.BindingAdapter
7 | import androidx.databinding.InverseMethod
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.bumptech.glide.Glide
10 | import com.bumptech.glide.load.DecodeFormat
11 | import com.bumptech.glide.request.RequestOptions
12 | import com.js.deepsleep.data.db.entity.AppInfo
13 | import com.js.deepsleep.ui.databinding.item.BaseItem
14 |
15 |
16 | object DataBind {
17 | @JvmStatic
18 | @BindingAdapter("loadIcon")
19 | fun loadIcon(imageView: ImageView, appInfo: AppInfo) {
20 | val options = RequestOptions()
21 | .error(R.drawable.sym_def_app_icon)
22 | .placeholder(R.drawable.sym_def_app_icon)
23 | val uri = Uri.parse("android.resource://" + appInfo.packageName + "/" + appInfo.icon)
24 | Glide.with(imageView.context)
25 | .applyDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
26 | .load(uri)
27 | .apply(options)
28 | .into(imageView)
29 | }
30 |
31 | @JvmStatic
32 | @BindingAdapter("items")
33 | fun setRecyclerViewItems(
34 | recyclerView: RecyclerView,
35 | items: List?
36 | ) {
37 | var adapter = (recyclerView.adapter as? RecycleAdapter)
38 | if (adapter == null) {
39 | adapter = RecycleAdapter()
40 | recyclerView.adapter = adapter
41 | }
42 | // items 为空 orEmpty 返回空实例
43 | adapter.submitList(items.orEmpty())
44 | }
45 | }
46 |
47 | object Converter {
48 |
49 | @InverseMethod("stringToSet")
50 | @JvmStatic
51 | fun setToString(values: Set?): String {
52 | return if (values == null || values.isEmpty()) {
53 | "\n"
54 | } else {
55 | var tmp = ""
56 | values.forEach {
57 | tmp += "$it\n"
58 | }
59 | // tmp = tmp.substring(0, tmp.length - 1)
60 | tmp
61 | }
62 | }
63 |
64 | @JvmStatic
65 | fun stringToSet(value: String?): Set {
66 | return if (value == null || value == "\n") {
67 | mutableSetOf()
68 | } else {
69 | value.split("\n")
70 | .filter { it.matches(Regex("[^\n ]+")) }
71 | .toSet()
72 | // value.split('\n').toSet()
73 | }
74 | }
75 |
76 |
77 | }
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/databinding/DiffCallback.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.databinding
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import com.js.deepsleep.ui.databinding.item.BaseItem
5 |
6 | class DiffCallback : DiffUtil.ItemCallback() {
7 | /*Is it the same object*/
8 | override fun areItemsTheSame(
9 | oldItem: BaseItem,
10 | newItem: BaseItem
11 | ): Boolean {
12 | return oldItem.getID() == newItem.getID()
13 | }
14 |
15 | /*Whether the content is the same*/
16 | override fun areContentsTheSame(
17 | oldItem: BaseItem,
18 | newItem: BaseItem
19 | ): Boolean {
20 | return oldItem.getContent() == newItem.getContent()
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/databinding/MyLayoutManager.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.databinding
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import androidx.recyclerview.widget.LinearLayoutManager
6 | import androidx.recyclerview.widget.RecyclerView
7 | import androidx.recyclerview.widget.RecyclerView.Recycler
8 | import com.js.deepsleep.tools.LogUtil
9 |
10 | class MyLayoutManager : LinearLayoutManager {
11 | constructor(context: Context?) : super(context)
12 | constructor(context: Context?, orientation: Int, reverseLayout: Boolean) : super(
13 | context,
14 | orientation,
15 | reverseLayout
16 | )
17 |
18 | constructor(
19 | context: Context?,
20 | attrs: AttributeSet?,
21 | defStyleAttr: Int,
22 | defStyleRes: Int
23 | ) : super(context, attrs, defStyleAttr, defStyleRes)
24 |
25 | override fun onLayoutChildren(
26 | recycler: Recycler,
27 | state: RecyclerView.State
28 | ) {
29 | try {
30 | super.onLayoutChildren(recycler, state)
31 | } catch (e: IndexOutOfBoundsException) {
32 | LogUtil.d("test2", "$e")
33 | e.printStackTrace()
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/databinding/RecycleAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.databinding
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.ListAdapter
7 | import com.js.deepsleep.ui.databinding.item.BaseItem
8 |
9 | class RecycleAdapter : ListAdapter(DiffCallback()) {
10 |
11 | init {
12 | setHasStableIds(true)//表示每个 item 都有唯一 id
13 | }
14 |
15 | // viewType 代表 layoutId ,需要覆写 getItemViewType()
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
17 | return ViewHolder(
18 | DataBindingUtil.inflate(
19 | LayoutInflater.from(parent.context),
20 | viewType,
21 | parent,
22 | false
23 | )
24 | )
25 | }
26 |
27 | // 绑定
28 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
29 | holder.bind(getItem(position))
30 | }
31 |
32 | // 复写 getItemViewType 返回 layoutId
33 | override fun getItemViewType(position: Int): Int {
34 | return getItem(position).layoutId
35 | }
36 |
37 | // very import 防止重复条目
38 | override fun getItemId(position: Int): Long = position.toLong()
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/databinding/ViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.databinding
2 |
3 | import androidx.databinding.ViewDataBinding
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.js.deepsleep.BR
6 | import com.js.deepsleep.ui.databinding.item.BaseItem
7 |
8 | class ViewHolder(private var binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
9 | // 绑定
10 | fun bind(item: BaseItem?) {
11 | binding.setVariable(BR.item, item)
12 | binding.executePendingBindings()
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/databinding/item/BaseItem.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.databinding.item
2 |
3 | import androidx.annotation.LayoutRes
4 |
5 | open class BaseItem(
6 | open val data: Any,
7 | open val handle: BaseItemHandle,
8 | @LayoutRes open val layoutId: Int
9 | ) {
10 | open fun getID(): String = ""//两个item 是不是一个 item
11 | open fun getContent(): Int = 0 //同一个 item 内容是否有更新
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/databinding/item/BaseItemHandle.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.databinding.item
2 |
3 | import com.js.deepsleep.tools.LogUtil
4 |
5 | open class BaseItemHandle {
6 | fun onClick() {
7 | LogUtil.d("ItemHandle", "base")
8 | }
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/extend/AlarmFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.extend
2 |
3 | import com.js.deepsleep.tools.Type
4 | import com.js.deepsleep.ui.extend.fbase.FBaseFragment
5 |
6 |
7 | class AlarmFragment : FBaseFragment() {
8 | override val type: Type = Type.Alarm
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/extend/AppAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.extend
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import androidx.viewpager2.adapter.FragmentStateAdapter
6 |
7 | class AppAdapter(fragment: Fragment, val packageName: String) : FragmentStateAdapter(fragment) {
8 |
9 | override fun getItemCount(): Int = 2
10 |
11 | override fun createFragment(position: Int): Fragment {
12 | val fragment = getFragment(position)
13 | fragment.arguments = Bundle().apply {
14 | putString("packageName", packageName)
15 | }
16 | return fragment
17 | }
18 |
19 | private fun getFragment(position: Int): Fragment {
20 | return when (position) {
21 | 0 -> WakeLockFragment()
22 | 1 -> AlarmFragment()
23 | else -> WakeLockFragment()
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/extend/ExtendFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.extend
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.recyclerview.widget.RecyclerView
9 | import androidx.viewpager2.widget.ViewPager2
10 | import com.google.android.material.tabs.TabLayout
11 | import com.google.android.material.tabs.TabLayoutMediator
12 | import com.js.deepsleep.R
13 |
14 |
15 | class ExtendFragment : Fragment() {
16 |
17 | private lateinit var packageName: String
18 | private lateinit var adapter: AppAdapter
19 | private lateinit var viewPager: ViewPager2
20 |
21 |
22 | override fun onCreateView(
23 | inflater: LayoutInflater, container: ViewGroup?,
24 | savedInstanceState: Bundle?
25 | ): View? {
26 | // 获取 packageName
27 | packageName = arguments?.getString("packageName") ?: ""
28 | return inflater.inflate(R.layout.fragment_extend, container, false)
29 | }
30 |
31 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
32 | adapter = AppAdapter(this, packageName)
33 | viewPager = view.findViewById(R.id.app_pager)
34 | viewPager.offscreenPageLimit = 1
35 | (viewPager.getChildAt(0) as RecyclerView).layoutManager!!.isItemPrefetchEnabled = false
36 | viewPager.adapter = adapter
37 |
38 | val tabLayout = view.findViewById(R.id.app_tab_layout)
39 | TabLayoutMediator(tabLayout, viewPager) { tab, position ->
40 | tab.text = getTabText(position)
41 | }.attach()
42 | }
43 |
44 |
45 | private fun getTabText(position: Int): String {
46 | return when (position) {
47 | 0 -> getString(R.string.wakelock)
48 | 1 -> getString(R.string.alarm)
49 | else -> getString(R.string.wakelock)
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/extend/WakeLockFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.extend
2 |
3 | import com.js.deepsleep.tools.Type
4 | import com.js.deepsleep.ui.extend.fbase.FBaseFragment
5 |
6 | class WakeLockFragment : FBaseFragment() {
7 | override val type: Type = Type.Wakelock
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/extend/fbase/FBaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.extend.fbase
2 |
3 | import android.os.Bundle
4 | import android.view.*
5 | import androidx.fragment.app.Fragment
6 | import com.js.deepsleep.R
7 | import com.js.deepsleep.tools.Type
8 | import com.js.deepsleep.tools.menuGone
9 | import com.js.deepsleep.databinding.FragmentFbaseBinding
10 | import org.koin.androidx.viewmodel.ext.android.viewModel
11 | import org.koin.core.parameter.parametersOf
12 | import org.koin.core.qualifier.named
13 |
14 |
15 | open class FBaseFragment : Fragment() {
16 |
17 | open val type: Type = Type.Wakelock
18 |
19 | lateinit var packageName: String
20 |
21 | private lateinit var binding: FragmentFbaseBinding
22 |
23 | open val viewModel: FBaseViewModel by viewModel(named("ExtendVm")) {
24 | parametersOf(packageName, type)
25 | }
26 |
27 | private val syncExViewModel: SyncExViewModel by viewModel(named("SyncExVm"))
28 |
29 | override fun onCreate(savedInstanceState: Bundle?) {
30 | // 获取 packageName
31 | packageName = arguments?.getString("packageName") ?: ""
32 | super.onCreate(savedInstanceState)
33 |
34 | syncExViewModel.syncEx()
35 | }
36 |
37 | override fun onCreateView(
38 | inflater: LayoutInflater, container: ViewGroup?,
39 | savedInstanceState: Bundle?
40 | ): View {
41 | binding = FragmentFbaseBinding.inflate(inflater, container, false)
42 | context ?: return binding.root
43 | //绑定
44 | binding.vm = viewModel
45 | binding.lifecycleOwner = this
46 |
47 | //fragment 对 toolbar 菜单操作
48 | setHasOptionsMenu(true)
49 |
50 | return binding.root
51 | }
52 |
53 | // 关闭多余 toolbar 菜单
54 | @Deprecated("Deprecated in Java")
55 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
56 | menuGone(menu, setOf(R.id.menu_filter, R.id.search))
57 | super.onCreateOptionsMenu(menu, inflater)
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/extend/fbase/FBaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.extend.fbase
2 |
3 | import android.os.Bundle
4 | import android.widget.Toast
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.asLiveData
7 | import androidx.lifecycle.viewModelScope
8 | import com.js.deepsleep.BasicApp
9 | import com.js.deepsleep.R
10 | import com.js.deepsleep.data.db.entity.Extend
11 | import com.js.deepsleep.data.repository.app.AppRepo
12 | import com.js.deepsleep.data.repository.extend.ExtendRepo
13 | import com.js.deepsleep.tools.XProviderMethods
14 | import com.js.deepsleep.tools.callStopApp
15 | import com.js.deepsleep.tools.getSetting
16 | import com.js.deepsleep.tools.getURI
17 | import kotlinx.coroutines.Dispatchers
18 | import kotlinx.coroutines.launch
19 | import kotlinx.coroutines.withContext
20 | import org.koin.core.component.KoinComponent
21 | import org.koin.core.component.inject
22 | import org.koin.core.qualifier.named
23 |
24 |
25 | class FBaseViewModel(packageName: String, private val extendRepo: ExtendRepo) : ViewModel(),
26 | KoinComponent {
27 |
28 | private val appAR: AppRepo by inject(named("AppR"))
29 |
30 |
31 | var extend = extendRepo.getExtend(packageName).asLiveData()
32 |
33 | fun setEx(extend: Extend) {
34 | viewModelScope.launch(Dispatchers.IO) {
35 | extendRepo.setExtend(extend)
36 | if (getSetting("ForceStopEnable"))
37 | stopApp(extend.packageName)
38 | }
39 | }
40 |
41 | // call system force stop app
42 | private suspend fun stopApp(packageName: String) {
43 | val appInfo = appAR.getAppInfo(packageName)
44 |
45 | if (appInfo.persistent || appInfo.system) {// if app is system or persistent
46 | return
47 | }
48 | val result = callStopApp(appInfo.packageName, appInfo.uid)
49 | withContext(Dispatchers.Main) {
50 | isSuccess(result)
51 | }
52 | }
53 |
54 | private fun isSuccess(result: Boolean) {
55 | if (!result) {
56 | Toast.makeText(
57 | BasicApp.context,
58 | BasicApp.context.getString(R.string.forcestopEnable),
59 | Toast.LENGTH_SHORT
60 | ).show()
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/extend/fbase/SyncExViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.extend.fbase
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.js.deepsleep.BasicApp
6 | import com.js.deepsleep.tools.SPTools
7 | import com.js.deepsleep.data.db.entity.Extend
8 | import com.js.deepsleep.data.repository.syncsp.SyncSpRepo
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import org.koin.core.component.KoinComponent
12 | import org.koin.core.component.inject
13 | import org.koin.core.qualifier.named
14 |
15 | class SyncExViewModel : ViewModel(), KoinComponent {
16 | private val syncSPR: SyncSpRepo by inject(named("syncSpR"))
17 |
18 | fun syncEx() {
19 | viewModelScope.launch(Dispatchers.IO) {
20 | syncSPR.getAllAppStEx().collect { exs ->
21 | exs.map {
22 | saveEx2SP(it)
23 | }
24 | // LogUtil.d("syncEx", "${exs.size}")
25 | }
26 | }
27 | }
28 |
29 | private fun saveEx2SP(ex: Extend) {
30 |
31 | // LogUtil.d("SyncSt", "getSyncSp: ${ex}")
32 |
33 | // if (ex.allowList.isNotEmpty()) {
34 | SPTools.setString(
35 | "${ex.packageName}_${ex.type}_allowList",
36 | BasicApp.gson.toJson(ex.allowList)
37 | )
38 | // }
39 |
40 | // if (ex.blockList.isNotEmpty()) {
41 | SPTools.setString(
42 | "${ex.packageName}_${ex.type}_blockList",
43 | BasicApp.gson.toJson(ex.blockList)
44 | )
45 | // }
46 |
47 | // if (ex.rE.isNotEmpty()) {
48 | // LogUtil.d("SyncSt", "getSyncSp: ${ex}")
49 | SPTools.setString(
50 | "${ex.packageName}_${ex.type}_rE",
51 | BasicApp.gson.toJson(ex.rE)
52 | )
53 | // }
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/help/Help.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.help
2 |
3 | import android.text.Spanned
4 | import androidx.core.text.HtmlCompat
5 | import com.js.deepsleep.BasicApp
6 | import com.js.deepsleep.R
7 |
8 | data class Help(
9 | var instructions: Spanned = HtmlCompat.fromHtml(
10 | BasicApp.context.getString(R.string.help_instructions),
11 | HtmlCompat.FROM_HTML_MODE_LEGACY
12 | ),
13 | var contact: String = BasicApp.context.getString(R.string.help_contact)
14 | // var issue:String = "https://github.com/Jasper-1024/NoWakeLock/issues",
15 | // var author:String = "JasperHale",
16 | // var email: String = "ljy087621@gmail.com"
17 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/help/HelpFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.help
2 |
3 | import android.os.Bundle
4 | import android.text.method.LinkMovementMethod
5 | import android.view.*
6 | import androidx.fragment.app.Fragment
7 | import com.js.deepsleep.R
8 | import com.js.deepsleep.tools.menuGone
9 | import com.js.deepsleep.databinding.FragmentHelpBinding
10 | import org.koin.androidx.viewmodel.ext.android.viewModel
11 | import org.koin.core.qualifier.named
12 |
13 |
14 | class HelpFragment : Fragment() {
15 |
16 | private val viewModel: HelpViewModel by viewModel(named("HelpVm"))
17 |
18 | private lateinit var binding: FragmentHelpBinding
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | setHasOptionsMenu(true)
22 | super.onCreate(savedInstanceState)
23 | }
24 |
25 | override fun onCreateView(
26 | inflater: LayoutInflater, container: ViewGroup?,
27 | savedInstanceState: Bundle?
28 | ): View {
29 | binding = FragmentHelpBinding.inflate(inflater, container, false)
30 | context ?: return binding.root
31 | binding.vm = viewModel
32 | binding.tvInstructions.movementMethod = LinkMovementMethod.getInstance()
33 | return binding.root
34 | }
35 |
36 | // 关闭多余 toolbar 菜单
37 | @Deprecated("Deprecated in Java")
38 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
39 | menuGone(menu, setOf(R.id.menu_filter, R.id.search))
40 | super.onCreateOptionsMenu(menu, inflater)
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/help/HelpViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.help
2 |
3 | import androidx.lifecycle.ViewModel
4 |
5 | class HelpViewModel : ViewModel() {
6 | var help: Help = Help()
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/mainactivity/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.mainactivity
2 |
3 | import android.os.Bundle
4 | import android.view.Menu
5 | import android.view.MenuItem
6 | import android.widget.Toast
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.appcompat.widget.SearchView
9 | import androidx.appcompat.widget.Toolbar
10 | import androidx.drawerlayout.widget.DrawerLayout
11 | import androidx.navigation.fragment.NavHostFragment
12 | import androidx.navigation.ui.AppBarConfiguration
13 | import androidx.navigation.ui.setupWithNavController
14 | import com.google.android.material.navigation.NavigationView
15 | import com.js.deepsleep.R
16 | import com.js.deepsleep.tools.AppType
17 | import org.koin.androidx.viewmodel.ext.android.viewModel
18 | import org.koin.core.qualifier.named
19 |
20 | class MainActivity : AppCompatActivity() {
21 |
22 | // 检查模块是否激活
23 | private fun isModuleActive(): Boolean {
24 | return false
25 | }
26 |
27 | private lateinit var toolbar: Toolbar
28 | private lateinit var drawerLayout: DrawerLayout
29 |
30 | // mainVm
31 | private val mainViewModel: MainViewModel by viewModel(named("MainVm"))
32 |
33 | override fun onCreate(savedInstanceState: Bundle?) {
34 | super.onCreate(savedInstanceState)
35 | setContentView(R.layout.activity_main)
36 |
37 | // 初始化
38 | drawerLayout = findViewById(R.id.drawer_layout)
39 | toolbar = findViewById(R.id.toolbar)
40 |
41 | val navHostFragment =
42 | supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
43 | val navController = navHostFragment.navController
44 |
45 | val appBarConfiguration = AppBarConfiguration(setOf(R.id.appFragment), drawerLayout)
46 |
47 | setSupportActionBar(toolbar)// toolbar 替换 ActionBar
48 | drawerLayout.setStatusBarBackground(R.color.colorPrimaryDark)//设置侧边栏颜色
49 |
50 | /* 设置导航组件,一定要在 setSupportActionBar 之后 */
51 | toolbar.setupWithNavController(navController, appBarConfiguration)
52 | findViewById(R.id.nav_view).setupWithNavController(navController)//设置导航组件
53 |
54 | //检查模块是否激活
55 | if (!isModuleActive()) {
56 | Toast.makeText(this, getString(R.string.active), Toast.LENGTH_LONG).show()
57 | }
58 | }
59 |
60 | //ToolBar menu
61 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
62 | menuInflater.inflate(R.menu.toolbar, menu)
63 | return true
64 | }
65 |
66 | fun statusUser(menu: MenuItem) {
67 | mainViewModel.type.postValue(AppType.User)
68 | menu.isChecked = true
69 | }
70 |
71 | fun statusSystem(menu: MenuItem) {
72 | mainViewModel.type.postValue(AppType.System)
73 | menu.isChecked = true
74 | }
75 |
76 | fun statusAll(menu: MenuItem) {
77 | mainViewModel.type.postValue(AppType.All)
78 | menu.isChecked = true
79 | }
80 |
81 | fun statusRestricted(menu: MenuItem) {
82 | mainViewModel.type.postValue(AppType.Restricted)
83 | menu.isChecked = true
84 | }
85 |
86 | fun statusExtend(menu: MenuItem) {
87 | mainViewModel.type.postValue(AppType.Extend)
88 | menu.isChecked = true
89 | }
90 |
91 | override fun onPrepareOptionsMenu(menu: Menu): Boolean {
92 | // 搜索栏
93 | val searchView = menu.findItem(R.id.search).actionView as SearchView
94 | setSearchView(searchView)
95 | return super.onPrepareOptionsMenu(menu)
96 | }
97 |
98 | private fun setSearchView(searchView: SearchView) {
99 | searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
100 | override fun onQueryTextSubmit(query: String): Boolean {
101 | mainViewModel.query.postValue(query)
102 | searchView.clearFocus()
103 | return true
104 | }
105 |
106 | override fun onQueryTextChange(query: String): Boolean {
107 | mainViewModel.query.postValue(query)
108 | return true
109 | }
110 | })
111 | }
112 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/mainactivity/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.mainactivity
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 | import com.js.deepsleep.tools.AppType
6 | import com.js.deepsleep.tools.Sort
7 |
8 | class MainViewModel : ViewModel() {
9 | // App 类型
10 | val type: MutableLiveData by lazy {
11 | MutableLiveData(AppType.User)
12 | }
13 |
14 | val sort: MutableLiveData by lazy {
15 | MutableLiveData(Sort.Name)
16 | }
17 |
18 | val query: MutableLiveData by lazy {
19 | MutableLiveData("")
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/settings/SettingViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.settings
2 |
3 | import android.net.Uri
4 | import android.widget.Toast
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.google.gson.reflect.TypeToken
8 | import com.js.deepsleep.BasicApp
9 | import com.js.deepsleep.R
10 | import com.js.deepsleep.tools.LogUtil
11 | import com.js.deepsleep.tools.getSetting
12 | import com.js.deepsleep.data.repository.backup.AppBackup
13 | import com.js.deepsleep.data.repository.backup.BackupRepository
14 | import kotlinx.coroutines.Dispatchers
15 | import kotlinx.coroutines.launch
16 | import kotlinx.coroutines.withContext
17 | import org.koin.core.component.KoinComponent
18 | import org.koin.core.component.inject
19 | import org.koin.core.qualifier.named
20 | import java.io.*
21 |
22 | class SettingViewModel : ViewModel(), KoinComponent {
23 | private val backupR: BackupRepository by inject(named("backupR"))
24 |
25 | // 保存备份
26 | fun backup(uri: Uri) {
27 | viewModelScope.launch(Dispatchers.Default) {
28 | val back = getBackup()//返回 AppBackup
29 | // LogUtil.d("test1", "$back")
30 | try {
31 | saveFile(uri, BasicApp.gson.toJson(back))//保存文件
32 | toast(BasicApp.context.getString(R.string.backup))
33 | } catch (e: Throwable) {
34 | LogUtil.e("backup", "saveFile: $e")//打印错误
35 | toast(BasicApp.context.getString(R.string.backupErr))
36 | }
37 | }
38 | }
39 |
40 | // 恢复备份
41 | fun restore(uri: Uri) {
42 | viewModelScope.launch(Dispatchers.Default) {
43 | val str =
44 | try {
45 | getString(uri)
46 | } catch (e: Throwable) {
47 | LogUtil.e("backup", "getString: $e")//打印错误
48 | toast(BasicApp.context.getString(R.string.restoreErr))
49 | ""
50 | }
51 | if (str != "") {
52 | jsonToAppBackup(str)?.let { restoreBackup(it) }
53 | }
54 | toast(BasicApp.context.getString(R.string.restore))
55 | }
56 | }
57 |
58 | //json 转换为 AppBackup
59 | private fun jsonToAppBackup(str: String): AppBackup? {
60 | val type = object : TypeToken() {}.type
61 | return BasicApp.gson.fromJson(str, type)
62 | }
63 |
64 | //存入
65 | @Suppress("BlockingMethodInNonBlockingContext")
66 | @Throws(IOException::class)
67 | private suspend fun saveFile(uri: Uri, str: String) = withContext(Dispatchers.IO) {
68 | BasicApp.context.contentResolver.openFileDescriptor(uri, "w")?.use { it ->
69 | // use{} lets the document provider know you're done by automatically closing the stream
70 | FileOutputStream(it.fileDescriptor).use { file ->
71 | file.write(
72 | str.toByteArray()
73 | )
74 | }
75 | }
76 | }
77 |
78 | // 从文件读取 json
79 | @Suppress("BlockingMethodInNonBlockingContext")
80 | @Throws(IOException::class)
81 | private suspend fun getString(uri: Uri): String = withContext(Dispatchers.IO) {
82 | val stringBuilder = StringBuilder()
83 | BasicApp.context.contentResolver.openInputStream(uri)?.use { inputStream ->
84 | BufferedReader(InputStreamReader(inputStream)).use { reader ->
85 | var line: String? = reader.readLine()
86 | while (line != null) {
87 | stringBuilder.append(line)
88 | line = reader.readLine()
89 | }
90 | }
91 | }
92 | return@withContext stringBuilder.toString()
93 | }
94 |
95 | // 获取备份 AppBackup
96 | private suspend fun getBackup(): AppBackup {
97 | return backupR.getBackup(getSetting("ExtendEnable"))
98 | }
99 |
100 | // 恢复 AppBackup
101 | private suspend fun restoreBackup(appBackup: AppBackup) {
102 | backupR.restoreBackup(appBackup)
103 | }
104 |
105 | private suspend fun toast(str: String) = withContext(Dispatchers.Main) {
106 | Toast.makeText(BasicApp.context, str, Toast.LENGTH_LONG).show()
107 | }
108 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/settings/SettingsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.settings
2 |
3 | import android.os.Bundle
4 | import android.view.Menu
5 | import android.view.MenuInflater
6 | import androidx.activity.result.contract.ActivityResultContracts
7 | import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
8 | import androidx.preference.ListPreference
9 | import androidx.preference.Preference
10 | import androidx.preference.PreferenceFragmentCompat
11 | import com.js.deepsleep.R
12 | import com.js.deepsleep.tools.menuGone
13 | import org.koin.androidx.viewmodel.ext.android.viewModel
14 | import org.koin.core.qualifier.named
15 | import java.util.*
16 |
17 | class SettingsFragment : PreferenceFragmentCompat() {
18 |
19 | private val viewModel: SettingViewModel by viewModel(named("SettingVm"))
20 |
21 | // 备份
22 | private val backupRAFR =
23 | registerForActivityResult(CreateDocument("todo/todo")) { uri ->
24 | if (uri != null) {
25 | viewModel.backup(uri)
26 | }
27 | }
28 |
29 | // 恢复
30 | private val restoreRAFR =
31 | registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
32 | if (uri != null) {
33 | viewModel.restore(uri)
34 | }
35 | }
36 |
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | setHasOptionsMenu(true)
39 | super.onCreate(savedInstanceState)
40 | }
41 |
42 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
43 | setPreferencesFromResource(R.xml.settings, rootKey)
44 |
45 | //主题切换
46 | val themePreference =
47 | findPreference("theme_list")
48 | if (themePreference != null) {
49 | themePreference.onPreferenceChangeListener =
50 | Preference.OnPreferenceChangeListener { _, newValue ->
51 | val themeOption = newValue as String
52 | ThemeHelper.applyTheme(themeOption)
53 | true
54 | }
55 | }
56 |
57 | // 备份按钮
58 | val backup: Preference? = findPreference("backup")
59 | if (backup != null) {
60 | backup.onPreferenceClickListener =
61 | Preference.OnPreferenceClickListener {
62 | // 创建备份文件
63 | backupRAFR.launch("DeepSleep-Backup-${getData()}.json")
64 | true
65 | }
66 | }
67 | // 恢复按钮
68 | val restore: Preference? = findPreference("restore")
69 | if (restore != null) {
70 | restore.onPreferenceClickListener =
71 | Preference.OnPreferenceClickListener {
72 | restoreRAFR.launch("*/*")
73 | true
74 | }
75 | }
76 | }
77 |
78 | // 关闭多余 toolbar 菜单
79 | @Deprecated("Deprecated in Java")
80 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
81 | menuGone(menu, setOf(R.id.menu_filter, R.id.search))
82 | super.onCreateOptionsMenu(menu, inflater)
83 | }
84 |
85 | // 现在时间
86 | private fun getData(): String {
87 | val c: Calendar = Calendar.getInstance()
88 | val year: Int = c.get(Calendar.YEAR)
89 | val month: Int = c.get(Calendar.MONTH) + 1
90 | val date: Int = c.get(Calendar.DATE)
91 | val hour: Int = c.get(Calendar.HOUR_OF_DAY)
92 | val minute: Int = c.get(Calendar.MINUTE)
93 | return "$year:$month:$date-$hour:$minute"
94 | }
95 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/ui/settings/ThemeHelper.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.ui.settings
2 |
3 | import android.os.Build
4 | import androidx.appcompat.app.AppCompatDelegate
5 |
6 | @Suppress("MemberVisibilityCanBePrivate")
7 | object ThemeHelper {
8 |
9 | const val LIGHT_MODE = "light"
10 | const val DARK_MODE = "dark"
11 | const val DEFAULT_MODE = "default"
12 | fun applyTheme(themePref: String) {
13 | when (themePref) {
14 | LIGHT_MODE -> {
15 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
16 | }
17 | DARK_MODE -> {
18 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
19 | }
20 | else -> {
21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
22 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
23 | } else {
24 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
25 | }
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/XpUtil.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import android.os.Bundle
6 | import com.js.deepsleep.data.provider.ProviderMethod
7 | import de.robv.android.xposed.XposedBridge
8 | import de.robv.android.xposed.XposedHelpers
9 |
10 |
11 | object XpUtil {
12 | private const val Tag = "xposed.deepsleep"
13 | private const val authority = "com.js.deepsleep"// cp 地址
14 |
15 | var packageName: String = ""
16 |
17 | private const val log = true
18 |
19 | fun log(string: String) {
20 | if (log) {
21 | XposedBridge.log("$Tag $packageName: $string")
22 | }
23 | }
24 |
25 | fun call(method: ProviderMethod, bundle: Bundle, context: Context): Bundle? {
26 | val url = Uri.parse("content://${authority}")
27 | val contentResolver = context.contentResolver
28 | return try {
29 | contentResolver.call(url, method.value, null, bundle)
30 | } catch (e: Exception) {
31 | log(": record $method err: $e")
32 | null
33 | }
34 | }
35 |
36 | fun getClass(name: String, classLoader: ClassLoader): Class<*>? {
37 | return try {
38 | XposedHelpers.findClass(name, classLoader)
39 | } catch (e: Throwable) {
40 | log("alarm getClass err: $e")
41 | null
42 | }
43 | }
44 |
45 | fun run(name: String, function: () -> Unit) {
46 | try {
47 | function()
48 | } catch (e: Throwable) {
49 | log("$name err: $e")
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/XposedModule.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed
2 |
3 | import com.js.deepsleep.BuildConfig
4 | import com.js.deepsleep.xposed.hook.*
5 | import com.js.deepsleep.xposed.model.XpNSP
6 | import de.robv.android.xposed.IXposedHookLoadPackage
7 | import de.robv.android.xposed.IXposedHookZygoteInit
8 | import de.robv.android.xposed.callbacks.XC_LoadPackage
9 |
10 |
11 | class XposedModule : IXposedHookZygoteInit, IXposedHookLoadPackage {
12 |
13 | override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam?) {
14 | XpUtil.log("initZygote")
15 | }
16 |
17 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
18 | XpUtil.packageName = lpparam.packageName // packageName
19 | XpNSP.getInstance(lpparam.packageName) // init
20 |
21 | when (lpparam.packageName) {
22 | BuildConfig.APPLICATION_ID -> SelfXp.hook(lpparam) // self hook
23 | "com.android.providers.settings" -> SettingsProviderXP.hook(lpparam) //system settings providers hook
24 | else -> { //other
25 | try {
26 | XpNSP.getInstance().apply {
27 | getSt()
28 | getExtends()
29 | }
30 | WakelockXp.hook(lpparam)
31 | AlarmXp.hook(lpparam)
32 | ServiceXp.hook(lpparam)
33 | SyncXp.hook(lpparam)
34 | } catch (e: Throwable) {
35 | XpUtil.log("get context err $e")
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/AlarmXp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import android.app.AlarmManager
4 | import android.app.PendingIntent
5 | import android.content.Intent
6 | import android.os.Handler
7 | import android.os.WorkSource
8 | import com.js.deepsleep.tools.Type
9 | import com.js.deepsleep.xposed.model.XpNSP
10 | import com.js.deepsleep.xposed.XpUtil
11 | import de.robv.android.xposed.XC_MethodHook
12 | import de.robv.android.xposed.XposedBridge
13 | import de.robv.android.xposed.XposedHelpers
14 | import de.robv.android.xposed.callbacks.XC_LoadPackage
15 |
16 | class AlarmXp {
17 | companion object {
18 |
19 | private var pendingIntent: Class<*>? = null
20 |
21 | fun hook(lpparam: XC_LoadPackage.LoadPackageParam) {
22 |
23 | pendingIntent = XpUtil.getClass("android.app.PendingIntent", lpparam.classLoader)
24 |
25 | pendingIntent?.let {
26 | XposedBridge.hookAllMethods(it, "getBroadcast", HandlePendingIntent(it))
27 | XposedBridge.hookAllMethods(it, "getActivity", HandlePendingIntent(it))
28 | XposedBridge.hookAllMethods(it, "getService", HandlePendingIntent(it))
29 | }
30 |
31 | XposedHelpers.findAndHookMethod(
32 | "android.app.AlarmManager",
33 | lpparam.classLoader,
34 | "setImpl",
35 | Int::class.java,
36 | Long::class.java,
37 | Long::class.java,
38 | Long::class.java,
39 | Int::class.java,
40 | PendingIntent::class.java,
41 | AlarmManager.OnAlarmListener::class.java,
42 | String::class.java,
43 | Handler::class.java,
44 | WorkSource::class.java,
45 | AlarmManager.AlarmClockInfo::class.java,
46 | HandleAlarm()
47 | )
48 | }
49 |
50 | }
51 |
52 | class HandlePendingIntent(private val pendingIntent: Class<*>) : XC_MethodHook() {
53 | @Throws(Throwable::class)
54 | override fun beforeHookedMethod(param: MethodHookParam) {
55 | // XpUtil.log("alarm pendingIntent hook")
56 |
57 | if (param.args.size < 2) return
58 | if (param.args[2] == null) return
59 | if (param.args[2] !is Intent) return
60 |
61 | XpUtil.run("pendingIntent") {
62 | val alarmName = (param.args[2] as Intent).action ?: "null"
63 | XposedHelpers.setAdditionalStaticField(pendingIntent, "alarmName", alarmName)
64 | }
65 | }
66 | }
67 |
68 |
69 | class HandleAlarm : XC_MethodHook() {
70 | @Throws(Throwable::class)
71 | override fun beforeHookedMethod(param: MethodHookParam) {
72 | val xpNSP = XpNSP.getInstance()
73 |
74 | val alarmName: String = param.args[7] as String?
75 | ?: (XposedHelpers.getAdditionalStaticField(
76 | pendingIntent,
77 | "alarmName"
78 | ) as String?).apply {
79 | if (this != null) {
80 | XposedHelpers.setAdditionalStaticField(pendingIntent, "alarmName", null)
81 | }
82 | }
83 | ?: "null"
84 |
85 | if (major(alarmName) || xpNSP.block(Type.Alarm, XpUtil.packageName, alarmName)) {
86 | param.result = null
87 | XpUtil.log("alarm block $alarmName")
88 | }
89 | }
90 |
91 | private fun major(alarmName: String): Boolean {
92 | return "android" == XpUtil.packageName ||
93 | alarmName == "android"
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/Application.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import com.js.deepsleep.xposed.XpUtil
6 | import de.robv.android.xposed.XC_MethodHook
7 | import de.robv.android.xposed.XposedHelpers
8 |
9 | class XpContext {
10 | companion object {
11 | fun hook(method: (context: Context) -> Unit) {
12 | try {
13 | XposedHelpers.findAndHookMethod(
14 | Application::class.java,
15 | "attach",
16 | Context::class.java,
17 | object : XC_MethodHook() {
18 | @Throws(Throwable::class)
19 | override fun beforeHookedMethod(param: MethodHookParam) {
20 | val context = param.args[0] as Context
21 | method(context)
22 | }
23 | })
24 |
25 | } catch (e: Throwable) {
26 | XpUtil.log("get context err $e")
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/BroadcastXP.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import com.js.deepsleep.xposed.XpUtil
6 | import de.robv.android.xposed.XC_MethodHook
7 | import de.robv.android.xposed.XposedBridge
8 | import de.robv.android.xposed.XposedHelpers
9 | import de.robv.android.xposed.callbacks.XC_LoadPackage
10 |
11 | class BroadcastXP {
12 | companion object {
13 | fun hook(lpparam: XC_LoadPackage.LoadPackageParam) {
14 |
15 | XpUtil.run {
16 | XposedHelpers.findAndHookMethod(
17 | "android.content.BroadcastReceiver",
18 | lpparam.classLoader,
19 | "onReceive",
20 | Context::class.java,
21 | Intent::class.java,
22 | Test()
23 | )
24 | }
25 |
26 | val tmp: Class<*>? =
27 | XpUtil.getClass("android.content.BroadcastReceiver", lpparam.classLoader)
28 |
29 | tmp?.let {
30 | XposedBridge.hookAllMethods(it, "onReceive", Test())
31 | }
32 | }
33 | }
34 |
35 | class Test : XC_MethodHook() {
36 | @Throws(Throwable::class)
37 | override fun beforeHookedMethod(param: MethodHookParam) {
38 | XpUtil.log("broadcast hook1")
39 | if (param.args[0] !is Context && param.args[0] != null) return
40 | if (param.args[1] !is Intent && param.args[1] != null) return
41 | val context = param.args[0] as Context
42 | val intent = param.args[1] as Intent
43 | XpUtil.log("broadcast ${context.packageName} ${intent.action}")
44 | // context.packageName
45 | // intent.action
46 | // if (XpAppSt.getInstance().block(Type.Broadcast, "", "")) {
47 | // param.result = null
48 | // XpUtil.log("service block ${it.className}")
49 | // }
50 | }
51 |
52 | @Throws(Throwable::class)
53 | override fun afterHookedMethod(param: MethodHookParam) {
54 | XpUtil.log("broadcast hook2")
55 | if (param.args[0] !is Context && param.args[0] != null) return
56 | if (param.args[1] !is Intent && param.args[1] != null) return
57 | val context = param.args[0] as Context
58 | val intent = param.args[1] as Intent
59 | XpUtil.log("broadcast ${context.packageName} ${intent.action}")
60 | // param.result = null
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/SelfXp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import com.js.deepsleep.BuildConfig
4 | import de.robv.android.xposed.XC_MethodHook
5 | import de.robv.android.xposed.XposedHelpers
6 | import de.robv.android.xposed.callbacks.XC_LoadPackage
7 |
8 | class SelfXp {
9 | companion object {
10 | fun hook(lpparam: XC_LoadPackage.LoadPackageParam) {
11 | XposedHelpers.findAndHookMethod(
12 | "${BuildConfig.APPLICATION_ID}.ui.mainactivity.MainActivity", lpparam.classLoader,
13 | "isModuleActive", HandleSelf()
14 | )
15 | }
16 | }
17 |
18 | class HandleSelf : XC_MethodHook() {
19 |
20 | override fun afterHookedMethod(param: MethodHookParam) {
21 | param.result = true
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/ServiceXp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import android.content.ComponentName
4 | import com.js.deepsleep.tools.Type
5 | import com.js.deepsleep.xposed.model.XpNSP
6 | import com.js.deepsleep.xposed.XpUtil
7 | import de.robv.android.xposed.XC_MethodHook
8 | import de.robv.android.xposed.XposedBridge
9 | import de.robv.android.xposed.callbacks.XC_LoadPackage
10 |
11 |
12 | class ServiceXp {
13 | companion object {
14 | fun hook(lpparam: XC_LoadPackage.LoadPackageParam) {
15 | // val contextWrapperClass =
16 | // XpUtil.getClass("android.content.ContextWrapper", lpparam.classLoader)
17 | // XposedHelpers.findAndHookMethod(
18 | // contextWrapperClass,
19 | // "startService",
20 | // Intent::class.java,
21 | // HandleService()
22 | // )
23 | // val tmp: Class<*>? = XpUtil.getClass("android.app.Service", lpparam.classLoader)
24 | // tmp?.let {
25 | // XposedBridge.hookAllMethods(it, "onCreate", Test())
26 | // }
27 |
28 | val tmp2: Class<*>? = XpUtil.getClass("android.app.ContextImpl", lpparam.classLoader)
29 | tmp2?.let {
30 | XposedBridge.hookAllMethods(it, "startServiceCommon", HandleService())
31 | }
32 |
33 | }
34 | }
35 |
36 | class HandleService : XC_MethodHook() {
37 | @Throws(Throwable::class)
38 | override fun afterHookedMethod(param: MethodHookParam) {
39 | super.afterHookedMethod(param)
40 |
41 | if (param.result == null) return
42 | if (param.result !is ComponentName) return
43 |
44 | val componentName = param.result as ComponentName?
45 | componentName?.let {
46 | if (XpNSP.getInstance().block(Type.Service, it.packageName, it.className)) {
47 | param.result = null
48 | XpUtil.log("service block ${it.className}")
49 | }
50 | }
51 | }
52 | }
53 |
54 | // class Test : XC_MethodHook() {
55 | // @Throws(Throwable::class)
56 | // override fun beforeHookedMethod(param: MethodHookParam) {
57 | // XpUtil.log("service hook3")
58 | // param.result = null
59 | // }
60 | //
61 | // @Throws(Throwable::class)
62 | // override fun afterHookedMethod(param: MethodHookParam) {
63 | // XpUtil.log("service hook4")
64 | // param.result = null
65 | // }
66 | // }
67 |
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/SettingsProviderXP.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.util.Log
6 | import com.js.deepsleep.tools.XProvider
7 | import com.js.deepsleep.xposed.XpUtil
8 | import de.robv.android.xposed.XC_MethodHook
9 | import de.robv.android.xposed.XposedBridge
10 | import de.robv.android.xposed.callbacks.XC_LoadPackage
11 | import java.lang.reflect.Method
12 |
13 |
14 | class SettingsProviderXP {
15 | companion object {
16 |
17 | fun hook(lpparam: XC_LoadPackage.LoadPackageParam) {
18 |
19 | XpUtil.log("SettingsProvider")
20 |
21 | // https://android.googlesource.com/platform/frameworks/base/+/master/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
22 | val clsSet = Class.forName(
23 | "com.android.providers.settings.SettingsProvider",
24 | false,
25 | lpparam.classLoader
26 | )
27 | // Bundle call(String method, String arg, Bundle extras)
28 | val mCall: Method = clsSet.getMethod(
29 | "call",
30 | String::class.java,
31 | String::class.java,
32 | Bundle::class.java
33 | )
34 |
35 | XposedBridge.hookMethod(mCall, object : XC_MethodHook() {
36 | @Throws(Throwable::class)
37 | override fun beforeHookedMethod(param: MethodHookParam) {
38 | makeCall(param)
39 | }
40 | })
41 | }
42 |
43 | private fun makeCall(param: XC_MethodHook.MethodHookParam) {
44 | try {
45 | val method = param.args[0] as String?
46 | val arg = param.args[1] as String?
47 | val extras = param.args[2] as Bundle?
48 |
49 | if ("DeepSleep" == method) { // if call form DeepSleep
50 | try {
51 | val mGetContext = param.thisObject.javaClass.getMethod("getContext")
52 | val context: Context =
53 | mGetContext.invoke(param.thisObject) as Context
54 |
55 | XpUtil.log("$method,$arg,$extras")
56 |
57 | param.result = XProvider.call(context, arg, extras) // call XProvider
58 | } catch (ex: IllegalArgumentException) {
59 | XpUtil.log("Error: " + ex.message)
60 | param.throwable = ex
61 | } catch (ex: Throwable) {
62 | XpUtil.log(Log.getStackTraceString(ex))
63 | param.result = null
64 | }
65 | }
66 | } catch (ex: Throwable) {
67 | XpUtil.log(Log.getStackTraceString(ex))
68 | }
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/SyncXp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import com.js.deepsleep.tools.Type
4 | import com.js.deepsleep.xposed.model.XpNSP
5 | import com.js.deepsleep.xposed.XpUtil
6 | import de.robv.android.xposed.XC_MethodHook
7 | import de.robv.android.xposed.XposedBridge
8 | import de.robv.android.xposed.callbacks.XC_LoadPackage
9 |
10 | class SyncXp {
11 | companion object {
12 | fun hook(lpparam: XC_LoadPackage.LoadPackageParam) {
13 | val tmp: Class<*>? =
14 | XpUtil.getClass("android.content.ContentResolver", lpparam.classLoader)
15 |
16 | tmp?.let {
17 | XposedBridge.hookAllMethods(it, "requestSync", HandleSync())
18 | XposedBridge.hookAllMethods(it, "addPeriodicSync", HandleSync())
19 | XposedBridge.hookAllMethods(it, "setSyncAutomatically", HandleSync())
20 | }
21 | }
22 | }
23 |
24 | class HandleSync : XC_MethodHook() {
25 | @Throws(Throwable::class)
26 | override fun beforeHookedMethod(param: MethodHookParam) {
27 | // XpUtil.log("sync hook")
28 | if (XpNSP.getInstance().block(Type.Sync, "", "")) {
29 | param.result = null
30 | XpUtil.log("sync block")
31 | }
32 |
33 | }
34 |
35 | // @Throws(Throwable::class)
36 | // override fun afterHookedMethod(param: MethodHookParam) {
37 | // super.afterHookedMethod(param)
38 | //
39 | //// XpUtil.log("service hook2")
40 | //
41 | // }
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/hook/WakelockXp.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.hook
2 |
3 | import android.os.PowerManager
4 | import com.js.deepsleep.tools.Type
5 | import com.js.deepsleep.xposed.model.XpNSP
6 | import com.js.deepsleep.xposed.XpUtil
7 | import de.robv.android.xposed.XC_MethodHook
8 | import de.robv.android.xposed.XposedHelpers
9 | import de.robv.android.xposed.callbacks.XC_LoadPackage
10 |
11 | class WakelockXp {
12 | companion object {
13 | fun hook(lpparam: XC_LoadPackage.LoadPackageParam) {
14 | XposedHelpers.findAndHookMethod(
15 | "android.os.PowerManager.WakeLock",
16 | lpparam.classLoader,
17 | "acquire",
18 | HandleWakelock()
19 | )
20 |
21 | XposedHelpers.findAndHookMethod(
22 | "android.os.PowerManager.WakeLock",
23 | lpparam.classLoader,
24 | "acquire",
25 | Long::class.java,
26 | HandleWakelock()
27 | )
28 |
29 | // XposedHelpers.findAndHookMethod(
30 | // "android.os.PowerManager",
31 | // lpparam.classLoader,
32 | // "newWakeLock",
33 | // Int::class.java,
34 | // String::class.java,
35 | // HandleWakelock()
36 | // )
37 | }
38 |
39 | }
40 |
41 | class HandleWakelock : XC_MethodHook() {
42 | @Throws(Throwable::class)
43 | override fun beforeHookedMethod(param: MethodHookParam) {
44 |
45 | if (param.thisObject !is PowerManager.WakeLock) return
46 |
47 | val xpNSP = XpNSP.getInstance()
48 |
49 | val mPackageName = getString(param, "mPackageName")
50 | val mTag = getString(param, "mTag")
51 |
52 |
53 | //非关键应用 和 设置禁止
54 | if (!major(mPackageName) && xpNSP.block(Type.Wakelock, mPackageName, mTag)) {
55 | param.result = null
56 | XpUtil.log("wakelock block $mTag")
57 | }
58 |
59 | }
60 |
61 | private fun getString(param: MethodHookParam, info: String): String {
62 | val tmp = param.thisObject::class.java.getDeclaredField(info)
63 | .apply { this.isAccessible = true }
64 | return (tmp[param.thisObject] as String).trim { it <= ' ' }
65 | }
66 |
67 | private fun major(mPackageName: String): Boolean {
68 | return "android" == XpUtil.packageName ||
69 | mPackageName == "android" ||
70 | mPackageName == "com.android.systemui" ||
71 | mPackageName == "com.android.phone"
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/model/XpAppSt.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.model
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import com.js.deepsleep.tools.Type
6 | import com.js.deepsleep.data.db.entity.AppSt
7 | import com.js.deepsleep.data.db.entity.Extend
8 | import com.js.deepsleep.data.provider.PParameters
9 | import com.js.deepsleep.data.provider.ProviderMethod
10 | import com.js.deepsleep.xposed.XpUtil
11 | import kotlinx.coroutines.GlobalScope
12 | import kotlinx.coroutines.launch
13 |
14 | class XpAppSt(private val packageName: String) {
15 |
16 | @Volatile
17 | var appSt: AppSt = AppSt()
18 |
19 | @Volatile
20 | var wakelockEx: Extend = Extend()
21 |
22 | @Volatile
23 | var alarmEx: Extend = Extend()
24 |
25 | companion object {
26 | @Volatile
27 | private var instance: XpAppSt? = null
28 |
29 | fun getInstance(packageName: String = "") = instance ?: synchronized(this) {
30 | XpAppSt(packageName).also {
31 | instance = it
32 | }
33 | }
34 | }
35 |
36 | fun getSt(context: Context) {
37 | GlobalScope.launch {
38 | try {
39 | val tmp = Bundle()
40 | tmp.putString(PParameters.packageName, packageName)
41 | val bundle = XpUtil.call(ProviderMethod.GetAppSt, tmp, context)//get st
42 | bundle?.let { bun ->
43 | bun.getSerializable(PParameters.appSt)?.let {//get st
44 | synchronized(this) {
45 | appSt = it as AppSt
46 | }
47 | }
48 | }
49 | } catch (e: Exception) {
50 | XpUtil.log("getSt err: $e")
51 | }
52 | }
53 | }
54 |
55 | fun getExtends(context: Context) {
56 | GlobalScope.launch {
57 | try {
58 | val tmp = Bundle()
59 | tmp.putString(PParameters.packageName, packageName)
60 | val bundle = XpUtil.call(ProviderMethod.GetExtends, tmp, context)//get st
61 | bundle?.let { bun ->
62 | bun.getSerializable(PParameters.wakelock)?.let {
63 | synchronized(this) {
64 | wakelockEx = it as Extend
65 | }
66 | }
67 | bun.getSerializable(PParameters.alarm)?.let {
68 | synchronized(this) {
69 | alarmEx = it as Extend
70 | }
71 | }
72 | }
73 | } catch (e: Exception) {
74 | XpUtil.log("getExtends err: $e")
75 | }
76 | }
77 | }
78 |
79 | fun block(type: Type, mPackageName: String, mTag: String): Boolean {
80 | return when (type) {
81 | Type.Wakelock -> getBlock(mTag, wakelockEx, appSt.wakelock)
82 | Type.Alarm -> getBlock(mTag, alarmEx, appSt.alarm)
83 | Type.Service -> appSt.service
84 | Type.Sync -> appSt.sync
85 | Type.Broadcast -> appSt.broadcast
86 | }
87 | }
88 |
89 | // 获取 Block
90 | private fun getBlock(mTag: String, extend: Extend, flag: Boolean): Boolean {
91 | if (mTag in extend.allowList) return false
92 | if (mTag in extend.blockList) return true
93 | if (getRE(mTag, extend.rE)) return true
94 | return flag
95 | }
96 |
97 | private fun getRE(mTag: String, rE: Set): Boolean {
98 | if (rE.isEmpty()) {
99 | return false
100 | } else {
101 | rE.forEach {
102 | if (mTag.matches(Regex(it))) {
103 | return true
104 | }
105 | }
106 | return false
107 | }
108 | }
109 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/js/deepsleep/xposed/model/XpNSP.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep.xposed.model
2 |
3 | import android.content.SharedPreferences
4 | import com.google.gson.Gson
5 | import com.google.gson.reflect.TypeToken
6 | import com.js.deepsleep.BuildConfig
7 | import com.js.deepsleep.tools.SPTools
8 | import com.js.deepsleep.tools.Type
9 | import com.js.deepsleep.data.db.entity.AppSt
10 | import com.js.deepsleep.data.db.entity.Extend
11 | import com.js.deepsleep.xposed.XpUtil
12 | import de.robv.android.xposed.XSharedPreferences
13 |
14 | class XpNSP(private val packageName: String) {
15 |
16 | @Volatile
17 | var appSt: AppSt = AppSt()
18 |
19 | @Volatile
20 | var wakelockEx: Extend = Extend()
21 |
22 | @Volatile
23 | var alarmEx: Extend = Extend()
24 |
25 | @Volatile
26 | private var pref: SharedPreferences? = null
27 |
28 | private var gson: Gson = Gson()
29 |
30 | companion object {
31 |
32 | @Volatile
33 | private var instance: XpNSP? = null
34 |
35 | fun getInstance(packageName: String = "") = instance ?: synchronized(this) {
36 | XpNSP(packageName).also {
37 | it.getPref()
38 | instance = it
39 | }
40 | }
41 | }
42 |
43 | fun getSt() {
44 | try {
45 | appSt.wakelock = getWakelock()
46 | appSt.alarm = getAlarm()
47 | appSt.sync = getSync()
48 | appSt.service = getService()
49 | appSt.broadcast = getBroadcast()
50 |
51 | // XpUtil.log("getSt $appSt")
52 |
53 | } catch (e: Exception) {
54 | XpUtil.log("getSt err: $e")
55 | }
56 | }
57 |
58 | fun getExtends() {
59 | try {
60 | wakelockEx.let {
61 | it.allowList = getAppSet(Type.Wakelock, "allowList")
62 | it.blockList = getAppSet(Type.Wakelock, "blockList")
63 | it.rE = getAppSet(Type.Wakelock, "rE")
64 |
65 | // XpUtil.log("getExtends wakelockEx $wakelockEx")
66 | }
67 | alarmEx.let {
68 | it.allowList = getAppSet(Type.Alarm, "allowList")
69 | it.blockList = getAppSet(Type.Alarm, "blockList")
70 | it.rE = getAppSet(Type.Alarm, "rE")
71 |
72 | // XpUtil.log("getExtends alarmEx $alarmEx")
73 | }
74 | } catch (e: Exception) {
75 | XpUtil.log("getExtends err: $e")
76 | }
77 | }
78 |
79 | fun block(type: Type, mPackageName: String, mTag: String): Boolean {
80 | return when (type) {
81 | Type.Wakelock -> getBlock(mTag, wakelockEx, appSt.wakelock)
82 | Type.Alarm -> getBlock(mTag, alarmEx, appSt.alarm)
83 | Type.Service -> appSt.service
84 | Type.Sync -> appSt.sync
85 | Type.Broadcast -> appSt.broadcast
86 | }
87 | }
88 |
89 | private fun getPref() = pref ?: synchronized(this) {
90 | val p = XSharedPreferences(BuildConfig.APPLICATION_ID, SPTools.SP_NAME)
91 | pref = if (p.file.canRead()) p else null
92 | }
93 |
94 | private fun getWakelock() = run { getAppFlag(Type.Wakelock) }
95 | private fun getAlarm() = run { getAppFlag(Type.Alarm) }
96 | private fun getService() = run { getAppFlag(Type.Service) }
97 | private fun getSync() = run { getAppFlag(Type.Sync) }
98 | private fun getBroadcast() = run { getAppFlag(Type.Broadcast) }
99 |
100 | // 获取 Block
101 | private fun getBlock(mTag: String, extend: Extend, flag: Boolean): Boolean {
102 | if (mTag in extend.allowList) return false
103 | if (mTag in extend.blockList) return true
104 | if (getRE(mTag, extend.rE)) return true
105 | return flag
106 | }
107 |
108 | private fun getRE(mTag: String, rE: Set): Boolean {
109 | if (rE.isEmpty()) {
110 | return false
111 | } else {
112 | rE.forEach {
113 | if (mTag.matches(Regex(it))) {
114 | return true
115 | }
116 | }
117 | return false
118 | }
119 | }
120 |
121 | private fun getAppSet(type: Type, index: String): Set {
122 | return getSet("${packageName}_${type}_$index")
123 | }
124 |
125 | private fun getAppFlag(type: Type): Boolean {
126 | return getBool("${packageName}_${type}")
127 | }
128 |
129 | private fun getBool(key: String, defValue: Boolean = false): Boolean {
130 | return pref?.getBoolean(key, defValue) ?: defValue
131 | }
132 |
133 | private fun getSet(key: String): Set {
134 | val str: String? = pref?.getString(key, "")
135 | return if (str.isNullOrBlank()) {
136 | mutableSetOf()
137 | } else {
138 | val type = object : TypeToken>() {}.type
139 | gson.fromJson(str, type)
140 | }
141 | }
142 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_expand_more_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_filter_list_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_help_24dp.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_other_24dp.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_outline_expand_less_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings_backup_restore_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_theme_24dp.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
15 |
23 |
24 |
31 |
32 |
33 |
34 |
45 |
46 |
47 |
48 |
49 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
19 |
20 |
30 |
31 |
42 |
43 |
53 |
54 |
64 |
65 |
75 |
76 |
88 |
89 |
99 |
100 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_app.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
19 |
20 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_extend.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
21 |
22 |
23 |
28 |
32 |
36 |
37 |
41 |
45 |
49 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | DeepSleep
4 | Test
5 | Test
6 |
7 | filtre
8 | Applications utilisateur
9 | Applications système
10 | Toutes les applications
11 | Applications restreintes
12 | Applications avec fonctionnalités étendues activées
13 | Rechercher
14 | Bonjour, fragment vide
15 | Verrouillage de réveil
16 | Alarme
17 | Serveur
18 | Synchronisation
19 | Diffusion
20 | Contrôlez le verrouillage de réveil, les alarmes, les services, la synchronisation, etc.
21 | Module non actif
22 | Enregistrer
23 | Liste blanche
24 | Liste noire
25 | Blocage - Expression régulière
26 |
27 | Paramètres
28 |
29 | Thème
30 | Thème global
31 | Léger
32 | Foncé
33 | Noir (AMOLED)
34 | Suivre le système
35 |
36 | A propos
37 |
38 | Aide
39 | Cliquez sur l\'icône de l\'application pour accéder aux paramètres globaux de l\'application.
40 |
]]> Appuyez longuement sur le nom de l\'application pour accéder aux paramètres étendus, y compris la liste blanche/liste noire/support d\'expression régulière.
41 |
]]> Priorité : paramètres étendus {Liste blanche> Liste noire> Régulier}> Paramètres globaux
42 |
]]> Si vous utilisez EdXposed ou LSPosed, l'application que vous souhaitez limiter doit être sélectionnée dans la portée d'activation du module.
43 |
]]> Avertissement sérieux : ne restreignez pas les applications système, cela entraînerait des conséquences imprévisibles.
44 |
45 | Contact :\n
46 | Si vous avez des questions ou rencontrez des bogues pendant l\'utilisation, vous pouvez m\'envoyer un e-mail ou ouvrir un nouveau problème. \n
47 | \n
48 | Problème : https://github.com/Jasper-1024/DeepSleep/issues \n
49 | \n
50 | JasperHale: ljy087621@gmail.com
51 | Nom d\'application
52 | Version
53 | Support
54 | Code source
55 | https://github.com/Jasper-1024/DeepSleep
56 | Licence
57 | Autre
58 | Fonctionnalités étendues
59 | Fonction expérimentale
60 | Prise en charge de la liste blanche/liste noire/expression régulière, appuyez longuement sur l\'application pour y accéder.
61 | Sauvegarde et restauration
62 | Sauvegarder les paramètres de toutes les applications installées dans un fichier
63 | Créer un nouveau fichier de sauvegarde
64 | La restauration à partir d\'un fichier de sauvegarde écrasera les paramètres actuels
65 | Restaurer à partir d\'un fichier de sauvegarde
66 | Sauvegarde terminée
67 | Restauration terminée
68 | Erreur de sauvegarde
69 | Erreur de restauration
70 | Les fonctionnalités étendues ne sont pas actives, veuillez les activer dans les paramètres.
71 | Arrêt forcé automatique de l\'application
72 | Forcer l\'arrêt de l\'application après modification des paramètres, la portée doit sélectionner le cadre système
73 | Échec de l\'arrêt forcé de l\'application. Assurez-vous que la portée d\'xposed a sélectionné le cadre système
74 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | DeepSleep
4 | Test
5 | Test
6 |
7 | filter
8 | 用户应用
9 | 系统应用
10 | 全应用
11 | 已限制应用
12 | 以设置拓展功能应用
13 | 搜索
14 | Hello blank fragment
15 | 唤醒锁
16 | 定时器
17 | 后台服务
18 | 同步
19 | 广播
20 | 控制唤醒锁,定时器,服务,同步等
21 | 模块未激活
22 | 保存
23 | 白名单
24 | 黑名单
25 | 拦截-正则表达式
26 |
27 | 设置
28 |
29 | 主题
30 | 全局主题
31 | 浅色
32 | 暗色
33 | 黑色(AMOLED)
34 | 跟随系统
35 |
36 | 关于
37 |
38 | 帮助
39 | 点击应用图标及左侧区域展开全局设置,可限制唤醒锁/闹钟/服务/同步.
40 |
]]>点击应用名称进入拓展设置,包括白名单/黑名单/限制正则支持(需要开启拓展功能支持).
41 |
]]>优先级: 拓展设置{白名单 > 黑名单 > 正则} > 全局设置
42 |
]]>设置后重启应用生效. EdXposed or LSPosed 作用域选中被限制应用.启用强制自动停止APP,需要选择系统框架
43 |
]]>严重警告: 不要轻易限制系统应用,会引起无法预计的后果.
44 |
]]>参见 Android 待机耗电篇 ]]> 以了解更多信息。
45 |
46 | 联系:\n
47 | 如果您在使用过程中有任何疑问或遇到 BUG,您可以邮件我,或者发起新的 Issue.\n
48 | \n
49 | Issue : https://github.com/Jasper-1024/DeepSleep/issues \n
50 | \n
51 | Email : ljy087621@gmail.com
52 | 应用名称
53 | 版本
54 | 支持
55 | 源码
56 | https://github.com/Jasper-1024/DeepSleep
57 | 许可协议
58 | 其他
59 | 拓展功能
60 | 实验功能
61 | 白名单/黑名单/正则表达式支持,长按应用进入.
62 | 备份与恢复
63 | 备份目前所有应用设置到文件
64 | 创建新的备份文件
65 | 从备份文件恢复,会覆盖当前设置
66 | 从备份文件恢复
67 | 备份完成
68 | 恢复完成
69 | 备份遇到错误
70 | 恢复遇到错误
71 | 拓展功能未激活,请在设置开启.
72 | 强制自动停止APP
73 | 设置更改后强制停止 APP,作用域需选择系统框架
74 | 终止程序失败,请确保 xposed 作用域选择了系统框架
75 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - Reply
5 | - Reply to all
6 |
7 |
8 |
9 | - reply
10 | - reply_all
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1C8ADB
4 | #67baff
5 | #005DA9
6 | #ffffff
7 |
8 | #1C8ADB
9 | #263238
10 | #3949AB
11 | #000000
12 |
13 | #757575
14 |
15 | #20B10000
16 | #40B10000
17 | #30B10000
18 | #00000000
19 |
20 | #401C8ADB
21 |
22 | #ff000000
23 | #424242
24 | #212121
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 | 16dp
8 |
9 | 8dp
10 | 192dp
11 | 16dp
12 | 100dp
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1C8ADB
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @string/light_theme_name
5 | - @string/dark_theme_name
6 | - @string/system_theme_name
7 |
8 |
9 |
10 | - light
11 | - dark
12 | - default
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DeepSleep
3 | Test
4 | Test
5 | filter
6 | show user app
7 | show system app
8 | show all app
9 | show restricted app
10 | show Extend enabled app
11 | search
12 | Hello blank fragment
13 | wakelock
14 | alarm
15 | server
16 | an test module
17 | sync
18 | Module is not active
19 | Save
20 | AllowList
21 | BlockList
22 | Block-Regular expression
23 |
24 | Settings
25 | Theme
26 | General theme
27 | Light
28 | Dark
29 | Black (AMOLED)
30 | Follow System
31 |
32 | About
33 |
34 | Help
35 | Click the application icon to enter the app\'s global settings.
36 |
]]> Long Click the application name to enter the extended settings, including whitelist/blacklist/restricted regular support.
37 |
]]> Priority: Extended settings {Whitelist> Blacklist> Regular}> Global Settings
38 |
]]> If you are using EdXposed or LSPosed, the app you want limited need to be selected in the module activation scope.
39 |
]]> Serious warning, don\'t restrict system application, it will cause unpredictable consequences.
40 |
41 | Contact:\n
42 | If you have any questions or encounter bugs during use, you can email me or initiate a new issue.\n
43 | \n
44 | Issue : https://github.com/Jasper-1024/DeepSleep/issues \n
45 | \n
46 | JasperHale: ljy087621@gmail.com
47 | AppName
48 | Version
49 | Support
50 | Source Code
51 | https://github.com/Jasper-1024/DeepSleep
52 | License
53 | Other
54 | Extend function
55 | Experimental function
56 | Allow list/Block list/Regular expression support
57 | Backup and restore
58 | Backup settings of installed app into file
59 | Create new backup file
60 | Restoring from a backup file will overwrite the current settings
61 | Restore from backup file
62 | Backup complete
63 | Restore complete
64 | Backup Error
65 | Restore Error
66 | Extend not active,please enable extend function.
67 | broadcast
68 |
69 |
70 |
71 | - com.js.deepsleep
72 |
73 | Force stop automatically
74 | Forced to stop APP after setting change,Lsposed/Edxposed scope need to select system framework
75 | Force stop failed,Maybe system framework not selected on xposed.
76 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
18 |
19 |
23 |
24 |
27 |
28 |
31 |
32 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_descriptor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/settings.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
18 |
19 |
20 |
21 |
24 |
25 |
29 |
30 |
34 |
35 |
36 |
37 |
41 |
42 |
47 |
48 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/test/java/com/js/deepsleep/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.js.deepsleep
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.8.22'
4 | ext.ksp_version = '1.8.22-1.0.11'
5 | repositories {
6 | google()
7 | gradlePluginPortal()
8 | mavenCentral()
9 | maven { url "https://jcenter.bintray.com" }
10 | maven { url "https://jitpack.io" }
11 | maven { url "https://api.xposed.info/" }
12 | // jcenter()
13 | }
14 | dependencies {
15 | classpath 'com.android.tools.build:gradle:8.0.2'
16 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
17 |
18 | // NOTE: Do not place your application dependencies here; they belong
19 | // in the individual module build.gradle files
20 | def nav_version = '2.6.0'
21 | classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
22 |
23 | }
24 | }
25 |
26 | allprojects {
27 | repositories {
28 | google()
29 | mavenCentral()
30 | maven { url 'https://jitpack.io' }
31 | maven { url 'https://api.xposed.info/' }
32 | }
33 | }
34 |
35 | task clean(type: Delete) {
36 | delete rootProject.buildDir
37 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.daemon=true
10 | org.gradle.parallel=true
11 | org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 | # AndroidX package structure to make it clearer which packages are bundled with the
17 | # Android operating system, and which are packaged with your app"s APK
18 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
19 | android.useAndroidX=true
20 | # Automatically convert third-party libraries to use AndroidX
21 | android.enableJetifier=true
22 | # Kotlin code style for this project: "official" or "obsolete":
23 | kotlin.code.style=official
24 | android.defaults.buildfeatures.buildconfig=true
25 | #android.nonTransitiveRClass=false
26 | android.nonFinalResIds=false
27 | # configuration cache
28 | org.gradle.unsafe.configuration-cache=true
29 | org.gradle.unsafe.configuration-cache-problems=warn
30 | # No R
31 | android.nonTransitiveRClass=true
32 | # ?????????
33 | kotlin.incremental.useClasspathSnapshot=true
34 | # ??kotlin????????
35 | kotlin.incremental=true
36 | kotlin.incremental.java=true
37 | kotlin.incremental.js=true
38 | kotlin.caching.enabled=true
39 | # ??kotlin????
40 | kotlin.parallel.tasks.in.project=true
41 | # ?????????
42 | kotlin.build.report.output=file
43 | #??kapt
44 | kapt.use.worker.api=true
45 | kapt.incremental.apt=true
46 | # kapt avoiding ???kapt???????????????????????????:app:kaptGenerateStubsDebugKotlin???
47 | kapt.include.compile.classpath=false
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jasper-1024/DeepSleep/6ced7ab75d1d724cba8885a1bb2734d839ae0ea8/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jun 19 20:27:14 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "DeepSleep"
--------------------------------------------------------------------------------