This commit is contained in:
2024-07-07 09:53:02 +08:00
12 changed files with 267 additions and 83 deletions

View File

@@ -21,6 +21,8 @@
package cc.hicore.hook;
import static io.github.qauxv.util.HostInfo.requireMinQQVersion;
import android.content.Context;
import androidx.annotation.NonNull;
import cc.ioctl.util.HookUtils;
@@ -31,6 +33,7 @@ import io.github.qauxv.bridge.AppRuntimeHelper;
import io.github.qauxv.dsl.FunctionEntryRouter;
import io.github.qauxv.hook.CommonSwitchFunctionHook;
import io.github.qauxv.util.Initiator;
import io.github.qauxv.util.QQVersion;
@FunctionHookEntry
@UiItemAgentEntry
@@ -55,6 +58,20 @@ public class ShowAccurateGaggedTime extends CommonSwitchFunctionHook {
@Override
protected boolean initOnce() throws Exception {
if (requireMinQQVersion(QQVersion.QQ_9_0_75)) {
HookUtils.hookBeforeIfEnabled(this,
Reflex.findMethod(Initiator.loadClass("com.tencent.qqnt.troop.impl.TroopGagUtils"), String.class,
"remainingTimeToStringCountDown", long.class), param -> {
long time = (long) param.args[0];
if (time <= 0) {
param.setResult("[0秒]");
return;
}
param.setResult(secondToTime(time));
});
return true;
}
HookUtils.hookBeforeIfEnabled(this,
Reflex.findMethod(Initiator.loadClass("com.tencent.mobileqq.troop.troopgag.api.impl.TroopGagServiceImpl"), String.class,
"gagTimeToStringCountDown", Context.class, long.class), param -> {

View File

@@ -23,6 +23,7 @@
package cc.ioctl.hook.chat
import cc.hicore.QApp.QAppUtils
import cc.ioctl.util.hookAfterIfEnabled
import cc.ioctl.util.hookBeforeIfEnabled
import io.github.qauxv.base.annotation.FunctionHookEntry
import io.github.qauxv.base.annotation.UiItemAgentEntry
@@ -36,9 +37,14 @@ import io.github.qauxv.dsl.FunctionEntryRouter
import io.github.qauxv.hook.CommonSwitchFunctionHook
import io.github.qauxv.util.Initiator
import io.github.qauxv.util.Log
import io.github.qauxv.util.QQVersion
import io.github.qauxv.util.SyncUtils
import io.github.qauxv.util.dexkit.CMessageRecordFactory
import io.github.qauxv.util.dexkit.DexKit
import io.github.qauxv.util.dexkit.Hd_GagInfoDisclosure_Method
import io.github.qauxv.util.dexkit.NContactUtils_getBuddyName
import io.github.qauxv.util.dexkit.NContactUtils_getDiscussionMemberShowName
import io.github.qauxv.util.requireMinQQVersion
import xyz.nextalone.util.get
@FunctionHookEntry
@@ -49,6 +55,8 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
targets = arrayOf(
CMessageRecordFactory,
NContactUtils_getDiscussionMemberShowName,
NContactUtils_getBuddyName,
Hd_GagInfoDisclosure_Method,
)
) {
@@ -57,6 +65,10 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.CHAT_CATEGORY
override val isAvailable = QAppUtils.isQQnt()
private fun getLongData(bArr: ByteArray, i: Int): Long {
return (((bArr[i].toInt() and 255) shl 24) + ((bArr[i + 1].toInt() and 255) shl 16) + ((bArr[i + 2].toInt() and 255) shl 8) + ((bArr[i + 3].toInt() and 255) shl 0)).toLong()
}
private fun getSecStr(sec: Long): String {
val (min, hour, day) = Triple("", "", "")
val d = sec / 86400
@@ -70,61 +82,81 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
}
private fun NtGrayTipHelper.NtGrayTipJsonBuilder.appendUserItem(uin: String, name: String) {
val uid = RelationNTUinAndUidApi.getUidFromUin(uin).takeIf { it.isNullOrEmpty() } ?: "u_0000000000000000000000"
val uid = RelationNTUinAndUidApi.getUidFromUin(uin).takeIf { it.isNullOrEmpty().not() } ?: "u_0000000000000000000000"
this.append(NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(uin, uid, name))
}
override fun initOnce(): Boolean {
val clzGagMgr = Initiator._TroopGagMgr()
val method = clzGagMgr.declaredMethods.single { method ->
val params = method.parameterTypes; params.size == 5
&& params[0] == Int::class.java
&& params[1] == Long::class.java
&& params[2] == Long::class.java
&& params[3] == Long::class.java
&& params[4] == ArrayList::class.java
&& method.returnType == Void.TYPE
private fun addGagTipMsg(selfUin: String, troopUin: String, opUin: String, victimUin: String, victimTime: Long) {
val opName = ContactUtils.getTroopMemberNick(troopUin, opUin)
val victimName = ContactUtils.getTroopMemberNick(troopUin, victimUin)
val builder = NtGrayTipHelper.NtGrayTipJsonBuilder()
when (victimUin) {
"0" -> {
if (opUin == selfUin) builder.appendUserItem(selfUin, "") else builder.appendUserItem(opUin, opName)
builder.appendText(if (victimTime == 0L) "关闭了全员禁言" else "开启了全员禁言")
}
selfUin -> {
builder.appendUserItem(selfUin, "")
builder.appendText("")
builder.appendUserItem(opUin, opName)
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
}
else -> {
builder.appendUserItem(victimUin, victimName)
builder.appendText("")
if (opUin == selfUin) builder.appendUserItem(selfUin, "") else builder.appendUserItem(opUin, opName)
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
}
}
hookBeforeIfEnabled(method) { param ->
val selfUin = AppRuntimeHelper.getAccount()
val troopUin = param.args[1].toString()
val opUin = param.args[2].toString()
val opName = ContactUtils.getDiscussionMemberShowName(AppRuntimeHelper.getAppRuntime()!!, troopUin, opUin)
val pushParams = param.args[4] as ArrayList<*>
val victimUin = pushParams[0].get("uin") as String
val victimName = ContactUtils.getDiscussionMemberShowName(AppRuntimeHelper.getAppRuntime()!!, troopUin, victimUin)
val victimTime = pushParams[0].get("gagLength") as Long
val builder = NtGrayTipHelper.NtGrayTipJsonBuilder()
when (victimUin) {
"0" -> {
if (opUin == selfUin) builder.appendUserItem(selfUin, "") else builder.appendUserItem(opUin, "$opName")
builder.appendText(if (victimTime == 0L) "关闭了全员禁言" else "开启了全员禁言")
}
NtGrayTipHelper.addLocalJsonGrayTipMsg(
AppRuntimeHelper.getAppRuntime()!!,
ContactCompat(ChatTypeConstants.GROUP, troopUin, ""),
NtGrayTipHelper.createLocalJsonElement(NtGrayTipHelper.AIO_AV_GROUP_NOTICE.toLong(), builder.build().toString(), ""),
true,
true
) { result, uin ->
if (result != 0) {
Log.e("GagInfoDisclosure error: addLocalJsonGrayTipMsg failed, result=$result, uin=$uin")
}
}
}
selfUin -> {
builder.appendUserItem(selfUin, "")
builder.appendText("")
builder.appendUserItem(opUin, "$opName")
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
}
else -> {
builder.appendUserItem(victimUin, "$victimName")
builder.appendText("")
if (opUin == selfUin) builder.appendUserItem(selfUin, "") else builder.appendUserItem(opUin, "$opName")
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
override fun initOnce(): Boolean {
if (requireMinQQVersion(QQVersion.QQ_9_0_73)) {
hookAfterIfEnabled(DexKit.requireMethodFromCache(Hd_GagInfoDisclosure_Method)) { param ->
val msgInfo = param.args[1]
val vMsg = msgInfo.get("vMsg") as ByteArray? ?: return@hookAfterIfEnabled
if (vMsg[4].toInt() == 12) {
val selfUin = AppRuntimeHelper.getAccount()
val troopUin = getLongData(vMsg, 0).toString()
val opUin = getLongData(vMsg, 6).toString()
val victimUinTmp = getLongData(vMsg, 16)
val victimUin = (victimUinTmp.takeIf { it > 0 } ?: (victimUinTmp and 0xFFFFFFFFL)).toString()
val victimTime = getLongData(vMsg, 20)
addGagTipMsg(selfUin, troopUin, opUin, victimUin, victimTime)
}
}
NtGrayTipHelper.addLocalJsonGrayTipMsg(
AppRuntimeHelper.getAppRuntime()!!,
ContactCompat(ChatTypeConstants.GROUP, troopUin, ""),
NtGrayTipHelper.createLocalJsonElement(NtGrayTipHelper.AIO_AV_GROUP_NOTICE.toLong(), builder.build().toString(), ""),
true,
true
) { result, uin ->
if (result != 0) {
Log.e("GagInfoDisclosure error: addLocalJsonGrayTipMsg failed, result=$result, uin=$uin")
}
} else {
val troopGagClass = Initiator.loadClass("com.tencent.mobileqq.troop.utils.TroopGagMgr")
val method = troopGagClass.declaredMethods.single { method ->
val params = method.parameterTypes; params.size == 5
&& params[0] == Int::class.java
&& params[1] == Long::class.java
&& params[2] == Long::class.java
&& params[3] == Long::class.java
&& params[4] == ArrayList::class.java
&& method.returnType == Void.TYPE
}
hookBeforeIfEnabled(method) { param ->
val selfUin = AppRuntimeHelper.getAccount()
val troopUin = param.args[1].toString()
val opUin = param.args[2].toString()
val pushParams = param.args[4] as ArrayList<*>
val victimUin = pushParams[0].get("uin") as String
val victimTime = pushParams[0].get("gagLength") as Long
addGagTipMsg(selfUin, troopUin, opUin, victimUin, victimTime)
}
}
return true

View File

@@ -32,6 +32,7 @@ import cc.ioctl.util.HookUtils
import com.github.kyuubiran.ezxhelper.utils.isAbstract
import de.robv.android.xposed.XC_MethodHook
import io.github.duzhaokun123.hook.MessageCopyHook
import io.github.duzhaokun123.hook.MessageTTSHook
import io.github.qauxv.base.annotation.FunctionHookEntry
import io.github.qauxv.hook.BasePersistBackgroundHook
import io.github.qauxv.util.Initiator
@@ -52,7 +53,8 @@ object MenuBuilderHook : BasePersistBackgroundHook() {
MessageCopyHook,
PicCopyToClipboard,
MiniAppDirectJump,
CopyMarkdown
CopyMarkdown,
MessageTTSHook,
)
override fun initOnce(): Boolean {

View File

@@ -22,6 +22,7 @@
package com.xiaoniu.hook
import com.github.kyuubiran.ezxhelper.utils.hookBefore
import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant
import io.github.qauxv.base.annotation.FunctionHookEntry
import io.github.qauxv.base.annotation.UiItemAgentEntry
@@ -29,7 +30,9 @@ import io.github.qauxv.dsl.FunctionEntryRouter
import io.github.qauxv.hook.CommonSwitchFunctionHook
import io.github.qauxv.util.QQVersion
import io.github.qauxv.util.requireMinQQVersion
import xyz.nextalone.util.clazz
import xyz.nextalone.util.method
import xyz.nextalone.util.set
import xyz.nextalone.util.throwOrTrue
@FunctionHookEntry
@@ -38,9 +41,18 @@ object DisableTroopFlame : CommonSwitchFunctionHook() {
override val name = "屏蔽群火苗"
override fun initOnce() = throwOrTrue {
"Lcom/tencent/mobileqq/troop/flame/api/impl/TroopFlameApiImpl;->getGroupExtFlameData(Lcom/tencent/mobileqq/data/troop/TroopInfoExt;)Ltencent/trpcprotocol/IqunFlameManageSvrPB\$GroupExtFlameData;"
.method
.hookReturnConstant(null)
if (requireMinQQVersion(QQVersion.QQ_9_0_75)) {
// Waiting for a better solution...
"com.tencent.mobileqq.troop.flame.api.impl.TroopFlameApiImpl".clazz!!
.method("getFlameViewDataFromPB")!!
.hookBefore {
it.args[0].set("switchState", 0)
it.args[0].set("state", 0)
}
} else
"Lcom/tencent/mobileqq/troop/flame/api/impl/TroopFlameApiImpl;->getGroupExtFlameData(Lcom/tencent/mobileqq/data/troop/TroopInfoExt;)Ltencent/trpcprotocol/IqunFlameManageSvrPB\$GroupExtFlameData;"
.method
.hookReturnConstant(null)
}
override val uiItemLocation = FunctionEntryRouter.Locations.Simplify.CHAT_GROUP_OTHER

View File

@@ -26,25 +26,37 @@ import android.app.Activity
import android.content.Context
import android.speech.tts.TextToSpeech
import android.view.View
import cc.hicore.QApp.QAppUtils
import cc.ioctl.util.HostInfo
import cc.ioctl.util.Reflex
import cc.ioctl.util.afterHookIfEnabled
import com.xiaoniu.dispatcher.OnMenuBuilder
import com.xiaoniu.util.ContextUtils
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import io.github.duzhaokun123.hook.MessageCopyHook.TAG
import io.github.duzhaokun123.util.TTS
import io.github.qauxv.R
import io.github.qauxv.base.annotation.FunctionHookEntry
import io.github.qauxv.base.annotation.UiItemAgentEntry
import io.github.qauxv.dsl.FunctionEntryRouter
import io.github.qauxv.hook.CommonSwitchFunctionHook
import io.github.qauxv.step.Step
import io.github.qauxv.ui.CommonContextWrapper
import io.github.qauxv.util.CustomMenu
import io.github.qauxv.util.Initiator
import io.github.qauxv.util.QQVersion
import io.github.qauxv.util.Toasts
import io.github.qauxv.util.dexkit.DexDeobfsProvider
import io.github.qauxv.util.dexkit.DexKit
import io.github.qauxv.util.dexkit.DexKitFinder
import io.github.qauxv.util.dexkit.TextMsgItem_getText
import java.lang.reflect.Modifier
@FunctionHookEntry
@UiItemAgentEntry
object MessageTTSHook : CommonSwitchFunctionHook() {
object MessageTTSHook : CommonSwitchFunctionHook(), OnMenuBuilder, DexKitFinder {
override val name: String
get() = "文字消息转语音 (使用系统 TTS)"
@@ -52,6 +64,8 @@ object MessageTTSHook : CommonSwitchFunctionHook() {
get() = "提示失败多半是没设置系统 TTS 引擎"
override fun initOnce(): Boolean {
if (QAppUtils.isQQnt()) return true
val cl_ArkAppItemBuilder = Initiator._TextItemBuilder()
XposedHelpers.findAndHookMethod(
cl_ArkAppItemBuilder, "a", Int::class.javaPrimitiveType, Context::class.java,
@@ -106,11 +120,93 @@ object MessageTTSHook : CommonSwitchFunctionHook() {
R.id.item_tts -> {
TTS.speak(wc, Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: "")
}
R.id.item_tts2 -> {
val msg = Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: ""
TTS.showConfigDialog(wc, msg)
}
}
}
override val targetComponentTypes: Array<String>
get() = arrayOf("com.tencent.mobileqq.aio.msglist.holder.component.text.AIOTextContentComponent")
override fun onGetMenuNt(msg: Any, componentType: String, param: XC_MethodHook.MethodHookParam) {
if (!isEnabled) return
val item = CustomMenu.createItemIconNt(msg, "TTS", 0, R.id.item_tts) {
val ctx = ContextUtils.getCurrentActivity()
val wc = CommonContextWrapper.createAppCompatContext(ctx)
val text = try {
DexKit.requireMethodFromCache(TextMsgItem_getText).also {
it.isAccessible = true
}.invoke(msg) as CharSequence
} catch (e: Exception) {
"${e.javaClass.name}: ${e.message}\n" + (e.stackTrace.joinToString("\n"))
}
TTS.speak(wc, text.toString())
}
val item2 = CustomMenu.createItemIconNt(msg, "TTS+", 0, R.id.item_tts2) {
val ctx = ContextUtils.getCurrentActivity()
val wc = CommonContextWrapper.createAppCompatContext(ctx)
val text = try {
DexKit.requireMethodFromCache(TextMsgItem_getText).also {
it.isAccessible = true
}.invoke(msg) as CharSequence
} catch (e: Exception) {
"${e.javaClass.name}: ${e.message}\n" + (e.stackTrace.joinToString("\n"))
}
TTS.showConfigDialog(wc, text.toString())
}
param.result = (param.result as List<*>) + item + item2
}
/**
* see MessageCopyHook
*/
override fun makePreparationSteps(): Array<Step> {
return arrayOf(object : Step {
override fun step(): Boolean {
return doFind()
}
override fun isDone(): Boolean {
return !isNeedFind
}
override fun getPriority(): Int {
return 0
}
override fun getDescription(): String {
return "文本消息相关方法查找中"
}
})
}
override val isNeedFind: Boolean
get() = HostInfo.requireMinQQVersion(QQVersion.QQ_8_9_63) && TextMsgItem_getText.descCache == null
override fun doFind(): Boolean {
DexDeobfsProvider.getCurrentBackend().use { backend ->
val dexKit = backend.getDexKitBridge()
android.util.Log.d(TAG, "doFind: doFind")
val getText = dexKit.findMethod {
searchPackages("com.tencent.mobileqq.aio.msg")
matcher {
modifiers = Modifier.PRIVATE
returnType = "java.lang.CharSequence"
paramCount = 0
usingNumbers(24)
usingStrings("biz_src_jc_aio")
// addCall {
// name = "getQQText"
// }
}
}.firstOrNull() ?: return false
android.util.Log.d(TAG, "doFind: $getText")
TextMsgItem_getText.descCache = getText.descriptor
}
return true
}
}

View File

@@ -136,6 +136,7 @@ object TTS {
}
fun showConfigDialog(wc: Context, text: String = "") {
if (!checkInit(wc)) return
val binding = Tts2DialogBinding.inflate(LayoutInflater.from(wc))
binding.etMsg.setText(text)
binding.tvVoice.text = instance.voice?.toString() ?: "null"

View File

@@ -29,8 +29,10 @@ import com.tencent.common.app.AppInterface;
import de.robv.android.xposed.XposedHelpers;
import io.github.qauxv.base.annotation.DexDeobfs;
import io.github.qauxv.bridge.ntapi.RelationNTUinAndUidApi;
import io.github.qauxv.util.HostInfo;
import io.github.qauxv.util.Initiator;
import io.github.qauxv.util.Log;
import io.github.qauxv.util.QQVersion;
import io.github.qauxv.util.dexkit.DexKit;
import io.github.qauxv.util.dexkit.NContactUtils_getBuddyName;
import io.github.qauxv.util.dexkit.NContactUtils_getDiscussionMemberShowName;
@@ -59,23 +61,25 @@ public class ContactUtils {
Objects.requireNonNull(memberUin);
AppRuntime app = AppRuntimeHelper.getQQAppInterface();
assert app != null;
try {
Object mTroopManager = ManagerHelper.getTroopManager();
Object troopMemberInfo = Reflex.invokeVirtualDeclaredOrdinal(mTroopManager, 0, 3, false,
troopUin, memberUin,
String.class, String.class,
Initiator._TroopMemberInfo());
if (troopMemberInfo != null) {
String troopnick = (String) XposedHelpers.getObjectField(troopMemberInfo, "troopnick");
if (troopnick != null) {
String ret = troopnick.replace(UNICODE_RLO, "");
if (ret.trim().length() > 0) {
return ret;
if (!HostInfo.requireMinQQVersion(QQVersion.QQ_9_0_25)) {
try {
Object mTroopManager = ManagerHelper.getTroopManager();
Object troopMemberInfo = Reflex.invokeVirtualDeclaredOrdinal(mTroopManager, 0, 3, false,
troopUin, memberUin,
String.class, String.class,
Initiator._TroopMemberInfo());
if (troopMemberInfo != null) {
String troopnick = (String) XposedHelpers.getObjectField(troopMemberInfo, "troopnick");
if (troopnick != null) {
String ret = troopnick.replace(UNICODE_RLO, "");
if (ret.trim().length() > 0) {
return ret;
}
}
}
} catch (Exception | LinkageError e) {
Log.e(e);
}
} catch (Exception | LinkageError e) {
Log.e(e);
}
try {
String ret = getDiscussionMemberShowName(app, troopUin, memberUin);

View File

@@ -125,4 +125,6 @@ public class QQVersion {
public static final long QQ_9_0_68 = 6612;
public static final long QQ_9_0_70 = 6676;
public static final long QQ_9_0_71 = 6702;
public static final long QQ_9_0_73 = 6722;
public static final long QQ_9_0_75 = 6786;
}

View File

@@ -995,3 +995,10 @@ data object Hd_DisableGrowHalfLayer_Method : DexKitTarget.UsingStringVector() {
m.returnType == Void.TYPE && m.paramCount == 3
}
}
data object Hd_GagInfoDisclosure_Method : DexKitTarget.UsingStr() {
override val findMethod = true
override val traitString = arrayOf("<---0x2dc push groupCode:")
override val declaringClass = "com.tencent.imcore.message"
override val filter = DexKitFilter.strInClsName("com/tencent/imcore/message/")
}

View File

@@ -97,6 +97,7 @@ object FakePicSize : BaseFunctionHook(
val msgServiceClass = Initiator.loadClass("com.tencent.qqnt.kernel.nativeinterface.IKernelMsgService\$CppProxy")
hookBeforeIfEnabled(msgServiceClass.method("sendMsg")!!) { param ->
val size = sizeMap.values.toList()[sizeIndex]
if (size == 0) return@hookBeforeIfEnabled
val elements = param.args[2] as ArrayList<*>
for (element in elements) {
val msgElement = (element as MsgElement)

View File

@@ -45,6 +45,7 @@ import cc.ioctl.util.HostInfo
import cc.ioctl.util.Reflex
import cc.ioctl.util.hookAfterIfEnabled
import cc.ioctl.util.hookBeforeIfEnabled
import com.github.kyuubiran.ezxhelper.utils.paramCount
import io.github.qauxv.base.annotation.FunctionHookEntry
import io.github.qauxv.base.annotation.UiItemAgentEntry
import io.github.qauxv.dsl.FunctionEntryRouter
@@ -100,11 +101,11 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
lateinit var buildNotification: Method
lateinit var recentInfoBuilder: Method
cNotificationFacade.declaredMethods.forEach {
if (it.parameterTypes.size != 3) return@forEach
if (it.parameterTypes[0] != cAppRuntime) return@forEach
if (it.parameterTypes[2] == cCommonInfo) {
if (it.paramCount < 3 || it.parameterTypes[0] != cAppRuntime) return@forEach
if (it.paramCount == 3 && it.parameterTypes[2] == cCommonInfo) {
buildNotification = it
} else if (it.parameterTypes[1] == cRecentInfo) {
} else if (it.paramCount >= 3 && it.parameterTypes[1] == cRecentInfo && it.parameterTypes[2] == Boolean::class.java) {
// paramCount=4 since 9.0.75
recentInfoBuilder = it
}
}
@@ -131,7 +132,8 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
val info = QQRecentContactInfo(pair.first)
notificationInfoMap.remove(oldNotification.contentIntent)
if (info.chatType == 1 || info.chatType == 2) {
val content = info.abstractContent?.joinToString(separator = "") { it.get("content", String::class.java) ?: "[未解析消息]" } ?: return@hookBeforeIfEnabled
val content =
info.abstractContent?.joinToString(separator = "") { it.get("content", String::class.java) ?: "[未解析消息]" } ?: return@hookBeforeIfEnabled
val senderName = info.getUserName() ?: return@hookBeforeIfEnabled
val senderUin = info.senderUin ?: return@hookBeforeIfEnabled
val senderIcon: IconCompat
@@ -146,17 +148,23 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
// 好友消息
when (info.chatType) {
1 -> {
senderIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
senderIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon())
?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
shortcut = getShortcut("private_$senderUin", senderName, senderIcon, pair.second)
}
2 -> {
groupName = info.peerName ?: return@hookBeforeIfEnabled
groupUin = info.peerUin ?: return@hookBeforeIfEnabled
senderIcon = avatarHelper.getAvatar(senderUin.toString()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
groupIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
senderIcon = avatarHelper.getAvatar(senderUin.toString()) ?: IconCompat.createWithBitmap(
ResUtils.loadDrawableFromAsset("face.png", context).toBitmap()
)
groupIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon())
?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
shortcut = getShortcut("group_$groupUin", groupName, groupIcon, pair.second)
}
else -> {
// Impossible
throw Error("what the hell?")
@@ -238,11 +246,13 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
var messageStyle = historyMessage["$channelId+$mainUin"]
if (messageStyle == null) {
messageStyle = MessagingStyle(Person.Builder()
.setName(mainName)
.setIcon(mainIcon)
.setKey(mainUin.toString())
.build())
messageStyle = MessagingStyle(
Person.Builder()
.setName(mainName)
.setIcon(mainIcon)
.setKey(mainUin.toString())
.build()
)
messageStyle.conversationTitle = mainName
messageStyle.isGroupConversation = groupUin != null
historyMessage["$channelId+$mainUin"] = messageStyle

View File

@@ -64,7 +64,7 @@ object ChatInputHint : CommonConfigFunctionHook("na_chat_input_hint", arrayOf(NB
override fun initOnce(): Boolean = throwOrTrue {
if (requireMinQQVersion(QQVersion.QQ_8_9_63)) {
// 私聊 && QQ_9_0_50版本后的群聊
// 私聊 && QQ9.0.35版本后的群聊
DexKit.requireMethodFromCache(AIO_InputRootInit_QQNT).hookAfter(this) {
it.thisObject.javaClass.declaredFields.single { it.type == EditText::class.java }.apply {
isAccessible = true
@@ -72,8 +72,8 @@ object ChatInputHint : CommonConfigFunctionHook("na_chat_input_hint", arrayOf(NB
et.hint = getValue()
}
}
// QQ_9_0_50版本前的群聊
if (!requireMinQQVersion(QQVersion.QQ_9_0_50)) {
// QQ9.0.35版本前的群聊
if (!requireMinQQVersion(QQVersion.QQ_9_0_35)) {
when { // Lcom/tencent/mobileqq/aio/input/anonymous/AnonymousModeInputVBDelegate;->setNotAnonymousHint()V
requireMinQQVersion(QQVersion.QQ_9_0_30) -> "Lcom/tencent/mobileqq/aio/input/c/c;->l()V"
requireMinQQVersion(QQVersion.QQ_9_0_20) -> "Lcom/tencent/mobileqq/aio/input/b/c;->l()V"