Compare commits
85 Commits
Author | SHA1 | Date | |
---|---|---|---|
6b0fe1014e
|
|||
bdf52ba463
|
|||
c2b95b9133
|
|||
2f64fb9ea9
|
|||
f48277f434
|
|||
047f746afb
|
|||
ac885baa64
|
|||
4332881dad
|
|||
49c0655412
|
|||
7eeda27937
|
|||
a8692e8a33
|
|||
39ec0e8ef7
|
|||
1dc22b90bb
|
|||
da955fc157
|
|||
94752010ec
|
|||
f9bc6fc013
|
|||
dcd95e4d8d
|
|||
7f63f93165
|
|||
e95af0bad9
|
|||
344104903b
|
|||
249cec2bee
|
|||
42387603c6
|
|||
fb3aa96c0a
|
|||
f7c31d9786
|
|||
8d00aca110
|
|||
00a1aaad5b
|
|||
a4602df9cb
|
|||
d5624e0e24
|
|||
60f9af38b2
|
|||
d3bea2ec83
|
|||
d085659fbb
|
|||
f2ec8bf33e
|
|||
3233e772bb
|
|||
e58da11553
|
|||
90d4c04593
|
|||
bcb7f6b2c5
|
|||
596726e8c7
|
|||
0a52914911
|
|||
3c30c532a4
|
|||
8f7772d047
|
|||
c148a535c8
|
|||
a5448a2c61
|
|||
a8a01e8afa
|
|||
c322c3dc29
|
|||
2e9761f01a
|
|||
0fd1a33533
|
|||
e465739f95
|
|||
52f992a6cd
|
|||
37be07f11d
|
|||
d8d9fc8c41
|
|||
f27fdb2f25
|
|||
3629ca3df5
|
|||
12a1c12f8a
|
|||
bc41ac2bdc
|
|||
5f13e203f0
|
|||
69a68999a5
|
|||
bc48d59b59
|
|||
cadf7b8873
|
|||
7f0c8dd2b5
|
|||
67349c45fd
|
|||
4ab612d5fa
|
|||
bb4b942dae
|
|||
ff0931b7bc
|
|||
fc42a0ddf0
|
|||
abab096ae0
|
|||
ce8e786b5b
|
|||
dd6c69b337
|
|||
69564cccf6
|
|||
a8c16d7823
|
|||
3616919978
|
|||
c5dfbcbe0d
|
|||
f21e8769e0
|
|||
eada17db44
|
|||
67209859c4
|
|||
a65b3c1dbe
|
|||
6375aa7844
|
|||
cbd6fd038d
|
|||
7fcf9228f4
|
|||
d995c69b5c
|
|||
376a2a5890
|
|||
e2ff60e2ef
|
|||
ad0b6d253a
|
|||
76af063ed8
|
|||
e0fdf269a0
|
|||
b1d4cd4017
|
104
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
name: 问题与 BUG 反馈
|
||||
description: 问题反馈必须使用此模板进行提交
|
||||
labels: [ bug ]
|
||||
title: "[问题与 BUG 反馈] (在这里简要描述问题原因)"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### 请在下方填写问题发生的具体原因和复现步骤。
|
||||
|
||||
我们只接受从官方渠道或应用市场下载的 QQ、TIM、微信,如果你正在第三方修改版,请不要提交任何 BUG 与问题,我们无义务去解决,请自求多福。
|
||||
|
||||
请务必知悉:部分问题可能是 APP 自身产生的 BUG,发生这种情况模块没有义务去负责解决与修复,你可以尝试关闭模块以验证该问题是否来源于 APP 自身原因。
|
||||
|
||||
发生异常、崩溃、闪退或功能性问题,必须提交问题 Log (日志),没有 Log 的 issues 将直接被关闭。
|
||||
- type: input
|
||||
attributes:
|
||||
label: 模块版本
|
||||
description: 请填写当前使用的模块完整版本号,例如:**3.0**
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: 作用域 APP
|
||||
description: 请选择出现问题的作用域 APP。
|
||||
options:
|
||||
- QQ
|
||||
- TIM
|
||||
- 微信
|
||||
- 两者或以上
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: 作用域 APP 版本
|
||||
description: |
|
||||
这里填写当前作用域 APP 的版本,例如:**QQ 8.9.28**、**微信 8.0.30**
|
||||
如果存在多个有问题的作用域 APP,请使用顿号分隔依次填写
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Android 版本
|
||||
options:
|
||||
- 13
|
||||
- 12L/12.1
|
||||
- 12
|
||||
- 11
|
||||
- 10
|
||||
- 9
|
||||
- 8.1
|
||||
- 8.0.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Xposed 框架名称与版本号
|
||||
description: 请填写当前使用的 Xposed 框架,例如:**LSPosed 1.8.4(次版本号)**
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: 系统是否已 Root
|
||||
options:
|
||||
- 否
|
||||
- 是
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: 与当前作用域 APP 同作用域的 Xposed 模块
|
||||
description: |
|
||||
此模块的作用域为 QQ、TIM、微信,为确保非其它模块冲突造成的问题,请一定要填写当前你同时激活的相关模块。
|
||||
若没有,请直接在下方填写“无”。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 详细描述问题发生的具体原因
|
||||
description: 请在下方详细描述问题发生的具体场景、复现步骤和经过,以便我们能够按照你所描述的步骤复现这个问题。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 提供模块问题 Log 或必要 Log
|
||||
description: LSPosed 可在日志管理中查看并筛选包含 `TSBattery` 的日志。
|
||||
value: |
|
||||
<details><summary>展开查看</summary><pre><code>
|
||||
|
||||
(此处粘贴问题 Log)
|
||||
|
||||
</code></pre></details>
|
||||
<!-- 提交时请将括号内容包括括号全部删除,粘贴你复制的日志,不要破坏代码格式 -->
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 确认一下你提交的信息
|
||||
description: |
|
||||
为了确保 issues 的质量和避免浪费不必要的时间,未勾选下方选项的 issues 将直接被关闭。
|
||||
请一定确保你已经**勾选下方的选项**后再提交。
|
||||
options:
|
||||
- label: 我确保上述信息准确无误
|
||||
required: false
|
63
.github/workflows/commit_ci.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Automatic Build on Commit
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.txt'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build CI
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1
|
||||
with:
|
||||
cmake-version: '3.22.1'
|
||||
- name: Prepare Java 11
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
java-package: jdk
|
||||
distribution: 'temurin'
|
||||
cache: 'gradle'
|
||||
- name: Cache Gradle Dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: gradle-deps-core-${{ hashFiles('**/build.gradle') }}
|
||||
restore-keys: |
|
||||
gradle-deps
|
||||
- name: Cache Gradle Build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: gradle-builds-core-${{ github.sha }}
|
||||
restore-keys: |
|
||||
gradle-builds
|
||||
- name: Build with Gradle
|
||||
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
|
||||
with:
|
||||
path: ${{ env.DEBUG_APK_FILE }}
|
||||
name: app-debug
|
||||
- name: Upload Artifacts(release)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: ${{ env.RELEASE_APK_FILE }}
|
||||
name: app-release
|
62
.github/workflows/pull_request_ci.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Pull Request Checker
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.txt'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Pull request check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1
|
||||
with:
|
||||
cmake-version: '3.22.1'
|
||||
- name: Prepare Java 11
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
java-package: jdk
|
||||
distribution: 'temurin'
|
||||
cache: 'gradle'
|
||||
- name: Cache Gradle Dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: gradle-deps-core-${{ hashFiles('**/build.gradle') }}
|
||||
restore-keys: |
|
||||
gradle-deps
|
||||
- name: Cache Gradle Build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: gradle-builds-core-${{ github.sha }}
|
||||
restore-keys: |
|
||||
gradle-builds
|
||||
- name: Build with Gradle
|
||||
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
|
||||
with:
|
||||
path: ${{ env.DEBUG_APK_FILE }}
|
||||
name: app-debug
|
||||
- name: Upload Artifacts(release)
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: ${{ env.RELEASE_APK_FILE }}
|
||||
name: app-release
|
BIN
.idea/icon.png
generated
Normal file
After Width: | Height: | Size: 12 KiB |
6
.idea/kotlinc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.7.20" />
|
||||
</component>
|
||||
</project>
|
6
.secret/key_store_secret.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"keyAlias": "public",
|
||||
"keyPassword": "123456",
|
||||
"storeFileName": "universal.p12",
|
||||
"storePassword": "123456"
|
||||
}
|
53
README.md
@@ -2,12 +2,12 @@
|
||||
|
||||
[](https://github.com/fankes/TSBattery)
|
||||
[](https://github.com/fankes/TSBattery/blob/master/LICENSE)
|
||||
[](https://github.com/fankes/TSBattery/releases)
|
||||
[](https://github.com/fankes/TSBattery/releases)
|
||||
[](https://github.com/fankes/TSBattery/releases)
|
||||
[](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases)
|
||||
[](https://t.me/XiaofangInternet)
|
||||
<br/><br/>
|
||||
<br/>
|
||||
<br/>
|
||||
A new way to save your battery avoid cancer apps hacker it.
|
||||
|
||||
TSBattery 是一个旨在使 QQ、TIM、微信 变得更省电的开源 Xposed 模块。
|
||||
@@ -18,24 +18,47 @@ TSBattery 是一个旨在使 QQ、TIM、微信 变得更省电的开源 Xposed
|
||||
|
||||
## 适配说明
|
||||
|
||||
- 支持并建议使用 **LSPosed**(若作用域没有自动出现推荐请勾选 QQ、TIM、微信)
|
||||
- 解锁 BL 并安装 **Magisk** 的设备建议使用 [LSPosed](https://github.com/LSPosed/LSPosed)
|
||||
|
||||
- 可以使用 **~~EdXposed~~**,但随时停止支持
|
||||
|
||||
- **太极无极 · 阴** 支持性不是很好,建议使用 **太极无极 · 阳** 或 **LSPatch (推荐)**
|
||||
- **太极无极 · 阴** 支持性不是很好,建议使用 [LSPatch](https://github.com/LSPosed/LSPatch)
|
||||
|
||||
- 支持 **Pine**(梦境模块) 但是部分功能有限制
|
||||
- 支持一些第三方免 Root 框架例如**应用转生**、**SandVXposed**,但是不推荐使用,可能会造成封号风险
|
||||
|
||||
- 请不要使用 **~~应用转生~~**,发生封号情况后果自负
|
||||
|
||||
- 如果微信不能在 **LSPosed** 中生效,请尝试勾选任意包含微信作用域的模块,例如 **微X模块**
|
||||
- 如果在微信设置界面右上角你无法找到 **TSBattery** 的图标,请尝试同时激活 [WeXposed (微X模块)](https://github.com/Xposed-Modules-Repo/com.fkzhang.wechatxposed)
|
||||
|
||||
## 请勿用于非法用途
|
||||
|
||||
- 本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
|
||||
本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
|
||||
|
||||
- 本模块发布地址仅有 [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.tsbattery/releases)、
|
||||
[Release](https://github.com/fankes/TSBattery/releases) 及 [蓝奏云](https://fankes.lanzouy.com/b02zfz3sj),从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
|
||||
## 发行渠道说明
|
||||
|
||||
- [Automatic Build on Commit](https://github.com/fankes/TSBattery/actions/workflows/commit_ci.yml)
|
||||
|
||||
上述更新为代码 `commit` 后自动触发,具体更新内容可点击上方的文字前往 **GitHub Actions** 进行查看,本更新由开源的流程自动编译发布,**不保证其稳定性**,所发布的版本**仅供测试**,且不会特殊说明甚至可能会变更版本号或保持与当前稳定版相同的版本号。
|
||||
|
||||
- [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)
|
||||
|
||||
上述更新为手动发布的稳定版,具体更新内容可点击上方的文字前往指定的发布页面查看,稳定版的更新将会同时发布到上述地址中,同步更新。
|
||||
|
||||
本模块发布地址仅限于上述所列出的地址,从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
|
||||
|
||||
## 发行状态说明
|
||||
|
||||

|
||||
|
||||
上述状态为当前稳定版与自动构建版本一致或当前代码改动与稳定版无功能差异。
|
||||
|
||||

|
||||
|
||||
上述状态为存在自动构建版本和新功能的更新但当前并未发布稳定版,处于预发行状态。
|
||||
|
||||

|
||||
|
||||
上述状态为当前发行的稳定版可能存在严重问题但并未及时进行修复且并未发布稳定版。
|
||||
|
||||
## 开始贡献
|
||||
|
||||
@@ -43,12 +66,16 @@ TSBattery 是一个旨在使 QQ、TIM、微信 变得更省电的开源 Xposed
|
||||
|
||||
- [CONTRIBUTING](https://github.com/fankes/TSBattery/blob/master/CONTRIBUTING.md)
|
||||
|
||||
## Star History
|
||||
|
||||

|
||||
|
||||
## 许可证
|
||||
|
||||
- [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html)
|
||||
|
||||
```
|
||||
Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
Copyright (C) 2017-2023 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
|
||||
@@ -66,4 +93,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Powered by [YukiHookAPI](https://github.com/fankes/YukiHookAPI)
|
||||
|
||||
版权所有 © 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
版权所有 © 2017-2023 Fankes Studio(qzmmcn@163.com)
|
2
app/.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
/build
|
||||
/release
|
||||
/src/main/assets/xposed_init
|
||||
/src/main/resources/META-INF/yukihookapi_init
|
@@ -1,38 +1,51 @@
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.devtools.ksp' version '1.7.10-1.0.6'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'com.google.devtools.ksp'
|
||||
}
|
||||
|
||||
android {
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('../keystore/public')
|
||||
storePassword '123456'
|
||||
keyAlias 'public'
|
||||
keyPassword '123456'
|
||||
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
|
||||
}
|
||||
}
|
||||
compileSdkVersion 33
|
||||
|
||||
namespace 'com.fankes.tsbattery'
|
||||
compileSdk rootProject.ext.android.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.fankes.tsbattery"
|
||||
minSdk 22
|
||||
targetSdk 33
|
||||
versionCode rootProject.ext.appVersionCode
|
||||
versionName rootProject.ext.appVersionName
|
||||
applicationId 'com.fankes.tsbattery'
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
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 rootProject.ext.enableR8
|
||||
shrinkResources rootProject.ext.enableR8
|
||||
zipAlignEnabled rootProject.ext.enableR8
|
||||
signingConfig signingConfigs.debug
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
zipAlignEnabled true
|
||||
signingConfig signingConfigs.universal
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
@@ -54,20 +67,20 @@ android {
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
aaptOptions.additionalParameters '--allow-reserved-package-id', '--package-id', '0x64'
|
||||
aaptOptions.additionalParameters '--allow-reserved-package-id', '--package-id', '0x37'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
implementation 'com.highcapable.yukihookapi:api:1.1.2'
|
||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.2'
|
||||
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.9.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.5.1'
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
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.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
}
|
6
app/proguard-rules.pro
vendored
@@ -37,6 +37,12 @@
|
||||
# 排除注入的 Activity
|
||||
-keep class com.fankes.tsbattery.ui.activity.parasitic.ConfigActivity
|
||||
|
||||
# 防止某些类被 R8 混淆 (可能是 BUG)
|
||||
# FIXME: 已知问题字符串类名 (即使是常量) 也会被 R8 处理为混淆后的类名
|
||||
# FIXME: 所以目前只能把不允许 R8 处理的类 keep 掉,同时在当前模块中也不会被混淆就是了
|
||||
-keep class kotlin.Unit
|
||||
-keep class kotlin.jvm.functions.Function0
|
||||
|
||||
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||
public static *** throwUninitializedProperty(...);
|
||||
public static *** throwUninitializedPropertyAccessException(...);
|
||||
|
@@ -11,6 +11,10 @@
|
||||
<package android:name="com.tencent.mobileqq" />
|
||||
<package android:name="com.tencent.tim" />
|
||||
<package android:name="com.tencent.mm" />
|
||||
|
||||
<intent>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
|
@@ -1 +0,0 @@
|
||||
com.fankes.tsbattery.hook.HookEntry_YukiHookXposedInit
|
@@ -1 +0,0 @@
|
||||
com.fankes.tsbattery.hook.HookEntry
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -19,11 +19,14 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/28.
|
||||
*/
|
||||
@file:Suppress("StaticFieldLeak")
|
||||
|
||||
package com.fankes.tsbattery.data
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.widget.CompoundButton
|
||||
import com.highcapable.yukihookapi.hook.factory.prefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge
|
||||
|
||||
/**
|
||||
* 全局配置存储控制类
|
||||
@@ -42,30 +45,30 @@ object ConfigData {
|
||||
/** 停用全部省电功能 (停用模块) */
|
||||
const val DISABLE_ALL_HOOK = "disable_all_hook"
|
||||
|
||||
/** 当前的 [SharedPreferences] */
|
||||
private var sharePrefs: SharedPreferences? = null
|
||||
/** 当前的 [YukiHookPrefsBridge] */
|
||||
private var prefs: YukiHookPrefsBridge? = null
|
||||
|
||||
/**
|
||||
* 读取 [SharedPreferences]
|
||||
* 读取 [YukiHookPrefsBridge]
|
||||
* @param key 键值名称
|
||||
* @param value 键值内容
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun getBoolean(key: String, value: Boolean = false) = sharePrefs?.getBoolean(key, value) ?: value
|
||||
private fun getBoolean(key: String, value: Boolean = false) = prefs?.getBoolean(key, value) ?: value
|
||||
|
||||
/**
|
||||
* 存入 [SharedPreferences]
|
||||
* 存入 [YukiHookPrefsBridge]
|
||||
* @param key 键值名称
|
||||
* @param value 键值内容
|
||||
*/
|
||||
private fun putBoolean(key: String, value: Boolean = false) = sharePrefs?.edit()?.putBoolean(key, value)?.apply()
|
||||
private fun putBoolean(key: String, value: Boolean = false) = prefs?.edit { putBoolean(key, value) }
|
||||
|
||||
/**
|
||||
* 初始化 [SharedPreferences]
|
||||
* 初始化 [YukiHookPrefsBridge]
|
||||
* @param context 实例
|
||||
*/
|
||||
fun init(context: Context) {
|
||||
sharePrefs = context.getSharedPreferences("tsbattery_config", Context.MODE_PRIVATE)
|
||||
prefs = context.prefs(name = "tsbattery_config").native()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -32,13 +32,10 @@ import com.highcapable.yukihookapi.hook.factory.encase
|
||||
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
|
||||
|
||||
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
|
||||
class HookEntry : IYukiHookXposedInit {
|
||||
|
||||
companion object {
|
||||
object HookEntry : IYukiHookXposedInit {
|
||||
|
||||
/** 是否完全支持当前版本 */
|
||||
var isHookClientSupport = true
|
||||
}
|
||||
|
||||
override fun onInit() = configs {
|
||||
debugLog { tag = "TSBattery" }
|
||||
@@ -47,8 +44,7 @@ class HookEntry : IYukiHookXposedInit {
|
||||
}
|
||||
|
||||
override fun onHook() = encase {
|
||||
loadApp(PackageName.QQ) { loadHooker(QQTIMHooker) }
|
||||
loadApp(PackageName.TIM) { loadHooker(QQTIMHooker) }
|
||||
loadApp(PackageName.WECHAT) { loadHooker(WeChatHooker) }
|
||||
loadApp(PackageName.QQ, PackageName.TIM) { loadHooker(QQTIMHooker) }
|
||||
loadApp(PackageName.WECHAT, WeChatHooker)
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -23,28 +23,34 @@ package com.fankes.tsbattery.hook.entity
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.app.ServiceCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.fankes.tsbattery.BuildConfig
|
||||
import com.fankes.tsbattery.R
|
||||
import com.fankes.tsbattery.const.PackageName
|
||||
import com.fankes.tsbattery.data.ConfigData
|
||||
import com.fankes.tsbattery.hook.HookEntry
|
||||
import com.fankes.tsbattery.hook.factory.hookSystemWakeLock
|
||||
import com.fankes.tsbattery.hook.factory.isQQNightMode
|
||||
import com.fankes.tsbattery.hook.factory.jumpToModuleSettings
|
||||
import com.fankes.tsbattery.hook.factory.startModuleSettings
|
||||
import com.fankes.tsbattery.utils.factory.appVersionName
|
||||
import com.fankes.tsbattery.utils.factory.dp
|
||||
import com.fankes.tsbattery.utils.factory.versionName
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.factory.*
|
||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.log.loggerI
|
||||
import com.highcapable.yukihookapi.hook.log.loggerW
|
||||
import com.highcapable.yukihookapi.hook.type.android.*
|
||||
import com.highcapable.yukihookapi.hook.type.java.*
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
/**
|
||||
* Hook QQ、TIM
|
||||
@@ -54,12 +60,24 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
/** QQ、TIM 存在的类 */
|
||||
const val JumpActivityClass = "${PackageName.QQ}.activity.JumpActivity"
|
||||
|
||||
/** QQ、TIM 存在的类 */
|
||||
/** QQ、TIM 存在的类 (NT 版本不再存在) */
|
||||
private const val QQSettingSettingActivityClass = "${PackageName.QQ}.activity.QQSettingSettingActivity"
|
||||
|
||||
/** QQ、TIM 存在的类 */
|
||||
/** QQ 新版存在的类 (Pad 模式 - NT 版本不再存在) */
|
||||
private const val QQSettingSettingFragmentClass = "${PackageName.QQ}.fragment.QQSettingSettingFragment"
|
||||
|
||||
/** QQ、TIM 存在的类 (NT 版本不再存在) */
|
||||
private const val AboutActivityClass = "${PackageName.QQ}.activity.AboutActivity"
|
||||
|
||||
/** QQ 新版本存在的类 */
|
||||
private const val GeneralSettingActivityClass = "${PackageName.QQ}.activity.GeneralSettingActivity"
|
||||
|
||||
/** QQ 新版本 (NT) 存在的类 */
|
||||
private const val MainSettingFragmentClass = "${PackageName.QQ}.setting.main.MainSettingFragment"
|
||||
|
||||
/** QQ 新版本 (NT) 存在的类 */
|
||||
private const val MainSettingConfigProviderClass = "${PackageName.QQ}.setting.main.MainSettingConfigProvider"
|
||||
|
||||
/** QQ、TIM 新版本存在的类 */
|
||||
private const val FormSimpleItemClass = "${PackageName.QQ}.widget.FormSimpleItem"
|
||||
|
||||
@@ -73,8 +91,10 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
private const val CoreService_KernelServiceClass = "${PackageName.QQ}.app.CoreService\$KernelService"
|
||||
|
||||
/** 根据多个版本存的不同的类 */
|
||||
private val BaseChatPieClass =
|
||||
VariousClass("${PackageName.QQ}.activity.aio.core.BaseChatPie", "${PackageName.QQ}.activity.BaseChatPie")
|
||||
private val BaseChatPieClass = VariousClass("${PackageName.QQ}.activity.aio.core.BaseChatPie", "${PackageName.QQ}.activity.BaseChatPie")
|
||||
|
||||
/** 一个内部进程的名称 (与 X5 浏览器内核有关) */
|
||||
private val privilegedProcessName = "$packageName:privileged_process"
|
||||
|
||||
/** 默认的 [Configuration] */
|
||||
var baseConfiguration: Configuration? = null
|
||||
@@ -85,8 +105,22 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
*/
|
||||
private val isQQ get() = packageName == PackageName.QQ
|
||||
|
||||
/**
|
||||
* 当前是否为 QQ 的 NT 版本
|
||||
*
|
||||
* 在 QQ NT 中 [AboutActivityClass] 已被移除 - 以此作为判断条件
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val isQQNTVersion get() = isQQ && AboutActivityClass.hasClass().not()
|
||||
|
||||
/** 当前宿主的版本 */
|
||||
private var appVersionName = "<unknown>"
|
||||
private var hostVersionName = "<unknown>"
|
||||
|
||||
/**
|
||||
* 通过 [Activity] or [Fragment] 实例得到上下文
|
||||
* @return [Activity] or null
|
||||
*/
|
||||
private fun Any.compatToActivity() = if (this is Activity) this else current().method { name = "getActivity"; superClass() }.invoke()
|
||||
|
||||
/**
|
||||
* 这个类 QQ 的 BaseChatPie 是控制聊天界面的
|
||||
@@ -106,118 +140,146 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
* - ❗Hook 错了方法会造成闪退!
|
||||
*/
|
||||
private fun hookQQBaseChatPie() {
|
||||
if (isQQ) when (appVersionName) {
|
||||
if (isQQ) when (hostVersionName) {
|
||||
"8.0.0" -> {
|
||||
hookBaseChatPie(methodName = "bq")
|
||||
hookBaseChatPie(methodName = "aL")
|
||||
hookBaseChatPie("bq")
|
||||
hookBaseChatPie("aL")
|
||||
}
|
||||
"8.0.5", "8.0.7" -> {
|
||||
hookBaseChatPie(methodName = "bw")
|
||||
hookBaseChatPie(methodName = "aQ")
|
||||
hookBaseChatPie("bw")
|
||||
hookBaseChatPie("aQ")
|
||||
}
|
||||
"8.1.0", "8.1.3" -> {
|
||||
hookBaseChatPie(methodName = "bE")
|
||||
hookBaseChatPie(methodName = "aT")
|
||||
hookBaseChatPie("bE")
|
||||
hookBaseChatPie("aT")
|
||||
}
|
||||
"8.1.5" -> {
|
||||
hookBaseChatPie(methodName = "bF")
|
||||
hookBaseChatPie(methodName = "aT")
|
||||
hookBaseChatPie("bF")
|
||||
hookBaseChatPie("aT")
|
||||
}
|
||||
"8.1.8", "8.2.0", "8.2.6" -> {
|
||||
hookBaseChatPie(methodName = "bC")
|
||||
hookBaseChatPie(methodName = "aT")
|
||||
hookBaseChatPie("bC")
|
||||
hookBaseChatPie("aT")
|
||||
}
|
||||
"8.2.7", "8.2.8", "8.2.11", "8.3.0" -> {
|
||||
hookBaseChatPie(methodName = "bE")
|
||||
hookBaseChatPie(methodName = "aV")
|
||||
hookBaseChatPie("bE")
|
||||
hookBaseChatPie("aV")
|
||||
}
|
||||
"8.3.5" -> {
|
||||
hookBaseChatPie(methodName = "bR")
|
||||
hookBaseChatPie(methodName = "aX")
|
||||
hookBaseChatPie("bR")
|
||||
hookBaseChatPie("aX")
|
||||
}
|
||||
"8.3.6" -> {
|
||||
hookBaseChatPie(methodName = "cp")
|
||||
hookBaseChatPie(methodName = "aX")
|
||||
hookBaseChatPie("cp")
|
||||
hookBaseChatPie("aX")
|
||||
}
|
||||
"8.3.9" -> {
|
||||
hookBaseChatPie(methodName = "cj")
|
||||
hookBaseChatPie(methodName = "aT")
|
||||
hookBaseChatPie("cj")
|
||||
hookBaseChatPie("aT")
|
||||
}
|
||||
"8.4.1", "8.4.5" -> {
|
||||
hookBaseChatPie(methodName = "ck")
|
||||
hookBaseChatPie(methodName = "aT")
|
||||
hookBaseChatPie("ck")
|
||||
hookBaseChatPie("aT")
|
||||
}
|
||||
"8.4.8", "8.4.10", "8.4.17", "8.4.18", "8.5.0" -> {
|
||||
hookBaseChatPie(methodName = "remainScreenOn")
|
||||
hookBaseChatPie(methodName = "cancelRemainScreenOn")
|
||||
hookBaseChatPie("remainScreenOn")
|
||||
hookBaseChatPie("cancelRemainScreenOn")
|
||||
}
|
||||
"8.5.5" -> {
|
||||
hookBaseChatPie(methodName = "bT")
|
||||
hookBaseChatPie(methodName = "aN")
|
||||
hookBaseChatPie("bT")
|
||||
hookBaseChatPie("aN")
|
||||
}
|
||||
"8.6.0", "8.6.5", "8.7.0", "8.7.5", "8.7.8", "8.8.0", "8.8.3", "8.8.5" -> {
|
||||
hookBaseChatPie(methodName = "ag")
|
||||
hookBaseChatPie(methodName = "ah")
|
||||
hookBaseChatPie("ag")
|
||||
hookBaseChatPie("ah")
|
||||
}
|
||||
"8.8.11", "8.8.12" -> {
|
||||
hookBaseChatPie(methodName = "bc")
|
||||
hookBaseChatPie(methodName = "bd")
|
||||
hookBaseChatPie("bc")
|
||||
hookBaseChatPie("bd")
|
||||
}
|
||||
"8.8.17", "8.8.20" -> {
|
||||
hookBaseChatPie(methodName = "bd")
|
||||
hookBaseChatPie(methodName = "be")
|
||||
hookBaseChatPie("bd")
|
||||
hookBaseChatPie("be")
|
||||
}
|
||||
"8.8.23", "8.8.28" -> {
|
||||
hookBaseChatPie(methodName = "bf")
|
||||
hookBaseChatPie(methodName = "bg")
|
||||
hookBaseChatPie("bf")
|
||||
hookBaseChatPie("bg")
|
||||
}
|
||||
"8.8.33" -> {
|
||||
hookBaseChatPie(methodName = "bg")
|
||||
hookBaseChatPie(methodName = "bh")
|
||||
hookBaseChatPie("bg")
|
||||
hookBaseChatPie("bh")
|
||||
}
|
||||
"8.8.35", "8.8.38" -> {
|
||||
hookBaseChatPie(methodName = "bi")
|
||||
hookBaseChatPie(methodName = "bj")
|
||||
hookBaseChatPie("bi")
|
||||
hookBaseChatPie("bj")
|
||||
}
|
||||
"8.8.50" -> {
|
||||
hookBaseChatPie(methodName = "bj")
|
||||
hookBaseChatPie(methodName = "bk")
|
||||
hookBaseChatPie("bj")
|
||||
hookBaseChatPie("bk")
|
||||
}
|
||||
"8.8.55", "8.8.68", "8.8.80" -> {
|
||||
hookBaseChatPie(methodName = "bk")
|
||||
hookBaseChatPie(methodName = "bl")
|
||||
hookBaseChatPie("bk")
|
||||
hookBaseChatPie("bl")
|
||||
}
|
||||
"8.8.83", "8.8.85", "8.8.88", "8.8.90" -> {
|
||||
hookBaseChatPie(methodName = "bl")
|
||||
hookBaseChatPie(methodName = "bm")
|
||||
hookBaseChatPie("bl")
|
||||
hookBaseChatPie("bm")
|
||||
}
|
||||
"8.8.93", "8.8.95" -> {
|
||||
hookBaseChatPie(methodName = "J3")
|
||||
hookBaseChatPie(methodName = "S")
|
||||
hookBaseChatPie("J3")
|
||||
hookBaseChatPie("S")
|
||||
}
|
||||
"8.8.98" -> {
|
||||
hookBaseChatPie(methodName = "M3")
|
||||
hookBaseChatPie(methodName = "S")
|
||||
hookBaseChatPie("M3")
|
||||
hookBaseChatPie("S")
|
||||
}
|
||||
"8.9.0", "8.9.1", "8.9.2" -> {
|
||||
hookBaseChatPie(methodName = "N3")
|
||||
hookBaseChatPie(methodName = "S")
|
||||
hookBaseChatPie("N3")
|
||||
hookBaseChatPie("S")
|
||||
}
|
||||
"8.9.3", "8.9.5" -> {
|
||||
hookBaseChatPie(methodName = "H3")
|
||||
hookBaseChatPie(methodName = "P")
|
||||
hookBaseChatPie("H3")
|
||||
hookBaseChatPie("P")
|
||||
}
|
||||
"8.9.8", "8.9.10" -> {
|
||||
hookBaseChatPie(methodName = "H3")
|
||||
hookBaseChatPie(methodName = "N")
|
||||
hookBaseChatPie("H3")
|
||||
hookBaseChatPie("N")
|
||||
}
|
||||
"8.9.13" -> {
|
||||
hookBaseChatPie(methodName = "y3")
|
||||
hookBaseChatPie(methodName = "H")
|
||||
hookBaseChatPie("y3")
|
||||
hookBaseChatPie("H")
|
||||
}
|
||||
"8.9.15", "8.9.18", "8.9.19", "8.9.20" -> {
|
||||
hookBaseChatPie("w3")
|
||||
hookBaseChatPie("H")
|
||||
}
|
||||
"8.9.23", "8.9.25" -> {
|
||||
hookBaseChatPie("z3")
|
||||
hookBaseChatPie("H")
|
||||
}
|
||||
"8.9.28", "8.9.30", "8.9.33" -> {
|
||||
hookBaseChatPie("A3")
|
||||
hookBaseChatPie("H")
|
||||
}
|
||||
"8.9.35", "8.9.38", "8.9.50" -> {
|
||||
hookBaseChatPie("B3")
|
||||
hookBaseChatPie("H")
|
||||
}
|
||||
"8.9.53", "8.9.55", "8.9.58" -> {
|
||||
hookBaseChatPie("C3")
|
||||
hookBaseChatPie("H")
|
||||
}
|
||||
"8.9.63", "8.9.68" -> {
|
||||
hookBaseChatPie("t3")
|
||||
hookBaseChatPie("J")
|
||||
}
|
||||
"8.9.70" -> {
|
||||
hookBaseChatPie("u3")
|
||||
hookBaseChatPie("J")
|
||||
}
|
||||
else -> {
|
||||
HookEntry.isHookClientSupport = false
|
||||
loggerD(msg = "$appVersionName not supported!")
|
||||
loggerW(msg = "$hostVersionName not supported!")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,7 +370,7 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
injectMember {
|
||||
method {
|
||||
name = "a"
|
||||
param(StringType, LongType)
|
||||
param(StringClass, LongType)
|
||||
returnType = UnitType
|
||||
}
|
||||
intercept()
|
||||
@@ -375,7 +437,7 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
injectMember {
|
||||
method {
|
||||
name = "onHook"
|
||||
param(StringType, AnyType, AnyArrayClass, AnyType)
|
||||
param(StringClass, AnyClass, AnyArrayClass, AnyClass)
|
||||
}
|
||||
intercept()
|
||||
}
|
||||
@@ -478,14 +540,14 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
injectMember {
|
||||
method {
|
||||
name = "onWriteLog"
|
||||
param(StringType, StringType)
|
||||
param(StringClass, StringClass)
|
||||
}
|
||||
intercept()
|
||||
}
|
||||
injectMember {
|
||||
method {
|
||||
name = "onCmdRequest"
|
||||
param(StringType)
|
||||
param(StringClass)
|
||||
}
|
||||
intercept()
|
||||
}
|
||||
@@ -506,15 +568,113 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
}
|
||||
|
||||
/** Hook QQ 的设置界面添加模块设置入口 (新版) */
|
||||
private fun hookQQSettingsUi() {
|
||||
if (MainSettingFragmentClass.hasClass().not()) return loggerE(msg = "Could not found main setting class, hook aborted")
|
||||
val kotlinUnit = "kotlin.Unit"
|
||||
val kotlinFunction0 = "kotlin.jvm.functions.Function0"
|
||||
val simpleItemProcessorClass = searchClass {
|
||||
from("${PackageName.QQ}.setting.processor").absolute()
|
||||
constructor { param(ContextClass, IntType, CharSequenceClass, IntType) }
|
||||
method {
|
||||
param(kotlinFunction0)
|
||||
returnType = UnitType
|
||||
}
|
||||
field().count { it >= 6 }
|
||||
}.get() ?: return loggerE(msg = "Could not found processor class, hook aborted")
|
||||
|
||||
/**
|
||||
* 创建入口点条目
|
||||
* @param context 当前实例
|
||||
* @return [Any]
|
||||
*/
|
||||
fun createTSEntryItem(context: Context): Any {
|
||||
/** 为了使用图标资源 ID - 这里需要重新注入模块资源防止不生效 */
|
||||
context.injectModuleAppResources()
|
||||
val iconResId = if (context.isQQNightMode()) R.mipmap.ic_tsbattery_entry_night else R.mipmap.ic_tsbattery_entry_day
|
||||
return simpleItemProcessorClass.buildOf(context, R.id.tsbattery_qq_entry_item_id, "TSBattery", iconResId) {
|
||||
param(ContextClass, IntType, CharSequenceClass, IntType)
|
||||
}?.also { entryItem ->
|
||||
val onClickMethod = simpleItemProcessorClass.method {
|
||||
param { it[0].name == kotlinFunction0 }
|
||||
paramCount = 1
|
||||
returnType = UnitType
|
||||
}.giveAll().lastOrNull() ?: error("Could not found processor method")
|
||||
val proxyOnClick = Proxy.newProxyInstance(appClassLoader, arrayOf(onClickMethod.parameterTypes[0])) { any, method, args ->
|
||||
if (method.name == "invoke") {
|
||||
context.startModuleSettings()
|
||||
kotlinUnit.toClass().field { name = "INSTANCE" }.get().any()
|
||||
} else method.invoke(any, args)
|
||||
}; onClickMethod.invoke(entryItem, proxyOnClick)
|
||||
} ?: error("Could not create TSBattery entry item")
|
||||
}
|
||||
MainSettingConfigProviderClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
param(ContextClass)
|
||||
returnType = ListClass
|
||||
}
|
||||
afterHook {
|
||||
val context = args().first().cast<Context>() ?: return@afterHook
|
||||
val processor = result<MutableList<Any?>>() ?: return@afterHook
|
||||
processor.add(1, processor[0]?.javaClass?.buildOf(arrayListOf<Any>().apply { add(createTSEntryItem(context)) }, "", "") {
|
||||
param(ListClass, CharSequenceClass, CharSequenceClass)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook QQ 的设置界面添加模块设置入口 (旧版)
|
||||
* @param instance 当前设置界面实例
|
||||
*/
|
||||
private fun hookQQSettingsUiLegacy(instance: Any?) {
|
||||
/** 当前的顶级 Item 实例 */
|
||||
val formItemRefRoot = instance?.current()?.field {
|
||||
type { it.name == FormSimpleItemClass || it.name == FormCommonSingleLineItemClass }.index(num = 1)
|
||||
}?.cast<View?>()
|
||||
/** 创建一个新的 Item */
|
||||
FormSimpleItemClass.toClassOrNull()?.buildOf<View>(instance?.compatToActivity()) { param(ContextClass) }?.current {
|
||||
method {
|
||||
name = "setLeftText"
|
||||
param(CharSequenceClass)
|
||||
}.call("TSBattery")
|
||||
method {
|
||||
name = "setRightText"
|
||||
param(CharSequenceClass)
|
||||
}.call("${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE})")
|
||||
method {
|
||||
name = "setBgType"
|
||||
param(IntType)
|
||||
}.call(if (isQQ) 0 else 2)
|
||||
}?.apply { setOnClickListener { context.startModuleSettings() } }?.also { item ->
|
||||
var listGroup = formItemRefRoot?.parent as? ViewGroup?
|
||||
val lparam = (if (listGroup?.childCount == 1) {
|
||||
listGroup = listGroup.parent as? ViewGroup
|
||||
(formItemRefRoot?.parent as? View?)?.layoutParams
|
||||
} else formItemRefRoot?.layoutParams)
|
||||
?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
/** 设置圆角和间距 */
|
||||
if (isQQ) (lparam as? ViewGroup.MarginLayoutParams?)?.setMargins(0, 15.dp(item.context), 0, 0)
|
||||
/** 将 Item 添加到设置界面 */
|
||||
listGroup?.also { if (isQQ) it.addView(item, lparam) else it.addView(item, 0, lparam) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHook() {
|
||||
onAppLifecycle {
|
||||
onAppLifecycle(isOnFailureThrowToApp = false) {
|
||||
attachBaseContext { baseContext, hasCalledSuper ->
|
||||
if (hasCalledSuper.not()) baseConfiguration = baseContext.resources.configuration
|
||||
}
|
||||
onCreate {
|
||||
appVersionName = versionName
|
||||
hostVersionName = appVersionName
|
||||
/** 不注入此进程防止部分系统发生 X5 浏览器内核崩溃问题 */
|
||||
if (processName.startsWith(privilegedProcessName)) return@onCreate
|
||||
ConfigData.init(context = this)
|
||||
registerModuleAppActivities(AboutActivityClass)
|
||||
if (isQQNTVersion)
|
||||
registerModuleAppActivities(GeneralSettingActivityClass)
|
||||
else registerModuleAppActivities(AboutActivityClass)
|
||||
if (ConfigData.isDisableAllHook) return@onCreate
|
||||
hookSystemWakeLock()
|
||||
hookQQBaseChatPie()
|
||||
@@ -535,48 +695,29 @@ object QQTIMHooker : YukiBaseHooker() {
|
||||
afterHook { instance<Activity>().jumpToModuleSettings() }
|
||||
}
|
||||
}
|
||||
/** 将条目注入设置界面 */
|
||||
/** Hook 设置界面入口点 */
|
||||
if (isQQNTVersion) hookQQSettingsUi()
|
||||
else {
|
||||
/** 将条目注入设置界面 (Activity) */
|
||||
QQSettingSettingActivityClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "doOnCreate"
|
||||
param(BundleClass)
|
||||
}
|
||||
afterHook {
|
||||
/** 当前的顶级 Item 实例 */
|
||||
val formItemRefRoot = field {
|
||||
type(FormSimpleItemClass).index(num = 1)
|
||||
}.ignored().get(instance).cast() ?: field {
|
||||
type(FormCommonSingleLineItemClass).index(num = 1)
|
||||
}.ignored().get(instance).cast<View?>()
|
||||
/** 创建一个新的 Item */
|
||||
FormSimpleItemClass.toClassOrNull()?.buildOf<View>(instance) { param(ContextClass) }?.current {
|
||||
afterHook { hookQQSettingsUiLegacy(instance) }
|
||||
}
|
||||
}
|
||||
/** 将条目注入设置界面 (Fragment) */
|
||||
QQSettingSettingFragmentClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "setLeftText"
|
||||
param(CharSequenceType)
|
||||
}.call("TSBattery")
|
||||
method {
|
||||
name = "setRightText"
|
||||
param(CharSequenceType)
|
||||
}.call(BuildConfig.VERSION_NAME)
|
||||
method {
|
||||
name = "setBgType"
|
||||
param(IntType)
|
||||
}.call(if (isQQ) 0 else 2)
|
||||
}?.apply { setOnClickListener { instance<Activity>().startModuleSettings() } }?.also { item ->
|
||||
var listGroup = formItemRefRoot?.parent as? ViewGroup?
|
||||
val lparam = (if (listGroup?.childCount == 1) {
|
||||
listGroup = listGroup.parent as? ViewGroup
|
||||
(formItemRefRoot?.parent as? View?)?.layoutParams
|
||||
} else formItemRefRoot?.layoutParams)
|
||||
?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
/** 设置圆角和间距 */
|
||||
if (isQQ) (lparam as? ViewGroup.MarginLayoutParams?)?.setMargins(0, 15.dp(item.context), 0, 0)
|
||||
/** 将 Item 添加到设置界面 */
|
||||
listGroup?.also { if (isQQ) it.addView(item, lparam) else it.addView(item, 0, lparam) }
|
||||
}
|
||||
}
|
||||
}
|
||||
name = "doOnCreateView"
|
||||
paramCount = 3
|
||||
}
|
||||
afterHook { hookQQSettingsUiLegacy(instance) }
|
||||
}
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -22,8 +22,10 @@
|
||||
package com.fankes.tsbattery.hook.entity
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
@@ -35,16 +37,16 @@ import com.fankes.tsbattery.hook.factory.hookSystemWakeLock
|
||||
import com.fankes.tsbattery.hook.factory.jumpToModuleSettings
|
||||
import com.fankes.tsbattery.hook.factory.startModuleSettings
|
||||
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.fankes.tsbattery.utils.factory.versionCode
|
||||
import com.fankes.tsbattery.utils.factory.versionName
|
||||
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.BundleClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.ViewClass
|
||||
|
||||
/**
|
||||
* Hook 微信
|
||||
@@ -65,6 +67,30 @@ object WeChatHooker : YukiBaseHooker() {
|
||||
/** 微信存在的类 - 未测试每个版本是否都存在 */
|
||||
private const val SettingsUIClass = "${PackageName.WECHAT}.plugin.setting.ui.setting.SettingsUI"
|
||||
|
||||
/** TSBattery 图标 TAG 名称 */
|
||||
private const val TSBARRERY_ICON_TAG = "tsbattery_icon"
|
||||
|
||||
/**
|
||||
* 创建 TSBattery 图标
|
||||
* @param context 当前实例
|
||||
* @return [LinearLayout]
|
||||
*/
|
||||
private fun createPreferenceIcon(context: Context) = LinearLayout(context).apply {
|
||||
tag = TSBARRERY_ICON_TAG
|
||||
gravity = Gravity.END or Gravity.BOTTOM
|
||||
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
addView(ImageView(context).apply {
|
||||
layoutParams = ViewGroup.MarginLayoutParams(20.dp(context), 20.dp(context)).apply {
|
||||
topMargin = context.absoluteStatusBarHeight + 15.dp(context)
|
||||
rightMargin = 20.dp(context)
|
||||
}
|
||||
setColorFilter(ResourcesCompat.getColor(resources, R.color.colorTextGray, null))
|
||||
setImageResource(R.drawable.ic_icon)
|
||||
if (Build.VERSION.SDK_INT >= 26) tooltipText = "TSBattery 设置"
|
||||
setOnClickListener { context.startModuleSettings() }
|
||||
})
|
||||
}
|
||||
|
||||
override fun onHook() {
|
||||
onAppLifecycle {
|
||||
onCreate {
|
||||
@@ -73,7 +99,7 @@ object WeChatHooker : YukiBaseHooker() {
|
||||
when {
|
||||
EmptyActivityClass.hasClass() -> EmptyActivityClass
|
||||
WelabMainUIClass.hasClass() -> WelabMainUIClass
|
||||
else -> error("Inject WeChat Activity Proxy failed, unsupport version $versionName($versionCode)")
|
||||
else -> error("Inject WeChat Activity Proxy failed, unsupport version $appVersionName($appVersionCode)")
|
||||
}
|
||||
)
|
||||
if (ConfigData.isDisableAllHook) return@onCreate
|
||||
@@ -97,32 +123,26 @@ object WeChatHooker : YukiBaseHooker() {
|
||||
SettingsUIClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "onCreate"
|
||||
param(BundleClass)
|
||||
name = "onResume"
|
||||
emptyParam()
|
||||
}
|
||||
afterHook {
|
||||
method {
|
||||
name = "get_fragment"
|
||||
emptyParam()
|
||||
superClass(isOnlySuperClass = true)
|
||||
}.get(instance).call()?.current()
|
||||
?.field { name = "mController" }
|
||||
?.current()?.method { name = "getContentView" }
|
||||
?.invoke<ViewGroup>()?.addView(LinearLayout(instance()).apply {
|
||||
context.injectModuleAppResources()
|
||||
gravity = Gravity.END or Gravity.BOTTOM
|
||||
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
addView(ImageView(context).apply {
|
||||
layoutParams = ViewGroup.MarginLayoutParams(20.dp(context), 20.dp(context)).apply {
|
||||
topMargin = context.absoluteStatusBarHeight + 15.dp(context)
|
||||
rightMargin = 20.dp(context)
|
||||
}
|
||||
setColorFilter(ResourcesCompat.getColor(resources, R.color.colorTextGray, null))
|
||||
setImageResource(R.drawable.ic_icon)
|
||||
if (Build.VERSION.SDK_INT >= 26) tooltipText = "TSBattery 设置"
|
||||
setOnClickListener { context.startModuleSettings() }
|
||||
})
|
||||
})
|
||||
}.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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -47,13 +47,13 @@ private val ThemeUtilClass = VariousClass("${PackageName.QQ}.theme.ThemeUtil", "
|
||||
* QQ、TIM 主题是否为夜间模式
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun Context.isQQNightMode() = runCatching {
|
||||
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(suffix = "1103") || it.endsWith(suffix = "2920") }
|
||||
).let { it.endsWith("1103") || it.endsWith("2920") }
|
||||
}.getOrNull() ?: false
|
||||
|
||||
/** 启动模块设置 [Activity] */
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -53,7 +53,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
"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.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()) {
|
||||
@@ -62,8 +65,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
"${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 timSupportVersion = "2+、3+ (并未完全测试每个版本)。"
|
||||
private const val wechatSupportVersion = "全版本仅支持基础省电,更多功能依然画饼。"
|
||||
|
||||
/** 预发布的版本标识 */
|
||||
private const val pendingFlag = ""
|
||||
@@ -81,7 +84,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
/** 判断 Hook 状态 */
|
||||
if (YukiHookAPI.Status.isModuleActive) {
|
||||
binding.mainLinStatus.setBackgroundResource(R.drawable.bg_green_round)
|
||||
binding.mainImgStatus.setImageResource(R.mipmap.ic_success)
|
||||
binding.mainImgStatus.setImageResource(R.drawable.ic_success)
|
||||
binding.mainTextStatus.text = "模块已激活"
|
||||
binding.mainTextApiWay.isVisible = true
|
||||
refreshActivateExecutor()
|
||||
@@ -95,9 +98,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
noCancelable()
|
||||
}
|
||||
/** 设置安装状态 */
|
||||
binding.mainTextQqVer.text = if (PackageName.QQ.isInstall) version(PackageName.QQ) else "未安装"
|
||||
binding.mainTextTimVer.text = if (PackageName.TIM.isInstall) version(PackageName.TIM) else "未安装"
|
||||
binding.mainTextWechatVer.text = if (PackageName.WECHAT.isInstall) version(PackageName.WECHAT) else "未安装"
|
||||
binding.mainTextQqVer.text = PackageName.QQ.takeIf { isInstall(it) }?.let { appVersionBrandOf(it) } ?: "未安装"
|
||||
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.mainQqItem.setOnClickListener {
|
||||
@@ -127,12 +130,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
/** 振动提醒 */
|
||||
it.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
|
||||
}
|
||||
/** 获取 Sp 存储的信息 */
|
||||
binding.hideIconInLauncherSwitch.isChecked = isLauncherIconShowing.not()
|
||||
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
hideOrShowLauncherIcon(b)
|
||||
}
|
||||
/** 快捷操作 QQ */
|
||||
binding.quickQqButton.setOnClickListener { startModuleSettings(PackageName.QQ) }
|
||||
/** 快捷操作 TIM */
|
||||
@@ -145,6 +142,12 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
binding.linkWithFollowMe.setOnClickListener {
|
||||
openBrowser(url = "https://www.coolapk.com/u/876977", packageName = "com.coolapk.market")
|
||||
}
|
||||
/** 设置桌面图标显示隐藏 */
|
||||
binding.hideIconInLauncherSwitch.isChecked = isLauncherIconShowing.not()
|
||||
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
hideOrShowLauncherIcon(b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +155,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
* @param packageName 包名
|
||||
*/
|
||||
private fun startModuleSettings(packageName: String) {
|
||||
if (packageName.isInstall) runCatching {
|
||||
if (isInstall(packageName)) runCatching {
|
||||
startActivity(Intent().apply {
|
||||
component = ComponentName(
|
||||
packageName,
|
||||
@@ -166,12 +169,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
|
||||
/** 刷新模块激活使用的方式 */
|
||||
private fun refreshActivateExecutor() {
|
||||
when {
|
||||
YukiHookAPI.Status.executorVersion > 0 ->
|
||||
binding.mainTextApiWay.text =
|
||||
"Activated by ${YukiHookAPI.Status.executorName} API ${YukiHookAPI.Status.executorVersion}"
|
||||
YukiHookAPI.Status.isTaiChiModuleActive -> binding.mainTextApiWay.text = "Activated by TaiChi"
|
||||
else -> binding.mainTextApiWay.text = "Activated by anonymous"
|
||||
}
|
||||
if (YukiHookAPI.Status.Executor.apiLevel > 0)
|
||||
binding.mainTextApiWay.text = "Activated by ${YukiHookAPI.Status.Executor.name} API ${YukiHookAPI.Status.Executor.apiLevel}"
|
||||
else binding.mainTextApiWay.text = "Activated by ${YukiHookAPI.Status.Executor.name}"
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -40,6 +40,7 @@ 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.utils.tool.GithubReleaseTool
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class ConfigActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
@@ -70,20 +71,37 @@ class ConfigActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
}
|
||||
}
|
||||
binding.titleNameText.text = "TSBattery 设置 (${appName.trim()})"
|
||||
binding.appIcon.setImageDrawable(findAppIcon())
|
||||
binding.appIcon.setImageDrawable(appIconOf())
|
||||
binding.appName.text = appName.trim()
|
||||
binding.appVersion.text = "${versionName}($versionCode)"
|
||||
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 -> "已启用完全模式"
|
||||
packageName == PackageName.WECHAT -> "基础省电模式"
|
||||
ConfigData.isEnableQQTimProtectMode -> "保守模式"
|
||||
else -> "完全模式"
|
||||
}
|
||||
}
|
||||
refreshCurrentModeText()
|
||||
@@ -94,29 +112,20 @@ class ConfigActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
refreshConfigItems()
|
||||
binding.infoTipText.replaceToAppName()
|
||||
binding.qqTimProtectTipText.replaceToAppName()
|
||||
binding.disableAllHookSwitch.bind(ConfigData.DISABLE_ALL_HOOK) { refreshConfigItems(); refreshCurrentModeText(); showRestartDialog() }
|
||||
binding.qqTimProtectModeSwitch.bind(ConfigData.ENABLE_QQ_TIM_PROTECT_MODE) { refreshCurrentModeText(); showRestartDialog() }
|
||||
binding.qqTimCoreServiceSwitch.bind(ConfigData.ENABLE_KILL_QQ_TIM_CORESERVICE) { showRestartDialog() }
|
||||
binding.qqTimCoreServiceChildSwitch.bind(ConfigData.ENABLE_KILLE_QQ_TIM_CORESERVICE_CHILD) { showRestartDialog() }
|
||||
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() }
|
||||
}
|
||||
|
||||
/** 显示重新启动对话框 */
|
||||
private fun showRestartDialog() {
|
||||
showDialog {
|
||||
title = "需要重新启动"
|
||||
msg = "你必须重新启动${appName}才能使当前更改生效,现在重新启动吗?"
|
||||
confirmButton {
|
||||
cancel()
|
||||
finish()
|
||||
exitProcess(status = 0)
|
||||
}
|
||||
cancelButton(text = "稍后再说")
|
||||
}
|
||||
/** 显示需要重新启动提示 */
|
||||
private fun showNeedRestartTip() {
|
||||
binding.needRestartTipText.isVisible = true
|
||||
}
|
||||
|
||||
/** 替换占位符到当前 APP 名称 */
|
||||
private fun TextView.replaceToAppName() {
|
||||
text = text.toString().replace(oldValue = "{APP_NAME}", appName)
|
||||
text = text.toString().replace("{APP_NAME}", appName)
|
||||
}
|
||||
|
||||
/** 重新设置 DPI 防止 QQ、TIM 修改它 */
|
||||
@@ -134,5 +143,5 @@ class ConfigActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
* 获取当前 APP 名称
|
||||
* @return [String]
|
||||
*/
|
||||
private val appName by lazy { findAppName().let { if (packageName == PackageName.WECHAT) it else " $it " } }
|
||||
private val appName by lazy { appNameOf().let { if (packageName == PackageName.WECHAT) it else " $it " } }
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
@file:Suppress("SameParameterValue")
|
||||
|
||||
package com.fankes.tsbattery.ui.view
|
||||
package com.fankes.tsbattery.ui.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -29,11 +29,11 @@ import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
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
|
||||
|
||||
@@ -89,7 +89,10 @@ class DialogBuilder(val context: Context) {
|
||||
customLayoutView = LinearLayout(context).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER or Gravity.START
|
||||
addView(ProgressBar(context))
|
||||
addView(CircularProgressIndicator(context).apply {
|
||||
isIndeterminate = true
|
||||
trackCornerRadius = 10.dp(context)
|
||||
})
|
||||
addView(View(context).apply { layoutParams = ViewGroup.LayoutParams(20.dp(context), 5) })
|
||||
addView(TextView(context).apply {
|
||||
tag = "progressContent"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -19,7 +19,7 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/7.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "unused", "DiscouragedApi", "InternalInsetResource")
|
||||
@file:Suppress("unused", "DiscouragedApi", "InternalInsetResource")
|
||||
|
||||
package com.fankes.tsbattery.utils.factory
|
||||
|
||||
@@ -29,14 +29,17 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.PackageInfoFlags
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
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.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
|
||||
@@ -66,76 +69,75 @@ val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Confi
|
||||
inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
|
||||
|
||||
/**
|
||||
* 得到安装包信息
|
||||
* @return [PackageInfo]
|
||||
* 得到 APP 安装包信息 (兼容)
|
||||
* @param packageName APP 包名
|
||||
* @param flag [PackageInfoFlags]
|
||||
* @return [PackageInfo] or null
|
||||
*/
|
||||
val Context.packageInfo get() = packageManager?.getPackageInfo(packageName, 0) ?: PackageInfo()
|
||||
private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching {
|
||||
@Suppress("DEPRECATION")
|
||||
if (Build.VERSION.SDK_INT >= 33)
|
||||
packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
|
||||
else packageManager?.getPackageInfo(packageName, flag.toInt())
|
||||
}.getOrNull()
|
||||
|
||||
/**
|
||||
* 判断应用是否安装
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val String.isInstall
|
||||
get() = try {
|
||||
appContext.packageManager.getPackageInfo(
|
||||
this,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到版本信息
|
||||
* @return [String]
|
||||
*/
|
||||
val Context.versionName get() = packageInfo.versionName ?: ""
|
||||
|
||||
/**
|
||||
* 得到版本号
|
||||
* 得到 APP 版本号 (兼容 [PackageInfo.getLongVersionCode])
|
||||
* @return [Int]
|
||||
*/
|
||||
val Context.versionCode get() = packageInfo.versionCode
|
||||
private val PackageInfo.versionCodeCompat get() = PackageInfoCompat.getLongVersionCode(this)
|
||||
|
||||
/**
|
||||
* 得到版本信息与版本号
|
||||
* @param packageName 包名
|
||||
* 判断 APP 是否安装
|
||||
* @param packageName APP 包名
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun Context.isInstall(packageName: String) = getPackageInfoCompat(packageName)?.let { true } ?: false
|
||||
|
||||
/**
|
||||
* 得到 APP 版本信息
|
||||
* @return [String]
|
||||
*/
|
||||
fun Context.version(packageName: String) = safeOfNothing {
|
||||
packageManager?.getPackageInfo(packageName, 0)?.let {
|
||||
"${it.versionName}(${it.versionCode})"
|
||||
} ?: ""
|
||||
}
|
||||
val Context.appVersionName get() = getPackageInfoCompat(packageName)?.versionName ?: ""
|
||||
|
||||
/**
|
||||
* 得到 APP 版本号
|
||||
* @return [Int]
|
||||
*/
|
||||
val Context.appVersionCode get() = getPackageInfoCompat(packageName)?.versionCodeCompat
|
||||
|
||||
/**
|
||||
* 得到 APP 版本信息与版本号
|
||||
* @param packageName APP 包名 - 默认为当前 APP
|
||||
* @return [String]
|
||||
*/
|
||||
fun Context.appVersionBrandOf(packageName: String = getPackageName()) =
|
||||
getPackageInfoCompat(packageName)?.let { "${it.versionName}(${it.versionCodeCompat})" } ?: ""
|
||||
|
||||
/**
|
||||
* 得到 APP 名称
|
||||
* @param name APP 包名 - 默认为当前 APP
|
||||
* @param packageName APP 包名 - 默认为当前 APP
|
||||
* @return [String]
|
||||
*/
|
||||
fun Context.findAppName(name: String = packageName) =
|
||||
safeOfNothing { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadLabel(packageManager).toString() }
|
||||
fun Context.appNameOf(packageName: String = getPackageName()) =
|
||||
getPackageInfoCompat(packageName)?.applicationInfo?.loadLabel(packageManager)?.toString() ?: ""
|
||||
|
||||
/**
|
||||
* 得到 APP 图标
|
||||
* @param name APP 包名 - 默认为当前 APP
|
||||
* @param packageName APP 包名 - 默认为当前 APP
|
||||
* @return [Drawable] or null
|
||||
*/
|
||||
fun Context.findAppIcon(name: String = packageName) =
|
||||
safeOfNull { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadIcon(packageManager) }
|
||||
fun Context.appIconOf(packageName: String = getPackageName()) = getPackageInfoCompat(packageName)?.applicationInfo?.loadIcon(packageManager)
|
||||
|
||||
/**
|
||||
* 网络连接是否正常
|
||||
* @return [Boolean] 网络是否连接
|
||||
*/
|
||||
val isNetWorkSuccess get() = appContext.isNetWorkSuccess
|
||||
|
||||
/**
|
||||
* 网络连接是否正常
|
||||
* @return [Boolean] 网络是否连接
|
||||
*/
|
||||
val Context.isNetWorkSuccess get() = safeOfFalse { getSystemService<ConnectivityManager>()?.activeNetworkInfo != null }
|
||||
val Context.isNetWorkSuccess
|
||||
get() = safeOfFalse {
|
||||
@Suppress("DEPRECATION")
|
||||
getSystemService<ConnectivityManager>()?.activeNetworkInfo != null
|
||||
}
|
||||
|
||||
/**
|
||||
* dp 转换为 pxInt
|
||||
@@ -190,7 +192,7 @@ fun Context.snake(msg: String, actionText: String = "", callback: () -> Unit = {
|
||||
* @param packageName 包名
|
||||
*/
|
||||
fun Context.openSelfSetting(packageName: String = appContext.packageName) = runCatching {
|
||||
if (packageName.isInstall)
|
||||
if (isInstall(packageName))
|
||||
startActivity(Intent().apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -36,7 +36,7 @@ import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 获取 Github Release 最新版本工具类
|
||||
* 获取 GitHub Release 最新版本工具类
|
||||
*/
|
||||
object GithubReleaseTool {
|
||||
|
||||
@@ -103,7 +103,7 @@ object GithubReleaseTool {
|
||||
(context as? Activity?)?.runOnUiThread {
|
||||
context.showDialog {
|
||||
title = "网络不可用"
|
||||
msg = "模块的联网权限可能已被禁用,请开启联网权限以定期检查更新。"
|
||||
msg = "应用的联网权限可能已被禁用,请开启联网权限以定期检查更新。"
|
||||
confirmButton(text = "去开启") { context.openSelfSetting() }
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
@@ -121,16 +121,16 @@ object GithubReleaseTool {
|
||||
* 格式化时间为本地时区
|
||||
* @return [String] 本地时区时间
|
||||
*/
|
||||
private fun String.localTime() = replace(oldValue = "T", newValue = " ").replace(oldValue = "Z", newValue = "").let {
|
||||
private fun String.localTime() = replace("T", " ").replace("Z", "").let {
|
||||
runCatching {
|
||||
val local = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT).apply { timeZone = Calendar.getInstance().timeZone }
|
||||
val current = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT).apply { timeZone = TimeZone.getTimeZone("GMT") }
|
||||
val local = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT).apply { timeZone = Calendar.getInstance().timeZone }
|
||||
val current = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT).apply { timeZone = TimeZone.getTimeZone("GMT") }
|
||||
local.format(current.parse(it))
|
||||
}.getOrNull() ?: it
|
||||
}
|
||||
|
||||
/**
|
||||
* Github Release bean
|
||||
* GitHub Release bean
|
||||
* @param name 版本名称
|
||||
* @param htmlUrl 网页地址
|
||||
* @param content 更新日志
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* 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
|
||||
@@ -26,7 +26,7 @@ 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.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.factory.prefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
|
||||
/**
|
||||
@@ -42,12 +42,12 @@ object YukiPromoteTool {
|
||||
* @param context 实例
|
||||
*/
|
||||
fun promote(context: Context) {
|
||||
fun saveReaded() = context.modulePrefs.put(YUKI_PROMOTE_READED, value = true)
|
||||
if (context.modulePrefs.get(YUKI_PROMOTE_READED).not())
|
||||
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 重新构建的高效 Xposed Hook API,助你的开发变得更轻松。"
|
||||
"快来体验 YukiHookAPI,这是一个使用 Kotlin 构建的高效 Hook API 与 Xposed 模块解决方案,助你的开发变得更轻松。"
|
||||
confirmButton(text = "去看看") {
|
||||
context.openBrowser(url = "https://github.com/fankes/YukiHookAPI")
|
||||
saveReaded()
|
||||
|
9
app/src/main/res/drawable/ic_about.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150.1dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1025"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M983.8,314.4c-25.7,-60.8 -62.5,-115.4 -109.4,-162.3 -46.9,-46.9 -101.5,-83.7 -162.3,-109.4 -62.9,-26.7 -129.9,-40.2 -198.8,-40.2S377.5,16 314.5,42.7C253.8,68.4 199.1,105.2 152.3,152.2c-46.9,46.9 -83.7,101.5 -109.4,162.3 -26.7,62.9 -40.2,129.9 -40.2,198.8s13.5,135.8 40.2,198.8c25.7,60.8 62.5,115.4 109.4,162.3 46.9,46.9 101.5,83.7 162.3,109.4 62.9,26.7 129.9,40.2 198.8,40.2s135.8,-13.5 198.8,-40.2c60.8,-25.7 115.4,-62.5 162.3,-109.4 46.9,-46.9 83.7,-101.5 109.4,-162.3 26.7,-62.9 40.2,-129.9 40.2,-198.8s-13.6,-135.9 -40.3,-198.9zM550.5,768.2c0,21 -17,38 -38,38s-38,-17 -38,-38L474.5,395.6c0,-21 17,-38 38,-38s38,17 38,38v372.6zM510.8,305.5c-29.2,0 -52.7,-23.7 -52.7,-52.7 0,-29.2 23.7,-52.7 52.7,-52.7 29.2,0 52.7,23.7 52.7,52.7 0.1,29.2 -23.6,52.7 -52.7,52.7z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_back.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="192dp"
|
||||
android:height="150.39165dp"
|
||||
android:viewportWidth="1307"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M268.7,566.5h929.6c36.3,0 72.6,-29 72.6,-72.6 0,-36.3 -29,-72.6 -72.6,-72.6H305l297.8,-297.8c29,-29 29,-72.6 0,-101.7 -29,-29 -72.6,-29 -101.7,0L72.6,450.3c-14.5,14.5 -21.8,36.3 -21.8,58.1 0,21.8 0,43.6 21.8,58.1l428.5,428.5c29,29 72.6,29 101.7,0 29,-29 29,-72.6 0,-101.7l-334.1,-326.8z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_error.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="896"
|
||||
android:viewportHeight="896">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M448,0C200.58,0 0,200.58 0,448 0,695.42 200.58,896 448,896 695.42,896 896,695.42 896,448 896,200.58 695.42,0 448,0ZM663,612.05a36.11,36.11 0,0 1,0 50.95,36.11 36.11,0 0,1 -50.91,0L448,498.91 284,663a36.11,36.11 0,0 1,-51 0,36.11 36.11,0 0,1 0,-50.91L397,448.09 233,284a36.11,36.11 0,0 1,0 -51,36.11 36.11,0 0,1 51,0l164,164.09 164,-164a36.11,36.11 0,0 1,51 -0.09,36.11 36.11,0 0,1 0,51L498.91,448Z" />
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_fast_op.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,4H37L26,18H41L17,44L22,25H8L19,4Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_github.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M512,12.6c-282.8,0 -512,229.2 -512,512 0,226.2 146.7,418.1 350.1,485.8 25.6,4.7 35,-11.1 35,-24.6 0,-12.2 -0.5,-52.5 -0.7,-95.3 -142.5,31 -172.5,-60.4 -172.5,-60.4 -23.3,-59.2 -56.8,-74.9 -56.8,-74.9 -46.5,-31.8 3.5,-31.1 3.5,-31.1 51.4,3.6 78.5,52.8 78.5,52.8 45.7,78.3 119.8,55.6 149,42.6 4.6,-33.1 17.9,-55.7 32.5,-68.5 -113.7,-12.9 -233.3,-56.9 -233.3,-253 0,-55.9 20,-101.6 52.8,-137.4 -5.3,-12.9 -22.8,-65 5,-135.5 0,0 43,-13.8 140.8,52.5 40.8,-11.4 84.6,-17 128.2,-17.2 43.5,0.2 87.3,5.9 128.3,17.2 97.7,-66.2 140.6,-52.5 140.6,-52.5 27.9,70.5 10.3,122.6 5,135.5 32.8,35.8 52.7,81.5 52.7,137.4 0,196.6 -119.8,239.9 -233.8,252.6 18.4,15.9 34.7,47 34.7,94.8 0,68.5 -0.6,123.6 -0.6,140.5 0,13.6 9.2,29.6 35.2,24.6 203.3,-67.8 349.9,-259.6 349.9,-485.8 0,-282.8 -229.2,-512 -512,-512z" />
|
||||
</vector>
|
25
app/src/main/res/drawable/ic_home.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,18V42H39V18L24,6L9,18Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29V42H29V29H19Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,42H39"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round" />
|
||||
</vector>
|
30
app/src/main/res/drawable/ic_info.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24,44C29.523,44 34.523,41.761 38.142,38.142C41.761,34.523 44,29.523 44,24C44,18.477 41.761,13.477 38.142,9.858C34.523,6.239 29.523,4 24,4C18.477,4 13.477,6.239 9.858,9.858C6.239,13.477 4,18.477 4,24C4,29.523 6.239,34.523 9.858,38.142C13.477,41.761 18.477,44 24,44Z"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M24,11C25.381,11 26.5,12.119 26.5,13.5C26.5,14.881 25.381,16 24,16C22.619,16 21.5,14.881 21.5,13.5C21.5,12.119 22.619,11 24,11Z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M24.5,34V20H23.5H22.5"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M21,34H28"
|
||||
android:strokeWidth="4"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
@@ -3,7 +3,8 @@
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="0.03609375"
|
||||
<group
|
||||
android:scaleX="0.03609375"
|
||||
android:scaleY="0.03609375"
|
||||
android:translateX="35.52"
|
||||
android:translateY="35.52">
|
||||
|
9
app/src/main/res/drawable/ic_success.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1008.7"
|
||||
android:viewportHeight="1008.7">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M504.4,0C226.3,0 0,226.3 0,504.4 0,782.5 226.3,1008.7 504.4,1008.7c278.1,0 504.4,-226.3 504.4,-504.4C1008.7,226.3 782.5,0 504.4,0ZM786.6,407.7 L458.6,743.9c-7.8,8 -18.6,12.6 -29.8,12.6h-0.2c-11.1,0 -21.8,-4.4 -29.7,-12.3L222.5,567.9c-16.4,-16.4 -16.4,-43 0,-59.4 16.4,-16.4 43,-16.4 59.4,0L428.2,654.8 726.5,348.9c16.3,-16.6 42.9,-16.9 59.4,-0.7 16.6,16.2 16.9,42.8 0.7,59.4z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_warn.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m512,794a44.8,44.8 0,1 1,44.8 -44.8,44.8 44.8,0 0,1 -44.8,44.8zM471.9,230.8a40.1,40.1 0,0 1,80.2 0v369.1a40.1,40.1 0,0 1,-79.8 0zM512,0A512,512 0,1 0,1024 512,512 512,0 0,0 512,0Z" />
|
||||
</vector>
|
@@ -26,7 +26,7 @@
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:src="@mipmap/ic_back"
|
||||
android:src="@drawable/ic_back"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="返回" />
|
||||
|
||||
@@ -83,6 +83,21 @@
|
||||
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"
|
||||
@@ -178,7 +193,7 @@
|
||||
android:id="@+id/active_mode_icon"
|
||||
android:layout_width="13dp"
|
||||
android:layout_height="13dp"
|
||||
android:src="@mipmap/ic_success"
|
||||
android:src="@drawable/ic_success"
|
||||
android:tint="#FF26A69A"
|
||||
android:visibility="gone" />
|
||||
|
||||
@@ -186,7 +201,7 @@
|
||||
android:id="@+id/inactive_mode_icon"
|
||||
android:layout_width="13dp"
|
||||
android:layout_height="13dp"
|
||||
android:src="@mipmap/ic_error"
|
||||
android:src="@drawable/ic_error"
|
||||
android:tint="#FF7043"
|
||||
android:visibility="gone" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
@@ -204,7 +219,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="检测到未适配的版本"
|
||||
android:text="未适配"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
|
||||
@@ -227,6 +242,26 @@
|
||||
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>
|
||||
@@ -266,7 +301,7 @@
|
||||
android:paddingRight="15dp"
|
||||
android:paddingBottom="15dp">
|
||||
|
||||
<com.fankes.tsbattery.ui.view.MaterialSwitch
|
||||
<com.fankes.tsbattery.ui.widget.MaterialSwitch
|
||||
android:id="@+id/disable_all_hook_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
@@ -306,7 +341,7 @@
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="15dp">
|
||||
|
||||
<com.fankes.tsbattery.ui.view.MaterialSwitch
|
||||
<com.fankes.tsbattery.ui.widget.MaterialSwitch
|
||||
android:id="@+id/qq_tim_protect_mode_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
@@ -340,7 +375,7 @@
|
||||
android:paddingRight="15dp"
|
||||
android:paddingBottom="15dp">
|
||||
|
||||
<com.fankes.tsbattery.ui.view.MaterialSwitch
|
||||
<com.fankes.tsbattery.ui.widget.MaterialSwitch
|
||||
android:id="@+id/qq_tim_core_service_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
@@ -355,11 +390,11 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="关闭后可能会影响消息接收与视频通话,但是会达到省电效果,如果你的系统拥有推送服务(HMS)或(GMS)可以尝试关闭。"
|
||||
android:text="关闭后可能会影响消息接收与视频通话,但是会达到省电效果,如果你的系统拥有推送服务 (HMS) 或 (MIPUSH) 可以尝试关闭。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<com.fankes.tsbattery.ui.view.MaterialSwitch
|
||||
<com.fankes.tsbattery.ui.widget.MaterialSwitch
|
||||
android:id="@+id/qq_tim_core_service_child_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
|
@@ -36,7 +36,7 @@
|
||||
android:layout_height="27dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/ic_github"
|
||||
android:src="@drawable/ic_github"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="项目地址" />
|
||||
</LinearLayout>
|
||||
@@ -59,7 +59,7 @@
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:src="@mipmap/ic_warn"
|
||||
android:src="@drawable/ic_warn"
|
||||
android:tint="@color/white" />
|
||||
|
||||
<LinearLayout
|
||||
@@ -250,7 +250,7 @@
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/ic_about"
|
||||
android:src="@drawable/ic_about"
|
||||
android:tint="@color/colorTextDark" />
|
||||
|
||||
<TextView
|
||||
@@ -282,11 +282,21 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_shot_icon" />
|
||||
app:cardBackgroundColor="#FF00BCD4"
|
||||
app:cardCornerRadius="50dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:padding="2.5dp"
|
||||
android:src="@drawable/ic_fast_op" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@@ -364,11 +374,21 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_home" />
|
||||
app:cardBackgroundColor="#FFFF9800"
|
||||
app:cardCornerRadius="50dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:padding="2.5dp"
|
||||
android:src="@drawable/ic_home" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@@ -380,7 +400,7 @@
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.fankes.tsbattery.ui.view.MaterialSwitch
|
||||
<com.fankes.tsbattery.ui.widget.MaterialSwitch
|
||||
android:id="@+id/hide_icon_in_launcher_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -428,11 +448,21 @@
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_help" />
|
||||
app:cardBackgroundColor="#FF03A9F4"
|
||||
app:cardCornerRadius="50dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:padding="2dp"
|
||||
android:src="@drawable/ic_info" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@@ -470,7 +500,7 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.8"
|
||||
android:lineSpacingExtra="10dp"
|
||||
android:text="Q.如何使用?\nA.目前模块支持 LSPosed、LSPatch 以及太极(无极)框架,在太极和 LSPosed 的作用域中,只需勾选 QQ、TIM、微信即可,模块可以做到即插即用,激活后无需重启手机,重启 QQ、TIM 或微信就可以了。"
|
||||
android:text="Q.如何使用?\nA.目前模块支持 LSPosed、LSPatch 以及太极和一些常见的免 Root 框架,在太极和 LSPosed 的作用域中,只需勾选 QQ、TIM、微信即可,模块可以做到即插即用,激活后无需重启手机,重启 QQ、TIM 或微信就可以了。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
|
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_tsbattery_entry_day.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_tsbattery_entry_night.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.0 KiB |
@@ -4,11 +4,11 @@
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorPrimaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnPrimary">@color/black</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorSecondaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnSecondary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnSecondary">@color/white</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
|
4
app/src/main/res/values/ids.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<item name="tsbattery_qq_entry_item_id" type="id" />
|
||||
</resources>
|
@@ -4,11 +4,11 @@
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorPrimaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnPrimary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorSecondaryVariant">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnSecondary">@color/colorPrimaryAccent</item>
|
||||
<item name="colorOnSecondary">@color/white</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
|
23
build.gradle
@@ -1,13 +1,24 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '7.3.0' apply false
|
||||
id 'com.android.library' version '7.3.0' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
|
||||
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 {
|
||||
appVersionName = "4.1"
|
||||
appVersionCode = 26
|
||||
enableR8 = true
|
||||
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) {
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Wed May 25 04:34:58 CST 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|