Skip to content

Commit b0bb0ce

Browse files
committed
feat: add support for version 2.26.12.xx
1 parent 76c6699 commit b0bb0ce

File tree

10 files changed

+130
-88
lines changed

10 files changed

+130
-88
lines changed

app/src/main/java/com/wmods/wppenhacer/xposed/core/db/MessageHistory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVers
202202
}
203203
}
204204

205+
@Override
206+
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
207+
}
208+
205209
private String createSeenMessageCacheKey(String jid, String message_id, MessageType type) {
206210
return jid + "_" + message_id + "_" + type.ordinal();
207211
}

app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import android.net.Uri;
1010
import android.view.LayoutInflater;
1111
import android.view.Menu;
12-
import android.view.MenuInflater;
12+
import android.view.MenuItem;
1313
import android.view.View;
1414
import android.view.ViewGroup;
1515
import android.widget.FrameLayout;
@@ -780,14 +780,19 @@ public synchronized static Method[] loadViewOnceMethod(ClassLoader classLoader)
780780
*/
781781
public synchronized static Method loadViewOnceDownloadMenuMethod(ClassLoader classLoader) throws Exception {
782782
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> {
783-
var clazz = XposedHelpers.findClass("com.whatsapp.mediaview.MediaViewFragment", classLoader);
784-
var method = Arrays.stream(clazz.getDeclaredMethods()).filter(m -> m.getParameterCount() == 2 &&
785-
Objects.equals(m.getParameterTypes()[0], Menu.class) &&
786-
Objects.equals(m.getParameterTypes()[1], MenuInflater.class) &&
787-
m.getDeclaringClass() == clazz).findFirst();
788-
if (!method.isPresent())
789-
throw new Exception("ViewOnceDownloadMenu method not found");
790-
return method.get();
783+
var id1 = Utils.getID("ic_viewonce", "drawable");
784+
var setShowAsAction = MenuItem.class.getDeclaredMethod("setShowAsAction", int.class);
785+
var methodData = dexkit.findMethod(
786+
FindMethod.create().matcher(MethodMatcher.create()
787+
.addUsingNumber(id1)
788+
.addInvoke(DexSignUtil.getMethodDescriptor(setShowAsAction))
789+
)
790+
);
791+
var result = methodData.stream().filter(m -> m.getParamCount() > 1 &&
792+
m.getParamTypeNames().contains(Menu.class.getName())
793+
).findFirst();
794+
if (!result.isPresent()) throw new Exception("ViewOnceDownloadMenu method not found");
795+
return result.get().getMethodInstance(classLoader);
791796
});
792797
}
793798

@@ -1582,36 +1587,6 @@ public synchronized static Method loadMaterialAlertDialog(ClassLoader loader) th
15821587
});
15831588
}
15841589

1585-
public synchronized static Method loadGetIntPreferences(ClassLoader loader) throws Exception {
1586-
return UnobfuscatorCache.getInstance().getMethod(loader, () -> {
1587-
var methodList = dexkit.findMethod(new FindMethod().matcher(
1588-
new MethodMatcher().paramCount(2).addParamType(SharedPreferences.class).addParamType(String.class)
1589-
.modifiers(Modifier.STATIC | Modifier.PUBLIC).returnType(int.class)));
1590-
if (methodList.isEmpty())
1591-
throw new RuntimeException("CallConfirmationLimit method not found");
1592-
return methodList.get(0).getMethodInstance(loader);
1593-
});
1594-
}
1595-
1596-
public synchronized static Method loadAudioProximitySensorMethod(ClassLoader loader) throws Exception {
1597-
return UnobfuscatorCache.getInstance().getMethod(loader, () -> {
1598-
var method = findFirstMethodUsingStrings(loader, StringMatchType.Contains,
1599-
"messageaudioplayer/onearproximity");
1600-
if (method == null)
1601-
throw new RuntimeException("ProximitySensor method not found");
1602-
return method;
1603-
});
1604-
}
1605-
1606-
public synchronized static Method loadGroupAdminMethod(ClassLoader loader) throws Exception {
1607-
return UnobfuscatorCache.getInstance().getMethod(loader, () -> {
1608-
var method = dexkit.findMethod(
1609-
FindMethod.create().matcher(MethodMatcher.create().name("setupUsernameInGroupViewContainer")));
1610-
if (method.isEmpty())
1611-
throw new RuntimeException("GroupAdmin method not found");
1612-
return method.get(0).getMethodInstance(loader);
1613-
});
1614-
}
16151590

16161591
public synchronized static Method loadJidFactory(ClassLoader loader) throws Exception {
16171592
return UnobfuscatorCache.getInstance().getMethod(loader, () -> {

app/src/main/java/com/wmods/wppenhacer/xposed/features/customization/HideSeenView.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ public void doHook() throws Throwable {
4040
// Register listener
4141
ConversationItemListener.conversationListeners.add(new ConversationItemListener.OnConversationItemListener() {
4242
@Override
43-
public void onItemBind(FMessageWpp fMessage, ViewGroup viewGroup) {
43+
public void onItemBind(FMessageWpp fMessage, ViewGroup view, int position, View convertView) {
4444
if (fMessage.getKey().isFromMe) return;
45-
updateBubbleView(fMessage, viewGroup);
45+
updateBubbleView(fMessage, view);
4646
}
4747
});
4848
}

app/src/main/java/com/wmods/wppenhacer/xposed/features/general/AntiRevoke.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.wmods.wppenhacer.xposed.features.general;
22

33
import android.text.TextUtils;
4+
import android.view.View;
45
import android.view.ViewGroup;
56
import android.widget.TextView;
67
import android.widget.Toast;
@@ -149,10 +150,10 @@ protected void beforeHookedMethod(MethodHookParam param) throws Exception {
149150

150151
ConversationItemListener.conversationListeners.add(new ConversationItemListener.OnConversationItemListener() {
151152
@Override
152-
public void onItemBind(FMessageWpp fMessage, ViewGroup viewGroup) {
153+
public void onItemBind(FMessageWpp fMessage, ViewGroup view, int position, View convertView) {
153154
if (fMessage.getKey().isFromMe)
154155
return;
155-
var dateTextView = (TextView) viewGroup.findViewById(Utils.getID("date", "id"));
156+
var dateTextView = (TextView) view.findViewById(Utils.getID("date", "id"));
156157
bindRevokedMessageUI(fMessage, dateTextView, "antirevoke");
157158
}
158159
});

app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Others.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
407407

408408
ConversationItemListener.conversationListeners.add(new ConversationItemListener.OnConversationItemListener() {
409409
@Override
410-
public void onItemBind(FMessageWpp fMessage, ViewGroup viewGroup) {
410+
public void onItemBind(FMessageWpp fMessage, ViewGroup view, int position, View convertView) {
411411
var onMultiClickListener = new OnMultiClickListener(2, 500) {
412412
@Override
413413
public void onMultiClick(View view) {
@@ -425,7 +425,7 @@ public void onMultiClick(View view) {
425425
WppCore.sendReaction(emoji, fMessage.getObject());
426426
}
427427
};
428-
viewGroup.setOnClickListener(onMultiClickListener);
428+
view.setOnClickListener(onMultiClickListener);
429429
}
430430
});
431431
}

app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
9494
new ConversationItemListener.OnConversationItemListener() {
9595

9696
@Override
97-
public void onItemBind(FMessageWpp fMessage, ViewGroup viewGroup) {
98-
var textView = (TextView) viewGroup.findViewById(Utils.getID("edit_label", "id"));
97+
public void onItemBind(FMessageWpp fMessage, ViewGroup view, int position, View convertView) {
98+
var textView = (TextView) view.findViewById(Utils.getID("edit_label", "id"));
9999
if (textView != null && !textView.getText().toString().contains(strEmoji)) {
100100
textView.getPaint().setUnderlineText(true);
101101
textView.append(strEmoji);

app/src/main/java/com/wmods/wppenhacer/xposed/features/listeners/ConversationItemListener.java

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.wmods.wppenhacer.xposed.features.listeners;
22

3+
import android.app.Activity;
34
import android.view.View;
45
import android.view.ViewGroup;
56
import android.widget.HeaderViewListAdapter;
@@ -13,7 +14,6 @@
1314
import com.wmods.wppenhacer.xposed.core.components.FMessageWpp;
1415

1516
import java.util.HashSet;
16-
import java.util.Objects;
1717

1818
import de.robv.android.xposed.XC_MethodHook;
1919
import de.robv.android.xposed.XSharedPreferences;
@@ -22,7 +22,7 @@
2222

2323
public class ConversationItemListener extends Feature {
2424

25-
public static HashSet<OnConversationItemListener> conversationListeners = new HashSet<>();
25+
public static final HashSet<OnConversationItemListener> conversationListeners = new HashSet<>();
2626
private static ListAdapter mAdapter;
2727
private static XC_MethodHook.Unhook hooked;
2828

@@ -39,33 +39,59 @@ public void doHook() throws Throwable {
3939
XposedHelpers.findAndHookMethod(ListView.class, "setAdapter", ListAdapter.class, new XC_MethodHook() {
4040
@Override
4141
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
42-
if (!WppCore.getCurrentActivity().getClass().getSimpleName().equals("Conversation"))
42+
Activity currentActivity = WppCore.getCurrentActivity();
43+
if (currentActivity == null || !currentActivity.getClass().getSimpleName().equals("Conversation")) {
4344
return;
44-
if (((ListView) param.thisObject).getId() != android.R.id.list) return;
45+
}
46+
47+
ListView listView = (ListView) param.thisObject;
48+
if (listView.getId() != android.R.id.list) {
49+
return;
50+
}
51+
4552
ListAdapter adapter = (ListAdapter) param.args[0];
4653
if (adapter instanceof HeaderViewListAdapter) {
4754
adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter();
4855
}
49-
if (adapter == null) return;
56+
57+
if (adapter == null) {
58+
return;
59+
}
60+
5061
mAdapter = adapter;
51-
if (hooked != null) hooked.unhook();
62+
63+
for (OnConversationItemListener listener : conversationListeners) {
64+
listener.onAttachAdapter(mAdapter);
65+
}
66+
67+
if (hooked != null) {
68+
hooked.unhook();
69+
}
70+
5271
var method = mAdapter.getClass().getDeclaredMethod("getView", int.class, View.class, ViewGroup.class);
5372
hooked = XposedBridge.hookMethod(method, new XC_MethodHook() {
5473
@Override
5574
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
5675
if (param.thisObject != mAdapter) return;
76+
5777
var position = (int) param.args[0];
78+
var convertView = (View) param.args[1];
5879
var viewGroup = (ViewGroup) param.getResult();
80+
5981
if (viewGroup == null) return;
82+
6083
Object fMessageObj = mAdapter.getItem(position);
6184
if (fMessageObj == null) return;
85+
6286
var fMessage = new FMessageWpp(fMessageObj);
63-
var extraFMessage = XposedHelpers.getAdditionalInstanceField(param.thisObject, "fMessage");
64-
if (Objects.equals(fMessage, extraFMessage)) return;
87+
6588
for (OnConversationItemListener listener : conversationListeners) {
66-
viewGroup.post(() -> listener.onItemBind(fMessage, viewGroup));
89+
try {
90+
listener.onItemBind(fMessage, viewGroup, position, convertView);
91+
} catch (Throwable e) {
92+
logDebug(e);
93+
}
6794
}
68-
XposedHelpers.setAdditionalInstanceField(param.thisObject, "fMessage", fMessage);
6995
}
7096
});
7197
}
@@ -82,9 +108,16 @@ public abstract static class OnConversationItemListener {
82108
/**
83109
* Called when a message item is rendered in the conversation
84110
*
85-
* @param fMessage The message
86-
* @param viewGroup The view associated with the item
111+
* @param fMessage The message
112+
* @param view The view associated with the item
113+
* @param position The position
114+
* @param convertView The view from the adapter
115+
* @throws Throwable Errors caught in the hook
87116
*/
88-
public abstract void onItemBind(FMessageWpp fMessage, ViewGroup viewGroup);
117+
public abstract void onItemBind(FMessageWpp fMessage, ViewGroup view, int position, View convertView) throws Throwable;
118+
119+
public void onAttachAdapter(ListAdapter adapter) {
120+
121+
}
89122
}
90-
}
123+
}
Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
package com.wmods.wppenhacer.xposed.features.others;
22

3-
import android.annotation.SuppressLint;
43
import android.view.Gravity;
54
import android.view.View;
5+
import android.view.ViewGroup;
66
import android.widget.ImageView;
77
import android.widget.LinearLayout;
88

99
import androidx.annotation.NonNull;
1010

11+
import com.wmods.wppenhacer.R;
1112
import com.wmods.wppenhacer.xposed.core.Feature;
1213
import com.wmods.wppenhacer.xposed.core.WppCore;
1314
import com.wmods.wppenhacer.xposed.core.components.FMessageWpp;
1415
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator;
16+
import com.wmods.wppenhacer.xposed.features.listeners.ConversationItemListener;
1517
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;
16-
import com.wmods.wppenhacer.xposed.utils.ResId;
1718
import com.wmods.wppenhacer.xposed.utils.Utils;
1819

19-
import de.robv.android.xposed.XC_MethodHook;
2020
import de.robv.android.xposed.XSharedPreferences;
21-
import de.robv.android.xposed.XposedBridge;
22-
import de.robv.android.xposed.XposedHelpers;
2321

2422
public class GroupAdmin extends Feature {
2523

@@ -30,51 +28,80 @@ public GroupAdmin(@NonNull ClassLoader classLoader, @NonNull XSharedPreferences
3028
@Override
3129
public void doHook() throws Throwable {
3230
if (!prefs.getBoolean("admin_grp", false)) return;
31+
3332
var jidFactory = Unobfuscator.loadJidFactory(classLoader);
34-
var grpAdmin1 = Unobfuscator.loadGroupAdminMethod(classLoader);
3533
var grpcheckAdmin = Unobfuscator.loadGroupCheckAdminMethod(classLoader);
36-
var hooked = new XC_MethodHook() {
37-
@SuppressLint("ResourceType")
34+
35+
ConversationItemListener.conversationListeners.add(new ConversationItemListener.OnConversationItemListener() {
3836
@Override
39-
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
40-
var targetObj = param.thisObject != null ? param.thisObject : param.args[1];
41-
Object fMessageObj = XposedHelpers.callMethod(targetObj, "getFMessage");
42-
var fMessage = new FMessageWpp(fMessageObj);
43-
var userJid = fMessage.getUserJid();
37+
public void onItemBind(FMessageWpp fMessage, ViewGroup view, int position, View convertView) throws Throwable {
4438
var chatCurrentJid = WppCore.getCurrentUserJid();
45-
if (!chatCurrentJid.isGroup()) return;
46-
var field = ReflectionUtils.getFieldByType(targetObj.getClass(), grpcheckAdmin.getDeclaringClass());
47-
var grpParticipants = field.get(targetObj);
48-
var jidGrp = jidFactory.invoke(null, chatCurrentJid.getUserRawString());
49-
var result = grpcheckAdmin.invoke(grpParticipants, jidGrp, userJid.userJid);
50-
var view = (View) targetObj;
39+
if (chatCurrentJid == null || !chatCurrentJid.isGroup()) return;
40+
var grpcheckAdminClass = grpcheckAdmin.getDeclaringClass();
41+
var field = ReflectionUtils.findFieldUsingFilter(view.getClass(), f -> f.getType().isAssignableFrom(grpcheckAdminClass));
42+
field.setAccessible(true);
43+
var grpParticipants = field.get(view);
5144
var context = view.getContext();
5245
ImageView iconAdmin;
53-
if ((iconAdmin = view.findViewById(0x7fff0010)) == null) {
46+
if ((iconAdmin = view.findViewWithTag("admin_icon")) == null) {
5447
var nameGroup = (LinearLayout) view.findViewById(Utils.getID("name_in_group", "id"));
48+
if (nameGroup == null) return;
5549
var view1 = new LinearLayout(context);
5650
view1.setOrientation(LinearLayout.HORIZONTAL);
5751
view1.setGravity(Gravity.CENTER_VERTICAL);
5852
var nametv = nameGroup.getChildAt(0);
5953
iconAdmin = new ImageView(context);
6054
var size = Utils.dipToPixels(16);
6155
iconAdmin.setLayoutParams(new LinearLayout.LayoutParams(size, size));
62-
iconAdmin.setImageResource(ResId.drawable.admin);
63-
iconAdmin.setId(0x7fff0010);
56+
iconAdmin.setImageResource(R.drawable.admin);
57+
iconAdmin.setTag("admin_icon");
6458
nameGroup.removeView(nametv);
6559
view1.addView(nametv);
6660
view1.addView(iconAdmin);
6761
nameGroup.addView(view1, 0);
6862
}
63+
64+
var groupRawJid = chatCurrentJid.getPhoneRawString();
65+
if (groupRawJid == null) {
66+
iconAdmin.setVisibility(View.GONE);
67+
return;
68+
}
69+
70+
var jidGrp = jidFactory.invoke(null, groupRawJid);
71+
var participantJid = resolveParticipantJidForAdminCheck(fMessage.getUserJid(), grpcheckAdmin);
72+
if (participantJid == null) {
73+
iconAdmin.setVisibility(View.GONE);
74+
return;
75+
}
76+
77+
var result = grpcheckAdmin.invoke(grpParticipants, jidGrp, participantJid);
6978
iconAdmin.setVisibility(result != null && (boolean) result ? View.VISIBLE : View.GONE);
7079
}
71-
};
72-
XposedBridge.hookMethod(grpAdmin1, hooked);
80+
});
81+
82+
}
83+
84+
private Object resolveParticipantJidForAdminCheck(FMessageWpp.UserJid userJid, java.lang.reflect.Method grpcheckAdmin) {
85+
if (userJid == null) return null;
86+
var expectedType = grpcheckAdmin.getParameterTypes()[1];
87+
if (userJid.userJid != null && expectedType.isInstance(userJid.userJid)) {
88+
return userJid.userJid;
89+
}
90+
if (userJid.phoneJid != null && expectedType.isInstance(userJid.phoneJid)) {
91+
return userJid.phoneJid;
92+
}
93+
if (userJid.userJid != null) {
94+
return userJid.userJid;
95+
}
96+
if (userJid.phoneJid != null) {
97+
return userJid.phoneJid;
98+
}
99+
return null;
73100
}
74101

75102
@NonNull
76103
@Override
77104
public String getPluginName() {
78105
return "GroupAdmin";
79106
}
80-
}
107+
}

0 commit comments

Comments
 (0)