├── .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 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 21 | 22 | 23 | 24 | 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 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 18 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/menu/toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 13 | 17 | 21 | 22 | 27 | 28 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 53 | -------------------------------------------------------------------------------- /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" --------------------------------------------------------------------------------