From a25d2b814b9850c12d3a1f97c12352ae173771a8 Mon Sep 17 00:00:00 2001 From: Fankesyooni Date: Tue, 9 Nov 2021 19:37:01 +0800 Subject: [PATCH] Update to 2.3 support QQ 8.8.38 --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 1 + .../java/com/fankes/tsbattery/MainActivity.kt | 114 ++++---- .../tsbattery/application/TSApplication.kt | 35 +++ .../com/fankes/tsbattery/hook/HookMain.kt | 260 ++++++++++-------- .../com/fankes/tsbattery/hook/HookMedium.kt | 79 ++++++ .../com/fankes/tsbattery/utils/XPrefUtils.kt | 2 + 7 files changed, 319 insertions(+), 176 deletions(-) create mode 100644 app/src/main/java/com/fankes/tsbattery/application/TSApplication.kt create mode 100644 app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt diff --git a/app/build.gradle b/app/build.gradle index 48e1a81..30a5d1d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,8 +22,8 @@ android { minSdkVersion 22 //noinspection ExpiredTargetSdkVersion,OldTargetApi targetSdkVersion 26 - versionCode 5 - versionName "2.2" + versionCode 6 + versionName "2.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 23441e8..bf604dc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ package="com.fankes.tsbattery"> (R.id.main_lin_status).setBackgroundResource(R.drawable.green_round) findViewById(R.id.main_img_status).setImageResource(R.mipmap.succcess) findViewById(R.id.main_text_status).text = "模块已激活" + /** 写入激活的模块版本 */ + putString(HookMedium.ENABLE_MODULE_VERSION, moduleVersion) } else AlertDialog.Builder(this) .setTitle("模块没有激活") .setMessage( "检测到模块没有激活,模块需要 Xposed 环境依赖,同时需要系统拥有 Root 权限(太极阴可以免 Root),请自行查看本页面使用帮助与说明第三条。\n" + - "太极、应用转生、梦境(Pine)和第三方 Xposed 激活后可能不会提示激活,若想验证是否激活请打开“提示模块运行信息”自行检查,如果生效就代表模块运行正常,这里的激活状态只是一个显示意义上的存在。" + "太极、应用转生、梦境(Pine)和第三方 Xposed 激活后可能不会提示激活,若想验证是否激活请打开“提示模块运行信息”自行检查,如果生效就代表模块运行正常,这里的激活状态只是一个显示意义上的存在。\n" + + "太极(无极)在 MIUI 设备上会提示打开授权,请进行允许,然后再次打开本应用查看激活状态。" ) .setPositiveButton("我知道了", null) .setCancelable(false) .show() - /*设置文本*/ + /** 设置文本 */ findViewById(R.id.main_text_version).text = "当前版本:$moduleVersion" findViewById(R.id.main_text_support).text = "支持 $moduleSupport" - /*初始化 View*/ + /** 初始化 View */ val protectModeSwitch = findViewById(R.id.protect_mode_switch) val hideIconInLauncherSwitch = findViewById(R.id.hide_icon_in_launcher_switch) val notifyModuleInfoSwitch = findViewById(R.id.notify_module_info_switch) - /*获取 Sp 存储的信息*/ + /** 获取 Sp 存储的信息 */ protectModeSwitch.isChecked = getBoolean("_white_mode") hideIconInLauncherSwitch.isChecked = getBoolean("_hide_icon") notifyModuleInfoSwitch.isChecked = getBoolean("_tip_run_info") protectModeSwitch.setOnCheckedChangeListener { btn, b -> if (!btn.isPressed) return@setOnCheckedChangeListener - putBoolean("_white_mode", b) + putBoolean(HookMedium.ENABLE_WHITE_MODE, b) } hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b -> if (!btn.isPressed) return@setOnCheckedChangeListener - putBoolean("_hide_icon", b) + putBoolean(HookMedium.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, @@ -114,16 +116,15 @@ class MainActivity : AppCompatActivity() { } notifyModuleInfoSwitch.setOnCheckedChangeListener { btn, b -> if (!btn.isPressed) return@setOnCheckedChangeListener - putBoolean("_tip_run_info", b) + putBoolean(HookMedium.ENABLE_RUN_INFO, b) } - /*项目地址点击事件*/ + /** 项目地址点击事件 */ findViewById(R.id.link_with_project_address).setOnClickListener { try { - val intent = Intent() - intent.action = "android.intent.action.VIEW" - val content_url = Uri.parse("https://github.com/fankes/TSBattery") - intent.data = content_url - startActivity(intent) + startActivity(Intent().apply { + action = "android.intent.action.VIEW" + data = Uri.parse("https://github.com/fankes/TSBattery") + }) } catch (e: Exception) { Toast.makeText(this, "无法启动系统默认浏览器", Toast.LENGTH_SHORT).show() } @@ -132,42 +133,9 @@ class MainActivity : AppCompatActivity() { /** * 判断模块是否激活 - * 在 [HookMain] 中 Hook 掉此方法 * @return 激活状态 */ - private fun isHooked(): Boolean { - Log.d("TSBattery", "isHooked: true") - return isExpModuleActive() - } - - /** - * 新增太极判断方式 - * @return 是否激活 - */ - private fun isExpModuleActive(): Boolean { - var isExp = false - try { - val uri = Uri.parse("content://me.weishu.exposed.CP/") - var result: Bundle? = null - try { - result = contentResolver.call(uri, "active", null, null) - } catch (e: RuntimeException) { - // TaiChi is killed, try invoke - try { - val intent = Intent("me.weishu.exp.ACTION_ACTIVE") - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - startActivity(intent) - } catch (e1: Throwable) { - return false - } - } - if (result == null) result = contentResolver.call(uri, "active", null, null) - if (result == null) return false - isExp = result.getBoolean("active", false) - } catch (ignored: Throwable) { - } - return isExp - } + private fun isHooked() = HookMedium.isHooked() override fun onResume() { super.onResume() @@ -206,6 +174,24 @@ class MainActivity : AppCompatActivity() { Context.MODE_PRIVATE ).edit().putBoolean(key, bool).apply() setWorldReadable() + /** 延迟继续设置强制允许 SP 可读可写 */ + Handler().postDelayed({ setWorldReadable() }, 500) + Handler().postDelayed({ setWorldReadable() }, 1000) + Handler().postDelayed({ setWorldReadable() }, 1500) + } + + /** + * 保存值 + * @param key 名称 + * @param value 值 + */ + private fun putString(key: String, value: String) { + getSharedPreferences( + packageName + "_preferences", + Context.MODE_PRIVATE + ).edit().putString(key, value).apply() + setWorldReadable() + /** 延迟继续设置强制允许 SP 可读可写 */ Handler().postDelayed({ setWorldReadable() }, 500) Handler().postDelayed({ setWorldReadable() }, 1000) Handler().postDelayed({ setWorldReadable() }, 1500) @@ -231,4 +217,10 @@ class MainActivity : AppCompatActivity() { Toast.makeText(this, "无法写入模块设置,请检查权限\n如果此提示一直显示,请不要双开模块", Toast.LENGTH_SHORT).show() } } + + override fun onDestroy() { + super.onDestroy() + /** 销毁实例防止内存泄漏 */ + instance = null + } } \ No newline at end of file diff --git a/app/src/main/java/com/fankes/tsbattery/application/TSApplication.kt b/app/src/main/java/com/fankes/tsbattery/application/TSApplication.kt new file mode 100644 index 0000000..5d958ab --- /dev/null +++ b/app/src/main/java/com/fankes/tsbattery/application/TSApplication.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com) + * + * This file is part of TSBattery. + * + * TSBattery is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * TSBattery 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file is Created by fankes on 2021/9/4. + */ +@file:Suppress("unused") + +package com.fankes.tsbattery.application + +import android.app.Application +import androidx.appcompat.app.AppCompatDelegate + +class TSApplication : Application() { + + override fun onCreate() { + super.onCreate() + /** 禁止系统夜间模式对自己造成干扰 - 模块要什么夜间模式?😅 (其实是我懒) */ + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt b/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt index cbd3b3c..54850d4 100644 --- a/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt +++ b/app/src/main/java/com/fankes/tsbattery/hook/HookMain.kt @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com) * * This file is part of TSBattery. @@ -27,6 +27,7 @@ import android.app.AlertDialog import android.os.Build import android.os.Bundle import android.util.Log +import android.widget.Toast import androidx.annotation.Keep import com.fankes.tsbattery.utils.XPrefUtils import de.robv.android.xposed.* @@ -36,6 +37,65 @@ import java.util.* @Keep class HookMain : IXposedHookLoadPackage { + /** 仅作用于替换的 Hook 方法体 */ + private val replaceToNull = object : XC_MethodReplacement() { + override fun replaceHookedMethod(param: MethodHookParam?): Any? { + return null + } + } + + /** 仅作用于替换的 Hook 方法体 */ + private val replaceToTrue = object : XC_MethodReplacement() { + override fun replaceHookedMethod(param: MethodHookParam?): Any { + return true + } + } + + /** + * 干掉目标方法体封装 + * @param clazz 类名缩写 + * @param name 方法名 + */ + private fun XC_LoadPackage.LoadPackageParam.replaceToNull(clazz: String, name: String) { + XposedHelpers.findAndHookMethod( + "com.tencent.mobileqq.$clazz", + classLoader, + name, + replaceToNull + ) + } + + /** + * 这个类 BaseChatPie 是控制聊天界面的 + * 里面有两个随机混淆的方法 + * 这两个方法一个是挂起电源锁常驻亮屏 + * 一个是停止常驻亮屏 + * 不由分说每个版本混淆的方法名都会变 + * 所以说每个版本重新适配 - 也可以提交分支帮我适配 + * 8.8.17 版本是 bd be + * 8.8.23 版本是 bf bg + * 8.8.38 版本是 bi bj + * ⚠️ Hook 错了方法会造成闪退! + * @param version QQ 版本 + */ + private fun XC_LoadPackage.LoadPackageParam.hookBaseChatPie(version: String) { + when (version) { + "8.8.17" -> { + replaceToNull("activity.aio.core.BaseChatPie", "bd") + replaceToNull("activity.aio.core.BaseChatPie", "be") + } + "8.8.23" -> { + replaceToNull("activity.aio.core.BaseChatPie", "bf") + replaceToNull("activity.aio.core.BaseChatPie", "bg") + } + "8.8.38" -> { + replaceToNull("activity.aio.core.BaseChatPie", "bi") + replaceToNull("activity.aio.core.BaseChatPie", "bj") + } + else -> logD("$version not supported!") + } + } + /** * Print the log * @param content @@ -57,29 +117,23 @@ class HookMain : IXposedHookLoadPackage { override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { if (lpparam == null) return when (lpparam.packageName) { - /*Hook 自身*/ + /** Hook 自身 */ "com.fankes.tsbattery" -> XposedHelpers.findAndHookMethod( - "com.fankes.tsbattery.MainActivity", + "com.fankes.tsbattery.hook.HookMedium", lpparam.classLoader, "isHooked", - object : XC_MethodReplacement() { - override fun replaceHookedMethod(param: MethodHookParam?): Any { - return true - } - }) - /*经过测试 QQ 与 TIM 这两个是一个模子里面的东西,所以他们的类名也基本上是一样的*/ + replaceToTrue + ) + /** 经过测试 QQ 与 TIM 这两个是一个模子里面的东西,所以他们的类名也基本上是一样的 */ "com.tencent.mobileqq", "com.tencent.tim" -> { try { XposedHelpers.findAndHookMethod( "android.os.PowerManager\$WakeLock", lpparam.classLoader, "acquire", - object : XC_MethodReplacement() { - override fun replaceHookedMethod(param: MethodHookParam?): Any? { - return null - } - }) + replaceToNull + ) } catch (e: Throwable) { logE("handleLoadPackage: hook wakeLock acquire() Failed", e) } @@ -89,16 +143,33 @@ class HookMain : IXposedHookLoadPackage { lpparam.classLoader, "acquire", Long::class.java, - object : XC_MethodReplacement() { - override fun replaceHookedMethod(param: MethodHookParam?): Any? { - return null - } - }) + replaceToNull + ) } catch (e: Throwable) { logE("handleLoadPackage: hook wakeLock acquire(time) Failed", e) } - /*判断是否开启提示模块运行信息*/ - if (XPrefUtils.getBoolean("_tip_run_info")) + /** 增加通知栏文本显示守护状态 */ + try { + XposedHelpers.findAndHookMethod( + "android.app.Notification\$Builder", + lpparam.classLoader, + "setContentText", + CharSequence::class.java, + object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam?) { + when (param?.args?.get(0) as? CharSequence?) { + "QQ正在后台运行" -> + param.args?.set(0, "QQ正在后台运行 - TSBattery 守护中") + "TIM正在后台运行" -> + param.args?.set(0, "TIM正在后台运行 - TSBattery 守护中") + } + } + }) + } catch (e: Throwable) { + logE("handleLoadPackage: hook Notification Failed", e) + } + /** 判断是否开启提示模块运行信息 */ + if (XPrefUtils.getBoolean(HookMedium.ENABLE_RUN_INFO)) try { /** * Hook 启动界面的第一个 [Activity] @@ -113,56 +184,50 @@ class HookMain : IXposedHookLoadPackage { object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam?) { - val self = param!!.thisObject as Activity - AlertDialog.Builder( - self, - android.R.style.Theme_Material_Dialog_Alert - ).setCancelable(false) - .setTitle("TSBattery 已激活") - .setMessage( - "模块工作看起来一切正常,请自行测试是否能达到省电效果。\n\n" + - "当前模式:${if (XPrefUtils.getBoolean("_white_mode")) "保守模式" else "完全模式"}" + - "\n\n包名:${self.packageName}\n版本:${ - self.packageManager.getPackageInfo( - self.packageName, - 0 - ).versionName - }(${ - self.packageManager.getPackageInfo( - self.packageName, - 0 - ).versionCode - })" + "\n\nPS:模块只对挂后台锁屏情况下有省电效果,请不要将过多的群提醒,消息通知打开,这样子在使用过程时照样会极其耗电。\n" + - "如果你不想看到此提示。请在模块设置中关闭运行信息提醒,此设置默认关闭。\n" + - "开发者 酷安 @星夜不荟\n未经允许禁止转载、修改或复制我的劳动成果。" - ) - .setPositiveButton("我知道了", null) - .show() + val self = param?.thisObject as? Activity ?: return + try { + AlertDialog.Builder( + self, + android.R.style.Theme_Material_Light_Dialog + ).setCancelable(false) + .setTitle("TSBattery 已激活") + .setMessage( + "[提示模块运行信息功能已打开]\n" + + "模块工作看起来一切正常,请自行测试是否能达到省电效果。\n\n" + + "已生效模块版本:${XPrefUtils.getString(HookMedium.ENABLE_MODULE_VERSION)}\n" + + "当前模式:${if (XPrefUtils.getBoolean(HookMedium.ENABLE_WHITE_MODE)) "保守模式" else "完全模式"}" + + "\n\n包名:${self.packageName}\n版本:${ + self.packageManager.getPackageInfo( + self.packageName, + 0 + ).versionName + }(${ + self.packageManager.getPackageInfo( + self.packageName, + 0 + ).versionCode + })" + "\n\nPS:模块只对挂后台锁屏情况下有省电效果,请不要将过多的群提醒,消息通知打开,这样子在使用过程时照样会极其耗电。\n" + + "如果你不想看到此提示。请在模块设置中关闭“提示模块运行信息”,此设置默认关闭。\n" + + "开发者 酷安 @星夜不荟\n未经允许禁止转载、修改或复制我的劳动成果。" + ) + .setPositiveButton("我知道了", null) + .show() + } catch (e: Exception) { + Toast.makeText( + self, + "模块已激活,但显示信息弹窗失败了\n$e", + Toast.LENGTH_SHORT + ).show() + } } }) } catch (e: Exception) { logE("handleLoadPackage: hook SplashActivity Failed", e) } - /*关闭保守模式后不再仅仅作用于系统电源锁*/ - if (!XPrefUtils.getBoolean("_white_mode")) { - val replaceMent = object : XC_MethodReplacement() { - override fun replaceHookedMethod(param: MethodHookParam?): Any? { - return null - } - } - /** - * 这个类 BaseChatPie 是控制聊天界面的 - * 里面有两个随机混淆的方法 - * 这两个方法一个是挂起电源锁常驻亮屏 - * 一个是停止常驻亮屏 - * 不由分说每个版本混淆的方法名都会变 - * 所以说每个版本重新适配 - 也可以提交分支帮我适配 - * 8.8.17 版本是 bd be - * 8.8.23 版本是 bf bg - * ⚠️ Hook 错了方法会造成闪退! - */ + /** 关闭保守模式后不再仅仅作用于系统电源锁 */ + if (!XPrefUtils.getBoolean(HookMedium.ENABLE_WHITE_MODE)) { try { - /*通过在 SplashActivity 里取到应用的版本号*/ + /** 通过在 SplashActivity 里取到应用的版本号 */ XposedHelpers.findAndHookMethod( "com.tencent.mobileqq.activity.SplashActivity", lpparam.classLoader, @@ -171,45 +236,14 @@ class HookMain : IXposedHookLoadPackage { object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam?) { - val self = param!!.thisObject as Activity + val self = param?.thisObject as? Activity ?: return val name = self.packageName val version = self.packageManager.getPackageInfo(name, 0).versionName - /*这个地方我们只处理 QQ*/ + /** 这个地方我们只处理 QQ */ try { - if (name == "com.tencent.mobileqq") { - when (version) { - "8.8.17" -> { - XposedHelpers.findAndHookMethod( - "com.tencent.mobileqq.activity.aio.core.BaseChatPie", - lpparam.classLoader, - "bd", - replaceMent - ) - XposedHelpers.findAndHookMethod( - "com.tencent.mobileqq.activity.aio.core.BaseChatPie", - lpparam.classLoader, - "be", - replaceMent - ) - } - "8.8.23" -> { - XposedHelpers.findAndHookMethod( - "com.tencent.mobileqq.activity.aio.core.BaseChatPie", - lpparam.classLoader, - "bf", - replaceMent - ) - XposedHelpers.findAndHookMethod( - "com.tencent.mobileqq.activity.aio.core.BaseChatPie", - lpparam.classLoader, - "bg", - replaceMent - ) - } - //TODO 后面的版本逐个适配 此方法没封装 目前比较笨蛋 主要是我懒得写 - } - } + if (name == "com.tencent.mobileqq") + lpparam.hookBaseChatPie(version) } catch (e: Exception) { logE("handleLoadPackage: hook BaseChatPie Failed", e) } @@ -227,7 +261,7 @@ class HookMain : IXposedHookLoadPackage { "com.tencent.mars.ilink.comm.WakerLock", lpparam.classLoader, "lock", Long::class.java, - replaceMent + replaceToNull ) } catch (e: Exception) { logE("handleLoadPackage: hook WakerLock Failed", e) @@ -246,7 +280,7 @@ class HookMain : IXposedHookLoadPackage { private var origDevice = "" override fun beforeHookedMethod(param: MethodHookParam?) { - /*由于在 onCreate 里有一行判断只要型号是 xiaomi 的设备就开电源锁,所以说这里临时替换成菊花厂*/ + /** 由于在 onCreate 里有一行判断只要型号是 xiaomi 的设备就开电源锁,所以说这里临时替换成菊花厂 */ origDevice = Build.MANUFACTURER if (Build.MANUFACTURER.toLowerCase(Locale.ROOT) == "xiaomi") XposedHelpers.setStaticObjectField( @@ -258,7 +292,7 @@ class HookMain : IXposedHookLoadPackage { override fun afterHookedMethod(param: MethodHookParam?) { (param?.thisObject as? Activity)?.finish() - /*这里再把型号替换回去 - 不影响应用变量等 Xposed 模块修改的型号*/ + /** 这里再把型号替换回去 - 不影响应用变量等 Xposed 模块修改的型号 */ XposedHelpers.setStaticObjectField( Build::class.java, "MANUFACTURER", @@ -276,7 +310,7 @@ class HookMain : IXposedHookLoadPackage { "com.tencent.mobileqq.activity.QQLSActivity\$14", lpparam.classLoader, "run", - replaceMent + replaceToNull ) } catch (e: Exception) { logE("handleLoadPackage: hook QQLSActivity Failed", e) @@ -345,15 +379,15 @@ class HookMain : IXposedHookLoadPackage { "writeReport", Boolean::class.java ).apply { isAccessible = true } - XposedBridge.hookMethod(onHook, replaceMent) - XposedBridge.hookMethod(doReport, replaceMent) - XposedBridge.hookMethod(afterHookedMethod, replaceMent) - XposedBridge.hookMethod(beforeHookedMethod, replaceMent) - XposedBridge.hookMethod(onAppBackground, replaceMent) - XposedBridge.hookMethod(onOtherProcReport, replaceMent) - XposedBridge.hookMethod(onProcessRun30Min, replaceMent) - XposedBridge.hookMethod(onProcessBG5Min, replaceMent) - XposedBridge.hookMethod(writeReport, replaceMent) + XposedBridge.hookMethod(onHook, replaceToNull) + XposedBridge.hookMethod(doReport, replaceToNull) + XposedBridge.hookMethod(afterHookedMethod, replaceToNull) + XposedBridge.hookMethod(beforeHookedMethod, replaceToNull) + XposedBridge.hookMethod(onAppBackground, replaceToNull) + XposedBridge.hookMethod(onOtherProcReport, replaceToNull) + XposedBridge.hookMethod(onProcessRun30Min, replaceToNull) + XposedBridge.hookMethod(onProcessBG5Min, replaceToNull) + XposedBridge.hookMethod(writeReport, replaceToNull) } } catch (e: Throwable) { logE("handleLoadPackage: hook WakerLockMonitor Failed", e) diff --git a/app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt b/app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt new file mode 100644 index 0000000..92e7a7d --- /dev/null +++ b/app/src/main/java/com/fankes/tsbattery/hook/HookMedium.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021. Fankes Studio(qzmmcn@163.com) + * + * This file is part of TSBattery. + * + * TSBattery is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * TSBattery 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file is Created by fankes on 2021/9/4. + */ + +package com.fankes.tsbattery.hook + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.util.Log +import androidx.annotation.Keep +import com.fankes.tsbattery.MainActivity + +@Keep +object HookMedium { + + const val ENABLE_HIDE_ICON = "_hide_icon" + const val ENABLE_RUN_INFO = "_tip_run_info" + const val ENABLE_WHITE_MODE = "_white_mode" + const val ENABLE_MODULE_VERSION = "_module_version" + + /** + * 判断模块是否激活 + * 在 [HookMain] 中 Hook 掉此方法 + * @return 激活状态 + */ + fun isHooked(): Boolean { + Log.d("TSBattery", "isHooked: true") + return isExpModuleActive() + } + + /** + * 新增太极判断方式 + * @return 是否激活 + */ + private fun isExpModuleActive(): Boolean { + var isExp = false + MainActivity.instance?.also { + try { + val uri = Uri.parse("content://me.weishu.exposed.CP/") + var result: Bundle? = null + try { + result = it.contentResolver.call(uri, "active", null, null) + } catch (e: RuntimeException) { + // TaiChi is killed, try invoke + try { + val intent = Intent("me.weishu.exp.ACTION_ACTIVE") + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + it.startActivity(intent) + } catch (e1: Throwable) { + return false + } + } + if (result == null) result = it.contentResolver.call(uri, "active", null, null) + if (result == null) return false + isExp = result.getBoolean("active", false) + } catch (ignored: Throwable) { + } + } + return isExp + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/tsbattery/utils/XPrefUtils.kt b/app/src/main/java/com/fankes/tsbattery/utils/XPrefUtils.kt index d74ba40..aad7d0d 100644 --- a/app/src/main/java/com/fankes/tsbattery/utils/XPrefUtils.kt +++ b/app/src/main/java/com/fankes/tsbattery/utils/XPrefUtils.kt @@ -26,6 +26,8 @@ object XPrefUtils { fun getBoolean(key: String) = pref.getBoolean(key, false) + fun getString(key: String) = pref.getString(key, "unknown") + private val pref: XSharedPreferences get() { val preferences = XSharedPreferences("com.fankes.tsbattery")