59 Commits
4.4 ... master

Author SHA1 Message Date
b7015f8a69 chore: bump dependencies 2025-08-24 03:00:30 +08:00
d39f50642a chore: update target sdk to 36 2025-08-19 16:48:18 +08:00
5a6a61b4be chore: update jdk to 21 2025-08-19 16:42:28 +08:00
114ec89764 chore: bump gradle to 8.14.3 2025-08-19 16:42:21 +08:00
476b6d6be6 chore: bump dependencies 2025-08-19 16:42:14 +08:00
53249108d1 refactor: update KavaRef usage to 1.0.1 2025-07-06 21:29:16 +08:00
147e4c117e refactor: migrate and update to YukiHookAPI 1.3.0 2025-06-25 23:20:11 +08:00
276820fdc5 docs: update README 2025-06-24 14:10:17 +08:00
0b7ade9076 docs: update README 2025-06-20 12:48:37 +08:00
6c26a8b0cd chore: disable type auto conversion for sweet-property 2025-05-09 23:19:38 +08:00
d925873c4c feat: test migrate to Hikage(https://github.com/BetterAndroid/Hikage) 2025-04-22 09:40:20 +08:00
9fb52332d5 feat: add BaseActivity2 2025-04-22 09:39:30 +08:00
bf92f0241c chore: bump dependencies 2025-03-16 23:02:29 +08:00
7ec8de4be0 chore: bump gradle to 8.13 2025-03-16 23:02:23 +08:00
df949cf56b chore: update project files 2025-03-16 23:02:14 +08:00
f1061b27fa chore: bump ci to v4 2025-02-22 01:05:12 +08:00
b8543130cc chore: update .gitignore 2025-02-22 01:05:00 +08:00
9ae395ecee docs: update license 2025-01-13 11:12:54 +08:00
8d2d233b93 refactor: support Android 15 edge-to-edge system bars 2024-11-25 18:50:55 +08:00
70757b1594 refactor: support TIM 4.0+ 2024-11-13 15:39:05 +08:00
a14a38e00f chore: update target sdk to 35 2024-11-10 20:40:51 +08:00
910c67a943 chore: some tweaks in build.gradle.kts 2024-11-10 20:40:40 +08:00
6a31eef23e chore: update project files 2024-11-10 20:30:10 +08:00
0517df5dc4 chore: bump dependencies 2024-11-10 20:09:28 +08:00
f25472b124 chore: update project files 2024-11-10 20:09:19 +08:00
ebb68c69b4 chore: bump gradle to 8.10.2 2024-11-10 20:09:12 +08:00
c89eb39a75 chore: bump dependencies 2024-09-29 00:06:34 +08:00
43e0dff6cb fix: wake lock acquire not release will cause problem in BasicHookFactory 2024-09-06 18:25:07 +08:00
215d680955 chore: bump dependencies 2024-09-05 10:56:47 +08:00
c25f316512 chore: bump gradle to 8.8 2024-09-01 00:09:05 +08:00
798a55a328 chore: update .editorconfig 2024-09-01 00:07:56 +08:00
3dea65c4c6 chore: update .editorconfig 2024-06-21 10:09:50 +08:00
46efaf7083 chore: update project files 2024-06-21 10:09:46 +08:00
760b7a42cd chore: bump dependencies 2024-06-20 11:12:02 +08:00
6be267f74d chore: bump gradle to 8.7 2024-06-20 11:11:57 +08:00
7d1dbbbf44 chore: update .editorconfig 2024-06-20 11:07:14 +08:00
fb0182f075 feat: support QQ NT (>= 9.0.0) version 2024-06-17 01:36:00 +08:00
80e89d087f refactor: make some change for dexkit 2024-06-17 01:22:15 +08:00
c5711338e3 chore: bump dependencies 2024-02-20 11:29:04 +08:00
2fac3c2709 chore: bump gradle to 8.6 2024-02-20 11:29:01 +08:00
7b65ca01fb chore: update .editorconfig 2024-01-13 21:22:31 +08:00
4d75fb9e8c chore: update project files 2024-01-13 21:22:25 +08:00
13d25dcafd docs: update copyright date to 2024 for all existing files 2024-01-01 01:29:39 +08:00
1298077c9f style: merge to new ktlint version & rules 2023-12-29 21:32:04 +08:00
374ffaab4f chore: bump dependencies 2023-12-28 23:46:46 +08:00
76904665cc chore: bump gradle to 8.5 2023-12-28 23:42:36 +08:00
dfdb18dcb7 chore: update .gitignore 2023-12-28 23:42:25 +08:00
d1fb794284 docs: use relative link 2023-12-11 02:48:23 +08:00
3adaad1040 chore: update project files 2023-12-11 02:48:19 +08:00
39b132cc1a chore: bump dependency versions 2023-12-11 00:00:19 +08:00
13837b3b33 docs: update piracy statement 2023-12-11 00:00:14 +08:00
4405808ff3 docs: update promotion 2023-11-18 18:15:31 +08:00
7c66519e2d chore: bump "com.highcapable.sweetdependency" version to 1.0.4 2023-11-14 01:01:15 +08:00
9b620d7688 chore: bump "com.highcapable.sweetproperty" version to 1.0.5 2023-11-08 15:13:34 +08:00
cde830b804 chore: update project files 2023-11-08 15:13:30 +08:00
884a743338 chore: bump dependencies 2023-11-04 04:01:34 +08:00
e9aa721902 chore: bump plugin versions
- bump "com.highcapable.sweetdependency" version to 1.0.3
- bump "com.highcapable.sweetproperty" version to 1.0.4
2023-11-04 03:57:42 +08:00
fa967c8dfb docs: replace download links 2023-11-03 14:32:07 +08:00
7fe6bd91f0 docs: update release channel 2023-10-26 21:15:02 +08:00
42 changed files with 1179 additions and 910 deletions

View File

@@ -10,6 +10,24 @@ ktlint_standard_argument-list-wrapping = disabled
ktlint_standard_parameter-list-wrapping = disabled
ktlint_standard_trailing-comma-on-declaration-site = disabled
ktlint_function_signature_body_expression_wrapping = multiline
ktlint_standard_string-template-indent = disabled
ktlint_standard_function-signature = disabled
ktlint_standard_trailing-comma-on-call-site = disabled
ktlint_standard_multiline-expression-wrapping = disabled
ktlint_standard_no-empty-first-line-in-class-body = disabled
ktlint_standard_if-else-wrapping = disabled
ktlint_standard_if-else-bracing = disabled
ktlint_standard_statement-wrapping = disabled
ktlint_standard_blank-line-before-declaration = disabled
ktlint_standard_no-empty-file = disabled
ktlint_standard_property-naming = disabled
ktlint_standard_function-naming = disabled
ktlint_standard_chain-method-continuation = disabled
ktlint_standard_class-signature = disabled
ktlint_standard_condition-wrapping = disabled
ktlint_standard_class-signature = disabled
ktlint_standard_no-trailing-spaces = disabled
ktlint_standard_multiline-loop = disabled
ij_continuation_indent_size = 2
indent_size = 4
indent_style = space

View File

@@ -27,7 +27,7 @@ jobs:
See commit detail [here](${{ github.event.head_commit.url }})
COMMIT_URL: ${{ github.event.head_commit.url }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Prepare GitHub Env
run: |
GITHUB_SHA=${{ github.sha }}
@@ -37,10 +37,10 @@ jobs:
uses: jwlawson/actions-setup-cmake@v1
with:
cmake-version: '3.22.1'
- name: Prepare Java 17
uses: actions/setup-java@v3
- name: Prepare Java 21
uses: actions/setup-java@v4
with:
java-version: 17
java-version: 21
java-package: jdk
distribution: 'temurin'
cache: 'gradle'
@@ -69,12 +69,12 @@ jobs:
echo "DEBUG_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts (Debug)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: ${{ env.DEBUG_APK_PATH }}
name: TSBattery-debug-${{ github.event.head_commit.id }}
- name: Upload Artifacts (Release)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: ${{ env.RELEASE_APK_PATH }}
name: TSBattery-release-${{ github.event.head_commit.id }}

View File

@@ -17,7 +17,7 @@ jobs:
env:
APK_OUTPUT_PATH: 'app/build/outputs/apk'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Prepare GitHub Env
run: |
GITHUB_SHA=${{ github.sha }}
@@ -27,10 +27,10 @@ jobs:
uses: jwlawson/actions-setup-cmake@v1
with:
cmake-version: '3.22.1'
- name: Prepare Java 17
uses: actions/setup-java@v3
- name: Prepare Java 21
uses: actions/setup-java@v4
with:
java-version: 17
java-version: 21
java-package: jdk
distribution: 'temurin'
cache: 'gradle'
@@ -59,12 +59,12 @@ jobs:
echo "DEBUG_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts (Debug)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: ${{ env.DEBUG_APK_PATH }}
name: TSBattery-debug-${{ github.event.head_commit.id }}
- name: Upload Artifacts (Release)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: ${{ env.RELEASE_APK_PATH }}
name: TSBattery-release-${{ github.event.head_commit.id }}

117
.gitignore vendored
View File

@@ -1,15 +1,110 @@
## Fully .gtignore for IntelliJ, Android Studio and Gradle based Java projects
## References:
## - https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
## - https://github.com/android/platform-samples/blob/main/.gitignore
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
.idea/.name
.idea/artifacts
.idea/compiler.xml
.idea/jarRepositories.xml
.idea/modules.xml
.idea/*.iml
.idea/modules
.idea/caches
.idea/material_theme**
.idea/other.xml
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
*.ipr
# Kotlin
.kotlin
# Misc
.idea/misc.xml
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# Android studio 3.1+ additional
.idea/deployment*.xml
.idea/assetWizardSettings.xml
.idea/androidTestResultsUserPreferences.xml
# Android projects
**/local.properties
/captures
.externalNativeBuild
.cxx
local.properties
# Gradle projects
.gradle
build/
# Mkdocs temporary serving folder
docs-gen
site
*.bak
.idea/appInsightsSettings.xml
# Mac OS
.DS_Store

5
.idea/.gitignore generated vendored
View File

@@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
/gradle.xml
/misc.xml

6
.idea/AndroidProjectSystem.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppInsightsSettings">
<option name="tabSettings">
<map>
<entry key="Firebase Crashlytics">
<value>
<InsightsFilterSettings>
<option name="connection">
<ConnectionSetting>
<option name="appId" value="PLACEHOLDER" />
<option name="mobileSdkAppId" value="" />
<option name="projectId" value="" />
<option name="projectNumber" value="" />
</ConnectionSetting>
</option>
<option name="signal" value="SIGNAL_UNSPECIFIED" />
<option name="timeIntervalDays" value="THIRTY_DAYS" />
<option name="visibilityType" value="ALL" />
</InsightsFilterSettings>
</value>
</entry>
</map>
</option>
</component>
</project>

6
.idea/compiler.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>

View File

@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven3" />
<option name="name" value="maven3" />
<option name="url" value="https://www.jitpack.io" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
<option name="name" value="maven" />
<option name="url" value="https://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven2" />
<option name="name" value="maven2" />
<option name="url" value="https://maven.aliyun.com/nexus/content/repositories/jcenter" />
</remote-repository>
</component>
</project>

2
.idea/kotlinc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.10" />
<option name="version" value="2.1.10" />
</component>
</project>

7
.idea/ktlint-plugin.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KtLint plugin">
<ktlintMode>MANUAL</ktlintMode>
<formatOnSave>false</formatOnSave>
</component>
</project>

17
.idea/runConfigurations.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@@ -1,17 +1,17 @@
# TSBattery
[![GitHub license](https://img.shields.io/github/license/fankes/TSBattery?color=blue)](https://github.com/fankes/TSBattery/blob/master/LICENSE)
[![GitHub CI](https://img.shields.io/github/actions/workflow/status/fankes/TSBattery/commit_ci.yml?label=CI%20builds)](https://github.com/fankes/TSBattery/actions/workflows/commit_ci.yml)
[![GitHub release](https://img.shields.io/github/v/release/fankes/TSBattery?display_name=release&logo=github&color=green)](https://github.com/fankes/TSBattery/releases)
![GitHub all releases](https://img.shields.io/github/downloads/fankes/TSBattery/total?label=downloads)
![GitHub all releases](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.tsbattery/total?label=LSPosed%20downloads&labelColor=F48FB1)
[![GitHub license](https://img.shields.io/github/license/fankes/TSBattery?color=blue&style=flat-square)](https://github.com/fankes/TSBattery/blob/master/LICENSE)
[![GitHub CI](https://img.shields.io/github/actions/workflow/status/fankes/TSBattery/commit_ci.yml?label=CI%20builds&style=flat-square)](https://github.com/fankes/TSBattery/actions/workflows/commit_ci.yml)
[![GitHub release](https://img.shields.io/github/v/release/fankes/TSBattery?display_name=release&logo=github&color=green&style=flat-square)](https://github.com/fankes/TSBattery/releases)
![GitHub all releases](https://img.shields.io/github/downloads/fankes/TSBattery/total?label=downloads&style=flat-square)
![GitHub all releases](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.tsbattery/total?label=LSPosed%20downloads&labelColor=F48FB1&style=flat-square)
[![Telegram CI](https://img.shields.io/badge/CI%20builds-Telegram-blue.svg?logo=telegram)](https://t.me/TSBATTERY_CI)
[![Telegram](https://img.shields.io/badge/discussion-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)
[![QQ](https://img.shields.io/badge/discussion-QQ-blue.svg?logo=tencent-qq&logoColor=red)](https://qm.qq.com/cgi-bin/qm/qr?k=dp2h5YhWiga9WWb_Oh7kSHmx01X8I8ii&jump_from=webapi&authKey=Za5CaFP0lk7+Zgsk2KpoBD7sSaYbeXbsDgFjiWelOeH4VSionpxFJ7V0qQBSqvFM)
[![QQ 频道](https://img.shields.io/badge/discussion-QQ%20频道-blue.svg?logo=tencent-qq&logoColor=red)](https://pd.qq.com/s/44gcy28h)
[![Telegram CI](https://img.shields.io/badge/CI%20builds-Telegram-blue.svg?logo=telegram&style=flat-square)](https://t.me/TSBattery_CI)
[![Telegram](https://img.shields.io/badge/discussion-Telegram-blue.svg?logo=telegram&style=flat-square)](https://t.me/XiaofangInternet)
[![QQ](https://img.shields.io/badge/discussion-QQ-blue.svg?logo=tencent-qq&logoColor=red&style=flat-square)](https://qm.qq.com/cgi-bin/qm/qr?k=dp2h5YhWiga9WWb_Oh7kSHmx01X8I8ii&jump_from=webapi&authKey=Za5CaFP0lk7+Zgsk2KpoBD7sSaYbeXbsDgFjiWelOeH4VSionpxFJ7V0qQBSqvFM)
[![QQ 频道](https://img.shields.io/badge/discussion-QQ%20频道-blue.svg?logo=tencent-qq&logoColor=red&style=flat-square)](https://pd.qq.com/s/44gcy28h)
![Banner](https://github.com/fankes/TSBattery/blob/master/img-src/banner.png?raw=true)
<img src="app/src/main/ic_launcher-playstore.png" width = "100" height = "100" alt="LOGO"/>
A new way to save your battery avoid cancer apps hacker it.
@@ -34,40 +34,48 @@ This Xposed Module is for use by specific apps for users in mainland China, you
- 如果在微信设置界面右上角你无法找到 **TSBattery**
的图标,请尝试同时激活 [WeXposed (微X模块)](https://github.com/Xposed-Modules-Repo/com.fkzhang.wechatxposed)
## 发行渠道说明
## 发行渠道
- [Automatic Build on Commit](https://github.com/fankes/TSBattery/actions/workflows/commit_ci.yml)
| <img src="https://avatars.githubusercontent.com/in/15368?s=64&v=4" width = "30" height = "30" alt="LOGO"/> | [GitHub CI](https://github.com/fankes/TSBattery/actions/workflows/commit_ci.yml) | CI 自动构建 (测试版) |
|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|---------------|
上述更新为代码 `commit` 后自动触发,具体更新内容可点击上方的文字前往 **GitHub Actions** 进行查看,本更新由开源的流程自动编译发布,
**不保证其稳定性** 所发布的版本**仅供测试**,且不会特殊说明甚至可能会变更版本号或保持与当前稳定版相同的版本号。
| <img src="https://github.com/peter-iakovlev/Telegram/blob/public/Icon.png?raw=true" width = "30" height = "30" alt="LOGO"/> | [Telegram CI 频道](https://t.me/TSBattery_CI) | CI 自动构建 (测试版) |
|-----------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|---------------|
如果你需要直接下载 CI 自动构建打包的安装包,请点击顶部的 `CI builds | Telegram` 标签加入 Telegram CI 自动构建频道。
| <img src="https://avatars.githubusercontent.com/in/15368?s=64&v=4" width = "30" height = "30" alt="LOGO"/> | [GitHub Releases](https://github.com/fankes/TSBattery/releases) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|-----------|
- [Release](https://github.com/fankes/TSBattery/releases)
- [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases)
- [蓝奏云 **密码tsbt**](https://fankes.lanzouy.com/b02zfz3sj)
| <img src="https://avatars.githubusercontent.com/u/78217009?s=200&v=4?raw=true" width = "30" height = "30" alt="LOGO"/> | [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|-----------|
上述更新为手动发布的稳定版,具体更新内容可点击上方的文字前往指定的发布页面查看,稳定版的更新将会同时发布到上述地址中,同步更新。
| <img src="https://github.com/fankes/fankes/assets/37344460/82113d3c-aa7b-4dd1-95c7-cda650065c12" width = "30" height = "30" alt="LOGO"/> | [123 云盘 **(密码tsbt)**](https://www.123pan.com/s/5SlUVv-N8DBh.html) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|-----------|
本模块发布地址仅限于上述所列出的地址,从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
## 请勿用于非法用途
## 注意事项
本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
<h3>1.&nbsp;本软件免费、由兴趣驱动开发,仅供学习交流使用。如果你是从其他非官方渠道付费获得本软件,可能已遭遇欺诈,欢迎向我们举报可疑行为。</h3>
<h3>2.&nbsp;本软件采用 <strong>GNU Affero General Public License (AGPL 3.0)</strong> 许可证。根据该许可证的要求:</h3>
- 任何衍生作品必须采用相同的 AGPL 许可证
- 分发本软件或其修改版本时,必须提供完整的源代码
- 必须保留原始的版权声明及许可证信息
- 不得额外施加限制来限制他人对本软件的自由使用
<h3>3.&nbsp;我们鼓励在遵守 AGPL 3.0 条款的前提下进行自由传播和改进,但请尊重作者署名权,勿冒用原作者名义。</h3>
## 项目推广
如果你正在寻找一个可以自动管理 Gradle 项目依赖的 Gradle 插件,你可以了解一下 [SweetDependency](https://github.com/HighCapable/SweetDependency) 项目。
如果你正在寻找一个可以自动生成属性键值的 Gradle 插件,你可以了解一下 [SweetProperty](https://github.com/HighCapable/SweetProperty) 项目。
本项目同样使用了 **SweetDependency****SweetProperty**
## 捐赠支持
工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。
<img src="https://github.com/fankes/fankes/blob/main/img-src/payment_code.jpg?raw=true" width = "500" alt="Payment Code"/>
<!--suppress HtmlDeprecatedAttribute -->
<div align="center">
<h2>嘿,还请君留步!👋</h2>
<h3>这里有 Android 开发工具、UI 设计、Gradle 插件、Xposed 模块和实用软件等相关项目。</h3>
<h3>如果下方的项目能为你提供帮助,不妨为我点个 star 吧!</h3>
<h3>所有项目免费、开源,遵循对应开源许可协议。</h3>
<h1><a href="https://github.com/fankes/fankes/blob/main/project-promote/README-zh-CN.md">→ 查看更多关于我的项目,请点击这里 ←</a></h1>
</div>
## Star History
@@ -78,7 +86,7 @@ This Xposed Module is for use by specific apps for users in mainland China, you
- [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html)
```
Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -96,4 +104,4 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Powered by [YukiHookAPI](https://github.com/HighCapable/YukiHookAPI)
版权所有 © 2017-2023 Fankes Studio(qzmmcn@163.com)
版权所有 © 2017 Fankes Studio(qzmmcn@163.com)

2
app/.gitignore vendored
View File

@@ -1,4 +1,2 @@
/build
/release
/src/main/assets/xposed_init
/src/main/resources/META-INF/yukihookapi_init

View File

@@ -38,14 +38,6 @@ android {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = listOf(
"-Xno-param-assertions",
"-Xno-call-assertions",
"-Xno-receiver-assertions"
)
}
buildFeatures {
buildConfig = true
viewBinding = true
@@ -58,7 +50,18 @@ androidComponents {
onVariants(selector().all()) {
it.outputs.forEach { output ->
val currentType = it.buildType
val currentSuffix = property.github.ci.commit.id.let { suffix -> if (suffix.isNotBlank()) "-$suffix" else "" }
// Workaround for GitHub Actions.
// Why? I don't know, but it works.
// Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
// public inline fun CharSequence.isNotBlank(): Boolean defined in kotlin.text.
@Suppress("UNNECESSARY_SAFE_CALL", "RemoveRedundantCallsOfConversionMethods")
val currentSuffix = property.github.ci.commit.id?.let { suffix ->
// Workaround for GitHub Actions.
// Strongly transfer type to [String].
val sSuffix = suffix.toString()
if (sSuffix.isNotBlank()) "-$sSuffix" else ""
}
val currentVersion = "${output.versionName.get()}$currentSuffix(${output.versionCode.get()})"
if (output is com.android.build.api.variant.impl.VariantOutputImpl)
output.outputFileName.set("${property.project.name}-v$currentVersion-$currentType.apk")
@@ -70,6 +73,13 @@ dependencies {
compileOnly(de.robv.android.xposed.api)
implementation(com.highcapable.yukihookapi.api)
ksp(com.highcapable.yukihookapi.ksp.xposed)
ksp(com.highcapable.hikage.hikage.compiler)
implementation(com.highcapable.kavaref.kavaref.core)
implementation(com.highcapable.kavaref.kavaref.extension)
implementation(com.highcapable.hikage.hikage.core)
implementation(com.highcapable.hikage.hikage.extension)
implementation(com.highcapable.hikage.hikage.widget.androidx)
implementation(com.highcapable.hikage.hikage.widget.material)
implementation(com.fankes.projectpromote.project.promote)
implementation(org.luckypray.dexkit)
implementation(com.github.duanhong169.drawabletoolbox)

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
@@ -26,8 +26,11 @@ package com.fankes.tsbattery.hook.entity
import android.app.Activity
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.os.Message
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ServiceCompat
@@ -44,29 +47,17 @@ import com.fankes.tsbattery.hook.factory.startModuleSettings
import com.fankes.tsbattery.hook.helper.DexKitHelper
import com.fankes.tsbattery.utils.factory.appVersionName
import com.fankes.tsbattery.utils.factory.dp
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.kavaref.KavaRef.Companion.asResolver
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.extension.ArrayClass
import com.highcapable.kavaref.extension.VariousClass
import com.highcapable.kavaref.extension.classOf
import com.highcapable.kavaref.extension.createInstanceAsTypeOrNull
import com.highcapable.kavaref.extension.createInstanceOrNull
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.buildOf
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.type.android.BuildClass
import com.highcapable.yukihookapi.hook.type.android.BundleClass
import com.highcapable.yukihookapi.hook.type.android.ContextClass
import com.highcapable.yukihookapi.hook.type.android.IntentClass
import com.highcapable.yukihookapi.hook.type.android.MessageClass
import com.highcapable.yukihookapi.hook.type.java.AnyArrayClass
import com.highcapable.yukihookapi.hook.type.java.AnyClass
import com.highcapable.yukihookapi.hook.type.java.BooleanType
import com.highcapable.yukihookapi.hook.type.java.CharSequenceClass
import com.highcapable.yukihookapi.hook.type.java.IntType
import com.highcapable.yukihookapi.hook.type.java.ListClass
import com.highcapable.yukihookapi.hook.type.java.LongType
import com.highcapable.yukihookapi.hook.type.java.StringClass
import com.highcapable.yukihookapi.hook.type.java.UnitType
import java.lang.reflect.Method
import java.lang.reflect.Proxy
@@ -119,6 +110,9 @@ object QQTIMHooker : YukiBaseHooker() {
)
)
/** 是否存在 [BaseChatPieClass] */
private val hasBaseChatPieClass by lazy { BaseChatPieClass != null }
/**
* DexKit 搜索结果数据实现类
*/
@@ -147,7 +141,7 @@ object QQTIMHooker : YukiBaseHooker() {
* 在 QQ NT 中 [AboutActivityClass] 已被移除 - 以此作为判断条件
* @return [Boolean]
*/
private val isQQNTVersion get() = isQQ && AboutActivityClass == null
private val isQQNTVersion get() = AboutActivityClass == null
/** 当前宿主的版本 */
private var hostVersionName = "<unknown>"
@@ -156,7 +150,9 @@ object QQTIMHooker : YukiBaseHooker() {
* 通过 [Activity] or [Fragment] 实例得到上下文
* @return [Activity] or null
*/
private fun Any.compatToActivity() = if (this is Activity) this else current().method { name = "getActivity"; superClass() }.invoke()
private fun Any.compatToActivity() = if (this !is Activity)
asResolver().optional().firstMethodOrNull { name = "getActivity"; superclass() }?.invoke()
else this
/** 使用 DexKit 进行搜索 */
private fun searchUsingDexKit() {
@@ -169,18 +165,18 @@ object QQTIMHooker : YukiBaseHooker() {
declaredClass(baseChatPieClassName)
usingStrings("remainScreenOn")
paramCount = 0
returnType = UnitType.name
returnType = Void.TYPE.name
}
}.firstOrNull()?.getMethodInstance(classLoader)
}.singleOrNull()?.getMethodInstance(classLoader)
DexKitData.BaseChatPie_CancelRemainScreenOnMethod =
findMethod {
matcher {
declaredClass(baseChatPieClassName)
usingStrings("cancelRemainScreenOn")
paramCount = 0
returnType = UnitType.name
returnType = Void.TYPE.name
}
}.firstOrNull()?.getMethodInstance(classLoader)
}.singleOrNull()?.getMethodInstance(classLoader)
}
val kotlinFunction0 = "kotlin.jvm.functions.Function0"
findClass {
@@ -189,26 +185,26 @@ object QQTIMHooker : YukiBaseHooker() {
methods {
add {
name = "<init>"
paramTypes(ContextClass.name, IntType.name, CharSequenceClass.name, IntType.name)
paramTypes(classOf<Context>().name, classOf<Int>().name, classOf<CharSequence>().name, classOf<Int>().name)
}
add {
paramTypes(kotlinFunction0)
returnType = UnitType.name
returnType = Void.TYPE.name
}
}
fields { count(6..Int.MAX_VALUE) }
}
}.firstOrNull()?.name?.also { className ->
}.singleOrNull()?.name?.also { className ->
DexKitData.SimpleItemProcessorClass = className.toClass()
DexKitData.SimpleItemProcessorClass_OnClickMethod =
findMethod {
matcher {
declaredClass = className
paramTypes(kotlinFunction0)
returnType = UnitType.name
returnType = Void.TYPE.name
usingNumbers(2)
}
}.firstOrNull()?.getMethodInstance(classLoader)
}.singleOrNull()?.getMethodInstance(classLoader)
}
}
}
@@ -221,8 +217,14 @@ object QQTIMHooker : YukiBaseHooker() {
* remainScreenOn、cancelRemainScreenOn
*
* 这两个方法一个是挂起电源锁常驻亮屏 - 一个是停止常驻亮屏
*
* - 在 QQ NT 版本中完全移除了 BaseChatPie 类 - 所以不再处理
*/
private fun hookQQBaseChatPie() {
if (hasBaseChatPieClass.not()) {
HookEntry.isHookClientSupport = true
return YLog.debug("Start for QQ NT version,.")
}
/**
* 打印警告信息
* @param index 序号
@@ -237,23 +239,23 @@ object QQTIMHooker : YukiBaseHooker() {
/** Hook CoreService QQ、TIM */
private fun hookCoreService() {
CoreServiceClass?.apply {
CoreServiceClass?.resolve()?.optional()?.apply {
if (isQQ) {
method {
firstMethodOrNull {
name = "startTempService"
}.ignored().hook().intercept()
method {
}?.hook()?.intercept()
firstMethodOrNull {
name = "startCoreService"
param(BooleanType)
}.ignored().hook().intercept()
method {
parameters(Boolean::class)
}?.hook()?.intercept()
firstMethodOrNull {
name = "onStartCommand"
param(IntentClass, IntType, IntType)
}.ignored().hook().replaceTo(any = 2)
parameters(Intent::class, Int::class, Int::class)
}?.hook()?.replaceTo(any = 2)
}
method {
firstMethodOrNull {
name = "onCreate"
}.ignored().hook().after {
}?.hook()?.after {
if (ConfigData.isEnableKillQQTimCoreService)
instance<Service>().apply {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
@@ -262,10 +264,10 @@ object QQTIMHooker : YukiBaseHooker() {
}
}
}
CoreService_KernelServiceClass?.apply {
method {
CoreService_KernelServiceClass?.resolve()?.optional()?.apply {
firstMethodOrNull {
name = "onCreate"
}.ignored().hook().after {
}?.hook()?.after {
if (ConfigData.isEnableKillQQTimCoreServiceChild)
instance<Service>().apply {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
@@ -273,10 +275,10 @@ object QQTIMHooker : YukiBaseHooker() {
YLog.debug("Shutdown CoreService\$KernelService OK!")
}
}
method {
firstMethodOrNull {
name = "onStartCommand"
param(IntentClass, IntType, IntType)
}.ignored().hook().replaceTo(any = 2)
parameters(Intent::class, Int::class, Int::class)
}?.hook()?.replaceTo(any = 2)
}
}
@@ -289,40 +291,46 @@ object QQTIMHooker : YukiBaseHooker() {
* 旧版本理论上没有这个类
*/
"${PackageName.QQ}.msf.service.y".toClassOrNull()
?.method {
?.resolve()
?.optional(silent = true)
?.firstMethodOrNull {
name = "a"
param(StringClass, LongType)
returnType = UnitType
}?.ignored()?.hook()?.intercept()
parameters(String::class, Long::class)
returnType = Void.TYPE
}?.hook()?.intercept()
/**
* 干掉自动上传服务的电源锁
* 每个版本的差异暂未做排查
*/
"com.tencent.upload.impl.UploadServiceImpl".toClassOrNull()
?.method {
?.resolve()
?.optional(silent = true)
?.firstMethodOrNull {
name = "acquireWakeLockIfNot"
}?.ignored()?.hook()?.intercept()
}?.hook()?.intercept()
/**
* Hook 掉一个一像素保活 Activity 真的我怎么都想不到讯哥的程序员做出这种事情
* 这个东西经过测试会在锁屏的时候吊起来,解锁的时候自动 finish(),无限耍流氓耗电
* 2022/1/25 后期查证:锁屏界面消息快速回复窗口的解锁后拉起保活界面,也是毒瘤
*/
"${PackageName.QQ}.activity.QQLSUnlockActivity".toClassOrNull()
?.method {
?.resolve()
?.optional(silent = true)
?.firstMethodOrNull {
name = "onCreate"
param(BundleClass)
}?.ignored()?.hook {
parameters(Bundle::class)
}?.hook {
var origDevice = ""
before {
/** 由于在 onCreate 里有一行判断只要型号是 xiaomi 的设备就开电源锁,所以说这里临时替换成菊花厂 */
origDevice = Build.MANUFACTURER
if (Build.MANUFACTURER.lowercase() == "xiaomi")
BuildClass.field { name = "MANUFACTURER" }.get().set("HUAWEI")
Build::class.resolve().firstField { name = "MANUFACTURER" }.set("HUAWEI")
}
after {
instance<Activity>().finish()
/** 这里再把型号替换回去 - 不影响应用变量等 Xposed 模块修改的型号 */
BuildClass.field { name = "MANUFACTURER" }.get().set(origDevice)
Build::class.resolve().firstField { name = "MANUFACTURER" }.set(origDevice)
}
}
/**
@@ -332,9 +340,11 @@ object QQTIMHooker : YukiBaseHooker() {
* 2022/1/25 后期查证:锁屏界面消息快速回复窗口
*/
VariousClass("${PackageName.QQ}.activity.QQLSActivity\$14", "ktq").toClassOrNull()
?.method {
?.resolve()
?.optional(silent = true)
?.firstMethodOrNull {
name = "run"
}?.ignored()?.hook()?.intercept()
}?.hook()?.intercept()
/**
* 这个是毒瘤核心类
* WakeLockMonitor
@@ -345,92 +355,98 @@ object QQTIMHooker : YukiBaseHooker() {
* 👮🏻 经过排查 Play 版本没这个类...... Emmmm 不想说啥了
* ✅ 备注8.9.x 版本已经基本移除了这个功能,没有再发现存在这个类
*/
"com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor".toClassOrNull()?.apply {
method {
name = "onHook"
param(StringClass, AnyClass, AnyArrayClass, AnyClass)
}.ignored().hook().intercept()
method {
name = "doReport"
param("com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor\$WakeLockEntity", IntType)
}.ignored().hook().intercept()
method {
name = "afterHookedMethod"
param("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}.ignored().hook().intercept()
method {
name = "beforeHookedMethod"
param("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}.ignored().hook().intercept()
method {
name = "onAppBackground"
}.ignored().hook().intercept()
method {
name = "onOtherProcReport"
param(BundleClass)
}.ignored().hook().intercept()
method {
name = "onProcessRun30Min"
}.ignored().hook().intercept()
method {
name = "onProcessBG5Min"
}.ignored().hook().intercept()
method {
name = "writeReport"
param(BooleanType)
}.ignored().hook().intercept()
}
"com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor".toClassOrNull()
?.resolve()
?.optional(silent = true)
?.apply {
firstMethodOrNull {
name = "onHook"
parameters(String::class, Any::class, ArrayClass(Any::class), Any::class)
}?.hook()?.intercept()
firstMethodOrNull {
name = "doReport"
parameters("com.tencent.qapmsdk.qqbattery.monitor.WakeLockMonitor\$WakeLockEntity", Int::class)
}?.hook()?.intercept()
firstMethodOrNull {
name = "afterHookedMethod"
parameters("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}?.hook()?.intercept()
firstMethodOrNull {
name = "beforeHookedMethod"
parameters("com.tencent.qapmsdk.qqbattery.monitor.MethodHookParam")
}?.hook()?.intercept()
firstMethodOrNull {
name = "onAppBackground"
}?.hook()?.intercept()
firstMethodOrNull {
name = "onOtherProcReport"
parameters(Bundle::class)
}?.hook()?.intercept()
firstMethodOrNull {
name = "onProcessRun30Min"
}?.hook()?.intercept()
firstMethodOrNull {
name = "onProcessBG5Min"
}?.hook()?.intercept()
firstMethodOrNull {
name = "writeReport"
parameters(Boolean::class)
}?.hook()?.intercept()
}
/**
* 这个是毒瘤核心操作类
* 功能同上、全部拦截
* 👮🏻 经过排查 Play 版本也没这个类...... Emmmm 不想说啥了
* ✅ 备注8.9.x 版本已经基本移除了这个功能,没有再发现存在这个类
*/
"com.tencent.qapmsdk.qqbattery.QQBatteryMonitor".toClassOrNull()?.apply {
method {
name = "start"
}.ignored().hook().intercept()
method {
name = "stop"
}.ignored().hook().intercept()
method {
name = "handleMessage"
param(MessageClass)
}.ignored().hook().intercept()
method {
name = "startMonitorInner"
}.ignored().hook().intercept()
method {
name = "onAppBackground"
}.ignored().hook().intercept()
method {
name = "onAppForeground"
}.ignored().hook().intercept()
method {
name = "setLogWhite"
paramCount = 2
}.ignored().hook().intercept()
method {
name = "setCmdWhite"
paramCount = 2
}.ignored().hook().intercept()
method {
name = "onWriteLog"
param(StringClass, StringClass)
}.ignored().hook().intercept()
method {
name = "onCmdRequest"
param(StringClass)
}.ignored().hook().intercept()
method {
name = "addData"
paramCount = 4
}.ignored().hook().intercept()
method {
name = "onGpsScan"
paramCount = 2
}.ignored().hook().intercept()
}
"com.tencent.qapmsdk.qqbattery.QQBatteryMonitor".toClassOrNull()
?.resolve()
?.optional(silent = true)
?.apply {
firstMethodOrNull {
name = "start"
}?.hook()?.intercept()
firstMethodOrNull {
name = "stop"
}?.hook()?.intercept()
firstMethodOrNull {
name = "handleMessage"
parameters(Message::class)
}?.hook()?.intercept()
firstMethodOrNull {
name = "startMonitorInner"
}?.hook()?.intercept()
firstMethodOrNull {
name = "onAppBackground"
}?.hook()?.intercept()
firstMethodOrNull {
name = "onAppForeground"
}?.hook()?.intercept()
firstMethodOrNull {
name = "setLogWhite"
parameterCount = 2
}?.hook()?.intercept()
firstMethodOrNull {
name = "setCmdWhite"
parameterCount = 2
}?.hook()?.intercept()
firstMethodOrNull {
name = "onWriteLog"
parameters(String::class, String::class)
}?.hook()?.intercept()
firstMethodOrNull {
name = "onCmdRequest"
parameters(String::class)
}?.hook()?.intercept()
firstMethodOrNull {
name = "addData"
parameterCount = 4
}?.hook()?.intercept()
firstMethodOrNull {
name = "onGpsScan"
parameterCount = 2
}?.hook()?.intercept()
}
}
/** Hook QQ 的设置界面添加模块设置入口 (新版) */
@@ -448,27 +464,30 @@ object QQTIMHooker : YukiBaseHooker() {
/** 为了使用图标资源 ID - 这里需要重新注入模块资源防止不生效 */
context.injectModuleAppResources()
val iconResId = if (context.isQQNightMode()) R.mipmap.ic_tsbattery_entry_night else R.mipmap.ic_tsbattery_entry_day
return simpleItemProcessorClass.buildOf(context, R.id.tsbattery_qq_entry_item_id, "TSBattery", iconResId) {
param(ContextClass, IntType, CharSequenceClass, IntType)
}?.also { entryItem ->
return simpleItemProcessorClass.createInstanceOrNull(context, R.id.tsbattery_qq_entry_item_id, "TSBattery", iconResId)?.also { item ->
val onClickMethod = DexKitData.SimpleItemProcessorClass_OnClickMethod ?: error("Could not found processor method")
val proxyOnClick = Proxy.newProxyInstance(appClassLoader, arrayOf(onClickMethod.parameterTypes[0])) { any, method, args ->
if (method.name == "invoke") {
context.startModuleSettings()
kotlinUnit.toClass().field { name = "INSTANCE" }.get().any()
kotlinUnit.toClass().resolve().firstField { name = "INSTANCE" }.get()
} else method.invoke(any, args)
}; onClickMethod.invoke(entryItem, proxyOnClick)
}; onClickMethod.invoke(item, proxyOnClick)
} ?: error("Could not create TSBattery entry item")
}
MainSettingConfigProviderClass?.method {
param(ContextClass)
returnType = ListClass
MainSettingConfigProviderClass?.resolve()?.optional()?.firstMethodOrNull {
parameters(Context::class)
returnType = List::class
}?.hook()?.after {
val context = args().first().cast<Context>() ?: return@after
val processor = result<MutableList<Any?>>() ?: return@after
processor.add(1, processor[0]?.javaClass?.buildOf(arrayListOf<Any>().apply { add(createTSEntryItem(context)) }, "", "") {
param(ListClass, CharSequenceClass, CharSequenceClass)
})
processor.add(
1,
processor[0]?.javaClass?.createInstanceOrNull(
arrayListOf<Any>().apply {
add(createTSEntryItem(context))
}.toList(), "", ""
)
)
}
}
@@ -478,35 +497,38 @@ object QQTIMHooker : YukiBaseHooker() {
*/
private fun hookQQSettingsUiLegacy(instance: Any?) {
/** 当前的顶级 Item 实例 */
val formItemRefRoot = instance?.current()?.field {
type { it == FormSimpleItemClass || it == FormCommonSingleLineItemClass }.index(num = 1)
}?.cast<View?>()
val formItemRefRoot = instance?.asResolver()?.optional()?.lastFieldOrNull {
type { it == FormSimpleItemClass || it == FormCommonSingleLineItemClass }
}?.get<View>()
/** 创建一个新的 Item */
FormSimpleItemClass?.buildOf<View>(instance?.compatToActivity()) { param(ContextClass) }?.current {
method {
val item = FormSimpleItemClass?.createInstanceAsTypeOrNull<View>(instance?.compatToActivity())
item?.asResolver()?.optional()?.apply {
firstMethodOrNull {
name = "setLeftText"
param(CharSequenceClass)
}.call("TSBattery")
method {
parameters(CharSequence::class)
}?.invoke("TSBattery")
firstMethodOrNull {
name = "setRightText"
param(CharSequenceClass)
}.call(ModuleVersion.toString())
method {
parameters(CharSequence::class)
}?.invoke(ModuleVersion.toString())
firstMethodOrNull {
name = "setBgType"
param(IntType)
}.call(if (isQQ) 0 else 2)
}?.apply { setOnClickListener { context.startModuleSettings() } }?.also { item ->
var listGroup = formItemRefRoot?.parent as? ViewGroup?
val lparam = (if (listGroup?.childCount == 1) {
listGroup = listGroup.parent as? ViewGroup
(formItemRefRoot?.parent as? View?)?.layoutParams
} else formItemRefRoot?.layoutParams)
?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
/** 设置圆角和间距 */
if (isQQ) (lparam as? ViewGroup.MarginLayoutParams?)?.setMargins(0, 15.dp(item.context), 0, 0)
/** 将 Item 添加到设置界面 */
listGroup?.also { if (isQQ) it.addView(item, lparam) else it.addView(item, 0, lparam) }
parameters(Int::class)
}?.invoke(if (isQQ) 0 else 2)
}
item ?: return
item.setOnClickListener { it.context.startModuleSettings() }
var listGroup = formItemRefRoot?.parent as? ViewGroup?
val lparam = (if (listGroup?.childCount == 1) {
listGroup = listGroup.parent as? ViewGroup
(formItemRefRoot?.parent as? View?)?.layoutParams
} else formItemRefRoot?.layoutParams)
?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
/** 设置圆角和间距 */
if (isQQ) (lparam as? ViewGroup.MarginLayoutParams?)?.setMargins(0, 15.dp(item.context), 0, 0)
/** 将 Item 添加到设置界面 */
listGroup?.also { if (isQQ) it.addView(item, lparam) else it.addView(item, 0, lparam) }
}
override fun onHook() {
@@ -535,22 +557,22 @@ object QQTIMHooker : YukiBaseHooker() {
/** 仅注入主进程 */
withProcess(mainProcessName) {
/** Hook 跳转事件 */
JumpActivityClass?.method {
JumpActivityClass?.resolve()?.optional()?.firstMethodOrNull {
name = "doOnCreate"
param(BundleClass)
parameters(Bundle::class)
}?.hook()?.after { instance<Activity>().jumpToModuleSettings() }
/** Hook 设置界面入口点 */
if (isQQNTVersion) hookQQSettingsUi()
else {
/** 将条目注入设置界面 (Activity) */
QQSettingSettingActivityClass?.method {
QQSettingSettingActivityClass?.resolve()?.optional()?.firstMethodOrNull {
name = "doOnCreate"
param(BundleClass)
parameters(Bundle::class)
}?.hook()?.after { hookQQSettingsUiLegacy(instance) }
/** 将条目注入设置界面 (Fragment) */
QQSettingSettingFragmentClass?.method {
QQSettingSettingFragmentClass?.resolve()?.optional()?.firstMethodOrNull {
name = "doOnCreateView"
paramCount = 3
parameterCount = 3
}?.hook()?.after { hookQQSettingsUiLegacy(instance) }
}
}

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
@@ -42,14 +42,13 @@ import com.fankes.tsbattery.utils.factory.absoluteStatusBarHeight
import com.fankes.tsbattery.utils.factory.appVersionCode
import com.fankes.tsbattery.utils.factory.appVersionName
import com.fankes.tsbattery.utils.factory.dp
import com.highcapable.kavaref.KavaRef.Companion.asResolver
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.factory.processName
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.type.android.ViewClass
/**
* Hook 微信
@@ -114,24 +113,24 @@ object WeChatHooker : YukiBaseHooker() {
/** 仅注入主进程 */
withProcess(mainProcessName) {
/** Hook 跳转事件 */
LauncherUIClass?.method {
LauncherUIClass?.resolve()?.optional()?.firstMethodOrNull {
name = "onResume"
emptyParam()
emptyParameters()
}?.hook()?.after { instance<Activity>().jumpToModuleSettings(isFinish = false) }
/** 向设置界面右上角添加按钮 */
SettingsUIClass?.method {
SettingsUIClass?.resolve()?.optional()?.firstMethodOrNull {
name = "onResume"
emptyParam()
emptyParameters()
}?.hook()?.after {
SettingsUIClass?.method {
SettingsUIClass?.resolve()?.optional()?.firstMethodOrNull {
name = "get_fragment"
emptyParam()
superClass(isOnlySuperClass = true)
}?.get(instance)?.call()?.current()?.method {
emptyParameters()
superclass()
}?.of(instance)?.invoke()?.asResolver()?.optional()?.firstMethodOrNull {
name = "getView"
emptyParam()
returnType = ViewClass
superClass(isOnlySuperClass = true)
emptyParameters()
returnType = View::class
superclass()
}?.invoke<ViewGroup?>()?.also {
it.context?.injectModuleAppResources()
runCatching { it.getChildAt(0) as? ViewGroup? }.getOrNull()?.also { rootView ->

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
@@ -24,17 +24,17 @@ package com.fankes.tsbattery.hook.factory
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.PowerManager
import androidx.appcompat.app.AppCompatDelegate
import com.fankes.tsbattery.const.JumpEvent
import com.fankes.tsbattery.const.PackageName
import com.fankes.tsbattery.hook.entity.QQTIMHooker.toClass
import com.fankes.tsbattery.ui.activity.parasitic.ConfigActivity
import com.highcapable.kavaref.KavaRef.Companion.asResolver
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.extension.VariousClass
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.type.android.PowerManager_WakeLockClass
import kotlin.system.exitProcess
/** QQ、TIM 存在的类 */
@@ -47,14 +47,27 @@ private val ThemeUtilClass = VariousClass("${PackageName.QQ}.theme.ThemeUtil", "
* QQ、TIM 主题是否为夜间模式
* @return [Boolean]
*/
fun Context.isQQNightMode() = runCatching {
ThemeUtilClass.get(classLoader).method {
name = "getUserCurrentThemeId"
paramCount = 1
}.get().string(MobileQQClass.toClass(classLoader)
.field { name = "sMobileQQ" }.ignored().get().current(ignored = true)?.field { name = "mAppRuntime" }?.any()
).let { it.endsWith("1103") || it.endsWith("2920") }
}.getOrNull() ?: false
fun Context.isQQNightMode(): Boolean {
val sMobileQQ = MobileQQClass.toClass(classLoader).resolve()
.optional()
.firstFieldOrNull {
name = "sMobileQQ"
superclass()
}?.get()
val mAppRuntime = sMobileQQ?.asResolver()
?.optional()
?.firstFieldOrNull {
name = "mAppRuntime"
superclass()
}?.get()
val currentThemeId = ThemeUtilClass.load(classLoader).resolve()
.optional()
.firstMethodOrNull {
name = "getUserCurrentThemeId"
parameterCount = 1
}?.invokeQuietly<String>(mAppRuntime)
return currentThemeId?.let { it.endsWith("1103") || it.endsWith("2920") } == true
}
/** 启动模块设置 [Activity] */
fun Context.startModuleSettings() {
@@ -81,8 +94,14 @@ fun Activity.jumpToModuleSettings(isFinish: Boolean = true) {
/** Hook 系统电源锁 */
fun PackageParam.hookSystemWakeLock() {
PowerManager_WakeLockClass.method {
name = "acquireLocked"
emptyParam()
}.hook().intercept()
PowerManager.WakeLock::class.resolve().apply {
firstMethod {
name = "acquireLocked"
emptyParameters()
}.hook().intercept()
firstMethod {
name = "release"
parameters(Int::class)
}.hook().intercept()
}
}

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
@@ -51,6 +51,6 @@ object DexKitHelper {
*/
fun create(param: PackageParam, initiate: DexKitBridge.() -> Unit) {
load()
runCatching { DexKitBridge.create(param.appInfo.sourceDir)?.use { initiate(it) } }
runCatching { DexKitBridge.create(param.appInfo.sourceDir).use { initiate(it) } }
}
}

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
@@ -21,19 +21,22 @@
*/
package com.fankes.tsbattery.ui.activity.base
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding
import com.fankes.tsbattery.R
import com.fankes.tsbattery.utils.factory.isNotSystemInDarkMode
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.base.ModuleAppCompatActivity
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.extension.genericSuperclassTypeArguments
import com.highcapable.kavaref.extension.toClassOrNull
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.proxy.ModuleActivity
abstract class BaseActivity<VB : ViewBinding> : ModuleAppCompatActivity() {
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity(), ModuleActivity {
override val moduleTheme get() = R.style.Theme_TSBattery
@@ -41,11 +44,14 @@ abstract class BaseActivity<VB : ViewBinding> : ModuleAppCompatActivity() {
lateinit var binding: VB
override fun onCreate(savedInstanceState: Bundle?) {
delegate.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)
binding = current().generic()?.argument()?.method {
val bindingClass = javaClass.genericSuperclassTypeArguments().firstOrNull()?.toClassOrNull()
binding = bindingClass?.resolve()?.optional()?.firstMethodOrNull {
name = "inflate"
param(LayoutInflaterClass)
}?.get()?.invoke<VB>(layoutInflater) ?: error("binding failed")
parameters(LayoutInflater::class)
}?.invoke<VB>(layoutInflater) ?: error("binding failed")
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
setContentView(binding.root)
/** 隐藏系统的标题栏 */
supportActionBar?.hide()
@@ -54,6 +60,7 @@ abstract class BaseActivity<VB : ViewBinding> : ModuleAppCompatActivity() {
isAppearanceLightStatusBars = isNotSystemInDarkMode
isAppearanceLightNavigationBars = isNotSystemInDarkMode
}
@Suppress("DEPRECATION")
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
window?.statusBarColor = it
window?.navigationBarColor = it
@@ -65,4 +72,16 @@ abstract class BaseActivity<VB : ViewBinding> : ModuleAppCompatActivity() {
/** 回调 [onCreate] 方法 */
abstract fun onCreate()
override fun getClassLoader() = delegate.getClassLoader()
override fun onConfigurationChanged(newConfig: Configuration) {
delegate.onConfigurationChanged(newConfig)
super.onConfigurationChanged(newConfig)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
delegate.onRestoreInstanceState(savedInstanceState)
super.onRestoreInstanceState(savedInstanceState)
}
}

View File

@@ -0,0 +1,78 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
* and/or modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is created by fankes on 2025/4/21.
*/
@file:Suppress("DEPRECATION")
package com.fankes.tsbattery.ui.activity.base
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.widget.FrameLayout
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.WindowCompat
import com.fankes.tsbattery.R
import com.fankes.tsbattery.utils.factory.isNotSystemInDarkMode
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.proxy.ModuleActivity
import android.R as Android_R
abstract class BaseActivity2 : AppCompatActivity(), ModuleActivity {
override val moduleTheme get() = R.style.Theme_TSBattery
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
delegate.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)
/** 隐藏系统的标题栏 */
supportActionBar?.hide()
/** 初始化沉浸状态栏 */
WindowCompat.getInsetsController(window, window.decorView).apply {
isAppearanceLightStatusBars = isNotSystemInDarkMode
isAppearanceLightNavigationBars = isNotSystemInDarkMode
}
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
window?.statusBarColor = it
window?.navigationBarColor = it
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) window?.navigationBarDividerColor = it
}
/** 装载子类 */
onCreate()
if (Build.VERSION.SDK_INT >= 35) findViewById<FrameLayout>(Android_R.id.content).getChildAt(0)?.fitsSystemWindows = true
}
/** 回调 [onCreate] 方法 */
abstract fun onCreate()
override fun getClassLoader() = delegate.getClassLoader()
override fun onConfigurationChanged(newConfig: Configuration) {
delegate.onConfigurationChanged(newConfig)
super.onConfigurationChanged(newConfig)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
delegate.onRestoreInstanceState(savedInstanceState)
super.onRestoreInstanceState(savedInstanceState)
}
}

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
@@ -23,22 +23,27 @@
package com.fankes.tsbattery.ui.activity.parasitic
import android.content.ComponentName
import android.content.Intent
import android.animation.LayoutTransition
import android.content.res.Resources
import android.graphics.Typeface
import android.view.Gravity
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.setPadding
import androidx.core.view.updateMargins
import androidx.core.view.updateMarginsRelative
import androidx.core.view.updatePadding
import com.fankes.projectpromote.ProjectPromote
import com.fankes.tsbattery.R
import com.fankes.tsbattery.const.ModuleVersion
import com.fankes.tsbattery.const.PackageName
import com.fankes.tsbattery.data.ConfigData
import com.fankes.tsbattery.data.ConfigData.bind
import com.fankes.tsbattery.databinding.ActivityConfigBinding
import com.fankes.tsbattery.hook.HookEntry
import com.fankes.tsbattery.hook.entity.QQTIMHooker
import com.fankes.tsbattery.ui.activity.MainActivity
import com.fankes.tsbattery.ui.activity.base.BaseActivity
import com.fankes.tsbattery.ui.activity.base.BaseActivity2
import com.fankes.tsbattery.utils.factory.appIconOf
import com.fankes.tsbattery.utils.factory.appNameOf
import com.fankes.tsbattery.utils.factory.appVersionCode
@@ -47,98 +52,510 @@ import com.fankes.tsbattery.utils.factory.showDialog
import com.fankes.tsbattery.utils.factory.snake
import com.fankes.tsbattery.utils.tool.GithubReleaseTool
import com.fankes.tsbattery.wrapper.BuildConfigWrapper
import com.highcapable.betterandroid.ui.extension.component.base.getThemeAttrsDrawable
import com.highcapable.betterandroid.ui.extension.component.startActivity
import com.highcapable.betterandroid.ui.extension.graphics.toNormalColorStateList
import com.highcapable.betterandroid.ui.extension.view.textColor
import com.highcapable.betterandroid.ui.extension.view.tooltipTextCompat
import com.highcapable.betterandroid.ui.extension.view.updateMargins
import com.highcapable.betterandroid.ui.extension.view.updatePadding
import com.highcapable.betterandroid.ui.extension.view.updateTypeface
import com.highcapable.hikage.extension.setContentView
import com.highcapable.hikage.widget.android.widget.ImageView
import com.highcapable.hikage.widget.android.widget.LinearLayout
import com.highcapable.hikage.widget.android.widget.TextView
import com.highcapable.hikage.widget.androidx.cardview.widget.CardView
import com.highcapable.hikage.widget.androidx.core.widget.NestedScrollView
import com.highcapable.hikage.widget.com.fankes.tsbattery.ui.widget.MaterialSwitch
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.classOf
import kotlin.system.exitProcess
import android.R as Android_R
class ConfigActivity : BaseActivity<ActivityConfigBinding>() {
class ConfigActivity : BaseActivity2() {
private lateinit var updateVersionText: TextView
private lateinit var needRestartTipText: TextView
private lateinit var currentModeText: TextView
private lateinit var itemQQTimConfig: LinearLayout
override fun onCreate() {
setContentView {
LinearLayout(
lparams = LayoutParams(matchParent = true),
init = {
orientation = LinearLayout.VERTICAL
setBackgroundResource(R.color.colorThemeBackground)
}
) {
LinearLayout(
lparams = LayoutParams(widthMatchParent = true),
init = {
gravity = Gravity.CENTER or Gravity.START
setPadding(15.dp)
}
) {
ImageView(
lparams = LayoutParams(20.dp, 20.dp) {
marginStart = 10.dp
marginEnd = 20.dp
}
) {
imageTintList = stateColorResource(R.color.colorTextGray)
tooltipTextCompat = "返回"
setImageResource(R.drawable.ic_back)
background = getThemeAttrsDrawable(Android_R.attr.selectableItemBackgroundBorderless)
setOnClickListener { finish() }
}
TextView(
lparams = LayoutParams(width = 0) {
marginEnd = 2.dp
weight = 1f
}
) {
isSingleLine = true
textSize = 19f
textColor = colorResource(R.color.colorTextGray)
text = "TSBattery 设置 (${appName.trim()})"
updateTypeface(Typeface.BOLD)
}
ImageView(
lparams = LayoutParams(23.dp, 23.dp) {
marginEnd = 10.dp
}
) {
setPadding(1.dp)
imageTintList = stateColorResource(R.color.colorTextGray)
tooltipTextCompat = "打开模块主界面"
setImageResource(R.drawable.ic_icon)
background = getThemeAttrsDrawable(Android_R.attr.selectableItemBackgroundBorderless)
setOnClickListener {
showDialog {
title = "打开模块主界面"
msg = "点击确定后将打开模块主界面,如果未安装模块本体将尝试打开寄生界面。"
confirmButton {
runCatching {
startActivity(
packageName = BuildConfigWrapper.APPLICATION_ID,
activityClass = classOf<MainActivity>().name
)
}.onFailure {
runCatching {
startActivity<MainActivity>()
}.onFailure { snake(msg = "打开失败,请确认你已安装模块 APP 或在模块更新后重启过$appName\n$it") }
}
}
cancelButton()
}
}
}
}
NestedScrollView(
lparams = LayoutParams(matchParent = true),
init = {
setFadingEdgeLength(10.dp)
isVerticalFadingEdgeEnabled = true
isVerticalScrollBarEnabled = false
isHorizontalScrollBarEnabled = false
}
) {
LinearLayout(
lparams = LayoutParams(widthMatchParent = true),
init = {
orientation = LinearLayout.VERTICAL
layoutTransition = LayoutTransition()
updatePadding(bottom = 15.dp)
}
) {
repeat(2) { index ->
TextView(
lparams = LayoutParams(widthMatchParent = true) {
updateMargins(horizontal = 15.dp)
updateMargins(bottom = 5.dp)
}
) {
setBackgroundResource(R.drawable.bg_orange_round)
setPadding(5.dp)
gravity = Gravity.CENTER
textSize = 13f
textColor = colorResource(R.color.white)
text = when (index) {
0 -> "点击更新 %1"
else -> "新的设置需要重新启动${appName}才能生效"
}
isVisible = false
when (index) {
0 -> updateVersionText = this
else -> {
needRestartTipText = this
setOnClickListener {
showDialog {
title = "需要重新启动"
msg = "你必须重新启动${appName}才能使当前更改生效,现在重新启动吗?"
confirmButton {
cancel()
finish()
exitProcess(status = 0)
}
cancelButton(text = "稍后再说") {
cancel()
it.isVisible = false
}
}
}
}
}
}
}
LinearLayout(
lparams = LayoutParams(widthMatchParent = true) {
updateMargins(horizontal = 15.dp)
updateMargins(top = 5.dp)
},
init = {
setBackgroundResource(R.drawable.bg_permotion_round)
setPadding(15.dp)
gravity = Gravity.CENTER
}
) {
ImageView(
lparams = LayoutParams(45.dp, 45.dp) {
marginEnd = 15.dp
}
) {
setImageDrawable(appIconOf())
}
LinearLayout(
lparams = LayoutParams(widthMatchParent = true),
init = {
orientation = LinearLayout.VERTICAL
}
) {
LinearLayout(
lparams = LayoutParams(widthMatchParent = true) {
bottomMargin = 5.dp
gravity = Gravity.CENTER or Gravity.START
}
) {
TextView(
lparams = LayoutParams {
marginEnd = 7.dp
}
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 15f
text = appName.trim()
}
TextView {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
text = "$appVersionName($appVersionCode)"
alpha = 0.85f
}
TextView(
lparams = LayoutParams {
updateMargins(horizontal = 6.dp)
}
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
text = "|"
alpha = 0.85f
}
TextView {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
text = "模块版本:$ModuleVersion"
alpha = 0.85f
}
}
LinearLayout(
lparams = LayoutParams(widthMatchParent = true),
init = {
gravity = Gravity.CENTER or Gravity.START
}
) {
CardView(
lparams = LayoutParams(13.dp, 13.dp) {
marginEnd = 6.dp
},
init = {
setCardBackgroundColor(colorResource(R.color.colorThemeBackground))
radius = 50f.dp
elevation = 0f
}
) {
ImageView(
lparams = LayoutParams(13.dp, 13.dp)
) {
setImageResource(if (HookEntry.isHookClientSupport)
R.drawable.ic_success
else R.drawable.ic_error)
imageTintList = (if (HookEntry.isHookClientSupport)
0xFF26A69A
else 0xFFFF7043).toInt().toNormalColorStateList()
}
}
if (!HookEntry.isHookClientSupport)
LinearLayout(
lparams = LayoutParams {
marginEnd = 6.dp
},
init = {
gravity = Gravity.CENTER or Gravity.START
}
) {
TextView {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
alpha = 0.85f
text = "未适配"
}
TextView(
lparams = LayoutParams {
updateMarginsRelative(start = 6.dp)
}
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
text = "|"
alpha = 0.85f
}
}
TextView {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
alpha = 0.85f
currentModeText = this
}
TextView(
lparams = LayoutParams {
updateMarginsRelative(start = 6.dp)
}
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
text = "|"
alpha = 0.85f
}
TextView(
lparams = LayoutParams {
updateMarginsRelative(start = 6.dp)
}
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
text = "${YukiHookAPI.Status.Executor.name} API ${YukiHookAPI.Status.Executor.apiLevel}"
alpha = 0.85f
}
}
}
}
TextView(
lparams = LayoutParams(widthMatchParent = true) {
updateMargins(horizontal = 15.dp)
updateMargins(top = 15.dp)
}
) {
setBackgroundResource(R.drawable.bg_permotion_round)
setPadding(15.dp)
textSize = 12f
textColor = colorResource(R.color.colorTextDark)
setLineSpacing(10f.dp, 1f)
text = "模块只对挂后台锁屏情况下有省电效果,请不要将过多的群提醒,消息通知打开,这样子在使用过程时照样会极其耗电。\n" +
"持续常驻使用${appName}依然会耗电,任何软件都是如此,模块是无法帮你做到前台不耗电的。"
}
LinearLayout(
lparams = LayoutParams(widthMatchParent = true) {
updateMargins(horizontal = 15.dp)
updateMargins(top = 15.dp)
},
init = {
orientation = LinearLayout.VERTICAL
}
) {
LinearLayout(
lparams = LayoutParams(widthMatchParent = true),
init = {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
setBackgroundResource(R.drawable.bg_permotion_round)
updatePadding(horizontal = 15.dp)
updatePadding(top = 10.dp, bottom = 15.dp)
}
) {
MaterialSwitch(
lparams = LayoutParams(widthMatchParent = true, height = 35.dp) {
bottomMargin = 5.dp
}
) {
text = "停用省电策略"
textColor = colorResource(R.color.colorTextGray)
textSize = 15f
bind(ConfigData.DISABLE_ALL_HOOK) {
refreshConfigItems()
refreshCurrentModeText()
showNeedRestartTip()
}
}
TextView(
lparams = LayoutParams(widthMatchParent = true)
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
alpha = 0.6f
setLineSpacing(6f.dp, 1f)
text = "选择停用后模块将关闭所有省电功能,模块停止使用。"
}
}
}
LinearLayout(
lparams = LayoutParams(widthMatchParent = true) {
updateMargins(horizontal = 15.dp)
updateMargins(top = 15.dp)
},
init = {
orientation = LinearLayout.VERTICAL
itemQQTimConfig = this
}
) {
LinearLayout(
lparams = LayoutParams(widthMatchParent = true),
init = {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
setBackgroundResource(R.drawable.bg_permotion_round)
updatePadding(horizontal = 15.dp)
updatePadding(top = 10.dp, bottom = 15.dp)
}
) {
MaterialSwitch(
lparams = LayoutParams(widthMatchParent = true, height = 35.dp) {
bottomMargin = 5.dp
}
) {
text = "启用保守模式"
textColor = colorResource(R.color.colorTextGray)
textSize = 15f
bind(ConfigData.ENABLE_QQ_TIM_PROTECT_MODE) {
refreshCurrentModeText()
showNeedRestartTip()
}
}
TextView(
lparams = LayoutParams(widthMatchParent = true)
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
alpha = 0.6f
setLineSpacing(6f.dp, 1f)
text = "此选项默认关闭,默认情况下模块将会干掉${appName}自身的电源锁控制类,开启后模块将只对系统电源锁生效," +
"如果你的${appName}视频通话等设置发生了故障,可以尝试开启这个功能。"
}
}
LinearLayout(
lparams = LayoutParams(widthMatchParent = true) {
topMargin = 15.dp
},
init = {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
setBackgroundResource(R.drawable.bg_permotion_round)
updatePadding(horizontal = 15.dp)
updatePadding(top = 10.dp, bottom = 15.dp)
}
) {
MaterialSwitch(
lparams = LayoutParams(widthMatchParent = true, height = 35.dp) {
bottomMargin = 5.dp
}
) {
text = "关闭 CoreService"
textColor = colorResource(R.color.colorTextGray)
textSize = 15f
bind(ConfigData.ENABLE_KILL_QQ_TIM_CORESERVICE) { showNeedRestartTip() }
}
TextView(
lparams = LayoutParams(widthMatchParent = true) {
bottomMargin = 10.dp
}
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
alpha = 0.6f
setLineSpacing(6f.dp, 1f)
text = "关闭后可能会影响消息接收与视频通话,但是会达到省电效果,如果你的系统拥有推送服务 (HMS) 或 (MIPUSH) 可以尝试关闭。"
}
MaterialSwitch(
lparams = LayoutParams(widthMatchParent = true, height = 35.dp) {
bottomMargin = 5.dp
}
) {
text = "关闭 CoreService\$KernelService"
textColor = colorResource(R.color.colorTextGray)
textSize = 15f
bind(ConfigData.ENABLE_KILLE_QQ_TIM_CORESERVICE_CHILD) { showNeedRestartTip() }
}
TextView(
lparams = LayoutParams(widthMatchParent = true)
) {
isSingleLine = true
textColor = colorResource(R.color.colorTextGray)
textSize = 12f
alpha = 0.6f
setLineSpacing(6f.dp, 1f)
text = "这是一个辅助子服务,理论主服务关闭后子服务同样不会被启动,建议在保证消息接收的前提下可以尝试关闭子服务。"
}
}
}
}
}
}
}
/** 检查更新 */
GithubReleaseTool.checkingForUpdate(context = this, ModuleVersion.NAME) { version, function ->
binding.updateVersionText.apply {
updateVersionText.apply {
text = "点击更新 $version"
isVisible = true
setOnClickListener { function() }
}
}
binding.titleBackIcon.setOnClickListener { finish() }
binding.titleModuleIcon.setOnClickListener {
showDialog {
title = "打开模块主界面"
msg = "点击确定后将打开模块主界面,如果未安装模块本体将尝试打开寄生界面。"
confirmButton {
runCatching {
startActivity(Intent().apply {
component = ComponentName(BuildConfigWrapper.APPLICATION_ID, MainActivity::class.java.name)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}.onFailure {
runCatching {
startActivity(Intent(this@ConfigActivity, MainActivity::class.java))
}.onFailure { snake(msg = "打开失败,请确认你已安装模块 APP 或在模块更新后重启过$appName\n$it") }
}
}
cancelButton()
}
}
binding.titleNameText.text = "TSBattery 设置 (${appName.trim()})"
binding.appIcon.setImageDrawable(appIconOf())
binding.appName.text = appName.trim()
binding.appVersion.text = "$appVersionName($appVersionCode)"
binding.moduleVersion.text = ModuleVersion.toString()
binding.activeModeIcon.isVisible = HookEntry.isHookClientSupport
binding.inactiveModeIcon.isGone = HookEntry.isHookClientSupport
binding.unsupportItem.isGone = HookEntry.isHookClientSupport
binding.executorInfoText.text = "${YukiHookAPI.Status.Executor.name} API ${YukiHookAPI.Status.Executor.apiLevel}"
binding.needRestartTipText.replaceToAppName()
binding.needRestartTipText.setOnClickListener {
showDialog {
title = "需要重新启动"
msg = "你必须重新启动${appName}才能使当前更改生效,现在重新启动吗?"
confirmButton {
cancel()
finish()
exitProcess(status = 0)
}
cancelButton(text = "稍后再说") {
cancel()
it.isVisible = false
}
}
}
/** 刷新当前模式文本 */
fun refreshCurrentModeText() {
binding.currentModeText.text = when {
ConfigData.isDisableAllHook -> "模块已停用"
packageName == PackageName.WECHAT -> "基础省电模式"
ConfigData.isEnableQQTimProtectMode -> "保守模式"
else -> "完全模式"
}
}
refreshCurrentModeText()
/** 刷新配置条目显示隐藏状态 */
fun refreshConfigItems() {
binding.itemQqTimConfig.isVisible = packageName != PackageName.WECHAT && ConfigData.isDisableAllHook.not()
}
refreshConfigItems()
binding.infoTipText.replaceToAppName()
binding.qqTimProtectTipText.replaceToAppName()
binding.disableAllHookSwitch.bind(ConfigData.DISABLE_ALL_HOOK) { refreshConfigItems(); refreshCurrentModeText(); showNeedRestartTip() }
binding.qqTimProtectModeSwitch.bind(ConfigData.ENABLE_QQ_TIM_PROTECT_MODE) { refreshCurrentModeText(); showNeedRestartTip() }
binding.qqTimCoreServiceSwitch.bind(ConfigData.ENABLE_KILL_QQ_TIM_CORESERVICE) { showNeedRestartTip() }
binding.qqTimCoreServiceChildSwitch.bind(ConfigData.ENABLE_KILLE_QQ_TIM_CORESERVICE_CHILD) { showNeedRestartTip() }
/** 推广、恰饭 */
ProjectPromote.show(activity = this, ModuleVersion.toString())
}
/** 显示需要重新启动提示 */
private fun showNeedRestartTip() {
binding.needRestartTipText.isVisible = true
needRestartTipText.isVisible = true
}
/** 替换占位符到当前 APP 名称 */
private fun TextView.replaceToAppName() {
text = text.toString().replace("{APP_NAME}", appName)
/** 刷新配置条目显示隐藏状态 */
private fun refreshConfigItems() {
itemQQTimConfig.isVisible = packageName != PackageName.WECHAT && ConfigData.isDisableAllHook.not()
}
/** 刷新当前模式文本 */
private fun refreshCurrentModeText() {
currentModeText.text = when {
ConfigData.isDisableAllHook -> "模块已停用"
packageName == PackageName.WECHAT -> "基础省电模式"
ConfigData.isEnableQQTimProtectMode -> "保守模式"
else -> "完全模式"
}
}
/** 重新设置 DPI 防止 QQ、TIM 修改它 */

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it
@@ -31,8 +31,10 @@ import android.util.AttributeSet
import androidx.appcompat.widget.SwitchCompat
import com.fankes.tsbattery.utils.factory.dp
import com.fankes.tsbattery.utils.factory.isSystemInDarkMode
import com.highcapable.hikage.annotation.HikageView
import top.defaults.drawabletoolbox.DrawableBuilder
@HikageView
class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
private fun toColors(selected: Int, pressed: Int, normal: Int): ColorStateList {

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,6 +1,6 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2017 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/TSBattery
*
* This software is non-free but opensource software: you can redistribute it

View File

@@ -1,418 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorThemeBackground"
android:orientation="vertical"
tools:context=".ui.activity.parasitic.ConfigActivity"
tools:ignore="HardcodedText,ContentDescription,UnusedAttribute,UselessParent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="0dp"
android:gravity="center|start"
android:paddingLeft="15dp"
android:paddingTop="15dp"
android:paddingRight="15dp"
android:paddingBottom="15dp">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/title_back_icon"
style="?android:attr/selectableItemBackgroundBorderless"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:src="@drawable/ic_back"
android:tint="@color/colorTextGray"
android:tooltipText="返回" />
<TextView
android:id="@+id/title_name_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="2.5dp"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/app_name"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/title_module_icon"
android:layout_width="23dp"
android:layout_height="23dp"
android:layout_marginEnd="10dp"
android:padding="1.5dp"
android:src="@drawable/ic_icon"
android:tint="@color/colorTextGray"
android:tooltipText="打开模块主界面" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdgeLength="10dp"
android:orientation="vertical"
android:requiresFadingEdge="vertical"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:paddingBottom="15dp">
<TextView
android:id="@+id/update_version_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="5dp"
android:background="@drawable/bg_orange_round"
android:gravity="center"
android:padding="5dp"
android:text="点击更新 %1"
android:textColor="@color/white"
android:textSize="13sp"
android:visibility="gone" />
<TextView
android:id="@+id/need_restart_tip_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="5dp"
android:background="@drawable/bg_orange_round"
android:gravity="center"
android:padding="5dp"
android:text="新的设置需要重新启动{APP_NAME}才能生效"
android:textColor="@color/white"
android:textSize="13sp"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="5dp"
android:layout_marginRight="15dp"
android:background="@drawable/bg_permotion_round"
android:elevation="0dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="15dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_marginEnd="15dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:gravity="center|start">
<TextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="7.5dp"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:id="@+id/app_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.85"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:alpha="0.85"
android:singleLine="true"
android:text="|"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.85"
android:singleLine="true"
android:text="模块版本:"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
<TextView
android:id="@+id/module_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.85"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center|start"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
android:layout_width="13dp"
android:layout_height="13dp"
android:layout_marginEnd="6dp"
app:cardBackgroundColor="@color/colorThemeBackground"
app:cardCornerRadius="50dp"
app:cardElevation="0dp">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/active_mode_icon"
android:layout_width="13dp"
android:layout_height="13dp"
android:src="@drawable/ic_success"
android:tint="#FF26A69A"
android:visibility="gone" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/inactive_mode_icon"
android:layout_width="13dp"
android:layout_height="13dp"
android:src="@drawable/ic_error"
android:tint="#FF7043"
android:visibility="gone" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:id="@+id/unsupport_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:gravity="center|start"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.85"
android:singleLine="true"
android:text="未适配"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:alpha="0.85"
android:singleLine="true"
android:text="|"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/current_mode_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.85"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:alpha="0.85"
android:singleLine="true"
android:text="|"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
<TextView
android:id="@+id/executor_info_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:alpha="0.85"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/info_tip_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp"
android:alpha="0.8"
android:background="@drawable/bg_permotion_round"
android:lineSpacingExtra="10dp"
android:padding="15dp"
android:text="模块只对挂后台锁屏情况下有省电效果,请不要将过多的群提醒,消息通知打开,这样子在使用过程时照样会极其耗电。\n持续常驻使用{APP_NAME}依然会耗电,任何软件都是如此,模块是无法帮你做到前台不耗电的。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_permotion_round"
android:elevation="0dp"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:paddingRight="15dp"
android:paddingBottom="15dp">
<com.fankes.tsbattery.ui.widget.MaterialSwitch
android:id="@+id/disable_all_hook_switch"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginBottom="5dp"
android:text="停用省电策略"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="选择停用后模块将关闭所有省电功能,模块停止使用。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/item_qq_tim_config"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_permotion_round"
android:elevation="0dp"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:paddingRight="15dp">
<com.fankes.tsbattery.ui.widget.MaterialSwitch
android:id="@+id/qq_tim_protect_mode_switch"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginBottom="5dp"
android:text="启用保守模式"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:id="@+id/qq_tim_protect_tip_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此选项默认关闭,默认情况下模块将会干掉{APP_NAME}自身的电源锁控制类,开启后模块将只对系统电源锁生效,如果你的{APP_NAME}视频通话等设置发生了故障,可以尝试开启这个功能。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:background="@drawable/bg_permotion_round"
android:elevation="0dp"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:paddingRight="15dp"
android:paddingBottom="15dp">
<com.fankes.tsbattery.ui.widget.MaterialSwitch
android:id="@+id/qq_tim_core_service_switch"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginBottom="5dp"
android:text="关闭 CoreService"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="关闭后可能会影响消息接收与视频通话,但是会达到省电效果,如果你的系统拥有推送服务 (HMS) 或 (MIPUSH) 可以尝试关闭。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<com.fankes.tsbattery.ui.widget.MaterialSwitch
android:id="@+id/qq_tim_core_service_child_switch"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginBottom="5dp"
android:text="关闭 CoreService$KernelService"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="这是一个辅助子服务,理论主服务关闭后子服务同样不会被启动,建议在保证消息接收的前提下可以尝试关闭子服务。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View File

@@ -635,6 +635,35 @@
android:textColor="@color/colorTextGray"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp"
android:background="@drawable/bg_permotion_round"
android:gravity="center|start"
android:orientation="horizontal"
android:padding="10dp">
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginEnd="10dp"
android:src="@mipmap/ic_kavaref" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:ellipsize="end"
android:lineSpacingExtra="6dp"
android:maxLines="2"
android:text="此模块使用 KavaRef 强力驱动。\n了解更多 https://github.com/HighCapable/KavaRef"
android:textColor="@color/colorTextGray"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,5 +1,21 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
plugins {
autowire(libs.plugins.android.application) apply false
autowire(libs.plugins.kotlin.android) apply false
autowire(libs.plugins.kotlin.ksp) apply false
}
allprojects {
tasks.withType<KotlinJvmCompile>().configureEach {
compilerOptions {
jvmTarget = JvmTarget.JVM_17
freeCompilerArgs.addAll(
"-Xno-param-assertions",
"-Xno-call-assertions",
"-Xno-receiver-assertions"
)
}
}
}

View File

@@ -3,12 +3,11 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
android.nonTransitiveRClass=true
kotlin.code.style=official
kotlin.incremental.useClasspathSnapshot=true
# Project Configuration
project.name=TSBattery
project.android.compileSdk=34
project.android.compileSdk=36
project.android.minSdk=24
project.android.targetSdk=34
project.android.targetSdk=36
project.app.packageName=com.fankes.tsbattery
project.app.versionName="4.4"
project.app.versionCode=30

View File

@@ -22,13 +22,13 @@ repositories:
plugins:
com.android.application:
alias: android-application
version: 8.1.2
version: 8.12.1
org.jetbrains.kotlin.android:
alias: kotlin-android
version: 1.9.10
version: 2.2.10
com.google.devtools.ksp:
alias: kotlin-ksp
version: 1.9.10-1.0.13
version: 2.2.10-2.0.2
libraries:
com.fankes.projectpromote:
@@ -43,36 +43,52 @@ libraries:
rovo89-xposed-api
com.highcapable.yukihookapi:
api:
version: 1.2.0
version: 1.3.0
ksp-xposed:
version-ref: <this>::api
com.highcapable.kavaref:
kavaref-core:
version: 1.0.1
kavaref-extension:
version: 1.0.1
com.highcapable.hikage:
hikage-core:
version: 1.0.2
hikage-compiler:
version: 1.0.1
hikage-extension:
version: 1.0.1
hikage-widget-androidx:
version: 1.0.1
hikage-widget-material:
version: 1.0.1
org.luckypray:
dexkit:
version: 2.0.0-rc7
version: 2.0.6
com.github.duanhong169:
drawabletoolbox:
version: 1.0.7
com.squareup.okhttp3:
okhttp:
version: 5.0.0-alpha.11
version: 5.1.0
androidx.core:
core-ktx:
version: 1.12.0
version: 1.17.0
androidx.appcompat:
appcompat:
version: 1.6.1
version: 1.7.1
com.google.android.material:
material:
version: 1.10.0
version: 1.12.0
androidx.constraintlayout:
constraintlayout:
version: 2.1.4
version: 2.2.1
androidx.test.ext:
junit:
version: 1.1.5
version: 1.3.0
androidx.test.espresso:
espresso-core:
version: 3.5.1
version: 3.7.0
junit:
junit:
version: 4.13.2

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

@@ -6,8 +6,8 @@ pluginManagement {
}
}
plugins {
id("com.highcapable.sweetdependency") version "1.0.2"
id("com.highcapable.sweetproperty") version "1.0.3"
id("com.highcapable.sweetdependency") version "1.0.4"
id("com.highcapable.sweetproperty") version "1.0.8"
}
sweetProperty {
global {
@@ -15,7 +15,11 @@ sweetProperty {
permanentKeyValues("GITHUB_CI_COMMIT_ID" to "")
generateFrom(ROOT_PROJECT, SYSTEM_ENV)
}
sourcesCode { includeKeys("GITHUB_CI_COMMIT_ID") }
sourcesCode {
includeKeys("GITHUB_CI_COMMIT_ID")
// 关闭类型自动转换功能,防止一些特殊 "COMMIT ID" 被生成为数值
isEnableTypeAutoConversion = false
}
}
rootProject { all { isEnable = false } }
}