├── app ├── .gitignore ├── src │ ├── main │ │ ├── ic_launcher-playstore.png │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── drawable │ │ │ │ ├── ic_applist.xml │ │ │ │ ├── gradient_color.xml │ │ │ │ ├── gradient_color_dark.xml │ │ │ │ ├── ic_warning.xml │ │ │ │ ├── ic_success_fill.xml │ │ │ │ ├── ic_error_fill.xml │ │ │ │ ├── ic_question_fill.xml │ │ │ │ ├── ic_log.xml │ │ │ │ ├── ic_save.xml │ │ │ │ ├── ic_trash.xml │ │ │ │ ├── ic_check_circle.xml │ │ │ │ ├── ic_settings.xml │ │ │ │ ├── ic_assignment.xml │ │ │ │ ├── ic_info.xml │ │ │ │ ├── ic_icon.xml │ │ │ │ ├── ic_rocket_fill.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── themes.xml │ │ │ │ └── strings.xml │ │ │ ├── menu │ │ │ │ ├── menu_run_log.xml │ │ │ │ ├── menu_settings.xml │ │ │ │ └── menu_show_app_list.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ ├── activity_settings.xml │ │ │ │ ├── toolbar.xml │ │ │ │ ├── tips_layout.xml │ │ │ │ ├── activity_application_list.xml │ │ │ │ ├── activity_doze_run_log.xml │ │ │ │ ├── activity_splash.xml │ │ │ │ ├── application_unit_layout.xml │ │ │ │ └── dialog_about.xml │ │ │ ├── xml │ │ │ │ ├── settings_preferences.xml │ │ │ │ └── shortcuts.xml │ │ │ ├── values-night │ │ │ │ └── themes.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── values-zh-rCN │ │ │ │ └── strings.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── hwwwwwlemon │ │ │ │ └── dozeconfig │ │ │ │ ├── activity │ │ │ │ ├── base │ │ │ │ │ └── BaseActivity.kt │ │ │ │ ├── shortcuts │ │ │ │ │ └── RefreshDozeWhitelist.kt │ │ │ │ ├── SplashActivity.kt │ │ │ │ ├── DozeRunLogActivity.kt │ │ │ │ ├── SettingsActivity.kt │ │ │ │ └── ApplicationsListActivity.kt │ │ │ │ ├── utils │ │ │ │ ├── ToastUtil.kt │ │ │ │ ├── MyPreferences.kt │ │ │ │ ├── Utils.kt │ │ │ │ └── DozeFileUtil.kt │ │ │ │ ├── DozeManager.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ └── adapter │ │ │ │ └── ApplicationAdapter.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── hwwwwwlemon │ │ │ └── dozeconfig │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── github │ │ └── hwwwwwlemon │ │ └── dozeconfig │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── dozewhitelist ├── META-INF │ └── com │ │ └── google │ │ └── android │ │ ├── updater-script │ │ └── update-binary ├── doze.conf ├── log.sh ├── module.prop ├── whitelist.sh ├── service.sh ├── customize.sh └── doze.sh ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── README.md ├── LICENSE ├── settings.gradle ├── gradle.properties ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /dozewhitelist/META-INF/com/google/android/updater-script: -------------------------------------------------------------------------------- 1 | #MAGISK 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /dozewhitelist/doze.conf: -------------------------------------------------------------------------------- 1 | whitelist=" 2 | +com.tencent.mm 3 | +com.tencent.qq 4 | +com.tencent.tim 5 | +com.netease.cloudmusic 6 | " -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hwwwww-dev/DozeConfig/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /dozewhitelist/log.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | export TZ=Asia/Shanghai 3 | Log() { 4 | txt="/sdcard/Android/doze.log" 5 | echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >>$txt 6 | 7 | } 8 | -------------------------------------------------------------------------------- /.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/ 17 | /app/release/ 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DozeConfig 2 | 3 | + 本APP配合我的深度Doze模块食用,更加简单方便添加白名单应用 4 | 5 | ### 使用条件 6 | 7 | + 必须刷了深度Doze模块,如果没有先刷一下模块哦(Magisk模块) 8 | + 必须给予读取应用列表和存储读写权限 9 | + 非必须授予Root权限,Root权限只是为了直接应用新的白名单 10 | 11 | ### 说明 12 | 13 | 1. 安卓开发新手,有不足可以指出 14 | 2. 要忙毕设了,有bug提交issues或者酷安私信和我说,会尽快修复 15 | 3. 参考了许多大佬的开源项目,非常感谢 16 | 17 | ### License 18 | 19 | 本项目基于[MIT] 20 | 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Hwwwww 2021 https://github.com/HwwwwwLemon/DozeConfig All Rights Reserved. 3 | # 4 | 5 | #Mon May 10 11:36:30 CST 2021 6 | distributionBase=GRADLE_USER_HOME 7 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-bin.zip 8 | distributionPath=wrapper/dists 9 | zipStorePath=wrapper/dists 10 | zipStoreBase=GRADLE_USER_HOME 11 | -------------------------------------------------------------------------------- /dozewhitelist/module.prop: -------------------------------------------------------------------------------- 1 | id=dozewhitelist 2 | name=深度Doze&清理电池优化白名单 3 | version=2021.05.18 4 | versionCode=3 5 | author=酷安ID:Hwwwww 6 | description=❗️在/sdcard/Android路径下doze.conf白名单配置文件,没有则不优化,如果没有请到Doze配置APP内生成。❗️❗️扫描时间定为8s,不生效或者开屏联网过慢请到service.sh修改,暂时不打算做并行扫描,得不偿失。❗️❗️❗️如果真的睡死了尝试使用温和一点的代码,doze.sh里修改,然后你得把不温和的注释掉。❗️❗️❗️❗️有问题可以留言但最好先看看楼里有没有解答或者去看看之前的版本下有没有相关的问题,实在没有私信或者Github提交issues。v3更新:1、去除Toast提示(之后也只会有一个版本)。2、加入白名单控制APP(详细见APP👉关于)3、一些优化 -------------------------------------------------------------------------------- /dozewhitelist/whitelist.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | source /data/adb/modules/dozewhitelist/log.sh 3 | 4 | #执行移出电池优化名单 5 | 6 | if [ -f "/sdcard/Android/doze.conf" ]; then 7 | source /sdcard/Android/doze.conf 8 | noDozes=$(pm list packages -e | sed "s/package:/-/g")$whitelist 9 | dumpsys deviceidle whitelist $noDozes 10 | check=$? 11 | Log "执行清理电池优化名单,应用白名单 code:$check" 12 | if [[ $check == 0 ]]; then 13 | Log "清理电池优化名单成功!" 14 | else 15 | Log "清理电池优化名单成功!" 16 | fi 17 | else 18 | Log "未找到doze.conf,Doze白名单优化未执行,请到APP生成白名单或者自行创建白名单。" 19 | fi 20 | -------------------------------------------------------------------------------- /dozewhitelist/service.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/... 3 | # This will make your scripts compatible even if Magisk change its mount point in the future 4 | 5 | until [ $(getprop init.svc.bootanim) = "stopped" ]; do 6 | sleep 2s 7 | done 8 | source /data/adb/modules/dozewhitelist/log.sh 9 | 10 | #扫描时间隔建议小于等于10s,不可以小于0,修改后重启生效,建议为8s 11 | scanInterval=8s 12 | 13 | sleep 20s 14 | 15 | echo "" >/sdcard/Android/doze.log 16 | 17 | Log "⚒开始执行doze.sh⚒" 18 | 19 | Log "👉开机首次刷新白名单" 20 | #首次刷新白名单 21 | sh /data/adb/modules/dozewhitelist/whitelist.sh 22 | 23 | while :; do 24 | sh /data/adb/modules/dozewhitelist/doze.sh 25 | sleep $scanInterval 26 | done 27 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /dozewhitelist/customize.sh: -------------------------------------------------------------------------------- 1 | SKIPUNZIP=0 2 | REPLACE=" 3 | " 4 | if [[ $(find /data/app -name "com.github.hwwwwwlemon.dozeconfig*" -type d) ]]; then 5 | echo " * 已存在Toast依赖" 6 | rm -rf $MODPATH/dozeconfig.apk 7 | else 8 | echo "正在安装DozeConfig" 9 | echo "酷安@Hwwwww" 10 | pm install -r -g $MODPATH/dozeconfig.apk >/dev/null 2>&1 11 | if [[ $? == 0 ]]; then 12 | echo " * 安裝成功" 13 | else 14 | echo " * 安裝失败" 15 | fi 16 | rm -rf $MODPATH/dozeconfig.apk 17 | fi 18 | 19 | echo "" 20 | echo " 正在创建白名单 " 21 | echo "Path:/Android/doze.conf" 22 | cat $MODPATH/doze.conf >/storage/emulated/0/Android/doze.conf 23 | 24 | if [[ $? == 0 ]]; then 25 | echo "******************" 26 | echo " 安装完成 " 27 | echo "******************" 28 | else 29 | echo "******************" 30 | echo " 安装失败 " 31 | echo "******************" 32 | fi 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_applist.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License (MIT) 3 | 4 | Copyright © 2021 Hwwwww 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | associated documentation files (the “Software”), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial 13 | portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /dozewhitelist/doze.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | export TZ=Asia/Shanghai 3 | source /data/adb/modules/dozewhitelist/log.sh 4 | 5 | #识别屏幕状态 6 | screen=$(dumpsys window policy | grep "mInputRestricted" | cut -d= -f2) 7 | 8 | #Log "运行状态: $screen,DEEP:$(dumpsys deviceidle get deep),FORCE: $(dumpsys deviceidle get force)" 9 | 10 | dumpsys deviceidle | grep -q Enabled=true 11 | check=$? 12 | 13 | if [[ $screen == true ]]; then 14 | if [[ $check == 1 ]]; then 15 | #执行移出电池优化名单 16 | sh /data/adb/modules/dozewhitelist/whitelist.sh 17 | sleep 3s 18 | #level 1 dumpsys deviceidle enable 19 | #level 2 dumpsys deviceidle enable deep 20 | #默认开启level 3 21 | dumpsys deviceidle enable deep 22 | dumpsys deviceidle force-idle deep 23 | 24 | #修改记得注释掉 25 | Log "😴熄灭屏幕进入深度 Doze😴" 26 | #日志 27 | Log "运行状态: $screen,DEEP:$(dumpsys deviceidle get deep),FORCE: $(dumpsys deviceidle get force)" 28 | fi 29 | else 30 | if [[ $check == 0 ]]; then 31 | 32 | dumpsys deviceidle disable all 33 | dumpsys deviceidle unforce 34 | 35 | Log "🥱点亮屏幕退出深度 Doze🥱" 36 | #日志 37 | Log "运行状态: $screen,DEEP:$(dumpsys deviceidle get deep),FORCE: $(dumpsys deviceidle get force)" 38 | fi 39 | fi 40 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | include ':app' 24 | rootProject.name = "DozeConfig" -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 | 16dp 26 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Hwwwww 2021 https://github.com/HwwwwwLemon/DozeConfig All Rights Reserved. 3 | # 4 | 5 | # Project-wide Gradle settings. 6 | # IDE (e.g. Android Studio) users: 7 | # Gradle settings configured through the IDE *will override* 8 | # any settings specified in this file. 9 | # For more details on how to configure your build environment visit 10 | # http://www.gradle.org/docs/current/userguide/build_environment.html 11 | # Specifies the JVM arguments used for the daemon process. 12 | # The setting is particularly useful for tweaking memory settings. 13 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | # AndroidX package structure to make it clearer which packages are bundled with the 19 | # Android operating system, and which are packaged with your app"s APK 20 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 21 | android.useAndroidX=true 22 | # Automatically convert third-party libraries to use AndroidX 23 | android.enableJetifier=true 24 | # Kotlin code style for this project: "official" or "obsolete": 25 | kotlin.code.style=official 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | #FFFFFF 27 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_run_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gradient_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 27 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gradient_color_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 28 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 32 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/test/java/com/github/hwwwwwlemon/dozeconfig/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig 24 | 25 | import org.junit.Test 26 | 27 | import org.junit.Assert.* 28 | 29 | /** 30 | * Example local unit test, which will execute on the development machine (host). 31 | * 32 | * See [testing documentation](http://d.android.com/tools/testing). 33 | */ 34 | class ExampleUnitTest { 35 | @Test 36 | fun addition_isCorrect() { 37 | assertEquals(4, 2 + 2) 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 29 | 30 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 35 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_success_fill.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 28 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tips_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 29 | 30 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_error_fill.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_question_fill.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 26 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/activity/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.activity.base 24 | 25 | import androidx.appcompat.app.AppCompatActivity 26 | import androidx.appcompat.widget.Toolbar 27 | import com.github.hwwwwwlemon.dozeconfig.R 28 | import com.github.hwwwwwlemon.dozeconfig.utils.StatusBarUtil 29 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 30 | 31 | open class BaseActivity : AppCompatActivity() { 32 | open lateinit var mToolbar: Toolbar 33 | 34 | open fun initStatusBar() { 35 | mToolbar = findViewById(R.id.toolbar) 36 | setSupportActionBar(mToolbar) 37 | StatusBarUtil.immersive(this) 38 | StatusBarUtil.setPaddingSmart(this, mToolbar) 39 | if (!Utils.isDarkMode(this)) { 40 | StatusBarUtil.darkMode(this) 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/github/hwwwwwlemon/dozeconfig/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig 24 | 25 | import androidx.test.platform.app.InstrumentationRegistry 26 | import androidx.test.ext.junit.runners.AndroidJUnit4 27 | 28 | import org.junit.Test 29 | import org.junit.runner.RunWith 30 | 31 | import org.junit.Assert.* 32 | 33 | /** 34 | * Instrumented test, which will execute on an Android device. 35 | * 36 | * See [testing documentation](http://d.android.com/tools/testing). 37 | */ 38 | @RunWith(AndroidJUnit4::class) 39 | class ExampleInstrumentedTest { 40 | @Test 41 | fun useAppContext() { 42 | // Context of the app under test. 43 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 44 | assertEquals("com.github.hwwwwwlemon.dozeconfig", appContext.packageName) 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_show_app_list.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 28 | 32 | 36 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_log.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_save.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_trash.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 26 | 28 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_circle.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 30 | 33 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings.xml: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_assignment.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 30 | 33 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/xml/settings_preferences.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 26 | 28 | 33 | 38 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | #FFd4bff9 27 | #FFBB86FC 28 | #FF9965f4 29 | #FF7e3ff2 30 | #FF6200EE 31 | #FF4B00D1 32 | #FF3700B3 33 | #FFB2DFDB 34 | #FF03DAC5 35 | #FF4DB6AC 36 | #FF26A69A 37 | #FF009688 38 | #FF018786 39 | #FF000000 40 | #FFFFFFFF 41 | #4CAE50 42 | #FF2828 43 | #7AB67C 44 | #FF5858 45 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 26 | 28 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_application_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 31 | 32 | 33 | 34 | 38 | 41 | 42 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/xml/shortcuts.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 33 | 37 | 38 | 44 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_doze_run_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 31 | 32 | 33 | 39 | 44 | 45 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 | 26 | 39 | 40 | 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/activity/shortcuts/RefreshDozeWhitelist.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | 24 | package com.github.hwwwwwlemon.dozeconfig.activity.shortcuts 25 | 26 | import android.app.Activity 27 | import android.os.Bundle 28 | import android.os.Handler 29 | import com.github.hwwwwwlemon.dozeconfig.R 30 | import com.github.hwwwwwlemon.dozeconfig.utils.DozeFileUtil 31 | import com.github.hwwwwwlemon.dozeconfig.utils.StatusBarUtil 32 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 33 | import kotlin.system.exitProcess 34 | 35 | class RefreshDozeWhitelist : Activity() { 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | StatusBarUtil.immersive(this) 39 | } 40 | 41 | override fun onResume() { 42 | super.onResume() 43 | if (DozeFileUtil.checkAppList.size == 0) { 44 | DozeFileUtil.loadDozeFile(this) 45 | } 46 | val handler = Handler() 47 | handler.postDelayed({ 48 | if (Utils.refreshDozeWhitelist(this)) { 49 | Utils.showToast(this, getString(R.string.whitelist_opt_success)) 50 | } else { 51 | Utils.showToast(this, getString(R.string.whitelist_opt_failed)) 52 | } 53 | finish() 54 | }, 500) 55 | handler.postDelayed({ 56 | exitProcess(0) 57 | }, 3000) 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_rocket_fill.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/utils/ToastUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.utils 24 | 25 | 26 | import android.R 27 | import android.annotation.SuppressLint 28 | import android.content.Context 29 | import android.graphics.Color 30 | import android.os.Handler 31 | import android.view.Gravity 32 | import android.widget.LinearLayout 33 | import android.widget.TextView 34 | import android.widget.Toast 35 | 36 | 37 | class ToastUtil { 38 | private var toast: Toast? = null 39 | 40 | fun init(ctx: Context, message: String): ToastUtil { 41 | default(ctx, message) 42 | return this 43 | } 44 | 45 | fun init(ctx: Context, res: Int): ToastUtil { 46 | default(ctx, ctx.getString(res)) 47 | return this 48 | } 49 | 50 | @SuppressLint("ShowToast") 51 | private fun default(ctx: Context, message: String): ToastUtil { 52 | toast = Toast.makeText(ctx, message, Toast.LENGTH_SHORT) 53 | val view: LinearLayout = toast?.view as LinearLayout 54 | view.gravity = Gravity.CENTER 55 | val tv = view.findViewById(R.id.message) as TextView 56 | tv.setBackgroundColor(Color.TRANSPARENT) 57 | tv.gravity = Gravity.CENTER 58 | return this 59 | } 60 | 61 | fun indefinite(duration: Long): ToastUtil { 62 | Handler().postDelayed({ toast?.cancel() }, duration) 63 | return this 64 | } 65 | 66 | fun show() { 67 | toast?.show() 68 | } 69 | } -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 | 26 | 39 | 49 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 27 | 28 | 30 | 31 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 58 | 59 | 62 | 63 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 30 | 32 | 33 | 39 | 42 | 45 | 46 | 47 | 48 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 30 | 37 | 38 | 42 | 47 | 51 | 57 | 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/activity/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.activity 24 | 25 | import android.content.Intent 26 | import android.os.Bundle 27 | import android.os.Handler 28 | import android.text.method.LinkMovementMethod 29 | import androidx.appcompat.app.AppCompatActivity 30 | import androidx.core.text.HtmlCompat 31 | import com.github.hwwwwwlemon.dozeconfig.DozeManager 32 | import com.github.hwwwwwlemon.dozeconfig.MainActivity 33 | import com.github.hwwwwwlemon.dozeconfig.R 34 | import com.github.hwwwwwlemon.dozeconfig.databinding.ActivitySplashBinding 35 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 36 | 37 | class SplashActivity : AppCompatActivity() { 38 | private lateinit var mBinding: ActivitySplashBinding 39 | override fun onCreate(savedInstanceState: Bundle?) { 40 | super.onCreate(savedInstanceState) 41 | mBinding = ActivitySplashBinding.inflate(layoutInflater) 42 | setContentView(mBinding.root) 43 | 44 | mBinding.author.movementMethod = LinkMovementMethod.getInstance(); 45 | mBinding.author.text = 46 | HtmlCompat.fromHtml( 47 | getString(R.string.author) + "@Hwwwww", 48 | HtmlCompat.FROM_HTML_MODE_LEGACY 49 | ) 50 | mBinding.version.text = "version: " + resources.getString(R.string.version) 51 | } 52 | 53 | override fun onResume() { 54 | try { 55 | val handler = Handler() 56 | handler.postDelayed({ 57 | if (DozeManager.checkPermission(this)) { 58 | Utils.showToast(this, "😴") 59 | val intent = Intent(this, MainActivity::class.java) 60 | startActivity(intent) 61 | finish() 62 | } else { 63 | mBinding.prompt.text = getString(R.string.permission_prompt) 64 | } 65 | 66 | }, 1500) 67 | } catch (e: Exception) { 68 | e.printStackTrace() 69 | } 70 | 71 | super.onResume() 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/utils/MyPreferences.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.utils 24 | 25 | import android.annotation.SuppressLint 26 | import android.content.Context 27 | import android.content.SharedPreferences 28 | import androidx.preference.PreferenceManager 29 | 30 | 31 | class MyPreferences { 32 | 33 | private val TAG = "MyPreferences" 34 | private lateinit var sharedPreferences: SharedPreferences 35 | private lateinit var editor: SharedPreferences.Editor 36 | 37 | @SuppressLint("CommitPrefEdits") 38 | constructor(ctx: Context) { 39 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx) 40 | editor = sharedPreferences.edit() 41 | } 42 | 43 | @SuppressLint("CommitPrefEdits") 44 | constructor(ctx: Context, fileName:String){ 45 | sharedPreferences = ctx.getSharedPreferences(fileName,Context.MODE_PRIVATE) 46 | editor = sharedPreferences.edit() 47 | } 48 | 49 | 50 | fun save(key: String, defValue: Any) { 51 | when (defValue) { 52 | is Int -> editor.putInt(key, defValue) 53 | is Float -> editor.putFloat(key, defValue) 54 | is String -> editor.putString(key, defValue) 55 | is Boolean -> editor.putBoolean(key, defValue) 56 | is Long -> editor.putLong(key, defValue) 57 | } 58 | editor.apply() 59 | 60 | } 61 | 62 | fun get(key: String, defValue: Any): Any { 63 | return when (defValue) { 64 | is Int -> sharedPreferences.getInt(key, defValue) 65 | is Float -> sharedPreferences.getFloat(key, defValue) 66 | is String -> sharedPreferences.getString(key, defValue) as Any 67 | is Boolean -> sharedPreferences.getBoolean(key, defValue) 68 | is Long -> sharedPreferences.getLong(key, defValue) 69 | else -> "" 70 | } 71 | } 72 | 73 | 74 | fun removeUserInfo(key: String) { 75 | editor.remove(key) 76 | editor.apply() 77 | } 78 | 79 | 80 | fun clearUserInfo() { 81 | editor.clear() 82 | editor.apply() 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/utils/Utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.utils 24 | 25 | import android.content.Context 26 | import android.content.pm.ApplicationInfo 27 | import android.content.pm.PackageManager 28 | import android.content.res.Configuration 29 | import android.util.Log 30 | import android.util.TypedValue 31 | import java.io.DataOutputStream 32 | 33 | 34 | object Utils { 35 | 36 | fun refreshDozeWhitelist(ctx: Context): Boolean { 37 | 38 | if (DozeFileUtil.checkAppList.size==0){ 39 | return false 40 | } 41 | val sb = StringBuffer("dumpsys deviceidle whitelist ") 42 | val app = getAppList(ctx) 43 | app.forEach { 44 | sb.append("-").append(it.packageName).append(" ") 45 | } 46 | DozeFileUtil.checkAppList.forEach { 47 | sb.append("+").append(it.packageName).append(" ") 48 | } 49 | val suProcess = Runtime.getRuntime().exec("su") 50 | val os = DataOutputStream(suProcess.outputStream) 51 | os.writeBytes(sb.toString()) 52 | os.flush() 53 | os.close() 54 | val exitValue = suProcess.waitFor() 55 | Log.e("code", exitValue.toString()) 56 | return exitValue == 0 57 | } 58 | 59 | 60 | fun isDarkMode(ctx: Context): Boolean { 61 | val mode = ctx.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK 62 | return mode == Configuration.UI_MODE_NIGHT_YES; 63 | } 64 | 65 | fun getColorPrimary(ctx: Context): Int { 66 | val typedValue = TypedValue() 67 | ctx.theme.resolveAttribute(android.R.attr.colorPrimary, typedValue, true) 68 | return typedValue.data 69 | } 70 | 71 | fun getAppList(ctx: Context): MutableList { 72 | val pm: PackageManager = ctx.packageManager 73 | return pm.getInstalledApplications(0) 74 | 75 | } 76 | 77 | fun showToast(ctx: Context, content: String, duration: Int = 3000) { 78 | ToastUtil().init(ctx, content).indefinite(duration.toLong()).show() 79 | } 80 | 81 | fun showToast(ctx: Context, res: Int, duration: Int = 3000) { 82 | ToastUtil().init(ctx, res).indefinite(duration.toLong()).show() 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/utils/DozeFileUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.utils 24 | 25 | import android.content.Context 26 | import android.content.pm.ApplicationInfo 27 | import com.github.hwwwwwlemon.dozeconfig.DozeManager 28 | import com.github.hwwwwwlemon.dozeconfig.adapter.ApplicationAdapter 29 | import kotlinx.coroutines.* 30 | 31 | object DozeFileUtil { 32 | val checkAppList = mutableListOf() 33 | val errorList = mutableListOf() 34 | var dozeApps = mutableListOf() 35 | private val controlScope = CoroutineScope(Dispatchers.Default) 36 | fun loadDozeFile(ctx: Context): Boolean { 37 | var flag = true 38 | try { 39 | checkAppList.clear() 40 | dozeApps.clear() 41 | errorList.clear() 42 | val dozeContent = DozeManager.readFile(DozeManager.DOZE_FILE_PATH, ctx, "\n") 43 | val pm = ctx.packageManager 44 | Regex("[a-z0-9]{1,24}\\.(.+)").findAll(dozeContent).forEach { 45 | dozeApps.add(it.value.trim()) 46 | } 47 | for (i in dozeApps) { 48 | try { 49 | val app = pm.getApplicationInfo(i, 0) 50 | val flag = if ((app.flags and ApplicationInfo.FLAG_SYSTEM) == 0) 1 else 2 51 | checkAppList.add( 52 | ApplicationAdapter.Apps( 53 | app, 54 | i, 55 | pm.getApplicationLabel(app).toString(), 56 | flag, 57 | ) 58 | ) 59 | } catch (e: Exception) { 60 | e.printStackTrace() 61 | errorList.add("\uD83D\uDC49 $i ❌") 62 | flag = false 63 | continue 64 | } 65 | } 66 | 67 | } catch (e: Exception) { 68 | e.printStackTrace() 69 | flag = false 70 | } 71 | return flag 72 | } 73 | 74 | 75 | fun saveDozeFile(ctx: Context): Boolean { 76 | return runBlocking { 77 | controlScope.launch { 78 | val sb = StringBuilder("whitelist=\"\n") 79 | checkAppList.forEach { 80 | sb.append("+").append(it.packageName).append("\n") 81 | } 82 | val result = sb.append("\"").toString() 83 | DozeManager.writeFile(DozeManager.DOZE_FILE_PATH, result, ctx) 84 | } 85 | delay(200L) 86 | return@runBlocking DozeManager.checkDozeFile(ctx) 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | plugins { 24 | id 'com.android.application' 25 | id 'kotlin-android' 26 | } 27 | repositories { 28 | maven { url 'https://www.jitpack.io' } 29 | } 30 | android { 31 | compileSdkVersion 29 32 | buildToolsVersion "30.0.3" 33 | 34 | defaultConfig { 35 | applicationId "com.github.hwwwwwlemon.dozeconfig" 36 | minSdkVersion 25 37 | targetSdkVersion 29 38 | versionCode 10202 39 | versionName "1.2.2 Release" 40 | 41 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 42 | 43 | ndk { 44 | abiFilters 'arm64-v8a'//'armeabi-v7a', 'x86','armeabi'','x86_64','arm64-v8a' 45 | } 46 | } 47 | 48 | buildTypes { 49 | release { 50 | minifyEnabled false 51 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 52 | } 53 | } 54 | buildFeatures { 55 | dataBinding true 56 | viewBinding true 57 | } 58 | compileOptions { 59 | sourceCompatibility JavaVersion.VERSION_1_8 60 | targetCompatibility JavaVersion.VERSION_1_8 61 | } 62 | android { 63 | packagingOptions { 64 | exclude 'META-INF/*.kotlin_module' 65 | } 66 | } 67 | 68 | kotlinOptions { 69 | jvmTarget = '1.8' 70 | } 71 | } 72 | 73 | dependencies { 74 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 75 | implementation 'androidx.core:core-ktx:1.3.2' 76 | implementation 'androidx.appcompat:appcompat:1.2.0' 77 | implementation 'com.google.android.material:material:1.3.0' 78 | implementation 'androidx.preference:preference-ktx:1.1.1' 79 | implementation 'com.android.support.constraint:constraint-layout:2.0.4' 80 | implementation "androidx.recyclerview:recyclerview:1.2.0" 81 | 82 | implementation 'me.zhanghai.android.fastscroll:library:1.1.5' 83 | implementation 'com.scwang.smart:refresh-layout-kernel:2.0.3' 84 | implementation 'com.scwang.smart:refresh-header-material:2.0.3' 85 | implementation 'com.github.bumptech.glide:glide:4.12.0' 86 | implementation 'androidx.preference:preference-ktx:1.1.1' 87 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 88 | annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' 89 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9' 90 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' 91 | testImplementation 'junit:junit:4.13.2' 92 | androidTestImplementation 'androidx.test.ext:junit:1.1.2' 93 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 94 | 95 | } 96 | 97 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | Doze配置 27 | 欢迎使用 28 | 模块运行日志 29 | 设置 30 | 关于 31 | 白名单列表 32 | 应用列表 33 | 选择Doze白名单 34 | 未找到白名单文件 35 | 请检查 sdcard/Android/doze.conf 是否存在? 36 | 找到白名单文件 37 | 尽情享用吧!🚀(点我) 38 | 白名单文件发生了错误!😭(点我查看错误) 39 | 搜索 40 | 请输入包名或应用名 41 | 日志文件 42 | 没有找到日志文件! 43 | 找到日志文件! 44 | 日志 45 | 显示系统应用 46 | 保存 47 | 删除日志 48 | 酷安: 49 | 50 | 这个应用是为了方便Doze模块添加白名单开发的。\n我们会获取一些隐私相关的权限来保证应用的正常运行:\n👉1、存储读写权限(读取白名单以及日志文件)\n👉2、读取应用列表权限(读取应用列表)\n👉3、Root权限(优化白名单)\n你在使用的过程中如果遇到任何问题(如Bug、程序崩溃等)可以在GitHub提交issues或者在酷安私信我 51 | 52 | 提示 53 | 你确定要删除日志文件? 54 | 更新日志:\n1、修复bug\n2、添加配置文件错误查看器 55 | 56 | 请给予相关权限(读写手机存储权限),否则无法正常使用本应用! 57 | 58 | 我还在滑动,给我停下来再操作! 59 | 保存成功! 60 | 保存失败! 61 | 62 | 常规 63 | 高级 64 | 延迟加载图标 65 | 在滑动的时候降低CPU的占用(开了约等于没开,作用也不是很大) 66 | 开启白名单优化 67 | 点击主界面卡片5次优化(需要Root) 68 | 自动保存Doze配置 69 | 自动保存doze.conf不需要点击右上角的保存 70 | 优化白名单 71 | 应用列表 72 | 优化成功! 73 | 优化失败! 74 | 删除配置文件 75 | 取消 76 | 确定 77 | 删除成功! 78 | 删除失败! 79 | 此操作会删除Doze白名单配置文件,这会直接导致模块和应用无法正常的工作。\n\n你确定删除吗? 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/application_unit_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 31 | 32 | 33 | 40 | 41 | 49 | 50 | 62 | 63 | 77 | 78 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/activity/DozeRunLogActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.activity 24 | 25 | import android.os.Bundle 26 | import android.view.Menu 27 | import android.view.MenuItem 28 | import android.widget.TextView 29 | import androidx.appcompat.app.AlertDialog 30 | import com.github.hwwwwwlemon.dozeconfig.DozeManager 31 | import com.github.hwwwwwlemon.dozeconfig.R 32 | import com.github.hwwwwwlemon.dozeconfig.activity.base.BaseActivity 33 | import com.github.hwwwwwlemon.dozeconfig.databinding.ActivityDozeRunLogBinding 34 | import com.github.hwwwwwlemon.dozeconfig.databinding.TipsLayoutBinding 35 | 36 | class DozeRunLogActivity : BaseActivity() { 37 | private lateinit var mBinding: ActivityDozeRunLogBinding 38 | private lateinit var mLogContent: String 39 | private lateinit var mLogTextView: TextView 40 | override fun onCreate(savedInstanceState: Bundle?) { 41 | super.onCreate(savedInstanceState) 42 | mBinding = ActivityDozeRunLogBinding.inflate(layoutInflater) 43 | setContentView(mBinding.root) 44 | initStatusBar() 45 | } 46 | 47 | override fun onResume() { 48 | loadLogData() 49 | super.onResume() 50 | } 51 | 52 | override fun initStatusBar() { 53 | super.initStatusBar() 54 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 55 | supportActionBar?.setHomeButtonEnabled(true) 56 | supportActionBar?.title = getString(R.string.doze_run_log) 57 | } 58 | 59 | private fun loadLogData() { 60 | try { 61 | mLogContent = DozeManager.readFile("Android/doze.log", this, "\n") 62 | if (mLogContent.isEmpty()) { 63 | mLogContent = getString(R.string.found_log_file) + "但是内容为空!" 64 | } 65 | } catch (e: Exception) { 66 | mLogContent = getString(R.string.not_found_log_file) 67 | } 68 | mLogTextView = mBinding.logContent 69 | mLogTextView.text = mLogContent 70 | } 71 | 72 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 73 | menuInflater.inflate(R.menu.menu_run_log, menu) 74 | return true 75 | } 76 | 77 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 78 | return when (item.itemId) { 79 | R.id.delete_log -> { 80 | val promptBinding = TipsLayoutBinding.inflate(layoutInflater) 81 | promptBinding.promptContent.text = getString(R.string.prompt_delete_log) 82 | val alertDialogBuilder = AlertDialog.Builder(this) 83 | alertDialogBuilder.setTitle(R.string.prompt) 84 | alertDialogBuilder.setView(promptBinding.root) 85 | alertDialogBuilder.setNegativeButton( 86 | "OK" 87 | ) { _, _ -> 88 | run { 89 | DozeManager.deleteFile("Android/doze.log", this) 90 | loadLogData() 91 | } 92 | } 93 | 94 | alertDialogBuilder.setPositiveButton( 95 | "Cancel" 96 | ) { dialog, _ -> 97 | dialog.cancel() 98 | } 99 | val dialog = alertDialogBuilder.create() 100 | dialog.show() 101 | true 102 | } 103 | android.R.id.home -> { 104 | finish() 105 | true 106 | } 107 | else -> super.onOptionsItemSelected(item) 108 | } 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /dozewhitelist/META-INF/com/google/android/update-binary: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | 3 | ################# 4 | # Initialization 5 | ################# 6 | 7 | umask 022 8 | 9 | # Global vars 10 | TMPDIR=/dev/tmp 11 | PERSISTDIR=/sbin/.magisk/mirror/persist 12 | 13 | rm -rf $TMPDIR 2>/dev/null 14 | mkdir -p $TMPDIR 15 | 16 | # echo before loading util_functions 17 | ui_print() { echo "$1"; } 18 | 19 | require_new_magisk() { 20 | ui_print "*******************************" 21 | ui_print " Please install Magisk v19.0+! " 22 | ui_print "*******************************" 23 | exit 1 24 | } 25 | 26 | is_legacy_script() { 27 | unzip -l "$ZIPFILE" install.sh | grep -q install.sh 28 | return $? 29 | } 30 | 31 | print_modname() { 32 | local len 33 | len=$(echo -n $MODNAME | wc -c) 34 | len=$((len + 2)) 35 | local pounds=$(printf "%${len}s" | tr ' ' '*') 36 | ui_print "$pounds" 37 | ui_print " $MODNAME " 38 | ui_print "$pounds" 39 | ui_print "******************************" 40 | ui_print "* Powered by Magisk " 41 | ui_print "******************************" 42 | ui_print "******************************" 43 | ui_print "* @Hwwwww " 44 | ui_print "******************************" 45 | } 46 | 47 | ############## 48 | # Environment 49 | ############## 50 | 51 | OUTFD=$2 52 | ZIPFILE=$3 53 | 54 | mount /data 2>/dev/null 55 | 56 | # Load utility functions 57 | [ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk 58 | . /data/adb/magisk/util_functions.sh 59 | [ $MAGISK_VER_CODE -gt 18100 ] || require_new_magisk 60 | 61 | # Preperation for flashable zips 62 | setup_flashable 63 | 64 | # Mount partitions 65 | mount_partitions 66 | 67 | # Detect version and architecture 68 | api_level_arch_detect 69 | 70 | # Setup busybox and binaries 71 | $BOOTMODE && boot_actions || recovery_actions 72 | 73 | ############## 74 | # Preparation 75 | ############## 76 | 77 | # Extract prop file 78 | unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2 79 | [ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!" 80 | 81 | $BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules 82 | MODULEROOT=$NVBASE/$MODDIRNAME 83 | MODID=$(grep_prop id $TMPDIR/module.prop) 84 | MODPATH=$MODULEROOT/$MODID 85 | MODNAME=$(grep_prop name $TMPDIR/module.prop) 86 | 87 | # Create mod paths 88 | rm -rf $MODPATH 2>/dev/null 89 | mkdir -p $MODPATH 90 | 91 | ########## 92 | # Install 93 | ########## 94 | 95 | if is_legacy_script; then 96 | unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2 97 | 98 | # Load install script 99 | . $TMPDIR/install.sh 100 | 101 | # Callbacks 102 | print_modname 103 | on_install 104 | 105 | # Custom uninstaller 106 | [ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh 107 | 108 | # Skip mount 109 | $SKIPMOUNT && touch $MODPATH/skip_mount 110 | 111 | # prop file 112 | $PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop 113 | 114 | # Module info 115 | cp -af $TMPDIR/module.prop $MODPATH/module.prop 116 | 117 | # post-fs-data scripts 118 | $POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh 119 | 120 | # service scripts 121 | $LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh 122 | 123 | ui_print "- Setting permissions" 124 | set_permissions 125 | else 126 | print_modname 127 | 128 | unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2 129 | 130 | if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then 131 | ui_print "- Extracting module files" 132 | unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2 133 | 134 | # Default permissions 135 | set_perm_recursive $MODPATH 0 0 0755 0644 136 | fi 137 | 138 | # Load customization script 139 | [ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh 140 | fi 141 | 142 | # Handle replace folders 143 | for TARGET in $REPLACE; do 144 | ui_print "- Replace target: $TARGET" 145 | mktouch $MODPATH$TARGET/.replace 146 | done 147 | 148 | if $BOOTMODE; then 149 | # Update info for Magisk Manager 150 | mktouch $NVBASE/modules/$MODID/update 151 | cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop 152 | fi 153 | 154 | # Copy over custom sepolicy rules 155 | if [ -f $MODPATH/sepolicy.rule -a -e $PERSISTDIR ]; then 156 | ui_print "- Installing custom sepolicy patch" 157 | PERSISTMOD=$PERSISTDIR/magisk/$MODID 158 | mkdir -p $PERSISTMOD 159 | cp -af $MODPATH/sepolicy.rule $PERSISTMOD/sepolicy.rule 160 | fi 161 | 162 | # Remove stuffs that don't belong to modules 163 | rm -rf \ 164 | $MODPATH/system/placeholder $MODPATH/customize.sh \ 165 | $MODPATH/README.md $MODPATH/.git* 2>/dev/null 166 | 167 | ############## 168 | # Finalizing 169 | ############## 170 | 171 | cd / 172 | $BOOTMODE || recovery_cleanup 173 | rm -rf $TMPDIR 174 | 175 | ui_print "- Done" 176 | exit 0 177 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 32 | 33 | 39 | 40 | 46 | 47 | 55 | 56 | 57 | 58 | 59 | 66 | 67 | 72 | 73 | 80 | 87 | 88 | 96 | 97 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/activity/SettingsActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.activity 24 | 25 | import android.content.DialogInterface 26 | import android.os.Bundle 27 | import android.os.CountDownTimer 28 | import android.view.Menu 29 | import android.view.MenuItem 30 | import android.widget.Button 31 | import androidx.appcompat.app.AlertDialog 32 | import androidx.preference.PreferenceFragmentCompat 33 | import com.github.hwwwwwlemon.dozeconfig.DozeManager 34 | import com.github.hwwwwwlemon.dozeconfig.R 35 | import com.github.hwwwwwlemon.dozeconfig.activity.base.BaseActivity 36 | import com.github.hwwwwwlemon.dozeconfig.databinding.ActivitySettingsBinding 37 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 38 | 39 | 40 | class SettingsActivity : BaseActivity() { 41 | private lateinit var mBinding: ActivitySettingsBinding 42 | private lateinit var mDialog: AlertDialog 43 | override fun onCreate(savedInstanceState: Bundle?) { 44 | super.onCreate(savedInstanceState) 45 | mBinding = ActivitySettingsBinding.inflate(layoutInflater) 46 | setContentView(mBinding.root) 47 | if (savedInstanceState == null) { 48 | supportFragmentManager.beginTransaction() 49 | .add(R.id.container, SettingsFragment()).commit() 50 | } 51 | 52 | initStatusBar() 53 | } 54 | 55 | override fun initStatusBar() { 56 | super.initStatusBar() 57 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 58 | supportActionBar?.setHomeButtonEnabled(true) 59 | supportActionBar?.title = getString(R.string.settings) 60 | } 61 | 62 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 63 | menuInflater.inflate(R.menu.menu_settings, menu) 64 | return true 65 | } 66 | 67 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 68 | return when (item.itemId) { 69 | android.R.id.home -> { 70 | finish() 71 | true 72 | } 73 | R.id.delete_config -> { 74 | 75 | val builder: AlertDialog.Builder = AlertDialog.Builder(this) 76 | builder.setTitle(R.string.prompt) 77 | builder.setMessage(R.string.delete_config_dialog) 78 | builder.setPositiveButton(getString(R.string.cancel)) { _, _ -> 79 | mDialog.dismiss() 80 | } 81 | builder.setNegativeButton(getString(R.string.confirm)) { _, _ -> 82 | try { 83 | if (DozeManager.deleteFile(DozeManager.DOZE_FILE_PATH, this)) { 84 | Utils.showToast(this, R.string.delete_success) 85 | } 86 | } catch (e: Exception) { 87 | Utils.showToast(this, R.string.delete_failed) 88 | } 89 | } 90 | mDialog = builder.create() 91 | mDialog.show() 92 | val btn: Button = mDialog.getButton(DialogInterface.BUTTON_NEGATIVE) 93 | val timer: CountDownTimer = object : CountDownTimer(6000, 1000) { 94 | override fun onTick(arg0: Long) { 95 | val thetime = (arg0 / 1000).toInt() 96 | mDialog.getButton(DialogInterface.BUTTON_NEGATIVE).text = 97 | "${getString(R.string.confirm)}${if (thetime > 0) "($thetime)" else ""}" 98 | } 99 | 100 | override fun onFinish() { 101 | btn.isEnabled = true 102 | } 103 | } 104 | btn.isEnabled = false 105 | timer.start() 106 | true 107 | } 108 | else -> super.onOptionsItemSelected(item) 109 | } 110 | } 111 | 112 | class SettingsFragment : PreferenceFragmentCompat() { 113 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 114 | setPreferencesFromResource(R.xml.settings_preferences, rootKey) 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 | DozeConfig 26 | Welcome 27 | Module run log 28 | Settings 29 | About 30 | Whitelist 31 | Applications 32 | Choose doze whitelist 33 | Not found whitelist file 34 | Please check sdcard/Android/doze.conf is exists? 35 | Found whitelist file! 36 | Please enjoy! 🚀(Click me) 37 | Whitelist file is error! 😭(Click me) 38 | Log File 39 | Not found log file! 40 | Found log file! 41 | Search 42 | Please input package name or app name 43 | Log 44 | Show system apps 45 | Save 46 | Delete log 47 | GitHub: 48 | Coolapk: 49 | This application was developed for the convenience of adding a whitelist to the 50 | Doze module. \nWe will obtain some privacy-related permissions to ensure the normal operation of the 51 | application:\n👉1, storage read and write permissions (read whitelist and log files)\n👉2, read application list 52 | permissions (read application list )\n👉3, Root permission (optimized whitelist)\nIf you encounter any problems 53 | (such as bugs, program crashes, etc.) during use, you can submit an issue on GitHub or privately write to me in 54 | Coolapk 55 | 56 | 1.2.2 Release 57 | Tips 58 | Are sure delete log file? 59 | Features:\n1. Fix bugs 60 | 61 | Please give relevant permissions (read and write mobile phone storage permissions), 62 | otherwise you will not be able to use this application normally! 63 | 64 | I\'m still sliding, please stop and do it again! 65 | Save successfully! 66 | Save failed! 67 | 68 | Common setting 69 | Advanced setting 70 | Lazy load icon 71 | Reduce the CPU usage when sliding 72 | Run doze whitelist optimization 73 | Tap the main interface card 5 times to optimize (Root) 74 | Auto save doze config 75 | Auto save doze.conf 76 | Optimize the whitelist 77 | APP List 78 | Successfully! 79 | Failed! 80 | Delete config file 81 | Cancel 82 | Confirm 83 | Delete successfully! 84 | Delete failed! 85 | This operation will delete the Doze whitelist configuration file, which will 86 | directly cause the module and application to not work properly.\n\nAre you sure to delete it? 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright (c) Hwwwww 2021 https://github.com/HwwwwwLemon/DozeConfig All Rights Reserved. 5 | # 6 | 7 | ############################################################################## 8 | ## 9 | ## Gradle start up script for UN*X 10 | ## 11 | ############################################################################## 12 | 13 | # Attempt to set APP_HOME 14 | # Resolve links: $0 may be a link 15 | PRG="$0" 16 | # Need this for relative symlinks. 17 | while [ -h "$PRG" ] ; do 18 | ls=`ls -ld "$PRG"` 19 | link=`expr "$ls" : '.*-> \(.*\)$'` 20 | if expr "$link" : '/.*' > /dev/null; then 21 | PRG="$link" 22 | else 23 | PRG=`dirname "$PRG"`"/$link" 24 | fi 25 | done 26 | SAVED="`pwd`" 27 | cd "`dirname \"$PRG\"`/" >/dev/null 28 | APP_HOME="`pwd -P`" 29 | cd "$SAVED" >/dev/null 30 | 31 | APP_NAME="Gradle" 32 | APP_BASE_NAME=`basename "$0"` 33 | 34 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 35 | DEFAULT_JVM_OPTS="" 36 | 37 | # Use the maximum available, or set MAX_FD != -1 to use that value. 38 | MAX_FD="maximum" 39 | 40 | warn () { 41 | echo "$*" 42 | } 43 | 44 | die () { 45 | echo 46 | echo "$*" 47 | echo 48 | exit 1 49 | } 50 | 51 | # OS specific support (must be 'true' or 'false'). 52 | cygwin=false 53 | msys=false 54 | darwin=false 55 | nonstop=false 56 | case "`uname`" in 57 | CYGWIN* ) 58 | cygwin=true 59 | ;; 60 | Darwin* ) 61 | darwin=true 62 | ;; 63 | MINGW* ) 64 | msys=true 65 | ;; 66 | NONSTOP* ) 67 | nonstop=true 68 | ;; 69 | esac 70 | 71 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 72 | 73 | # Determine the Java command to use to start the JVM. 74 | if [ -n "$JAVA_HOME" ] ; then 75 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 76 | # IBM's JDK on AIX uses strange locations for the executables 77 | JAVACMD="$JAVA_HOME/jre/sh/java" 78 | else 79 | JAVACMD="$JAVA_HOME/bin/java" 80 | fi 81 | if [ ! -x "$JAVACMD" ] ; then 82 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 83 | 84 | Please set the JAVA_HOME variable in your environment to match the 85 | location of your Java installation." 86 | fi 87 | else 88 | JAVACMD="java" 89 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 90 | 91 | Please set the JAVA_HOME variable in your environment to match the 92 | location of your Java installation." 93 | fi 94 | 95 | # Increase the maximum file descriptors if we can. 96 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 97 | MAX_FD_LIMIT=`ulimit -H -n` 98 | if [ $? -eq 0 ] ; then 99 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 100 | MAX_FD="$MAX_FD_LIMIT" 101 | fi 102 | ulimit -n $MAX_FD 103 | if [ $? -ne 0 ] ; then 104 | warn "Could not set maximum file descriptor limit: $MAX_FD" 105 | fi 106 | else 107 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 108 | fi 109 | fi 110 | 111 | # For Darwin, add options to specify how the application appears in the dock 112 | if $darwin; then 113 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 114 | fi 115 | 116 | # For Cygwin, switch paths to Windows format before running java 117 | if $cygwin ; then 118 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 119 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 120 | JAVACMD=`cygpath --unix "$JAVACMD"` 121 | 122 | # We build the pattern for arguments to be converted via cygpath 123 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 124 | SEP="" 125 | for dir in $ROOTDIRSRAW ; do 126 | ROOTDIRS="$ROOTDIRS$SEP$dir" 127 | SEP="|" 128 | done 129 | OURCYGPATTERN="(^($ROOTDIRS))" 130 | # Add a user-defined pattern to the cygpath arguments 131 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 132 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 133 | fi 134 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 135 | i=0 136 | for arg in "$@" ; do 137 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 138 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 139 | 140 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 141 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 142 | else 143 | eval `echo args$i`="\"$arg\"" 144 | fi 145 | i=$((i+1)) 146 | done 147 | case $i in 148 | (0) set -- ;; 149 | (1) set -- "$args0" ;; 150 | (2) set -- "$args0" "$args1" ;; 151 | (3) set -- "$args0" "$args1" "$args2" ;; 152 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 153 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 154 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 155 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 156 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 157 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 158 | esac 159 | fi 160 | 161 | # Escape application args 162 | save () { 163 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 164 | echo " " 165 | } 166 | APP_ARGS=$(save "$@") 167 | 168 | # Collect all arguments for the java command, following the shell quoting and substitution rules 169 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 170 | 171 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 172 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 173 | cd "$(dirname "$0")" 174 | fi 175 | 176 | exec "$JAVACMD" "$@" 177 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 31 | 33 | 35 | 37 | 39 | 41 | 43 | 45 | 47 | 49 | 51 | 53 | 55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 73 | 75 | 77 | 79 | 81 | 83 | 85 | 87 | 89 | 91 | 93 | 95 | 97 | 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/DozeManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig 24 | 25 | import android.Manifest 26 | import android.app.Activity 27 | import android.content.Context 28 | import android.content.Intent 29 | import android.content.pm.PackageManager 30 | import android.os.Environment 31 | import android.os.Process 32 | import android.util.Log 33 | import androidx.core.app.ActivityCompat 34 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 35 | import java.io.* 36 | 37 | 38 | object DozeManager { 39 | private const val REQUEST_EXTERNAL_STORAGE = 1 40 | const val DOZE_FILE_PATH = "Android/doze.conf" 41 | const val DOZE_LOG_PATH = "Android/doze.log" 42 | private val SDCARD_PATH = File(Environment.getExternalStorageDirectory().path) 43 | private val PERMISSIONS_STORAGE = arrayOf( 44 | "android.permission.READ_EXTERNAL_STORAGE", 45 | "android.permission.WRITE_EXTERNAL_STORAGE" 46 | ) 47 | 48 | 49 | fun checkDozeFile(ctx: Context): Boolean { 50 | try { 51 | if (checkPermission(ctx)) { 52 | val file = File(SDCARD_PATH, DOZE_FILE_PATH) 53 | return file.exists() 54 | } 55 | } catch (e: FileNotFoundException) { 56 | e.printStackTrace() 57 | } 58 | return false 59 | } 60 | 61 | fun deleteFile(path: String, ctx: Context): Boolean { 62 | if (checkPermission(ctx)) { 63 | val file = File(SDCARD_PATH, path) 64 | if (!file.exists()) { 65 | throw FileNotFoundException(file.absolutePath) 66 | } else { 67 | return file.delete() 68 | } 69 | } 70 | return false 71 | } 72 | 73 | fun writeFile(path: String, content: String, ctx: Context) { 74 | if (checkPermission(ctx)) { 75 | val file = File(SDCARD_PATH, path) 76 | if (!file.exists()) { 77 | try { 78 | file.createNewFile() 79 | } catch (e: IOException) { 80 | e.printStackTrace() 81 | } 82 | } 83 | var fileOutputStream: FileOutputStream? = null 84 | try { 85 | fileOutputStream = FileOutputStream(file) 86 | fileOutputStream.write(content.toByteArray()) 87 | } catch (e: java.lang.Exception) { 88 | e.printStackTrace() 89 | } finally { 90 | try { 91 | fileOutputStream?.close() 92 | } catch (e: IOException) { 93 | e.printStackTrace() 94 | } 95 | } 96 | } 97 | } 98 | 99 | fun readFile(path: String, ctx: Context, suffix: String = ""): String { 100 | val result = StringBuilder() 101 | if (checkPermission(ctx)) { 102 | var inputStream: InputStream? = null 103 | var reader: Reader? = null 104 | var bufferedReader: BufferedReader? = null 105 | try { 106 | val file = File(SDCARD_PATH, path) 107 | if (!file.exists()) { 108 | throw FileNotFoundException(file.absolutePath) 109 | } 110 | inputStream = FileInputStream(file) 111 | reader = InputStreamReader(inputStream) 112 | bufferedReader = BufferedReader(reader) 113 | var temp: String? 114 | while (bufferedReader.readLine().also { temp = it } != null) { 115 | result.append(temp).append(suffix) 116 | } 117 | } catch (e: Exception) { 118 | throw e 119 | } finally { 120 | try { 121 | bufferedReader?.close() 122 | } catch (e: IOException) { 123 | e.printStackTrace() 124 | } 125 | try { 126 | reader?.close() 127 | } catch (e: IOException) { 128 | e.printStackTrace() 129 | } 130 | try { 131 | inputStream?.close() 132 | } catch (e: IOException) { 133 | e.printStackTrace() 134 | } 135 | } 136 | } 137 | return result.toString() 138 | } 139 | 140 | fun checkPermission(ctx: Context): Boolean { 141 | //检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权 142 | if (ActivityCompat.checkSelfPermission( 143 | ctx, 144 | Manifest.permission.WRITE_EXTERNAL_STORAGE 145 | ) == PackageManager.PERMISSION_DENIED 146 | ) { 147 | ActivityCompat.requestPermissions(ctx as Activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE) 148 | Utils.showToast(ctx, ctx.getString(R.string.permission_prompt)) 149 | Log.e( 150 | "DozeManager", "The external storage read and write permissions are failed obtained!" + 151 | "${ 152 | ActivityCompat.checkSelfPermission( 153 | ctx, 154 | Manifest.permission.WRITE_EXTERNAL_STORAGE 155 | ) == PackageManager.PERMISSION_GRANTED 156 | }" 157 | ) 158 | return ActivityCompat.checkSelfPermission( 159 | ctx, 160 | Manifest.permission.WRITE_EXTERNAL_STORAGE 161 | ) == PackageManager.PERMISSION_GRANTED 162 | } else { 163 | Log.d("DozeManager", "The external storage read and write permissions are successfully obtained!") 164 | } 165 | return true 166 | } 167 | 168 | private fun restartApp(ctx: Context) { 169 | val intent = Intent(ctx, MainActivity::class.java) 170 | intent.putExtra("PackageName", ctx.packageName) 171 | intent.putExtra("Delayed", 1000) 172 | ctx.startService(intent) 173 | Log.e("DozeManager", "Restart") 174 | Process.killProcess(Process.myPid()) 175 | 176 | } 177 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig 24 | 25 | 26 | import android.content.Intent 27 | import android.os.Bundle 28 | import android.os.Handler 29 | import android.text.method.LinkMovementMethod 30 | import android.view.LayoutInflater 31 | import android.widget.ImageView 32 | import android.widget.TextView 33 | import androidx.appcompat.app.AlertDialog 34 | import androidx.appcompat.app.AppCompatActivity 35 | import androidx.core.content.ContextCompat 36 | import androidx.core.text.HtmlCompat 37 | import com.bumptech.glide.Glide 38 | import com.github.hwwwwwlemon.dozeconfig.activity.ApplicationsListActivity 39 | import com.github.hwwwwwlemon.dozeconfig.activity.DozeRunLogActivity 40 | import com.github.hwwwwwlemon.dozeconfig.activity.SettingsActivity 41 | import com.github.hwwwwwlemon.dozeconfig.databinding.ActivityMainBinding 42 | import com.github.hwwwwwlemon.dozeconfig.databinding.DialogAboutBinding 43 | import com.github.hwwwwwlemon.dozeconfig.utils.DozeFileUtil 44 | import com.github.hwwwwwlemon.dozeconfig.utils.MyPreferences 45 | import com.github.hwwwwwlemon.dozeconfig.utils.StatusBarUtil 46 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 47 | import com.google.android.material.card.MaterialCardView 48 | 49 | 50 | class MainActivity : AppCompatActivity() { 51 | private lateinit var binding: ActivityMainBinding 52 | private lateinit var statusSummary: TextView 53 | private lateinit var statusTitle: TextView 54 | private lateinit var statusCard: MaterialCardView 55 | private lateinit var statusIcon: ImageView 56 | private var preferences: MyPreferences? = null 57 | private var runDozeWhitelistOpt = false 58 | private var firstPressedTime: Long = 10000 59 | private var handlerFlag = true 60 | private var status = 0 61 | private val counts = 5 // 点击次数 62 | private var count = 0 63 | private var isRun = false 64 | private var mHits = LongArray(counts) 65 | 66 | 67 | override fun onCreate(savedInstanceState: Bundle?) { 68 | super.onCreate(savedInstanceState) 69 | StatusBarUtil.immersive(this) 70 | preferences = MyPreferences(this) 71 | if (!Utils.isDarkMode(this)) { 72 | StatusBarUtil.darkMode(this); 73 | } 74 | binding = ActivityMainBinding.inflate(layoutInflater) 75 | setContentView(binding.root) 76 | 77 | 78 | //设置Title logo 79 | Glide.with(binding.dozeIcon).load(R.mipmap.ic_launcher_foreground).into(binding.dozeIcon) 80 | //应用列表 81 | binding.status.setOnClickListener { 82 | 83 | when (status) { 84 | 0 -> { 85 | 86 | continuousClick { 87 | if (runDozeWhitelistOpt) { 88 | Utils.refreshDozeWhitelist(this) 89 | } else { 90 | Utils.showToast(this, "\uD83E\uDD73") 91 | } 92 | } 93 | 94 | } 95 | 1 -> { 96 | Utils.showToast(this, "\uD83E\uDD7A") 97 | showDozeConfigurationFile() 98 | } 99 | 2 -> Utils.showToast(this, "\uD83D\uDE29") 100 | else -> Utils.showToast(this, "\uD83E\uDD76") 101 | } 102 | 103 | 104 | } 105 | 106 | binding.applicationsList.setOnClickListener { 107 | startActivity( 108 | Intent( 109 | this, 110 | ApplicationsListActivity::class.java 111 | ) 112 | ) 113 | } 114 | //Log 115 | binding.dozeRunLog.setOnClickListener { 116 | startActivity( 117 | Intent( 118 | this, 119 | DozeRunLogActivity::class.java 120 | ) 121 | ) 122 | } 123 | binding.settings.setOnClickListener { 124 | startActivity( 125 | Intent( 126 | this, 127 | SettingsActivity::class.java 128 | ) 129 | ) 130 | } 131 | //about 132 | binding.about.setOnClickListener { 133 | val alertDialogBuilder = AlertDialog.Builder(this) 134 | val dialogBinding = DialogAboutBinding.inflate(LayoutInflater.from(this), null, false) 135 | alertDialogBuilder.setView(dialogBinding.root) 136 | dialogBinding.aboutCard.background = ContextCompat.getDrawable(this, R.drawable.gradient_color) 137 | dialogBinding.github.movementMethod = LinkMovementMethod.getInstance(); 138 | dialogBinding.github.text = 139 | HtmlCompat.fromHtml( 140 | getString(R.string.github) + "Issues", 141 | HtmlCompat.FROM_HTML_MODE_LEGACY 142 | ) 143 | 144 | dialogBinding.author.movementMethod = LinkMovementMethod.getInstance(); 145 | dialogBinding.author.text = 146 | HtmlCompat.fromHtml( 147 | getString(R.string.author) + "@Hwwwww", 148 | HtmlCompat.FROM_HTML_MODE_LEGACY 149 | ) 150 | dialogBinding.appVersion.text = "version : " + getString(R.string.version) 151 | dialogBinding.description.text = getString(R.string.about_description) 152 | alertDialogBuilder.show() 153 | } 154 | 155 | 156 | } 157 | 158 | private fun continuousClick(func: () -> Any) { 159 | if (!runDozeWhitelistOpt || status != 0) { 160 | func() 161 | return 162 | } 163 | 164 | System.arraycopy(mHits, 1, mHits, 0, mHits.size - 1) 165 | mHits[mHits.size - 1] = System.currentTimeMillis() 166 | if (!isRun) { 167 | if (handlerFlag) { 168 | handlerFlag = false 169 | Handler().postDelayed({ 170 | runOnUiThread { 171 | handlerFlag = true 172 | count = 0 173 | mHits = LongArray(counts) 174 | } 175 | }, 1500) 176 | } 177 | 178 | count++ 179 | Utils.showToast(this, "再点击 ${counts - count} 次优化白名单 ", 600) 180 | } 181 | if (!isRun and (mHits[0] >= System.currentTimeMillis() - 3000) and (count == 5)) { 182 | mHits = LongArray(counts) //重新初始化数组 183 | isRun = true 184 | count = 0 185 | func() 186 | Handler().postDelayed({ runOnUiThread { isRun = false } }, 5000) 187 | } 188 | 189 | } 190 | 191 | override fun onResume() { 192 | runDozeWhitelistOpt = preferences?.get("run_doze_whitelist", false) as Boolean 193 | if (DozeManager.checkPermission(this)) { 194 | init() 195 | } else { 196 | finish() 197 | } 198 | super.onResume() 199 | } 200 | 201 | private fun init() { 202 | statusSummary = findViewById(R.id.status_summary) 203 | statusTitle = findViewById(R.id.status_title) 204 | statusCard = findViewById(R.id.status) 205 | statusIcon = findViewById(R.id.status_icon) 206 | var successColor = getColor(R.color.success) 207 | var errorColor = getColor(R.color.error) 208 | if (Utils.isDarkMode(this)) { 209 | successColor = getColor(R.color.success_dark) 210 | errorColor = getColor(R.color.error_dark) 211 | } 212 | 213 | 214 | 215 | when { 216 | DozeManager.checkDozeFile(this) and DozeFileUtil.loadDozeFile(this) -> { 217 | statusCard.setCardBackgroundColor(successColor) 218 | statusIcon.setImageResource(R.drawable.ic_success_fill) 219 | statusSummary.text = getString(R.string.found_whitelist_file_prompt) 220 | statusTitle.text = getString(R.string.found_whitelist_file) 221 | status = 0 222 | } 223 | DozeManager.checkDozeFile(this) and !DozeFileUtil.loadDozeFile(this) -> { 224 | statusCard.setCardBackgroundColor(errorColor) 225 | statusIcon.setImageResource(R.drawable.ic_question_fill) 226 | statusSummary.text = getString(R.string.whitelist_file_error) 227 | statusTitle.text = getString(R.string.found_whitelist_file) 228 | status = 1 229 | } 230 | else -> { 231 | statusCard.setCardBackgroundColor(errorColor) 232 | statusIcon.setImageResource(R.drawable.ic_error_fill) 233 | statusSummary.text = getString(R.string.not_found_whitelist_file_prompt) 234 | statusTitle.text = getString(R.string.not_found_whitelist_file) 235 | status = 2 236 | } 237 | } 238 | 239 | } 240 | 241 | private fun showDozeConfigurationFile() { 242 | 243 | val sb = StringBuilder("Error List:\n") 244 | DozeFileUtil.errorList.forEach { 245 | sb.append(it).append("\n") 246 | } 247 | sb.append("也许您没安装这个应用或者包名有错误。\n应用列表更新一次即可。") 248 | val dozeWhitelist = sb.toString() 249 | val builder = AlertDialog.Builder(this) 250 | builder.setTitle(R.string.prompt) 251 | builder.setMessage(dozeWhitelist) 252 | builder.create() 253 | builder.show() 254 | 255 | } 256 | 257 | override fun onBackPressed() { 258 | if (System.currentTimeMillis() - firstPressedTime < 2000) { 259 | super.onBackPressed(); //不要调用父类的方法 260 | } else { 261 | Utils.showToast(this, "再按一次退出") 262 | firstPressedTime = System.currentTimeMillis() 263 | } 264 | 265 | } 266 | } 267 | 268 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/activity/ApplicationsListActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.activity 24 | 25 | 26 | import android.content.Context 27 | import android.graphics.Rect 28 | import android.os.Bundle 29 | import android.util.AttributeSet 30 | import android.view.Menu 31 | import android.view.MenuItem 32 | import android.view.View 33 | import androidx.appcompat.widget.SearchView 34 | import androidx.recyclerview.widget.LinearLayoutManager 35 | import androidx.recyclerview.widget.RecyclerView 36 | import com.bumptech.glide.Glide 37 | import com.github.hwwwwwlemon.dozeconfig.DozeManager 38 | import com.github.hwwwwwlemon.dozeconfig.R 39 | import com.github.hwwwwwlemon.dozeconfig.activity.base.BaseActivity 40 | import com.github.hwwwwwlemon.dozeconfig.adapter.ApplicationAdapter 41 | import com.github.hwwwwwlemon.dozeconfig.databinding.ActivityApplicationListBinding 42 | import com.github.hwwwwwlemon.dozeconfig.utils.DozeFileUtil 43 | import com.github.hwwwwwlemon.dozeconfig.utils.MyPreferences 44 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 45 | import com.scwang.smart.refresh.header.MaterialHeader 46 | import com.scwang.smart.refresh.layout.api.RefreshLayout 47 | import kotlinx.coroutines.CoroutineScope 48 | import kotlinx.coroutines.Dispatchers 49 | import kotlinx.coroutines.launch 50 | import kotlinx.coroutines.withContext 51 | import me.zhanghai.android.fastscroll.FastScroller 52 | import me.zhanghai.android.fastscroll.FastScrollerBuilder 53 | 54 | 55 | class ApplicationsListActivity : BaseActivity() { 56 | private var refreshLayout: RefreshLayout? = null 57 | private var rv: RecyclerView? = null 58 | private var fastScroll: FastScroller? = null 59 | private var adapter: ApplicationAdapter? = null 60 | private var enableShowSystemApps: Int = 1 61 | private var self = this 62 | private val controlScope = CoroutineScope(Dispatchers.Default) 63 | private var searchView: SearchView? = null 64 | private lateinit var binding: ActivityApplicationListBinding 65 | private var preferences: MyPreferences? = null 66 | 67 | override fun onCreate(savedInstanceState: Bundle?) { 68 | super.onCreate(savedInstanceState) 69 | binding = ActivityApplicationListBinding.inflate(layoutInflater) 70 | preferences = MyPreferences(this) 71 | setContentView(binding.root) 72 | initStatusBar() 73 | 74 | } 75 | 76 | override fun onResume() { 77 | if (DozeFileUtil.checkAppList.size == 0) { 78 | if (DozeManager.checkDozeFile(this)) { 79 | DozeFileUtil.loadDozeFile(this) 80 | } 81 | } 82 | 83 | initLayout() 84 | super.onResume() 85 | } 86 | 87 | override fun initStatusBar() { 88 | super.initStatusBar() 89 | enableHomeButton(true) 90 | supportActionBar?.title = getString(R.string.applications) 91 | } 92 | 93 | private fun initLayout() { 94 | refreshLayout = findViewById(R.id.refreshLayout) as RefreshLayout 95 | refreshLayout?.setRefreshHeader(MaterialHeader(this)) 96 | refreshLayout?.apply { 97 | setOnRefreshListener { loadApps(true) } 98 | autoRefresh() 99 | } 100 | 101 | rv = findViewById(R.id.my_recycler_view) 102 | val llm = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) 103 | adapter = ApplicationAdapter(self, enableShowSystemApps, rv!!) 104 | adapter?.setHasStableIds(true); 105 | adapter?.refresh(true) 106 | rv?.addItemDecoration(SpaceItemDecoration(10)); 107 | fastScroll = FastScrollerBuilder(rv!!).useMd2Style().build() 108 | if (preferences?.get("lazy_load_icon", false) as Boolean) { 109 | rv?.addOnScrollListener(AutoLoadRecyclerView(this).init()) 110 | } 111 | rv?.itemAnimator?.changeDuration = 1500; 112 | rv?.layoutManager = llm 113 | rv?.adapter = adapter 114 | } 115 | 116 | private fun loadApps(force: Boolean = false) { 117 | try { 118 | adapter?.filterType = enableShowSystemApps 119 | adapter?.refresh(force) 120 | val close = if (adapter?.itemCount!! > 0) 100 else 2000 121 | refreshLayout?.finishRefresh(close) 122 | 123 | } catch (e: Exception) { 124 | e.printStackTrace() 125 | } 126 | } 127 | 128 | private fun enableHomeButton(status: Boolean) { 129 | supportActionBar?.setDisplayHomeAsUpEnabled(status) 130 | supportActionBar?.setHomeButtonEnabled(status) 131 | } 132 | 133 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 134 | menuInflater.inflate(R.menu.menu_show_app_list, menu) 135 | //Toolbar的搜索框 136 | val searchItem = menu?.findItem(R.id.toolbar_search) 137 | searchView = searchItem?.actionView as SearchView 138 | 139 | searchView?.queryHint = getString(R.string.search_hint) 140 | searchView?.setOnCloseListener { 141 | adapter?.searchStr = "" 142 | enableHomeButton(true) 143 | false 144 | } 145 | searchView?.setOnSearchClickListener { 146 | enableHomeButton(false) 147 | } 148 | searchView?.setOnQueryTextListener(adapter?.getSearchListener()) 149 | return true 150 | } 151 | 152 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 153 | if (rv?.scrollState == 0) { 154 | return when (item.itemId) { 155 | R.id.toolbar_show_system_apps -> { 156 | item.isChecked = !item.isChecked 157 | enableShowSystemApps = if (item.isChecked) 2 else 1 158 | loadApps() 159 | true 160 | } 161 | R.id.toolbar_save -> { 162 | if (DozeFileUtil.saveDozeFile(this)) { 163 | Utils.showToast(this, getString(R.string.save_success)) 164 | } else { 165 | Utils.showToast(this, getString(R.string.save_failed)) 166 | } 167 | finish() 168 | true 169 | } 170 | android.R.id.home -> { 171 | finish() 172 | true 173 | } 174 | else -> super.onOptionsItemSelected(item) 175 | } 176 | } else { 177 | Utils.showToast(this, getString(R.string.in_loop)) 178 | return false 179 | } 180 | 181 | } 182 | 183 | private fun release() { 184 | try { 185 | if (isFinishing) { 186 | Glide.with(self.applicationContext).pauseAllRequests() 187 | controlScope.launch { 188 | withContext(Dispatchers.Main) { 189 | Glide.get(self.applicationContext).clearMemory(); 190 | } 191 | adapter?.clear() 192 | adapter = null 193 | rv = null 194 | } 195 | } 196 | } catch (e: Exception) { 197 | e.printStackTrace() 198 | } 199 | 200 | } 201 | 202 | override fun onBackPressed() { 203 | if (!searchView!!.isIconified) { 204 | searchView?.isIconified = true; 205 | } else { 206 | super.onBackPressed() 207 | } 208 | 209 | } 210 | 211 | override fun onStop() { 212 | release() 213 | super.onStop() 214 | } 215 | 216 | 217 | inner class AutoLoadRecyclerView(ctx: Context, attrs: AttributeSet?, defStyle: Int) : 218 | RecyclerView(ctx, attrs, defStyle) { 219 | constructor(ctx: Context) : this(ctx, null) {} 220 | constructor(ctx: Context, attrs: AttributeSet?) : this(ctx, attrs, 0) {} 221 | 222 | fun init(): ImageAutoLoadScrollListener { 223 | return ImageAutoLoadScrollListener() 224 | } 225 | 226 | //监听滚动来对图片加载进行判断处理 227 | inner class ImageAutoLoadScrollListener : OnScrollListener() { 228 | override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { 229 | super.onScrolled(recyclerView, dx, dy) 230 | } 231 | 232 | override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { 233 | super.onScrollStateChanged(recyclerView, newState) 234 | when (newState) { 235 | SCROLL_STATE_IDLE -> //当屏幕停止滚动,加载图片 236 | try { 237 | if (context != null) Glide.with(context).resumeRequests() 238 | } catch (e: Exception) { 239 | e.printStackTrace() 240 | } 241 | SCROLL_STATE_DRAGGING -> //当屏幕滚动且用户使用的触碰或手指还在屏幕上,停止加载图片 242 | try { 243 | if (context != null) Glide.with(context).pauseRequests() 244 | } catch (e: Exception) { 245 | e.printStackTrace() 246 | } 247 | SCROLL_STATE_SETTLING -> //由于用户的操作,屏幕产生惯性滑动,停止加载图片 248 | try { 249 | 250 | if (context != null) { 251 | Glide.with(context).pauseRequests() 252 | } 253 | } catch (e: Exception) { 254 | e.printStackTrace() 255 | } 256 | } 257 | } 258 | } 259 | } 260 | 261 | inner class SpaceItemDecoration(var mSpace: Int) : RecyclerView.ItemDecoration() { 262 | /** 263 | * Retrieve any offsets for the given item. Each field of `outRect` specifies 264 | * the number of pixels that the item view should be inset by, similar to padding or margin. 265 | * The default implementation sets the bounds of outRect to 0 and returns. 266 | 267 | * If this ItemDecoration does not affect the positioning of item views, it should set 268 | * all four fields of `outRect` (left, top, right, bottom) to zero 269 | * before returning. 270 | * 271 | 272 | * If you need to access Adapter for additional data, you can call 273 | * [RecyclerView.getChildAdapterPosition] to get the adapter position of the 274 | * View. 275 | * 276 | * @param outRect Rect to receive the output. 277 | * @param view The child view to decorate 278 | * @param parent RecyclerView this ItemDecoration is decorating 279 | * @param state The current state of RecyclerView. 280 | */ 281 | override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { 282 | super.getItemOffsets(outRect, view, parent, state) 283 | // outRect.left = mSpace 284 | // outRect.right = mSpace 285 | outRect.bottom = mSpace 286 | if (parent.getChildAdapterPosition(view) == 0) { 287 | outRect.top = mSpace 288 | } 289 | } 290 | } 291 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/hwwwwwlemon/dozeconfig/adapter/ApplicationAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License (MIT) 3 | * 4 | * Copyright © 2021 Hwwwww 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | * associated documentation files (the “Software”), to deal in the Software without restriction, 8 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all copies or substantial 13 | * portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 16 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | * 21 | * 22 | */ 23 | package com.github.hwwwwwlemon.dozeconfig.adapter 24 | 25 | import android.app.Activity 26 | import android.content.pm.ApplicationInfo 27 | import android.content.pm.PackageManager 28 | import android.graphics.drawable.Drawable 29 | import android.os.Handler 30 | import android.util.Log 31 | import android.view.LayoutInflater 32 | import android.view.View 33 | import android.view.ViewGroup 34 | import android.widget.Filter 35 | import android.widget.ImageView 36 | import android.widget.Switch 37 | import android.widget.TextView 38 | import androidx.appcompat.widget.SearchView 39 | import androidx.recyclerview.widget.RecyclerView 40 | import com.bumptech.glide.Glide 41 | import com.bumptech.glide.request.target.CustomTarget 42 | import com.bumptech.glide.request.transition.Transition 43 | import com.github.hwwwwwlemon.dozeconfig.R 44 | import com.github.hwwwwwlemon.dozeconfig.utils.DozeFileUtil 45 | import com.github.hwwwwwlemon.dozeconfig.utils.MyPreferences 46 | import com.github.hwwwwwlemon.dozeconfig.utils.Utils 47 | import kotlinx.coroutines.* 48 | 49 | 50 | class ApplicationAdapter() : RecyclerView.Adapter() { 51 | 52 | private val apps: MutableList = mutableListOf() 53 | private var showApps: MutableList = mutableListOf() 54 | private var searchApps: MutableList = mutableListOf() 55 | private var checkApps: MutableList = mutableListOf() 56 | private lateinit var rv: RecyclerView 57 | private lateinit var pm: PackageManager 58 | private lateinit var activity: Activity 59 | var filterType: Int = 1 60 | var searchStr: String = "" 61 | private var preferences: MyPreferences? = null 62 | private var isRefreshing = false 63 | private val viewModelJob = SupervisorJob() 64 | private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob) 65 | private val controlScope = CoroutineScope(Dispatchers.Default) 66 | private val mHandler = Handler() 67 | 68 | constructor( 69 | activity: Activity, 70 | filterType: Int, 71 | rv: RecyclerView 72 | ) : this() { 73 | preferences = MyPreferences(activity) 74 | this.rv = rv 75 | this.pm = activity.packageManager 76 | this.activity = activity 77 | this.filterType = filterType 78 | } 79 | 80 | inner class AppViewHolder constructor(itemView: View) : 81 | RecyclerView.ViewHolder(itemView) { 82 | var appName: TextView = itemView.findViewById(R.id.app_name) as TextView 83 | var packageName: TextView = itemView.findViewById(R.id.package_name) as TextView 84 | var appIcon: ImageView = itemView.findViewById(R.id.app_icon) as ImageView 85 | var switchIcon: Switch = itemView.findViewById(R.id.check_white_list_app) as Switch 86 | } 87 | 88 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder { 89 | val v: View = LayoutInflater.from(parent.context).inflate(R.layout.application_unit_layout, parent, false) 90 | return AppViewHolder(v) 91 | } 92 | 93 | override fun onBindViewHolder(holder: AppViewHolder, position: Int, payloads: MutableList) { 94 | if (payloads.isEmpty()) { 95 | bind(holder, position) 96 | } 97 | 98 | } 99 | 100 | override fun onBindViewHolder(holder: AppViewHolder, position: Int) { 101 | bind(holder, position) 102 | } 103 | 104 | private fun bind(holder: AppViewHolder, position: Int) { 105 | try { 106 | holder.appName.text = showApps[position].appName 107 | holder.packageName.text = showApps[position].packageName 108 | Glide.with(holder.appIcon) 109 | .load(showApps[position].applicationInfo.loadIcon(pm)) 110 | .into(object : CustomTarget() { 111 | override fun onResourceReady(resource: Drawable, transition: Transition?) { 112 | holder.appIcon.setImageDrawable(resource) 113 | } 114 | 115 | override fun onLoadCleared(placeholder: Drawable?) {} 116 | override fun onLoadFailed(errorDrawable: Drawable?) { 117 | holder.appIcon.setImageDrawable(pm.defaultActivityIcon) 118 | } 119 | }) 120 | holder.switchIcon.setOnCheckedChangeListener(null) 121 | holder.switchIcon.isChecked = DozeFileUtil.checkAppList.contains(showApps[position]) 122 | holder.itemView.setOnClickListener { 123 | holder.switchIcon.toggle() 124 | } 125 | holder.switchIcon.setOnCheckedChangeListener { _, isChecked -> 126 | if (rv.scrollState == 0) { 127 | onCheckedChange(isChecked, showApps[position]) 128 | } 129 | } 130 | } catch (e: Exception) { 131 | e.printStackTrace() 132 | } 133 | } 134 | 135 | private fun onCheckedChange(isChecked: Boolean, app: Apps) { 136 | if (isChecked) { 137 | DozeFileUtil.checkAppList.add(app) 138 | searchApps.remove(app) 139 | } else { 140 | DozeFileUtil.checkAppList.remove(app) 141 | searchApps.add(app) 142 | } 143 | mHandler.post { 144 | controlScope.launch { 145 | if (preferences?.get("auto_save", false) as Boolean) { 146 | DozeFileUtil.saveDozeFile(activity) 147 | withContext(Dispatchers.Main) { 148 | Utils.showToast(activity, activity.getString(R.string.auto_save), 1000) 149 | } 150 | 151 | } 152 | } 153 | 154 | } 155 | 156 | 157 | } 158 | 159 | override fun onViewRecycled(holder: AppViewHolder) { 160 | /* holder.appIcon.setImageDrawable(null) 161 | Glide.with(holder.appIcon).clear(holder.appIcon)*/ 162 | super.onViewRecycled(holder) 163 | } 164 | 165 | override fun getItemCount(): Int { 166 | return showApps.size 167 | 168 | } 169 | 170 | private fun getFilter(): AppFilter { 171 | return AppFilter() 172 | } 173 | 174 | @Synchronized 175 | private fun setRefreshStatus(status: Boolean) { 176 | this.isRefreshing = status 177 | } 178 | 179 | @Synchronized 180 | private fun getRefreshStatus(): Boolean { 181 | return isRefreshing 182 | } 183 | 184 | 185 | override fun getItemId(position: Int): Long { 186 | val info = showApps[position].applicationInfo; 187 | return (info.packageName + "!" + info.uid / 100000).hashCode().toLong() 188 | } 189 | 190 | fun refresh(force: Boolean) { 191 | synchronized(this) { 192 | if (getRefreshStatus()) { 193 | Log.e("isRefreshing", "Cancel Refreshing") 194 | return; 195 | } 196 | setRefreshStatus(true) 197 | } 198 | 199 | try { 200 | controlScope.launch { 201 | async { 202 | checkApps.clear() 203 | checkApps.addAll(DozeFileUtil.checkAppList) 204 | sortList(checkApps) 205 | }.join() 206 | 207 | if (force) { 208 | val loadAppsJob = async { loadApps() } 209 | loadAppsJob.join() 210 | val searchAppsJob = async { sortList(searchApps) } 211 | searchAppsJob.join() 212 | 213 | joinAll(loadAppsJob, searchAppsJob) 214 | } 215 | val ready = async { 216 | withContext(Dispatchers.Main) { 217 | synchronized(this) { 218 | getFilter().filter(searchStr); 219 | setRefreshStatus(false) 220 | } 221 | } 222 | } 223 | ready.join() 224 | } 225 | } catch (e: Exception) { 226 | e.printStackTrace() 227 | } 228 | } 229 | 230 | private suspend fun loadApps() = withContext(Dispatchers.Default) { 231 | try { 232 | apps.clear() 233 | searchApps.clear() 234 | var flag: Int? 235 | val appList: MutableList = Utils.getAppList(activity.applicationContext) 236 | for (i in appList) { 237 | flag = if ((i.flags and ApplicationInfo.FLAG_SYSTEM) == 0) 1 else 2 238 | val excludeApp = !(i.packageName.contains("com.qti") 239 | || i.packageName.contains("com.android.theme") 240 | || i.packageName.contains("com.qualcomm") 241 | || i.packageName.contains("overlay") 242 | || i.packageName.contains("android.internal") 243 | ) 244 | 245 | if (excludeApp) { 246 | val app = Apps(i, i.packageName, pm.getApplicationLabel(i).toString(), flag) 247 | if (checkApps.contains(app)) { 248 | continue 249 | } 250 | apps.add(app) 251 | } 252 | } 253 | searchApps.addAll(apps) 254 | } catch (e: Exception) { 255 | e.printStackTrace() 256 | false 257 | } 258 | } 259 | 260 | 261 | private suspend fun sortList(list: MutableList) = withContext(Dispatchers.Default) { 262 | try { 263 | list.sortBy { 264 | it.appName 265 | } 266 | } catch (e: Exception) { 267 | e.printStackTrace() 268 | } 269 | 270 | } 271 | 272 | 273 | fun getSearchListener(): SearchView.OnQueryTextListener { 274 | return object : SearchView.OnQueryTextListener { 275 | override fun onQueryTextSubmit(query: String): Boolean { 276 | searchStr = query 277 | refresh(false) 278 | return true 279 | } 280 | 281 | override fun onQueryTextChange(newText: String): Boolean { 282 | searchStr = newText 283 | refresh(false) 284 | return true 285 | } 286 | } 287 | } 288 | 289 | 290 | fun clear() { 291 | apps.clear() 292 | showApps.clear() 293 | checkApps.clear() 294 | searchApps.clear() 295 | uiScope.cancel() 296 | controlScope.cancel() 297 | viewModelJob.cancel() 298 | } 299 | 300 | inner class AppFilter : Filter() { 301 | override fun performFiltering(constraint: CharSequence): FilterResults { 302 | val filterResults = FilterResults() 303 | val filtered: MutableList = mutableListOf() 304 | val filteredCheck: MutableList = mutableListOf() 305 | 306 | if (constraint.toString().isEmpty()) { 307 | filtered.addAll(checkApps) 308 | filtered.addAll( 309 | if (filterType == 1) { 310 | searchApps.filter { (it.flag == 1) or checkApps.contains(it) } 311 | } else { 312 | searchApps.filter { !checkApps.contains(it) } 313 | } 314 | ) 315 | 316 | } else { 317 | val showSystemApps = filterType == 2 318 | for (i in searchApps) { 319 | if ((i.packageName.contains(constraint.toString(), true) || 320 | i.appName.contains(constraint.toString(), true)) 321 | ) { 322 | if (((i.flag == 2) and !showSystemApps) or checkApps.contains(i)) { 323 | continue 324 | } 325 | filtered.add(i) 326 | } 327 | 328 | } 329 | for (i in checkApps) { 330 | if ((i.packageName.contains(constraint.toString(), true) || 331 | i.appName.contains(constraint.toString(), true)) 332 | ) { 333 | filteredCheck.add(i) 334 | } 335 | 336 | } 337 | } 338 | filtered.addAll(0, filteredCheck) 339 | filterResults.values = filtered 340 | filterResults.count = filtered.size 341 | return filterResults 342 | } 343 | 344 | override fun publishResults(constraint: CharSequence?, results: FilterResults) { 345 | showApps.clear() 346 | showApps.addAll(results.values as Collection) 347 | notifyDataSetChanged() 348 | } 349 | } 350 | 351 | 352 | class Apps( 353 | var applicationInfo: ApplicationInfo, 354 | var packageName: String, 355 | var appName: String, 356 | var flag: Int, 357 | ) { 358 | override fun equals(other: Any?): Boolean { 359 | if (other !is Apps) { 360 | return false; 361 | } 362 | return this.appName == other.appName && this.packageName == other.packageName 363 | } 364 | 365 | override fun hashCode(): Int { 366 | var result = 31 * packageName.hashCode() 367 | result = 31 * result + appName.hashCode() 368 | return result 369 | } 370 | } 371 | 372 | } --------------------------------------------------------------------------------