89 Commits
4.3 ... 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
8025b45b06 Bump version to 4.4 2023-10-21 00:56:03 +08:00
d8b3884cb0 feat(docs): update YukiHookAPI owner link 2023-10-21 00:55:59 +08:00
1a3c8d9bcb refactor: remove DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION 2023-10-21 00:48:02 +08:00
b6d8040bfa refactor: make state to unsupported when methods not found 2023-10-21 00:36:40 +08:00
d4f8d7d3fd chore: bump "org.luckypray:dexkit" version to 2.0.0-rc7 2023-10-21 00:33:31 +08:00
a4970747c0 chore: update target sdk to 34 2023-10-21 00:30:38 +08:00
4a8816de37 chore: bump "org.luckypray:dexkit" version to 2.0.0-rc5 2023-10-09 01:26:44 +08:00
6969d7b2c6 feat: simple support dexkit test 2023-10-08 03:55:25 +08:00
ea0b46020f refactor: migrate to YukiHookAPI new usage 2023-10-07 20:51:34 +08:00
4436815525 chore: bump dependency versions 2023-10-07 19:45:35 +08:00
e96b6a5d2a feat: support QQ 8.9.83 2023-10-02 17:35:15 +08:00
576c8574c8 chore: bump plugin versions
- bump "com.highcapable.sweetdependency" version to 1.0.2
- bump "com.highcapable.sweetproperty" version to 1.0.3
2023-09-26 09:05:17 +08:00
94d425fcf7 refactor: add new R8 rules to fix possible problems 2023-09-19 08:18:53 +08:00
58510cef52 feat: support QQ 8.9.80 2023-09-16 01:17:19 +08:00
efe000d690 docs: optimize comments 2023-09-16 01:13:55 +08:00
c9d49a398f feat: lots of changes
- add BuildConfigWrapper
- merge to new project promote
- add ci version tag support
- add open parasitic from Host App
2023-09-16 01:12:03 +08:00
bd027b37f5 docs: update README 2023-09-16 01:11:03 +08:00
2e56baa6c7 style: optimize code 2023-09-16 01:11:02 +08:00
147b7fa6f5 docs: move banner to img-src 2023-09-16 01:11:02 +08:00
6bd906a51e refactor: use new payment code 2023-09-16 01:11:02 +08:00
5c92671ae2 fix: class not found when R8 since android gradle plugin 8+ 2023-09-16 01:11:02 +08:00
b5bb7eb892 ci: optimize and add artifacts post to Telegram 2023-09-16 01:11:02 +08:00
3361284f16 chore: add Android 14 option 2023-09-16 01:11:02 +08:00
5b4da6df45 chore: migrate build script from groovy to kts
- using SweetDependency, SweetProperty
- change support min sdk to 24
- merge singing key file configs to properties
- update gradle and dependencies
2023-09-16 01:11:01 +08:00
f520983d32 chore: clean up build step files 2023-09-16 00:53:18 +08:00
1e67116f0a [Change Commit Specification] Use the new commit spec from here on
child commits:
chore: add .editorconfig
2023-09-16 00:53:17 +08:00
7257127c0f Modify support QQ 8.9.78 2023-09-02 18:18:06 +08:00
63d5043f31 Modify support QQ 8.9.75~8.9.76 2023-08-19 04:28:08 +08:00
64c4c282b2 Modify support QQ 8.9.73 2023-08-03 21:31:52 +08:00
89cbc49287 Modify support QQ 8.9.71 2023-08-01 18:05:30 +08:00
58 changed files with 1961 additions and 1536 deletions

35
.editorconfig Normal file
View File

@@ -0,0 +1,35 @@
# noinspection EditorConfigKeyCorrectness
[{*.kt,*.kts}]
ktlint_standard_annotation = disabled
ktlint_standard_filename = disabled
ktlint_standard_wrapping = disabled
ktlint_standard_import-ordering = enabled
ktlint_standard_max-line-length = disabled
ktlint_standard_multiline-if-else = disabled
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
insert_final_newline = false
max_line_length = 150

View File

@@ -42,6 +42,7 @@ body:
attributes:
label: Android 版本
options:
- 14
- 13
- 12L/12.1
- 12

View File

@@ -13,17 +13,34 @@ on:
jobs:
build:
name: Build CI
if: ${{ success() }}
runs-on: ubuntu-latest
env:
APK_OUTPUT_PATH: 'app/build/outputs/apk'
TG_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TG_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
COMMIT_MESSAGE: |+
New push to GitHub\!
```
${{ github.event.head_commit.message }}
```by `${{ github.event.head_commit.author.name }}`
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 }}
GITHUB_CI_COMMIT_ID=${GITHUB_SHA:0:7}
echo "GITHUB_CI_COMMIT_ID=$GITHUB_CI_COMMIT_ID" >> $GITHUB_ENV
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1
with:
cmake-version: '3.22.1'
- name: Prepare Java 11
uses: actions/setup-java@v3
- name: Prepare Java 21
uses: actions/setup-java@v4
with:
java-version: 11
java-version: 21
java-package: jdk
distribution: 'temurin'
cache: 'gradle'
@@ -34,7 +51,7 @@ jobs:
~/.gradle/caches
~/.gradle/wrapper
!~/.gradle/caches/build-cache-*
key: gradle-deps-core-${{ hashFiles('**/build.gradle') }}
key: gradle-deps-core-${{ hashFiles('**/build.gradle.kts') }}
restore-keys: |
gradle-deps
- name: Cache Gradle Build
@@ -49,15 +66,23 @@ jobs:
run: |
./gradlew :app:assembleDebug
./gradlew :app:assembleRelease
echo "DEBUG_APK_FILE=$(find app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(debug)
uses: actions/upload-artifact@v3
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@v4
with:
path: ${{ env.DEBUG_APK_FILE }}
name: app-debug
- name: Upload Artifacts(release)
uses: actions/upload-artifact@v3
path: ${{ env.DEBUG_APK_PATH }}
name: TSBattery-debug-${{ github.event.head_commit.id }}
- name: Upload Artifacts (Release)
uses: actions/upload-artifact@v4
with:
path: ${{ env.RELEASE_APK_FILE }}
name: app-release
path: ${{ env.RELEASE_APK_PATH }}
name: TSBattery-release-${{ github.event.head_commit.id }}
- name: Post Artifacts to Telegram
run: |
export debug=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name "*.apk")
export release=$(find ${{ env.APK_OUTPUT_PATH }}/release -name "*.apk")
ESCAPED=`python3 -c 'import json,os,urllib.parse; msg = json.dumps(os.environ["COMMIT_MESSAGE"]); print(urllib.parse.quote(msg if len(msg) <= 1024 else json.dumps(os.environ["COMMIT_URL"])))'`
curl -v "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMediaGroup?chat_id=${TG_CHAT_ID}&media=%5B%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Fdebug%22%7D%2C%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Frelease%22%2C%22parse_mode%22%3A%22MarkdownV2%22%2C%22caption%22:${ESCAPED}%7D%5D" \
-F debug="@$debug" \
-F release="@$release"

View File

@@ -11,18 +11,26 @@ on:
jobs:
build:
name: Pull request check
name: Pull Request Check
if: ${{ success() }}
runs-on: ubuntu-latest
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 }}
GITHUB_CI_COMMIT_ID=${GITHUB_SHA:0:7}
echo "GITHUB_CI_COMMIT_ID=$GITHUB_CI_COMMIT_ID" >> $GITHUB_ENV
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1
with:
cmake-version: '3.22.1'
- name: Prepare Java 11
uses: actions/setup-java@v3
- name: Prepare Java 21
uses: actions/setup-java@v4
with:
java-version: 11
java-version: 21
java-package: jdk
distribution: 'temurin'
cache: 'gradle'
@@ -33,7 +41,7 @@ jobs:
~/.gradle/caches
~/.gradle/wrapper
!~/.gradle/caches/build-cache-*
key: gradle-deps-core-${{ hashFiles('**/build.gradle') }}
key: gradle-deps-core-${{ hashFiles('**/build.gradle.kts') }}
restore-keys: |
gradle-deps
- name: Cache Gradle Build
@@ -48,15 +56,15 @@ jobs:
run: |
./gradlew :app:assembleDebug
./gradlew :app:assembleRelease
echo "DEBUG_APK_FILE=$(find app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(debug)
uses: actions/upload-artifact@v3
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@v4
with:
path: ${{ env.DEBUG_APK_FILE }}
name: app-debug
- name: Upload Artifacts(release)
uses: actions/upload-artifact@v3
path: ${{ env.DEBUG_APK_PATH }}
name: TSBattery-debug-${{ github.event.head_commit.id }}
- name: Upload Artifacts (Release)
uses: actions/upload-artifact@v4
with:
path: ${{ env.RELEASE_APK_FILE }}
name: app-release
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

3
.idea/.gitignore generated vendored
View File

@@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.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>

117
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,117 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

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="11" />
</component>
</project>

20
.idea/gradle.xml generated
View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="11" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@@ -7,5 +7,6 @@
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
<inspection_tool class="YAMLSchemaValidation" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

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.7.20" />
<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>

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

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KtlintProjectConfiguration">
<treatAsErrors>false</treatAsErrors>
</component>
</project>

10
.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

24
.idea/misc.xml generated
View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/drawable-v24/dark_round.xml" value="0.4482051282051282" />
<entry key="app/src/main/res/drawable/bg_orange_round.xml" value="0.229" />
<entry key="app/src/main/res/drawable/bg_permotion_round.xml" value="0.2495" />
<entry key="app/src/main/res/drawable/button_round.xml" value="0.44871794871794873" />
<entry key="app/src/main/res/drawable/dark_round.xml" value="0.4482051282051282" />
<entry key="app/src/main/res/drawable/permotion_round.xml" value="0.4482051282051282" />
<entry key="app/src/main/res/drawable/red_round.xml" value="0.4482051282051282" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.3413246647704185" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.2495" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</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,6 +0,0 @@
{
"keyAlias": "public",
"keyPassword": "123456",
"storeFileName": "universal.p12",
"storePassword": "123456"
}

View File

@@ -1,70 +1,81 @@
# TSBattery
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/TSBattery)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/TSBattery/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v4.3-green)](https://github.com/fankes/TSBattery/releases)
[![Blank](https://img.shields.io/github/downloads/fankes/TSBattery/total?label=Release)](https://github.com/fankes/TSBattery/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.tsbattery/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases)
[![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)
<br/><br/>
![banner](https://github.com/fankes/TSBattery/blob/master/banner.png?raw=true)<br/>
[![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&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)
<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.
TSBattery 是一个旨在使 QQ、TIM、微信 变得更省电的开源 Xposed 模块。
## Developer
## For Non-Chinese Users
[酷安 @星夜不荟](http://www.coolapk.com/u/876977)
This Xposed Module is for use by specific apps for users in mainland China, you should not need it.
## 适配说明
- 解锁 BL 并安装 **Magisk** 的设备建议使用 [LSPosed](https://github.com/LSPosed/LSPosed)
- 解锁 BootLoader 并安装 **KernelSU****Magisk** 的设备建议使用 [LSPosed](https://github.com/LSPosed/LSPosed)
- 可以使用 **~~EdXposed~~**,但随时停止支持
- **太极 (无极)** 支持性不是很好,建议使用 [LSPatch](https://github.com/LSPosed/LSPatch)
- **太极无极 · 阴** 支持性不是很好,建议使用 [LSPatch](https://github.com/LSPosed/LSPatch)
- 支持一些第三方 Xposed 框架,但是不保证其稳定性
- 支持一些第三方免 Root 框架例如**应用转生**、**SandVXposed**,但是不推荐使用,可能会造成封号风险
- 如果在微信设置界面右上角你无法找到 **TSBattery** 的图标,请尝试同时激活 [WeXposed (微X模块)](https://github.com/Xposed-Modules-Repo/com.fkzhang.wechatxposed)
- 如果在微信设置界面右上角你无法找到 **TSBattery**
的图标,请尝试同时激活 [WeXposed (微X模块)](https://github.com/Xposed-Modules-Repo/com.fkzhang.wechatxposed)
## 请勿用于非法用途
## 发行渠道
本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
| <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 自动构建 (测试版) |
|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|---------------|
## 发行渠道说明
| <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 自动构建 (测试版) |
|-----------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|---------------|
- [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 Releases](https://github.com/fankes/TSBattery/releases) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|-----------|
上述更新为代码 `commit` 后自动触发,具体更新内容可点击上方的文字前往 **GitHub Actions** 进行查看,本更新由开源的流程自动编译发布,**不保证其稳定性**,所发布的版本**仅供测试**,且不会特殊说明甚至可能会变更版本号或保持与当前稳定版相同的版本号。
| <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) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|-----------|
- [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://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) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|-----------|
本模块发布地址仅限于上述所列出的地址,从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
## 发行状态说明
## 注意事项
![Blank](https://img.shields.io/badge/build-passing-brightgreen)
<h3>1.&nbsp;本软件免费、由兴趣驱动开发,仅供学习交流使用。如果你是从其他非官方渠道付费获得本软件,可能已遭遇欺诈,欢迎向我们举报可疑行为。</h3>
上述状态为当前稳定版与自动构建版本一致或当前代码改动与稳定版无功能差异。
<h3>2.&nbsp;本软件采用 <strong>GNU Affero General Public License (AGPL 3.0)</strong> 许可证。根据该许可证的要求:</h3>
![Blank](https://img.shields.io/badge/build-pending-dbab09)
- 任何衍生作品必须采用相同的 AGPL 许可证
- 分发本软件或其修改版本时,必须提供完整的源代码
- 必须保留原始的版权声明及许可证信息
- 不得额外施加限制来限制他人对本软件的自由使用
上述状态为存在自动构建版本和新功能的更新但当前并未发布稳定版,处于预发行状态。
<h3>3.&nbsp;我们鼓励在遵守 AGPL 3.0 条款的前提下进行自由传播和改进,但请尊重作者署名权,勿冒用原作者名义。</h3>
![Blank](https://img.shields.io/badge/build-problem-red)
## 项目推广
上述状态为当前发行的稳定版可能存在严重问题但并未及时进行修复且并未发布稳定版。
## 开始贡献
欢迎为此项目进行新版本的适配代码贡献<br/>
- [CONTRIBUTING](https://github.com/fankes/TSBattery/blob/master/CONTRIBUTING.md)
<!--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
@@ -75,7 +86,7 @@ TSBattery 是一个旨在使 QQ、TIM、微信 变得更省电的开源 Xposed
- [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
@@ -88,9 +99,9 @@ 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
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
```
Powered by [YukiHookAPI](https://github.com/fankes/YukiHookAPI)
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

@@ -1,86 +0,0 @@
import groovy.json.JsonSlurper
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.devtools.ksp'
}
android {
signingConfigs {
universal {
def dirPath = rootProject.ext.app.signingConfigs.secretConfigsDirPath
def fileName = rootProject.ext.app.signingConfigs.secretConfigsFileName
def configs = new JsonSlurper().parse(file("${dirPath}/${fileName}"))
keyAlias configs.keyAlias
keyPassword configs.keyPassword
storeFile file("${dirPath}/${configs.storeFileName}")
storePassword configs.storePassword
v1SigningEnabled true
v2SigningEnabled true
}
}
namespace 'com.fankes.tsbattery'
compileSdk rootProject.ext.android.compileSdk
defaultConfig {
applicationId 'com.fankes.tsbattery'
minSdk rootProject.ext.android.minSdk
targetSdk rootProject.ext.android.targetSdk
versionCode rootProject.ext.app.versionCode
versionName rootProject.ext.app.versionName
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.universal
}
release {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
signingConfig signingConfigs.universal
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
freeCompilerArgs = [
'-Xno-param-assertions',
'-Xno-call-assertions',
'-Xno-receiver-assertions'
]
}
buildFeatures {
viewBinding true
}
lintOptions {
checkReleaseBuilds false
}
aaptOptions.additionalParameters '--allow-reserved-package-id', '--package-id', '0x37'
}
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.1.11'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.11'
implementation 'com.github.duanhong169:drawabletoolbox:1.0.7'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

94
app/build.gradle.kts Normal file
View File

@@ -0,0 +1,94 @@
plugins {
autowire(libs.plugins.android.application)
autowire(libs.plugins.kotlin.android)
autowire(libs.plugins.kotlin.ksp)
}
android {
namespace = property.project.app.packageName
compileSdk = property.project.android.compileSdk
signingConfigs {
create("universal") {
keyAlias = property.project.app.signing.keyAlias
keyPassword = property.project.app.signing.keyPassword
storeFile = rootProject.file(property.project.app.signing.storeFilePath)
storePassword = property.project.app.signing.storePassword
enableV1Signing = true
enableV2Signing = true
}
}
defaultConfig {
applicationId = property.project.app.packageName
minSdk = property.project.android.minSdk
targetSdk = property.project.android.targetSdk
versionName = property.project.app.versionName
versionCode = property.project.app.versionCode
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
all { signingConfig = signingConfigs.getByName("universal") }
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildFeatures {
buildConfig = true
viewBinding = true
}
lint { checkReleaseBuilds = false }
androidResources.additionalParameters += listOf("--allow-reserved-package-id", "--package-id", "0x37")
}
androidComponents {
onVariants(selector().all()) {
it.outputs.forEach { output ->
val currentType = it.buildType
// 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")
}
}
}
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)
implementation(com.squareup.okhttp3.okhttp)
implementation(androidx.core.core.ktx)
implementation(androidx.appcompat.appcompat)
implementation(com.google.android.material.material)
implementation(androidx.constraintlayout.constraintlayout)
testImplementation(junit.junit)
androidTestImplementation(androidx.test.ext.junit)
androidTestImplementation(androidx.test.espresso.espresso.core)
}

View File

@@ -32,11 +32,16 @@
-adaptresourcefilecontents
-renamesourcefileattribute P
-keepattributes SourceFile,LineNumberTable
-keepattributes SourceFile,Signature,LineNumberTable
# 排除注入的 Activity
-keep class com.fankes.tsbattery.ui.activity.parasitic.ConfigActivity
# DexKit
-keep class org.luckypray.dexkit.DexKitBridge {
native <methods>;
}
# 防止某些类被 R8 混淆 (可能是 BUG)
# FIXME: 已知问题字符串类名 (即使是常量) 也会被 R8 处理为混淆后的类名
# FIXME: 所以目前只能把不允许 R8 处理的类 keep 掉,同时在当前模块中也不会被混淆就是了
@@ -48,6 +53,8 @@
public static *** throwUninitializedPropertyAccessException(...);
}
-keepclassmembers class * implements androidx.viewbinding.ViewBinding {
-keep class * extends android.app.Activity
-keep class * implements androidx.viewbinding.ViewBinding {
<init>();
*** inflate(android.view.LayoutInflater);
}

View File

@@ -1,11 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.fankes.tsbattery">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
tools:node="remove" />
<permission
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
tools:node="remove" />
<!-- 作用域 APP -->
<queries>
<package android:name="com.tencent.mobileqq" />

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
@@ -17,7 +17,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2021/11/9.
* This file is created by fankes on 2021/11/9.
*/
package com.fankes.tsbattery.application

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
@@ -17,10 +17,15 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/9/29.
* This file is created by fankes on 2022/9/29.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package com.fankes.tsbattery.const
import com.fankes.tsbattery.generated.AppProperties
import com.fankes.tsbattery.wrapper.BuildConfigWrapper
/**
* 包名常量定义类
*/
@@ -44,3 +49,26 @@ object JumpEvent {
/** 启动模块设置 */
const val OPEN_MODULE_SETTING = "tsbattery_open_module_settings"
}
/**
* 模块版本常量定义类
*/
object ModuleVersion {
/** 当前 GitHub 提交的 ID (CI 自动构建) */
const val GITHUB_COMMIT_ID = AppProperties.GITHUB_CI_COMMIT_ID
/** 版本名称 */
const val NAME = BuildConfigWrapper.VERSION_NAME
/** 版本号 */
const val CODE = BuildConfigWrapper.VERSION_CODE
/** 是否为 CI 自动构建版本 */
val isCiMode = GITHUB_COMMIT_ID.isNotBlank()
/** 当前版本名称后缀 */
val suffix = GITHUB_COMMIT_ID.let { if (it.isNotBlank()) "-$it" else "" }
override fun toString() = "$NAME$suffix($CODE)"
}

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
@@ -17,7 +17,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/9/28.
* This file is created by fankes on 2022/9/28.
*/
@file:Suppress("StaticFieldLeak")

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
@@ -17,10 +17,8 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/2/15.
* This file is created by fankes on 2022/2/15.
*/
@file:Suppress("IMPLICIT_CAST_TO_ANY")
package com.fankes.tsbattery.hook
import com.fankes.tsbattery.const.PackageName
@@ -31,7 +29,7 @@ import com.highcapable.yukihookapi.hook.factory.configs
import com.highcapable.yukihookapi.hook.factory.encase
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
@InjectYukiHookWithXposed
object HookEntry : IYukiHookXposedInit {
/** 是否完全支持当前版本 */

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
@@ -17,8 +17,10 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/9/29.
* This file is created by fankes on 2022/9/29.
*/
@file:Suppress("ConstPropertyName")
package com.fankes.tsbattery.hook.entity
import android.app.Activity
@@ -40,13 +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.processName
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.type.android.ViewClass
import com.highcapable.yukihookapi.hook.log.YLog
/**
* Hook 微信
@@ -56,16 +58,19 @@ import com.highcapable.yukihookapi.hook.type.android.ViewClass
object WeChatHooker : YukiBaseHooker() {
/** 微信存在的类 - 未测试每个版本是否都存在 */
const val LauncherUIClass = "${PackageName.WECHAT}.ui.LauncherUI"
const val LauncherUIClassName = "${PackageName.WECHAT}.ui.LauncherUI"
/** 微信存在的类 - 未测试每个版本是否都存在 */
private const val EmptyActivityClass = "${PackageName.WECHAT}.ui.EmptyActivity"
private val LauncherUIClass by lazyClassOrNull("${PackageName.WECHAT}.ui.LauncherUI")
/** 微信存在的类 - 未测试每个版本是否都存在 */
private const val WelabMainUIClass = "${PackageName.WECHAT}.plugin.welab.ui.WelabMainUI"
private val EmptyActivityClass by lazyClassOrNull("${PackageName.WECHAT}.ui.EmptyActivity")
/** 微信存在的类 - 未测试每个版本是否都存在 */
private const val SettingsUIClass = "${PackageName.WECHAT}.plugin.setting.ui.setting.SettingsUI"
private val WelabMainUIClass by lazyClassOrNull("${PackageName.WECHAT}.plugin.welab.ui.WelabMainUI")
/** 微信存在的类 - 未测试每个版本是否都存在 */
private val SettingsUIClass by lazyClassOrNull("${PackageName.WECHAT}.plugin.setting.ui.setting.SettingsUI")
/** TSBattery 图标 TAG 名称 */
private const val TSBARRERY_ICON_TAG = "tsbattery_icon"
@@ -95,54 +100,42 @@ object WeChatHooker : YukiBaseHooker() {
onAppLifecycle {
onCreate {
ConfigData.init(context = this)
registerModuleAppActivities(
when {
EmptyActivityClass.hasClass() -> EmptyActivityClass
WelabMainUIClass.hasClass() -> WelabMainUIClass
else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)")
}
)
registerModuleAppActivities(when {
EmptyActivityClass != null -> EmptyActivityClass
WelabMainUIClass != null -> WelabMainUIClass
else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)")
})
if (ConfigData.isDisableAllHook) return@onCreate
hookSystemWakeLock()
loggerI(msg = "All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
YLog.info("All processes are completed for \"${processName.takeIf { it != packageName } ?: packageName}\"")
}
}
/** 仅注入主进程 */
withProcess(mainProcessName) {
/** Hook 跳转事件 */
LauncherUIClass.hook {
injectMember {
method {
name = "onResume"
emptyParam()
}
afterHook { instance<Activity>().jumpToModuleSettings(isFinish = false) }
}
}
LauncherUIClass?.resolve()?.optional()?.firstMethodOrNull {
name = "onResume"
emptyParameters()
}?.hook()?.after { instance<Activity>().jumpToModuleSettings(isFinish = false) }
/** 向设置界面右上角添加按钮 */
SettingsUIClass.hook {
injectMember {
method {
name = "onResume"
emptyParam()
}
afterHook {
method {
name = "get_fragment"
emptyParam()
superClass(isOnlySuperClass = true)
}.get(instance).call()?.current()?.method {
name = "getView"
emptyParam()
returnType = ViewClass
superClass(isOnlySuperClass = true)
}?.invoke<ViewGroup?>()?.also {
it.context?.injectModuleAppResources()
runCatching { it.getChildAt(0) as? ViewGroup? }.getOrNull()?.also { rootView ->
if (rootView.findViewWithTag<View>(TSBARRERY_ICON_TAG) == null)
rootView.addView(createPreferenceIcon(it.context))
}
}
SettingsUIClass?.resolve()?.optional()?.firstMethodOrNull {
name = "onResume"
emptyParameters()
}?.hook()?.after {
SettingsUIClass?.resolve()?.optional()?.firstMethodOrNull {
name = "get_fragment"
emptyParameters()
superclass()
}?.of(instance)?.invoke()?.asResolver()?.optional()?.firstMethodOrNull {
name = "getView"
emptyParameters()
returnType = View::class
superclass()
}?.invoke<ViewGroup?>()?.also {
it.context?.injectModuleAppResources()
runCatching { it.getChildAt(0) as? ViewGroup? }.getOrNull()?.also { rootView ->
if (rootView.findViewWithTag<View>(TSBARRERY_ICON_TAG) == null)
rootView.addView(createPreferenceIcon(it.context))
}
}
}

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
@@ -17,24 +17,24 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/9/29.
* This file is created by fankes on 2022/9/29.
*/
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,13 +94,14 @@ fun Activity.jumpToModuleSettings(isFinish: Boolean = true) {
/** Hook 系统电源锁 */
fun PackageParam.hookSystemWakeLock() {
PowerManager_WakeLockClass.hook {
injectMember {
method {
name = "acquireLocked"
emptyParam()
}
intercept()
}
PowerManager.WakeLock::class.resolve().apply {
firstMethod {
name = "acquireLocked"
emptyParameters()
}.hook().intercept()
firstMethod {
name = "release"
parameters(Int::class)
}.hook().intercept()
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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 2023/10/8.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package com.fankes.tsbattery.hook.helper
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.param.PackageParam
import org.luckypray.dexkit.DexKitBridge
/**
* DexKit 工具类
*/
object DexKitHelper {
/** 是否已装载 */
private var isLoaded = false
/** 装载 */
fun load() {
if (isLoaded) return
runCatching {
System.loadLibrary("dexkit")
isLoaded = true
}.onFailure { YLog.error("Load DexKit failed!", it) }
}
/**
* 创建 [DexKitBridge]
* @param param 当前实例
* @param initiate 方法体
*/
fun create(param: PackageParam, initiate: DexKitBridge.() -> Unit) {
load()
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
@@ -17,7 +17,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2021/9/4.
* This file is created by fankes on 2021/9/4.
*/
@file:Suppress("SetTextI18n", "LocalVariableName", "SameParameterValue")
@@ -27,54 +27,37 @@ import android.content.ComponentName
import android.content.Intent
import android.view.HapticFeedbackConstants
import androidx.core.view.isVisible
import com.fankes.tsbattery.BuildConfig
import com.fankes.projectpromote.ProjectPromote
import com.fankes.tsbattery.R
import com.fankes.tsbattery.const.JumpEvent
import com.fankes.tsbattery.const.ModuleVersion
import com.fankes.tsbattery.const.PackageName
import com.fankes.tsbattery.databinding.ActivityMainBinding
import com.fankes.tsbattery.hook.entity.QQTIMHooker
import com.fankes.tsbattery.hook.entity.WeChatHooker
import com.fankes.tsbattery.ui.activity.base.BaseActivity
import com.fankes.tsbattery.utils.factory.*
import com.fankes.tsbattery.utils.factory.appVersionBrandOf
import com.fankes.tsbattery.utils.factory.hideOrShowLauncherIcon
import com.fankes.tsbattery.utils.factory.isInstall
import com.fankes.tsbattery.utils.factory.isLauncherIconShowing
import com.fankes.tsbattery.utils.factory.openBrowser
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.utils.tool.YukiPromoteTool
import com.fankes.tsbattery.wrapper.BuildConfigWrapper
import com.highcapable.yukihookapi.YukiHookAPI
class MainActivity : BaseActivity<ActivityMainBinding>() {
companion object {
private val qqSupportVersions = arrayOf(
"8.0.0", "8.0.5", "8.0.7", "8.1.0", "8.1.3", "8.1.5", "8.1.8",
"8.2.0", "8.2.6", "8.2.7", "8.2.8", "8.2.11", "8.3.0", "8.3.5",
"8.3.6", "8.3.9", "8.4.1", "8.4.5", "8.4.8", "8.4.10", "8.4.17",
"8.4.18", "8.5.0", "8.5.5", "8.6.0", "8.6.5", "8.7.0", "8.7.5",
"8.7.8", "8.8.0", "8.8.3", "8.8.5", "8.8.11", "8.8.12", "8.8.17",
"8.8.20", "8.8.23", "8.8.28", "8.8.33", "8.8.35", "8.8.38", "8.8.50",
"8.8.55", "8.8.68", "8.8.80", "8.8.83", "8.8.85", "8.8.88", "8.8.90",
"8.8.93", "8.8.95", "8.8.98", "8.9.0", "8.9.1", "8.9.2", "8.9.3",
"8.9.5", "8.9.8", "8.9.10", "8.9.13", "8.9.15", "8.9.18", "8.9.19",
"8.9.20", "8.9.23", "8.9.25", "8.9.28", "8.9.30", "8.9.33",
"8.9.35", "8.9.38", "8.9.50", "8.9.53", "8.9.55", "8.9.58",
"8.9.63", "8.9.68", "8.9.70"
)
private val qqSupportVersion by lazy {
if (qqSupportVersions.isNotEmpty()) {
var value = ""
qqSupportVersions.forEach { value += "$it" }
"${value.trim().let { it.substring(0, it.lastIndex) }}\n\n其余版本请自行测试是否有效。"
} else "empty"
}
private const val timSupportVersion = "2+、3+ (并未完全测试每个版本)。"
private const val wechatSupportVersion = "全版本仅支持基础省电,更多功能依然画饼。"
/** 预发布的版本标识 */
private const val pendingFlag = ""
private const val QQ_SUPPORT_VERSION = "理论支持 8.0.0+ 及以上版本。"
private const val TIM_SUPPORT_VERSION = "2+、3+ (并未完全测试每个版本)。"
private const val WECHAT_SUPPORT_VERSION = "全版本仅支持基础省电,更多功能依然画饼。"
}
override fun onCreate() {
/** 检查更新 */
GithubReleaseTool.checkingForUpdate(context = this, BuildConfig.VERSION_NAME) { version, function ->
GithubReleaseTool.checkingForUpdate(context = this, ModuleVersion.NAME) { version, function ->
binding.mainTextReleaseVersion.apply {
text = "点击更新 $version"
isVisible = true
@@ -89,7 +72,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.mainTextApiWay.isVisible = true
refreshActivateExecutor()
/** 推广、恰饭 */
YukiPromoteTool.promote(context = this)
ProjectPromote.show(activity = this, ModuleVersion.toString())
} else
showDialog {
title = "模块没有激活"
@@ -102,11 +85,31 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.mainTextTimVer.text = PackageName.TIM.takeIf { isInstall(it) }?.let { appVersionBrandOf(it) } ?: "未安装"
binding.mainTextWechatVer.text = PackageName.WECHAT.takeIf { isInstall(it) }?.let { appVersionBrandOf(it) } ?: "未安装"
/** 设置文本 */
binding.mainTextVersion.text = "模块版本:${BuildConfig.VERSION_NAME} $pendingFlag"
binding.mainTextVersion.text = "模块版本:${ModuleVersion.NAME}"
/** 设置 CI 自动构建标识 */
if (ModuleVersion.isCiMode)
binding.mainTextReleaseVersion.apply {
text = "CI ${ModuleVersion.GITHUB_COMMIT_ID}"
isVisible = true
setOnClickListener {
showDialog {
title = "CI 自动构建说明"
msg = """
你正在使用的是 CI 自动构建版本Commit ID 为 ${ModuleVersion.GITHUB_COMMIT_ID}
它是由代码提交后自动触发并构建、自动编译发布的,并未经任何稳定性测试,使用风险自负。
CI 构建的版本不支持太极 (也请不要提交 CI 版本的适配,因为它们是不稳定的),你可以使用 LSPosed / LSPatch。
""".trimIndent()
confirmButton(text = "我知道了")
noCancelable()
}
}
}
binding.mainQqItem.setOnClickListener {
showDialog {
title = "兼容的 QQ 版本"
msg = qqSupportVersion
msg = QQ_SUPPORT_VERSION
confirmButton(text = "我知道了")
}
/** 振动提醒 */
@@ -115,7 +118,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.mainTimItem.setOnClickListener {
showDialog {
title = "兼容的 TIM 版本"
msg = timSupportVersion
msg = TIM_SUPPORT_VERSION
confirmButton(text = "我知道了")
}
/** 振动提醒 */
@@ -124,7 +127,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.mainWechatItem.setOnClickListener {
showDialog {
title = "兼容的微信版本"
msg = wechatSupportVersion
msg = WECHAT_SUPPORT_VERSION
confirmButton(text = "我知道了")
}
/** 振动提醒 */
@@ -148,6 +151,11 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (btn.isPressed.not()) return@setOnCheckedChangeListener
hideOrShowLauncherIcon(b)
}
/** 判断当前启动模式 */
if (packageName != BuildConfigWrapper.APPLICATION_ID) {
binding.quickActionItem.isVisible = false
binding.displaySettingItem.isVisible = false
}
}
/**
@@ -159,7 +167,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
startActivity(Intent().apply {
component = ComponentName(
packageName,
if (packageName != PackageName.WECHAT) QQTIMHooker.JumpActivityClass else WeChatHooker.LauncherUIClass
if (packageName != PackageName.WECHAT) QQTIMHooker.JumpActivityClassName else WeChatHooker.LauncherUIClassName
)
putExtra(JumpEvent.OPEN_MODULE_SETTING, YukiHookAPI.Status.compiledTimestamp)
flags = Intent.FLAG_ACTIVITY_NEW_TASK

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
@@ -17,25 +17,26 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/30.
* This file is created by fankes on 2022/1/30.
*/
@file:Suppress("UNCHECKED_CAST")
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
@@ -43,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()
@@ -56,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
@@ -67,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
@@ -17,115 +17,545 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/9/28.
* This file is created by fankes on 2022/9/28.
*/
@file:Suppress("SetTextI18n", "DEPRECATION")
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 com.fankes.tsbattery.BuildConfig
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.utils.factory.*
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
import com.fankes.tsbattery.utils.factory.appVersionName
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, BuildConfig.VERSION_NAME) { version, function ->
binding.updateVersionText.apply {
GithubReleaseTool.checkingForUpdate(context = this, ModuleVersion.NAME) { version, function ->
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(BuildConfig.APPLICATION_ID, MainActivity::class.java.name)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}.onFailure { snake(msg = "打开失败,请确认你已安装模块 APP\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 = "${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE})"
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
@@ -17,7 +17,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/8.
* This file is created by fankes on 2022/1/8.
*/
@file:Suppress("SameParameterValue")
@@ -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
@@ -17,9 +17,9 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/7.
* This file is created by fankes on 2022/1/7.
*/
@file:Suppress("unused", "OPT_IN_USAGE", "EXPERIMENTAL_API_USAGE")
@file:Suppress("unused")
package com.fankes.tsbattery.utils.factory
@@ -34,7 +34,6 @@ import androidx.appcompat.app.AlertDialog
import com.fankes.tsbattery.R
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
import com.highcapable.yukihookapi.hook.factory.applyModuleTheme
/**
@@ -134,7 +133,6 @@ class DialogBuilder(val context: Context) {
fun cancel() = dialogInstance?.cancel()
/** 显示对话框 */
@CauseProblemsApi
fun show() = runInSafe {
instance?.create()?.apply {
customLayoutView?.let { setView(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
@@ -17,13 +17,13 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/13.
* This file is created by fankes on 2022/3/13.
*/
@file:Suppress("unused")
@file:Suppress("unused", "UnusedReceiverParameter")
package com.fankes.tsbattery.utils.factory
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.YLog
/**
* 忽略异常返回值
@@ -78,5 +78,5 @@ inline fun <T> safeOf(default: T, result: () -> T) = try {
* @param block 正常回调
*/
inline fun <T> T.runInSafe(msg: String = "", block: () -> Unit) {
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
runCatching(block).onFailure { if (msg.isNotBlank()) YLog.error(msg, 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
@@ -17,7 +17,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/7.
* This file is created by fankes on 2022/1/7.
*/
@file:Suppress("unused", "DiscouragedApi", "InternalInsetResource")
@@ -40,7 +40,7 @@ import android.provider.Settings
import android.widget.Toast
import androidx.core.content.getSystemService
import androidx.core.content.pm.PackageInfoCompat
import com.fankes.tsbattery.BuildConfig
import com.fankes.tsbattery.wrapper.BuildConfigWrapper
import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
@@ -75,7 +75,7 @@ inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
* @return [PackageInfo] or null
*/
private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching {
@Suppress("DEPRECATION")
@Suppress("DEPRECATION", "KotlinRedundantDiagnosticSuppress")
if (Build.VERSION.SDK_INT >= 33)
packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
else packageManager?.getPackageInfo(packageName, flag.toInt())
@@ -227,7 +227,7 @@ fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
*/
fun Context.hideOrShowLauncherIcon(isShow: Boolean) {
packageManager?.setComponentEnabledSetting(
ComponentName(packageName, "${BuildConfig.APPLICATION_ID}.Home"),
ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home"),
if (isShow) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
@@ -239,5 +239,5 @@ fun Context.hideOrShowLauncherIcon(isShow: Boolean) {
*/
val Context.isLauncherIconShowing
get() = packageManager?.getComponentEnabledSetting(
ComponentName(packageName, "${BuildConfig.APPLICATION_ID}.Home")
ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home")
) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED

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
@@ -17,7 +17,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/20.
* This file is created by fankes on 2022/3/20.
*/
@file:Suppress("NewApi")
@@ -28,12 +28,20 @@ import android.content.Context
import android.icu.text.SimpleDateFormat
import android.icu.util.Calendar
import android.icu.util.TimeZone
import com.fankes.tsbattery.utils.factory.*
import okhttp3.*
import com.fankes.tsbattery.utils.factory.isNetWorkSuccess
import com.fankes.tsbattery.utils.factory.openBrowser
import com.fankes.tsbattery.utils.factory.openSelfSetting
import com.fankes.tsbattery.utils.factory.runInSafe
import com.fankes.tsbattery.utils.factory.showDialog
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONObject
import java.io.IOException
import java.io.Serializable
import java.util.*
import java.util.Locale
/**
* 获取 GitHub Release 最新版本工具类
@@ -60,7 +68,6 @@ object GithubReleaseTool {
.build()
).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) = runInSafe {
JSONObject(response.body.string()).apply {
GithubReleaseBean(
@@ -72,7 +79,7 @@ object GithubReleaseTool {
fun showUpdate() = context.showDialog {
title = "最新版本 $name"
msg = "发布于 $date\n\n" +
"更新日志\n\n" + content
"更新日志\n\n" + content
confirmButton(text = "更新") { context.openBrowser(htmlUrl) }
cancelButton()
}

View File

@@ -1,59 +0,0 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2017-2023 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 2022/5/30.
*/
package com.fankes.tsbattery.utils.tool
import android.content.Context
import com.fankes.tsbattery.BuildConfig
import com.fankes.tsbattery.utils.factory.openBrowser
import com.fankes.tsbattery.utils.factory.showDialog
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
/**
* [YukiHookAPI] 的自动推广工具类
*/
object YukiPromoteTool {
/** 推广已读存储键值 */
private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed_${BuildConfig.VERSION_NAME}", false)
/**
* 显示推广对话框
* @param context 实例
*/
fun promote(context: Context) {
fun saveReaded() = context.prefs().edit { put(YUKI_PROMOTE_READED, value = true) }
if (context.prefs().get(YUKI_PROMOTE_READED).not())
context.showDialog {
title = "面向开发者的推广"
msg = "你想快速拥有一个自己的 Xposed 模块吗,你只需要拥有基础的 Android 开发经验以及使用 Kotlin 编程语言即可。\n\n" +
"快来体验 YukiHookAPI这是一个使用 Kotlin 构建的高效 Hook API 与 Xposed 模块解决方案,助你的开发变得更轻松。"
confirmButton(text = "去看看") {
context.openBrowser(url = "https://github.com/fankes/YukiHookAPI")
saveReaded()
}
cancelButton(text = "我不是开发者") { saveReaded() }
noCancelable()
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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 2023/9/16.
*/
@file:Suppress("unused")
package com.fankes.tsbattery.wrapper
import com.fankes.tsbattery.BuildConfig
/**
* 对 [BuildConfig] 的包装
*/
object BuildConfigWrapper {
const val APPLICATION_ID = BuildConfig.APPLICATION_ID
const val VERSION_NAME = BuildConfig.VERSION_NAME
const val VERSION_CODE = BuildConfig.VERSION_CODE
val isDebug = BuildConfig.DEBUG
}

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

@@ -265,6 +265,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/quick_action_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
@@ -356,6 +357,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/display_setting_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
@@ -590,7 +592,8 @@
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/bg_qr_pay" />
android:adjustViewBounds="true"
android:src="@mipmap/bg_payment_code" />
</androidx.cardview.widget.CardView>
<TextView
@@ -628,7 +631,36 @@
android:ellipsize="end"
android:lineSpacingExtra="6dp"
android:maxLines="2"
android:text="此模块使用 YukiHookAPI 构建。\n了解更多 https://github.com/fankes/YukiHookAPI"
android:text="此模块使用 YukiHookAPI 构建。\n了解更多 https://github.com/HighCapable/YukiHookAPI"
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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,26 +0,0 @@
plugins {
id 'com.android.application' version '7.4.1' apply false
id 'com.android.library' version '7.4.1' apply false
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
id 'com.google.devtools.ksp' version '1.8.20-1.0.10' apply false
}
ext {
android = [
compileSdk: 33,
minSdk : 21,
targetSdk : 33
]
app = [
versionName : '4.3',
versionCode : 29,
signingConfigs: [
secretConfigsDirPath : "${projectDir.getAbsolutePath()}/.secret",
secretConfigsFileName: "key_store_secret.json"
]
]
}
task clean(type: Delete) {
delete rootProject.buildDir
}

21
build.gradle.kts Normal file
View File

@@ -0,0 +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

@@ -1,23 +1,17 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-XX:+UseParallelGC
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
# Compiler Configuration
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
android.nonTransitiveRClass=true
kotlin.code.style=official
# Incremental
kotlin.incremental.useClasspathSnapshot=true
# Project Configuration
project.name=TSBattery
project.android.compileSdk=36
project.android.minSdk=24
project.android.targetSdk=36
project.app.packageName=com.fankes.tsbattery
project.app.versionName="4.4"
project.app.versionCode=30
project.app.signing.keyAlias=public
project.app.signing.keyPassword="123456"
project.app.signing.storePassword="123456"
project.app.signing.storeFilePath=.secret/universal.p12

View File

@@ -0,0 +1,94 @@
preferences:
autowire-on-sync-mode: UPDATE_OPTIONAL_DEPENDENCIES
repositories-mode: FAIL_ON_PROJECT_REPOS
repositories:
gradle-plugin-portal:
scope: PLUGINS
google:
maven-central:
jit-pack:
sonatype-oss-releases:
rovo89-xposed-api:
scope: LIBRARIES
url: https://api.xposed.info/
content:
include:
group:
de.robv.android.xposed
fankes-maven-releases:
url: https://raw.githubusercontent.com/fankes/maven-repository/main/repository/releases
plugins:
com.android.application:
alias: android-application
version: 8.12.1
org.jetbrains.kotlin.android:
alias: kotlin-android
version: 2.2.10
com.google.devtools.ksp:
alias: kotlin-ksp
version: 2.2.10-2.0.2
libraries:
com.fankes.projectpromote:
project-promote:
version: 1.0.0
repositories:
fankes-maven-releases
de.robv.android.xposed:
api:
version: 82
repositories:
rovo89-xposed-api
com.highcapable.yukihookapi:
api:
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.6
com.github.duanhong169:
drawabletoolbox:
version: 1.0.7
com.squareup.okhttp3:
okhttp:
version: 5.1.0
androidx.core:
core-ktx:
version: 1.17.0
androidx.appcompat:
appcompat:
version: 1.7.1
com.google.android.material:
material:
version: 1.12.0
androidx.constraintlayout:
constraintlayout:
version: 2.2.1
androidx.test.ext:
junit:
version: 1.3.0
androidx.test.espresso:
espresso-core:
version: 3.7.0
junit:
junit:
version: 4.13.2

View File

@@ -1,6 +1,5 @@
#Wed May 25 04:34:58 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-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

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -1,19 +0,0 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
maven { url "https://api.xposed.info/" }
maven { url "https://www.jitpack.io" }
maven { url "https://s01.oss.sonatype.org/content/repositories/releases" }
mavenCentral()
}
}
rootProject.name = "TSBattery"
include ':app'

27
settings.gradle.kts Normal file
View File

@@ -0,0 +1,27 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
plugins {
id("com.highcapable.sweetdependency") version "1.0.4"
id("com.highcapable.sweetproperty") version "1.0.8"
}
sweetProperty {
global {
all {
permanentKeyValues("GITHUB_CI_COMMIT_ID" to "")
generateFrom(ROOT_PROJECT, SYSTEM_ENV)
}
sourcesCode {
includeKeys("GITHUB_CI_COMMIT_ID")
// 关闭类型自动转换功能,防止一些特殊 "COMMIT ID" 被生成为数值
isEnableTypeAutoConversion = false
}
}
rootProject { all { isEnable = false } }
}
rootProject.name = "TSBattery"
include(":app")