15 Commits
3.5 ... 3.6

Author SHA1 Message Date
2d31d46cd2 Update version to 3.6,support QQ 8.8.85 2022-03-31 15:04:17 +08:00
3a1a20e688 Merge code 2022-03-31 15:00:34 +08:00
24346c056f 加入设置页面显示守护状态功能,加入新的省电 Hook 点 2022-03-31 14:58:54 +08:00
e05c8fce30 适配 QQ 8.8.85 2022-03-31 12:38:17 +08:00
e1b15c4c0a Remove some hook when bug 2022-03-31 12:28:15 +08:00
5b99288ea8 Update YukiHookAPI 2022-03-30 14:12:01 +08:00
da958920b3 Merge code 2022-03-29 21:06:31 +08:00
035e07db89 Update YukiHookAPI 2022-03-29 21:06:11 +08:00
90de1612f3 Update YukiHookAPI 2022-03-29 21:04:49 +08:00
9d2a87449d Merge code 2022-03-28 14:19:13 +08:00
7a8bc6c8f8 Merge code 2022-03-28 13:58:34 +08:00
b1e1e15412 Update YukiHookAPI 2022-03-28 00:38:44 +08:00
569d4e278a 添加本地化 LSPosed 作用域 2022-03-25 14:22:58 +08:00
2729724e93 Update YukiHookAPI 2022-03-25 01:54:34 +08:00
64f87bd69f Update YukiHookAPI 2022-03-25 01:07:26 +08:00
13 changed files with 341 additions and 139 deletions

2
.idea/misc.xml generated
View File

@@ -10,7 +10,7 @@
<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.3504380475594493" />
<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>

View File

@@ -2,7 +2,7 @@
[![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-v3.5-green)](https://github.com/fankes/TSBattery/releases)
[![Blank](https://img.shields.io/badge/version-v3.6-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/static/v1?label=Telegram&message=交流讨论&color=0088cc)](https://t.me/XiaofangInternet)

View File

@@ -1,7 +1,7 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.google.devtools.ksp' version '1.6.10-1.0.2'
id 'com.google.devtools.ksp' version '1.6.10-1.0.4'
}
android {
@@ -44,33 +44,17 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '11'
}
buildFeatures {
viewBinding true
}
}
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.0.6'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.6'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
/** 移除无效耗时 lint Task */
tasks.whenTaskAdded {
task -> if (task.name == "lintVitalRelease") task.enabled = false
@@ -84,4 +68,20 @@ tasks.whenTaskAdded {
/** 移除无效耗时 lint Task */
tasks.whenTaskAdded {
task -> if (task.name == "lintVitalReportRelease") task.enabled = false
}
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.0.69'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.69'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

View File

@@ -26,14 +26,15 @@
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="Tencent 社交毒瘤一键省电模块。\n目前支持 QQ、TIM、微信\n开发者酷安 @星夜不荟" />
<meta-data
android:name="xposedminversion"
android:value="93" />
<meta-data
android:name="xposedscope"
android:resource="@array/module_scope" />
<activity
android:name="com.fankes.tsbattery.ui.activity.MainActivity"

View File

@@ -0,0 +1,37 @@
/*
* TSBattery - A new way to save your battery avoid cancer apps hacker it.
* Copyright (C) 2019-2022 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/3/28.
*/
package com.fankes.tsbattery.data
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
object DataConst {
val ENABLE_HIDE_ICON = PrefsData("_hide_icon", false)
val ENABLE_RUN_INFO = PrefsData("_tip_run_info", false)
val ENABLE_NOTIFY_TIP = PrefsData("_tip_in_notify", true)
val ENABLE_SETTING_TIP = PrefsData("_tip_in_setting", true)
val ENABLE_QQTIM_WHITE_MODE = PrefsData("_qqtim_white_mode", false)
val ENABLE_QQTIM_CORESERVICE_BAN = PrefsData("_qqtim_core_service_ban", false)
val ENABLE_QQTIM_CORESERVICE_CHILD_BAN = PrefsData("_qqtim_core_service_child_ban", false)
val DISABLE_WECHAT_HOOK = PrefsData("_disable_wechat_hook", false)
val ENABLE_MODULE_VERSION = PrefsData("_module_version", "")
}

View File

@@ -23,15 +23,6 @@ package com.fankes.tsbattery.hook
object HookConst {
const val ENABLE_HIDE_ICON = "_hide_icon"
const val ENABLE_RUN_INFO = "_tip_run_info"
const val ENABLE_NOTIFY_TIP = "_tip_in_notify"
const val ENABLE_QQTIM_WHITE_MODE = "_qqtim_white_mode"
const val ENABLE_QQTIM_CORESERVICE_BAN = "_qqtim_core_service_ban"
const val ENABLE_QQTIM_CORESERVICE_CHILD_BAN = "_qqtim_core_service_child_ban"
const val DISABLE_WECHAT_HOOK = "_disable_wechat_hook"
const val ENABLE_MODULE_VERSION = "_module_version"
const val QQ_PACKAGE_NAME = "com.tencent.mobileqq"
const val TIM_PACKAGE_NAME = "com.tencent.tim"
const val WECHAT_PACKAGE_NAME = "com.tencent.mm"

View File

@@ -25,26 +25,26 @@ package com.fankes.tsbattery.hook
import android.app.Activity
import android.app.Service
import android.content.ComponentName
import android.content.Intent
import android.os.Build
import com.fankes.tsbattery.hook.HookConst.DISABLE_WECHAT_HOOK
import com.fankes.tsbattery.hook.HookConst.ENABLE_MODULE_VERSION
import com.fankes.tsbattery.hook.HookConst.ENABLE_NOTIFY_TIP
import com.fankes.tsbattery.hook.HookConst.ENABLE_QQTIM_CORESERVICE_BAN
import com.fankes.tsbattery.hook.HookConst.ENABLE_QQTIM_CORESERVICE_CHILD_BAN
import com.fankes.tsbattery.hook.HookConst.ENABLE_QQTIM_WHITE_MODE
import com.fankes.tsbattery.hook.HookConst.ENABLE_RUN_INFO
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.Toast
import com.fankes.tsbattery.BuildConfig
import com.fankes.tsbattery.data.DataConst
import com.fankes.tsbattery.hook.HookConst.QQ_PACKAGE_NAME
import com.fankes.tsbattery.hook.HookConst.TIM_PACKAGE_NAME
import com.fankes.tsbattery.hook.HookConst.WECHAT_PACKAGE_NAME
import com.fankes.tsbattery.ui.activity.MainActivity
import com.fankes.tsbattery.utils.factory.showDialog
import com.fankes.tsbattery.utils.factory.versionCode
import com.fankes.tsbattery.utils.factory.versionName
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.factory.configs
import com.highcapable.yukihookapi.hook.factory.encase
import com.highcapable.yukihookapi.hook.factory.field
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.param.PackageParam
@@ -66,6 +66,12 @@ class HookEntry : YukiHookXposedInitProxy {
/** QQ、TIM 存在的类 */
private const val CoreService_KernelServiceClass = "$QQ_PACKAGE_NAME.app.CoreService\$KernelService"
/** QQ、TIM 新版本存在的类 */
private const val FormSimpleItemClass = "$QQ_PACKAGE_NAME.widget.FormSimpleItem"
/** QQ、TIM 旧版本存在的类 */
private const val FormCommonSingleLineItemClass = "$QQ_PACKAGE_NAME.widget.FormCommonSingleLineItem"
/** 微信存在的类 */
private const val LauncherUIClass = "$WECHAT_PACKAGE_NAME.ui.LauncherUI"
@@ -122,7 +128,7 @@ class HookEntry : YukiHookXposedInitProxy {
interceptBaseChatPie(methodName = "bk")
interceptBaseChatPie(methodName = "bl")
}
"8.8.83" -> {
"8.8.83", "8.8.85" -> {
interceptBaseChatPie(methodName = "bl")
interceptBaseChatPie(methodName = "bm")
}
@@ -166,8 +172,8 @@ class HookEntry : YukiHookXposedInitProxy {
param(CharSequenceType)
}
beforeHook {
if (prefs.getBoolean(ENABLE_NOTIFY_TIP, default = true))
when (firstArgs as CharSequence) {
if (prefs.get(DataConst.ENABLE_NOTIFY_TIP))
when (firstArgs<CharSequence>()) {
"QQ正在后台运行" ->
args().set("QQ正在后台运行 - TSBattery 守护中")
"TIM正在后台运行" ->
@@ -195,20 +201,20 @@ class HookEntry : YukiHookXposedInitProxy {
param(BundleClass)
}
afterHook {
if (prefs.getBoolean(ENABLE_RUN_INFO))
if (prefs.get(DataConst.ENABLE_RUN_INFO))
instance<Activity>().apply {
showDialog {
title = "TSBattery 已激活"
msg = "[提示模块运行信息功能已打开]\n\n" +
"模块工作看起来一切正常,请自行测试是否能达到省电效果。\n\n" +
"已生效模块版本:${prefs.getString(ENABLE_MODULE_VERSION)}\n" +
"当前模式:${if (prefs.getBoolean(ENABLE_QQTIM_WHITE_MODE)) "保守模式" else "完全模式"}" +
"已生效模块版本:${prefs.get(DataConst.ENABLE_MODULE_VERSION)}\n" +
"当前模式:${if (prefs.get(DataConst.ENABLE_QQTIM_WHITE_MODE)) "保守模式" else "完全模式"}" +
"\n\n包名:${packageName}\n版本:$versionName($versionCode)" +
"\n\n模块只对挂后台锁屏情况下有省电效果," +
"请不要将过多的群提醒,消息通知打开,这样子在使用过程时照样会极其耗电。\n\n" +
"如果你不想看到此提示。请在模块设置中关闭“提示模块运行信息”,此设置默认关闭。\n\n" +
"持续常驻使用 QQ 依然会耗电,任何软件都是如此," +
"模块无法帮你做到前台不耗电,永远记住这一点\n\n" +
"持续常驻使用 QQ、TIM 依然会耗电,任何软件都是如此," +
"模块无法帮你做到前台不耗电\n\n" +
"开发者 酷安 @星夜不荟\n未经允许禁止转载、修改或复制我的劳动成果。"
confirmButton(text = "我知道了")
noCancelable()
@@ -228,19 +234,19 @@ class HookEntry : YukiHookXposedInitProxy {
param(BundleClass)
}
afterHook {
if (prefs.getBoolean(ENABLE_RUN_INFO))
if (prefs.get(DataConst.ENABLE_RUN_INFO))
instance<Activity>().apply {
showDialog(isUseBlackTheme = true) {
title = "TSBattery 已激活"
msg = "[提示模块运行信息功能已打开]\n\n" +
"模块工作看起来一切正常,请自行测试是否能达到省电效果。\n\n" +
"已生效模块版本:${prefs.getString(ENABLE_MODULE_VERSION)}\n" +
"已生效模块版本:${prefs.get(DataConst.ENABLE_MODULE_VERSION)}\n" +
"当前模式:基础省电" +
"\n\n包名:${packageName}\n版本:$versionName($versionCode)" +
"\n\n当前只支持微信的基础省电,即系统电源锁,后续会继续适配微信相关的省电功能(在新建文件夹了)。\n\n" +
"如果你不想看到此提示。请在模块设置中关闭“提示模块运行信息”,此设置默认关闭。\n\n" +
"持续常驻使用微信依然会耗电,任何软件都是如此," +
"模块无法帮你做到前台不耗电,永远记住这一点\n\n" +
"模块无法帮你做到前台不耗电\n\n" +
"开发者 酷安 @星夜不荟\n未经允许禁止转载、修改或复制我的劳动成果。"
confirmButton(text = "我知道了")
noCancelable()
@@ -280,10 +286,10 @@ class HookEntry : YukiHookXposedInitProxy {
injectMember {
method { name = "onCreate" }
afterHook {
if (prefs.getBoolean(ENABLE_QQTIM_CORESERVICE_BAN))
if (prefs.get(DataConst.ENABLE_QQTIM_CORESERVICE_BAN))
instance<Service>().apply {
stopForeground(true)
stopService(Intent(applicationContext, javaClass))
stopSelf()
loggerD(msg = "Shutdown CoreService OK!")
}
}
@@ -293,10 +299,10 @@ class HookEntry : YukiHookXposedInitProxy {
injectMember {
method { name = "onCreate" }
afterHook {
if (prefs.getBoolean(ENABLE_QQTIM_CORESERVICE_CHILD_BAN))
if (prefs.get(DataConst.ENABLE_QQTIM_CORESERVICE_CHILD_BAN))
instance<Service>().apply {
stopForeground(true)
stopService(Intent(applicationContext, javaClass))
stopSelf()
loggerD(msg = "Shutdown CoreService\$KernelService OK!")
}
}
@@ -311,6 +317,101 @@ class HookEntry : YukiHookXposedInitProxy {
}
}
/**
* 将激活状态插入到设置页面
* @param isQQ 是否为 QQ - 单独处理
*/
private fun PackageParam.hookQQSettingsSettingActivity(isQQ: Boolean) =
findClass(name = "$QQ_PACKAGE_NAME.activity.QQSettingSettingActivity").hook {
injectMember {
method {
name = "doOnCreate"
param(BundleClass)
afterHook {
/** 是否启用 Hook */
if (prefs.get(DataConst.ENABLE_SETTING_TIP).not()) return@afterHook
/** 当前的顶级 Item 实例 */
var formItemRefRoot: View? = null
/**
* 使用循环筛选
* @param target 目标变量名称
* @return [View] or null
*/
fun match(target: String) = runCatching {
field {
name = target
type = FormSimpleItemClass.clazz
}.ignoredError().get(instance).cast() ?: field {
name = target
type = FormCommonSingleLineItemClass.clazz
}.ignoredError().get(instance).cast<View?>()
}.getOrNull()
/** 循环出当前设置界面存在的顶级 Item */
arrayOf(
"a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u",
"v", "w", "x", "y", "z", "A", "B"
).forEach { match(it)?.also { e -> formItemRefRoot = e } }
/** 创建一个新的 Item */
FormSimpleItemClass.clazz.constructor { param(ContextClass) }.get().newInstance<View>(instance)?.also {
it.javaClass.apply {
method {
name = "setLeftText"
param(CharSequenceType)
}.get(it).call("TSBattery")
method {
name = "setRightText"
param(CharSequenceType)
}.get(it).call(prefs.get(DataConst.ENABLE_MODULE_VERSION))
method {
name = "setBgType"
param(IntType)
}.get(it).call(2)
}
it.setOnClickListener {
instance<Activity>().apply {
showDialog {
title = "TSBattery 守护中"
msg = "已生效模块版本:${prefs.get(DataConst.ENABLE_MODULE_VERSION)}\n" +
"当前模式:${if (prefs.get(DataConst.ENABLE_QQTIM_WHITE_MODE)) "保守模式" else "完全模式"}" +
"\n\n包名:${packageName}\n版本:$versionName($versionCode)" +
"\n\n模块只对挂后台锁屏情况下有省电效果," +
"请不要将过多的群提醒,消息通知打开,这样子在使用过程时照样会极其耗电。\n\n" +
"持续常驻使用 QQ、TIM 依然会耗电,任何软件都是如此," +
"模块是无法帮你做到前台不耗电的。\n\n" +
"开发者 酷安 @星夜不荟\n未经允许禁止转载、修改或复制我的劳动成果。"
confirmButton(text = "打开模块设置") {
runCatching {
startActivity(Intent().apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
component = ComponentName(
BuildConfig.APPLICATION_ID,
MainActivity::class.java.name
)
})
}.onFailure { Toast.makeText(context, "启动失败", Toast.LENGTH_SHORT).show() }
}
cancelButton(text = "关闭")
}
}
}
}.apply {
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(MATCH_PARENT, WRAP_CONTENT)
/** 将 Item 添加到设置界面 */
listGroup?.also { if (isQQ) it.addView(this, lparam) else it.addView(this, 0, lparam) }
}
}
}
}
}
override fun onInit() = configs {
debugTag = "TSBattery"
isDebug = false
@@ -323,7 +424,8 @@ class HookEntry : YukiHookXposedInitProxy {
hookNotification()
hookCoreService(isQQ = true)
hookModuleRunningInfo(isQQTIM = true)
if (prefs.getBoolean(ENABLE_QQTIM_WHITE_MODE)) return@loadApp
hookQQSettingsSettingActivity(isQQ = true)
if (prefs.get(DataConst.ENABLE_QQTIM_WHITE_MODE)) return@loadApp
/** 通过在 [SplashActivityClass] 里取到应用的版本号 */
SplashActivityClass.hook {
injectMember {
@@ -334,43 +436,6 @@ class HookEntry : YukiHookXposedInitProxy {
afterHook { hookQQBaseChatPie(instance<Activity>().versionName) }
}
}
/**
* 一个不知道是什么作用的电源锁
* 同样直接干掉
*/
findClass(name = "com.tencent.mars.ilink.comm.WakerLock").hook {
injectMember {
method {
name = "lock"
param(LongType)
}
intercept()
}.ignoredAllFailure()
}.ignoredHookClassNotFoundFailure()
/**
* 一个不知道是什么作用的电源锁
* 同样直接干掉
*/
findClass(name = "com.tencent.mars.comm.WakerLock").hook {
injectMember {
method {
name = "lock"
param(LongType)
}
intercept()
}.ignoredAllFailure()
injectMember {
method {
name = "lock"
param(StringType)
}
intercept()
}.ignoredAllFailure()
injectMember {
method { name = "lock" }
intercept()
}.ignoredAllFailure()
}.ignoredHookClassNotFoundFailure()
/**
* 干掉消息收发功能的电源锁
* 每个版本的差异暂未做排查
@@ -427,7 +492,7 @@ class HookEntry : YukiHookXposedInitProxy {
* 讯哥的程序员真的有你的
* 2022/1/25 后期查证:锁屏界面消息快速回复窗口
*/
findClass(name = "$QQ_PACKAGE_NAME.activity.QQLSActivity\$14").hook {
findClass("$QQ_PACKAGE_NAME.activity.QQLSActivity\$14", "ktq").hook {
injectMember {
method { name = "run" }
intercept()
@@ -497,12 +562,80 @@ class HookEntry : YukiHookXposedInitProxy {
}
intercept()
}
}.ignoredHookClassNotFoundFailure()
/**
* 这个是毒瘤核心操作类
* 功能同上、全部拦截
*/
findClass(name = "com.tencent.qapmsdk.qqbattery.QQBatteryMonitor").hook {
injectMember {
method { name = "start" }
intercept()
}
injectMember {
method { name = "stop" }
intercept()
}
injectMember {
method {
name = "handleMessage"
param(MessageClass)
}
replaceToFalse()
replaceToTrue()
}
injectMember {
method { name = "startMonitorInner" }
intercept()
}
injectMember {
method { name = "onAppBackground" }
intercept()
}
injectMember {
method { name = "onAppForeground" }
intercept()
}
injectMember {
method {
name = "setLogWhite"
paramCount = 2
}
intercept()
}
injectMember {
method {
name = "setCmdWhite"
paramCount = 2
}
intercept()
}
injectMember {
method {
name = "onWriteLog"
param(StringType, StringType)
}
intercept()
}
injectMember {
method {
name = "onCmdRequest"
param(StringType)
}
intercept()
}
injectMember {
method {
name = "addData"
paramCount = 4
}
intercept()
}
injectMember {
method {
name = "onGpsScan"
paramCount = 2
}
intercept()
}
}.ignoredHookClassNotFoundFailure()
}
@@ -511,9 +644,10 @@ class HookEntry : YukiHookXposedInitProxy {
hookNotification()
hookCoreService(isQQ = false)
hookModuleRunningInfo(isQQTIM = true)
hookQQSettingsSettingActivity(isQQ = false)
}
loadApp(WECHAT_PACKAGE_NAME) {
if (prefs.getBoolean(DISABLE_WECHAT_HOOK)) return@loadApp
if (prefs.get(DataConst.DISABLE_WECHAT_HOOK)) return@loadApp
hookSystemWakeLock()
hookModuleRunningInfo(isQQTIM = false)
loggerD(msg = "ウイチャット:それが機能するかどうかはわかりませんでした")

View File

@@ -29,15 +29,8 @@ import android.view.HapticFeedbackConstants
import androidx.core.view.isVisible
import com.fankes.tsbattery.BuildConfig
import com.fankes.tsbattery.R
import com.fankes.tsbattery.data.DataConst
import com.fankes.tsbattery.databinding.ActivityMainBinding
import com.fankes.tsbattery.hook.HookConst.DISABLE_WECHAT_HOOK
import com.fankes.tsbattery.hook.HookConst.ENABLE_HIDE_ICON
import com.fankes.tsbattery.hook.HookConst.ENABLE_MODULE_VERSION
import com.fankes.tsbattery.hook.HookConst.ENABLE_NOTIFY_TIP
import com.fankes.tsbattery.hook.HookConst.ENABLE_QQTIM_CORESERVICE_BAN
import com.fankes.tsbattery.hook.HookConst.ENABLE_QQTIM_CORESERVICE_CHILD_BAN
import com.fankes.tsbattery.hook.HookConst.ENABLE_QQTIM_WHITE_MODE
import com.fankes.tsbattery.hook.HookConst.ENABLE_RUN_INFO
import com.fankes.tsbattery.hook.HookConst.QQ_PACKAGE_NAME
import com.fankes.tsbattery.hook.HookConst.TIM_PACKAGE_NAME
import com.fankes.tsbattery.hook.HookConst.WECHAT_PACKAGE_NAME
@@ -55,7 +48,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private const val moduleVersion = BuildConfig.VERSION_NAME
private const val qqSupportVersion =
"8.2.11(Play)、8.8.17、8.8.23、8.8.35、8.8.38、8.8.50、8.8.55、8.8.68、8.8.80、8.8.83 (8.2.11、8.5.5~8.8.83)"
"8.2.11(Play)、8.8.17、8.8.23、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.2.11、8.5.5~8.8.85)"
private const val timSupportVersion = "2+、3+ (并未完全测试每个版本)"
private const val wechatSupportVersion = "全版本仅支持基础省电,更多功能依然画饼"
@@ -80,7 +73,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.mainTextApiWay.isVisible = true
refreshActivateExecutor()
/** 写入激活的模块版本 */
modulePrefs.putString(ENABLE_MODULE_VERSION, moduleVersion)
modulePrefs.put(DataConst.ENABLE_MODULE_VERSION, moduleVersion)
} else
showDialog {
title = "模块没有激活"
@@ -144,34 +137,35 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
it.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
}
/** 获取 Sp 存储的信息 */
binding.qqtimProtectModeSwitch.isChecked = modulePrefs.getBoolean(ENABLE_QQTIM_WHITE_MODE)
binding.qqTimCoreServiceSwitch.isChecked = modulePrefs.getBoolean(ENABLE_QQTIM_CORESERVICE_BAN)
binding.qqTimCoreServiceKnSwitch.isChecked = modulePrefs.getBoolean(ENABLE_QQTIM_CORESERVICE_CHILD_BAN)
binding.wechatDisableHookSwitch.isChecked = modulePrefs.getBoolean(DISABLE_WECHAT_HOOK)
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.getBoolean(ENABLE_HIDE_ICON)
binding.notifyModuleInfoSwitch.isChecked = modulePrefs.getBoolean(ENABLE_RUN_INFO)
binding.notifyNotifyTipSwitch.isChecked = modulePrefs.getBoolean(ENABLE_NOTIFY_TIP, default = true)
binding.qqtimProtectModeSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_QQTIM_WHITE_MODE)
binding.qqTimCoreServiceSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_QQTIM_CORESERVICE_BAN)
binding.qqTimCoreServiceKnSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_QQTIM_CORESERVICE_CHILD_BAN)
binding.wechatDisableHookSwitch.isChecked = modulePrefs.get(DataConst.DISABLE_WECHAT_HOOK)
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON)
binding.notifyModuleInfoSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_RUN_INFO)
binding.notifyNotifyTipSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_TIP)
binding.settingModuleTipSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_SETTING_TIP)
binding.qqtimProtectModeSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
modulePrefs.putBoolean(ENABLE_QQTIM_WHITE_MODE, b)
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_QQTIM_WHITE_MODE, b)
snake(msg = "修改需要重启 QQ 以生效")
}
binding.qqTimCoreServiceSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
modulePrefs.putBoolean(ENABLE_QQTIM_CORESERVICE_BAN, b)
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_QQTIM_CORESERVICE_BAN, b)
}
binding.qqTimCoreServiceKnSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
modulePrefs.putBoolean(ENABLE_QQTIM_CORESERVICE_CHILD_BAN, b)
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_QQTIM_CORESERVICE_CHILD_BAN, b)
}
binding.wechatDisableHookSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
modulePrefs.putBoolean(DISABLE_WECHAT_HOOK, b)
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.DISABLE_WECHAT_HOOK, b)
snake(msg = "修改需要重启微信以生效")
}
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
modulePrefs.putBoolean(ENABLE_HIDE_ICON, b)
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_HIDE_ICON, b)
packageManager.setComponentEnabledSetting(
ComponentName(this@MainActivity, "com.fankes.tsbattery.Home"),
if (b) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
@@ -179,12 +173,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
)
}
binding.notifyModuleInfoSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
modulePrefs.putBoolean(ENABLE_RUN_INFO, b)
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_RUN_INFO, b)
}
binding.notifyNotifyTipSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
modulePrefs.putBoolean(ENABLE_NOTIFY_TIP, b)
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_TIP, b)
}
binding.settingModuleTipSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_SETTING_TIP, b)
}
/** 快捷操作 QQ */
binding.quickQqButton.setOnClickListener { openSelfSetting(QQ_PACKAGE_NAME) }

View File

@@ -31,6 +31,7 @@ import android.util.AttributeSet
import androidx.appcompat.widget.SwitchCompat
import com.fankes.tsbattery.utils.drawable.drawabletoolbox.DrawableBuilder
import com.fankes.tsbattery.utils.factory.dp
import com.fankes.tsbattery.utils.factory.isSystemInDarkMode
class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
@@ -43,6 +44,8 @@ class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(cont
return ColorStateList(states, colors)
}
private val thumbColor get() = if (context.isSystemInDarkMode) 0xFF7C7C7C else 0xFFCCCCCC
init {
trackDrawable = DrawableBuilder()
.rectangle()
@@ -62,8 +65,8 @@ class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(cont
.build()
trackTintList = toColors(
0xFF656565.toInt(),
0xFFCCCCCC.toInt(),
0xFFCCCCCC.toInt()
thumbColor.toInt(),
thumbColor.toInt()
)
isSingleLine = true
ellipsize = TextUtils.TruncateAt.END

View File

@@ -19,7 +19,7 @@
*
* This file is Created by fankes on 2022/1/7.
*/
@file:Suppress("DEPRECATION")
@file:Suppress("DEPRECATION", "unused")
package com.fankes.tsbattery.utils.factory
@@ -42,8 +42,7 @@ import com.google.android.material.snackbar.Snackbar
* 系统深色模式是否开启
* @return [Boolean] 是否开启
*/
val isSystemInDarkMode
get() = (appContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
val isSystemInDarkMode get() = appContext.isSystemInDarkMode
/**
* 系统深色模式是否没开启
@@ -51,6 +50,18 @@ val isSystemInDarkMode
*/
inline val isNotSystemInDarkMode get() = !isSystemInDarkMode
/**
* 系统深色模式是否开启
* @return [Boolean] 是否开启
*/
val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
/**
* 系统深色模式是否没开启
* @return [Boolean] 是否开启
*/
inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
/**
* 得到安装包信息
* @return [PackageInfo]
@@ -131,7 +142,7 @@ fun toast(msg: String) = Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).sho
fun Context.snake(msg: String, actionText: String = "", it: () -> Unit = {}) =
Snackbar.make((this as Activity).findViewById(android.R.id.content), msg, Snackbar.LENGTH_LONG).apply {
if (actionText.isBlank()) return@apply
setActionTextColor(Color.WHITE)
setActionTextColor(if (isSystemInDarkMode) Color.BLACK else Color.WHITE)
setAction(actionText) { it() }
}.show()
@@ -146,7 +157,7 @@ fun Context.openSelfSetting(packageName: String = appContext.packageName) = runC
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", packageName, null)
})
else toast(msg = "你没有安装此应用")
else snake(msg = "你没有安装此应用")
}.onFailure { toast(msg = "启动 $packageName 应用信息失败") }
/**

View File

@@ -543,6 +543,25 @@
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<com.fankes.tsbattery.ui.view.MaterialSwitch
android:id="@+id/setting_module_tip_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:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此功能仅支持 QQ、TIM开启后将会在宿主设置页面显示一个条目来展示激活状态与大部分 QQ、TIM 模块显示方式一致,建议保持开启以快速确定模块是否正常生效。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<com.fankes.tsbattery.ui.view.MaterialSwitch
android:id="@+id/notify_module_info_switch"
android:layout_width="match_parent"

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="module_scope">
<item>com.tencent.mobileqq</item>
<item>com.tencent.tim</item>
<item>com.tencent.mm</item>
</string-array>
</resources>

View File

@@ -5,8 +5,8 @@ plugins {
}
ext {
appVersionName = "3.5"
appVersionCode = 13
appVersionName = "3.6"
appVersionCode = 14
}
task clean(type: Delete) {