diff --git a/app/src/main/java/com/wmods/wppenhacer/App.java b/app/src/main/java/com/wmods/wppenhacer/App.java index 165ca184..d0d06faf 100644 --- a/app/src/main/java/com/wmods/wppenhacer/App.java +++ b/app/src/main/java/com/wmods/wppenhacer/App.java @@ -1,16 +1,15 @@ package com.wmods.wppenhacer; import android.app.Application; +import android.content.Intent; import android.os.Handler; import android.os.Looper; import androidx.appcompat.app.AppCompatDelegate; import androidx.preference.PreferenceManager; -import com.wmods.wppenhacer.xposed.core.Utils; +import com.wmods.wppenhacer.xposed.core.MainFeatures; -import java.io.File; -import java.lang.reflect.Field; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -58,4 +57,9 @@ public static Handler getMainHandler() { } + public void restartApp(String packageWpp) { + Intent intent = new Intent(BuildConfig.APPLICATION_ID + ".WHATSAPP.RESTART"); + intent.putExtra("PKG", MainFeatures.PACKAGE_WPP); + sendBroadcast(intent); + } } diff --git a/app/src/main/java/com/wmods/wppenhacer/ui/fragments/HomeFragment.java b/app/src/main/java/com/wmods/wppenhacer/ui/fragments/HomeFragment.java index b36f0247..b0f25ea3 100644 --- a/app/src/main/java/com/wmods/wppenhacer/ui/fragments/HomeFragment.java +++ b/app/src/main/java/com/wmods/wppenhacer/ui/fragments/HomeFragment.java @@ -26,15 +26,18 @@ import com.wmods.wppenhacer.databinding.FragmentHomeBinding; import com.wmods.wppenhacer.ui.fragments.base.BaseFragment; import com.wmods.wppenhacer.xposed.core.MainFeatures; +import com.wmods.wppenhacer.xposed.core.Utils; +import org.json.JSONArray; import org.json.JSONObject; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.Locale; -import java.util.stream.Collectors; +import java.util.Objects; import rikka.core.util.IOUtils; @@ -62,62 +65,70 @@ public void onReceive(Context context, Intent intent) { }, intentFilter, ContextCompat.RECEIVER_EXPORTED); } + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + binding = FragmentHomeBinding.inflate(inflater, container, false); + + checkStateWpp(requireActivity()); + + binding.rebootBtn.setOnClickListener(view -> { + App.getInstance().restartApp(MainFeatures.PACKAGE_WPP); + disableWpp(requireActivity()); + }); + + binding.rebootBtn2.setOnClickListener(view -> { + App.getInstance().restartApp(MainFeatures.PACKAGE_BUSINESS); + disableBusiness(requireActivity()); + }); + + binding.exportBtn.setOnClickListener(view -> saveConfigs(this.getContext())); + binding.importBtn.setOnClickListener(view -> importConfigs(this.getContext())); + binding.resetBtn.setOnClickListener(view -> resetConfigs(this.getContext())); + + return binding.getRoot(); + } + @SuppressLint("StringFormatInvalid") private void receiverBroadcastBusiness(Context context, Intent intent) { binding.statusTitle3.setText(R.string.business_in_background); var version = intent.getStringExtra("VERSION"); var supported_list = Arrays.asList(context.getResources().getStringArray(R.array.supported_versions_business)); if (supported_list.contains(version)) { - binding.statusSummary3.setText(String.format(getString(R.string.version_s), version)); + binding.statusSummary3.setText(getString(R.string.version_s, version)); binding.status3.setCardBackgroundColor(context.getColor(rikka.material.R.color.material_green_500)); } else { - binding.statusSummary3.setText(String.format(getString(R.string.version_s_not_listed), version)); + binding.statusSummary3.setText(getString(R.string.version_s_not_listed, version)); binding.status3.setCardBackgroundColor(context.getColor(rikka.material.R.color.material_yellow_500)); } + binding.rebootBtn2.setVisibility(View.VISIBLE); binding.statusSummary3.setVisibility(View.VISIBLE); binding.statusIcon3.setImageResource(R.drawable.ic_round_check_circle_24); } + @SuppressLint("StringFormatInvalid") private void receiverBroadcastWpp(Context context, Intent intent) { binding.statusTitle2.setText(R.string.whatsapp_in_background); var version = intent.getStringExtra("VERSION"); var supported_list = Arrays.asList(context.getResources().getStringArray(R.array.supported_versions_wpp)); if (supported_list.contains(version)) { - binding.statusSummary1.setText(String.format(getString(R.string.version_s), version)); + binding.statusSummary1.setText(getString(R.string.version_s, version)); binding.status2.setCardBackgroundColor(context.getColor(rikka.material.R.color.material_green_500)); } else { - binding.statusSummary1.setText(String.format(getString(R.string.version_s_not_listed), version)); + binding.statusSummary1.setText(getString(R.string.version_s_not_listed, version)); binding.status2.setCardBackgroundColor(context.getColor(rikka.material.R.color.material_yellow_500)); } + binding.rebootBtn.setVisibility(View.VISIBLE); binding.statusSummary1.setVisibility(View.VISIBLE); binding.statusIcon2.setImageResource(R.drawable.ic_round_check_circle_24); } - public View onCreateView(@NonNull LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { - binding = FragmentHomeBinding.inflate(inflater, container, false); - - checkStateWpp(requireActivity()); - - binding.rebootBtn.setOnClickListener(view -> { - Intent intent = new Intent(BuildConfig.APPLICATION_ID + ".WHATSAPP.RESTART"); - intent.putExtra("PKG", MainFeatures.PACKAGE_WPP); - requireActivity().sendBroadcast(intent); - disableWpp(requireActivity()); - }); - - binding.rebootBtn2.setOnClickListener(view -> { - Intent intent = new Intent(BuildConfig.APPLICATION_ID + ".WHATSAPP.RESTART"); - intent.putExtra("PKG", MainFeatures.PACKAGE_BUSINESS); - requireActivity().sendBroadcast(intent); - disableBusiness(requireActivity()); - }); - - binding.exportBtn.setOnClickListener(view -> saveConfigs(this.getContext())); - binding.importBtn.setOnClickListener(view -> importConfigs(this.getContext())); - - return binding.getRoot(); + private void resetConfigs(Context context) { + var prefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs.getAll().forEach((key, value) -> prefs.edit().remove(key).apply()); + App.getInstance().restartApp(MainFeatures.PACKAGE_WPP); + App.getInstance().restartApp(MainFeatures.PACKAGE_BUSINESS); + Utils.showToast(context.getString(R.string.configs_reset), Toast.LENGTH_SHORT); } private void saveConfigs(Context context) { @@ -128,9 +139,13 @@ private void saveConfigs(Context context) { var entries = prefs.getAll(); var JSOjsonObject = new JSONObject(); for (var entry : entries.entrySet()) { - JSOjsonObject.put(entry.getKey(), entry.getValue()); + var keyValue = entry.getValue(); + if (keyValue instanceof HashSet hashSet) { + keyValue = new JSONArray(new ArrayList<>(hashSet)); + } + JSOjsonObject.put(entry.getKey(), keyValue); } - output.write(JSOjsonObject.toString().getBytes()); + Objects.requireNonNull(output).write(JSOjsonObject.toString().getBytes()); } Toast.makeText(context, context.getString(R.string.configs_saved), Toast.LENGTH_SHORT).show(); } catch (Exception e) { @@ -154,27 +169,28 @@ private void importConfigs(Context context) { while (key.hasNext()) { var keyName = key.next(); var value = jsonObject.get(keyName); - if (value instanceof String stringValue) { - if (stringValue.startsWith("[") && stringValue.endsWith("]")) { - if (stringValue.length() > 2) { - var arr = Arrays.stream(stringValue.substring(1, stringValue.length() - 1).split(",")).map(String::trim).collect(Collectors.toList()); - prefs.edit().putStringSet(keyName, new HashSet<>(arr)).apply(); - } - } else { - prefs.edit().putString(keyName, value.toString()).apply(); + if (value instanceof JSONArray jsonArray) { + HashSet hashSet = new HashSet<>(); + for (var i = 0; i < jsonArray.length(); i++) { + hashSet.add(jsonArray.getString(i)); } - } else if (value instanceof Boolean) { - prefs.edit().putBoolean(keyName, (boolean) value).apply(); - } else if (value instanceof Integer) { - prefs.edit().putInt(keyName, (int) value).apply(); - } else if (value instanceof Long) { - prefs.edit().putLong(keyName, (long) value).apply(); - } else if (value instanceof Float) { - prefs.edit().putFloat(keyName, (float) value).apply(); + prefs.edit().putStringSet(keyName, hashSet).apply(); + } else if (value instanceof String stringValue) { + prefs.edit().putString(keyName, stringValue).apply(); + } else if (value instanceof Boolean booleanValue) { + prefs.edit().putBoolean(keyName, booleanValue).apply(); + } else if (value instanceof Integer intValue) { + prefs.edit().putInt(keyName, intValue).apply(); + } else if (value instanceof Long longValue) { + prefs.edit().putLong(keyName, longValue).apply(); + } else if (value instanceof Float floatValue) { + prefs.edit().putFloat(keyName, floatValue).apply(); } } } Toast.makeText(context, context.getString(R.string.configs_imported), Toast.LENGTH_SHORT).show(); + App.getInstance().restartApp(MainFeatures.PACKAGE_WPP); + App.getInstance().restartApp(MainFeatures.PACKAGE_BUSINESS); } catch (Exception e) { Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show(); } @@ -182,6 +198,7 @@ private void importConfigs(Context context) { FilePicker.fileCapture.launch(new String[]{"application/json"}); } + @SuppressLint("StringFormatInvalid") private void checkStateWpp(FragmentActivity activity) { if (MainActivity.isXposedEnabled()) { @@ -227,6 +244,7 @@ private void disableBusiness(FragmentActivity activity) { binding.statusTitle3.setText(R.string.business_is_not_running_or_has_not_been_activated_in_lsposed); binding.status3.setCardBackgroundColor(activity.getColor(rikka.material.R.color.material_red_500)); binding.statusSummary3.setVisibility(View.GONE); + binding.rebootBtn2.setVisibility(View.GONE); } private void disableWpp(FragmentActivity activity) { @@ -234,6 +252,7 @@ private void disableWpp(FragmentActivity activity) { binding.statusTitle2.setText(R.string.whatsapp_is_not_running_or_has_not_been_activated_in_lsposed); binding.status2.setCardBackgroundColor(activity.getColor(rikka.material.R.color.material_red_500)); binding.statusSummary1.setVisibility(View.GONE); + binding.rebootBtn.setVisibility(View.GONE); } private static void checkWpp(FragmentActivity activity) { diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/Utils.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/Utils.java index c0f7f561..978fa3f3 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/Utils.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/Utils.java @@ -17,6 +17,9 @@ import android.util.TypedValue; import android.widget.Toast; +import androidx.annotation.NonNull; + +import com.wmods.wppenhacer.App; import com.wmods.wppenhacer.xposed.utils.MimeTypeUtils; import java.io.File; @@ -33,8 +36,9 @@ public class Utils { + @NonNull public static Application getApplication() { - return MainFeatures.mApp; + return MainFeatures.mApp == null ? App.getInstance() : MainFeatures.mApp; } public static boolean doRestart(Context context) { @@ -148,11 +152,11 @@ public static void debugMethods(Class cls, Object thisObject) { } } - public static String getDestination(SharedPreferences prefs, File file, String name) { + public static String getDestination(SharedPreferences prefs, String name) { var folderPath = prefs.getString("localdownload", Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download") + "/WhatsApp/Wa Enhancer/" + name + "/"; var filePath = new File(folderPath); if (!filePath.exists()) filePath.mkdirs(); - return filePath.getAbsolutePath() + "/" + (file == null ? "" : file.getName()); + return filePath.getAbsolutePath() + "/"; } public static String copyFile(File srcFile, File destFile) { @@ -166,12 +170,6 @@ public static String copyFile(File srcFile, File destFile) { if (read <= 0) { in.close(); out.close(); - MediaScannerConnection.scanFile(Utils.getApplication(), - new String[]{destFile.getAbsolutePath()}, - new String[]{MimeTypeUtils.getMimeTypeFromExtension(srcFile.getAbsolutePath())}, - (path, uri) -> { - }); - return ""; } out.write(bArr, 0, read); @@ -196,4 +194,24 @@ public static void setToClipboard(String string) { ClipData clip = ClipData.newPlainText("label", string); clipboard.setPrimaryClip(clip); } + + public static String generateName(Object userJid, String fileFormat) { + var contactName = WppCore.getContactName(userJid); + var number = WppCore.stripJID(WppCore.getRawString(userJid)); + return padronizarNome(contactName) + "_" + number + "_" + new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.getDefault()).format(new Date()) + "." + fileFormat; + } + + @NonNull + public static String padronizarNome(@NonNull String nome) { + String nomePadronizado = nome.replaceAll("[^a-zA-Z0-9 _]", ""); + nomePadronizado = nomePadronizado.replace(' ', '_'); + return nomePadronizado; + } + + public static void scanFile(File file) { + MediaScannerConnection.scanFile(Utils.getApplication(), + new String[]{file.getAbsolutePath()}, + new String[]{MimeTypeUtils.getMimeTypeFromExtension(file.getAbsolutePath())}, + null); + } } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java index cc1885c5..22a3c4eb 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java @@ -10,8 +10,10 @@ import android.view.Menu; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; import java.io.File; @@ -139,6 +141,8 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { // Load wa database loadDatabase(); + + FMessageWpp.init(loader); } public static void loadDatabase() { @@ -177,10 +181,10 @@ public static int getDefaultTheme() { return startup_prefs.getInt("night_mode", 0); } - @Nullable + @NonNull public static String getContactName(Object userJid) { loadDatabase(); - if (mWaDatabase == null) return ""; + if (mWaDatabase == null || userJid == null) return ""; var rawJid = getRawString(userJid); var cursor = mWaDatabase.query("wa_contacts", new String[]{"display_name"}, "jid = ?", new String[]{rawJid}, null, null, null); if (cursor != null && cursor.moveToFirst()) { diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/components/FMessageWpp.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/components/FMessageWpp.java new file mode 100644 index 00000000..74a2ed86 --- /dev/null +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/components/FMessageWpp.java @@ -0,0 +1,116 @@ +package com.wmods.wppenhacer.xposed.core.components; + +import com.wmods.wppenhacer.xposed.core.Unobfuscator; +import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +public class FMessageWpp { + + public static Class TYPE; + private static boolean initialized; + private static Method userJidMethod; + private static Field keyMessage; + private static Field getFieldIdMessage; + private static Method deviceJidMethod; + private static Method messageMethod; + private static Method messageWithMediaMethod; + private final Object fmessage; + + public FMessageWpp(Object fMessage) { + if (fMessage == null) throw new RuntimeException("fMessage is null"); + this.fmessage = fMessage; + try { + init(fMessage.getClass().getClassLoader()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void init(ClassLoader classLoader) throws Exception { + if (initialized) return; + initialized = true; + var fMessageClass = Unobfuscator.loadFMessageClass(classLoader); + TYPE = fMessageClass; + var userJidClass = classLoader.loadClass("com.whatsapp.jid.UserJid"); + userJidMethod = ReflectionUtils.findMethodUsingFilter(fMessageClass, method -> method.getReturnType() == userJidClass); + keyMessage = Unobfuscator.loadMessageKeyField(classLoader); + messageMethod = Unobfuscator.loadNewMessageMethod(classLoader); + messageWithMediaMethod = Unobfuscator.loadNewMessageWithMediaMethod(classLoader); + getFieldIdMessage = Unobfuscator.loadSetEditMessageField(classLoader); + deviceJidMethod = ReflectionUtils.findMethodUsingFilter(fMessageClass, method -> method.getReturnType().equals(XposedHelpers.findClass("com.whatsapp.jid.DeviceJid", classLoader))); + } + + public Object getUserJid() { + try { + return userJidMethod.invoke(fmessage); + } catch (Exception e) { + XposedBridge.log(e); + } + return null; + } + + public Object getDeviceJid() { + try { + return deviceJidMethod.invoke(fmessage); + } catch (Exception e) { + XposedBridge.log(e); + } + return null; + } + + public long getRowId() { + try { + return getFieldIdMessage.getLong(fmessage); + } catch (Exception e) { + XposedBridge.log(e); + } + return 0; + } + + + public Key getKey() { + try { + return new Key(keyMessage.get(fmessage)); + } catch (Exception e) { + XposedBridge.log(e); + } + return null; + } + + public Object getObject() { + return fmessage; + } + + public String getMessageStr() { + try { + var message = (String) messageMethod.invoke(fmessage); + if (message != null) return message; + return (String) messageWithMediaMethod.invoke(fmessage); + } catch (Exception e) { + XposedBridge.log(e); + return null; + } + } + + public static class Key { + + public final Object thisObject; + public final String messageID; + public final boolean isFromMe; + public final Object remoteJid; + + public Key(Object key) { + this.thisObject = key; + this.messageID = (String) XposedHelpers.getObjectField(key, "A01"); + this.isFromMe = XposedHelpers.getBooleanField(key, "A02"); + this.remoteJid = XposedHelpers.getObjectField(key, "A00"); + } + + } + +} diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/AntiRevoke.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/AntiRevoke.java index fb4a46f0..4c65926f 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/AntiRevoke.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/AntiRevoke.java @@ -21,9 +21,9 @@ import com.wmods.wppenhacer.xposed.core.UnobfuscatorCache; import com.wmods.wppenhacer.xposed.core.Utils; import com.wmods.wppenhacer.xposed.core.WppCore; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import com.wmods.wppenhacer.xposed.core.db.DelMessageStore; import com.wmods.wppenhacer.xposed.core.db.MessageStore; -import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; import java.lang.reflect.Field; import java.text.DateFormat; @@ -42,8 +42,6 @@ public class AntiRevoke extends Feature { private static final HashMap> messageRevokedMap = new HashMap<>(); - private static Field fieldMessageKey; - private static Field getFieldIdMessage; public AntiRevoke(ClassLoader loader, XSharedPreferences preferences) { super(loader, preferences); @@ -55,16 +53,6 @@ public void doHook() throws Exception { var antiRevokeMessageMethod = Unobfuscator.loadAntiRevokeMessageMethod(classLoader); logDebug(Unobfuscator.getMethodDescriptor(antiRevokeMessageMethod)); - var classThreadMessage = Unobfuscator.loadFMessageClass(classLoader); - logDebug("Class: " + classThreadMessage); - - fieldMessageKey = Unobfuscator.loadMessageKeyField(classLoader); - logDebug(Unobfuscator.getFieldDescriptor(fieldMessageKey)); - - getFieldIdMessage = Unobfuscator.loadSetEditMessageField(classLoader); - logDebug(Unobfuscator.getFieldDescriptor(getFieldIdMessage)); - - var bubbleMethod = Unobfuscator.loadAntiRevokeBubbleMethod(classLoader); logDebug(Unobfuscator.getMethodDescriptor(bubbleMethod)); @@ -78,13 +66,10 @@ public void doHook() throws Exception { XposedBridge.hookMethod(antiRevokeMessageMethod, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Exception { - var objMessage = classThreadMessage.cast(param.args[0]); - var fieldMessageDetails = fieldMessageKey.get(objMessage); - var deviceJidMethod = ReflectionUtils.findMethodUsingFilter(fieldMessageKey.getDeclaringClass(), method -> method.getReturnType().equals(XposedHelpers.findClass("com.whatsapp.jid.DeviceJid", classLoader))); - var deviceJid = ReflectionUtils.callMethod(deviceJidMethod, objMessage); - var isFromMe = XposedHelpers.getBooleanField(fieldMessageDetails, "A02"); - var userJid = XposedHelpers.getObjectField(fieldMessageDetails, "A00"); - var id = getFieldIdMessage.getLong(objMessage); + var fMessage = new FMessageWpp(param.args[0]); + var messageKey = fMessage.getKey(); + var deviceJid = fMessage.getDeviceJid(); + var id = fMessage.getRowId(); // Caso o proprio usuario tenha deletado o status if (id == -1 & DeleteStatus.bypassAntiRevoke) { DeleteStatus.bypassAntiRevoke = false; @@ -95,12 +80,12 @@ protected void beforeHookedMethod(MethodHookParam param) throws Exception { } return; } - var rawString = WppCore.getRawString(userJid); + var rawString = WppCore.getRawString(messageKey.remoteJid); if (WppCore.isGroup(rawString)) { - if (deviceJid != null && antiRevoke(objMessage) != 0) { + if (deviceJid != null && antiRevoke(fMessage) != 0) { param.setResult(true); } - } else if (!isFromMe && antiRevoke(objMessage) != 0) { + } else if (!messageKey.isFromMe && antiRevoke(fMessage) != 0) { param.setResult(true); } } @@ -157,14 +142,16 @@ public static Drawable scaleImage(Resources resources, Drawable image, float sca return new BitmapDrawable(resources, bitmapResized); } - private static void saveRevokedMessage(String authorJid, String messageKey, Object objMessage) { - HashSet messages = getRevokedMessages(objMessage); + private static void saveRevokedMessage(FMessageWpp fMessage) { + var messageKey = (String) XposedHelpers.getObjectField(fMessage.getObject(), "A01"); + var stripJID = WppCore.stripJID(WppCore.getRawString(fMessage.getKey().remoteJid)); + HashSet messages = getRevokedMessages(fMessage); messages.add(messageKey); - DelMessageStore.getInstance(Utils.getApplication()).insertMessage(authorJid, messageKey, System.currentTimeMillis()); + DelMessageStore.getInstance(Utils.getApplication()).insertMessage(stripJID, messageKey, System.currentTimeMillis()); } - private static HashSet getRevokedMessages(Object objMessage) { - String jid = stripJID(getJidAuthor(objMessage)); + private static HashSet getRevokedMessages(FMessageWpp fMessage) { + String jid = WppCore.stripJID(WppCore.getRawString(fMessage.getKey().remoteJid)); if (messageRevokedMap.containsKey(jid)) { return messageRevokedMap.get(jid); } @@ -174,32 +161,16 @@ private static HashSet getRevokedMessages(Object objMessage) { return messages; } - public static String stripJID(String str) { - try { - return (str.contains("@g.us") || str.contains("@s.whatsapp.net") || str.contains("@broadcast")) ? str.substring(0, str.indexOf("@")) : str; - } catch (Exception e) { - XposedBridge.log(e.getMessage()); - return str; - } - } - - public static String getJidAuthor(Object objMessage) { - Object fieldMessageDetails = XposedHelpers.getObjectField(objMessage, fieldMessageKey.getName()); - Object fieldMessageAuthorJid = XposedHelpers.getObjectField(fieldMessageDetails, "A00"); - if (fieldMessageAuthorJid == null) return ""; - else return WppCore.getRawString(fieldMessageAuthorJid); - } - private void isMRevoked(Object objMessage, TextView dateTextView, String antirevokeType) { if (dateTextView == null) return; - var fieldMessageDetails = XposedHelpers.getObjectField(objMessage, fieldMessageKey.getName()); - var messageKey = (String) XposedHelpers.getObjectField(fieldMessageDetails, "A01"); - var messageRevokedList = getRevokedMessages(objMessage); - var id = XposedHelpers.getLongField(objMessage, getFieldIdMessage.getName()); + var fMessage = new FMessageWpp(objMessage); + var key = fMessage.getKey(); + var messageRevokedList = getRevokedMessages(fMessage); + var id = fMessage.getRowId(); String keyOrig = null; - if (messageRevokedList.contains(messageKey) || ((keyOrig = MessageStore.getOriginalMessageKey(id)) != null && messageRevokedList.contains(keyOrig))) { - var timestamp = DelMessageStore.getInstance(Utils.getApplication()).getTimestampByMessageId(keyOrig == null ? messageKey : keyOrig); + if (messageRevokedList.contains(key.messageID) || ((keyOrig = MessageStore.getOriginalMessageKey(id)) != null && messageRevokedList.contains(keyOrig))) { + var timestamp = DelMessageStore.getInstance(Utils.getApplication()).getTimestampByMessageId(keyOrig == null ? key.messageID : keyOrig); if (timestamp > 0) { Locale locale = Utils.getApplication().getResources().getConfiguration().getLocales().get(0); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale); @@ -233,18 +204,17 @@ private void isMRevoked(Object objMessage, TextView dateTextView, String antirev } - private int antiRevoke(Object objMessage) { - showToast(objMessage); - var messageKey = (String) XposedHelpers.getObjectField(objMessage, "A01"); - var stripJID = stripJID(getJidAuthor(objMessage)); + private int antiRevoke(FMessageWpp fMessage) { + showToast(fMessage); + var messageKey = (String) XposedHelpers.getObjectField(fMessage.getObject(), "A01"); + var stripJID = WppCore.stripJID(WppCore.getRawString(fMessage.getKey().remoteJid)); var revokeboolean = stripJID.equals("status") ? Integer.parseInt(prefs.getString("antirevokestatus", "0")) : Integer.parseInt(prefs.getString("antirevoke", "0")); if (revokeboolean == 0) return revokeboolean; - - var messageRevokedList = getRevokedMessages(objMessage); + var messageRevokedList = getRevokedMessages(fMessage); if (!messageRevokedList.contains(messageKey)) { try { AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { - saveRevokedMessage(stripJID, messageKey, objMessage); + saveRevokedMessage(fMessage); try { var mConversation = WppCore.getCurrentConversation(); if (mConversation != null && WppCore.stripJID(WppCore.getCurrentRawJID()).equals(stripJID)) { @@ -269,26 +239,24 @@ private int antiRevoke(Object objMessage) { return revokeboolean; } - private void showToast(Object fMessage) { - var jidAuthor = getJidAuthor(fMessage); - + private void showToast(FMessageWpp fMessage) { + var jidAuthor = WppCore.getRawString(fMessage.getKey().remoteJid); var messageSuffix = Utils.getApplication().getString(ResId.string.deleted_message); - var isStatus = Objects.equals(stripJID(jidAuthor), "status"); + var isStatus = Objects.equals(WppCore.stripJID(jidAuthor), "status"); if (isStatus) { messageSuffix = Utils.getApplication().getString(ResId.string.deleted_status); - var getUserJid = ReflectionUtils.findMethodUsingFilter(fieldMessageKey.getDeclaringClass(), method -> method.getReturnType().equals(XposedHelpers.findClass("com.whatsapp.jid.UserJid", classLoader))); - jidAuthor = WppCore.getRawString(ReflectionUtils.callMethod(getUserJid, fMessage)); + jidAuthor = WppCore.getRawString(fMessage.getUserJid()); } if (TextUtils.isEmpty(jidAuthor)) return; String name = WppCore.getContactName(WppCore.createUserJid(jidAuthor)); if (TextUtils.isEmpty(name)) { - name = stripJID(jidAuthor); + name = WppCore.stripJID(jidAuthor); } String message = name + " " + messageSuffix; if (prefs.getBoolean("toastdeleted", false)) { Utils.showToast(message, Toast.LENGTH_SHORT); } - Tasker.sendTaskerEvent(WppCore.stripJID(jidAuthor), isStatus ? "deleted_status" : "deleted_message"); + Tasker.sendTaskerEvent(name, WppCore.stripJID(jidAuthor), isStatus ? "deleted_status" : "deleted_message"); } } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/DeleteStatus.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/DeleteStatus.java index f7e0304f..9eda0d01 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/DeleteStatus.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/DeleteStatus.java @@ -10,6 +10,7 @@ import com.wmods.wppenhacer.xposed.core.ResId; import com.wmods.wppenhacer.xposed.core.Unobfuscator; import com.wmods.wppenhacer.xposed.core.WppCore; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; import java.lang.reflect.Field; @@ -44,7 +45,7 @@ public void doHook() throws Throwable { logDebug("Menu class: " + clazzMenu.getName()); var menuField = Unobfuscator.getFieldByType(clazzSubMenu, clazzMenu); logDebug("Menu field: " + menuField.getName()); - var fMessageKey = Unobfuscator.loadMessageKeyField(classLoader); + Class StatusPlaybackBaseFragmentClass = classLoader.loadClass("com.whatsapp.status.playback.fragment.StatusPlaybackBaseFragment"); Class StatusPlaybackContactFragmentClass = classLoader.loadClass("com.whatsapp.status.playback.fragment.StatusPlaybackContactFragment"); var listStatusField = ReflectionUtils.getFieldsByExtendType(StatusPlaybackContactFragmentClass, List.class).get(0); @@ -73,7 +74,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { if (fMessage == null) return true; try { var status = StatusDeleteDialogFragmentClass.newInstance(); - var key = fMessageKey.get(fMessage); + var key = new FMessageWpp(fMessage).getKey(); var bundle = getBundle(key); bypassAntiRevoke = true; fieldBundle.set(status, bundle); @@ -94,14 +95,11 @@ public String getPluginName() { } @NonNull - private static Bundle getBundle(Object key) { - var id = XposedHelpers.getObjectField(key, "A01"); - var isFromMe = XposedHelpers.getBooleanField(key, "A02"); - var remoteJid = XposedHelpers.getObjectField(key, "A00"); + private static Bundle getBundle(FMessageWpp.Key key) { var bundle = new Bundle(); - bundle.putString("fMessageKeyJid", WppCore.getRawString(remoteJid)); - bundle.putBoolean("fMessageKeyFromMe", isFromMe); - bundle.putString("fMessageKeyId", (String) id); + bundle.putString("fMessageKeyJid", WppCore.getRawString(key.remoteJid)); + bundle.putBoolean("fMessageKeyFromMe", key.isFromMe); + bundle.putString("fMessageKeyId", key.messageID); return bundle; } } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Others.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Others.java index b9c3635e..75af6256 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Others.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Others.java @@ -227,7 +227,7 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { var raw = WppCore.getRawString(PhoneUserJid); var UserJid = WppCore.createUserJid(raw); var contactName = WppCore.getContactName(UserJid); - if (contactName == null) { + if (TextUtils.isEmpty(contactName)) { contactName = WppCore.stripJID(raw); } var sql = MessageStore.database.getReadableDatabase(); @@ -236,7 +236,7 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { if (toast_viewed_status) { Utils.showToast(String.format("%s viewed your status", contactName), Toast.LENGTH_LONG); } - Tasker.sendTaskerEvent(WppCore.stripJID(raw), "viewed_status"); + Tasker.sendTaskerEvent(contactName, WppCore.stripJID(raw), "viewed_status"); } else if (!Objects.equals(WppCore.getCurrentRawJID(), raw)) { try (var result2 = sql.query("message", null, "_id = ?", new String[]{String.valueOf(id)}, null, null, null)) { if (result2.moveToNext()) { @@ -245,7 +245,7 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { if (result3.moveToNext()) { if (toast_viewed_message) Utils.showToast(String.format("%s viewed your message", contactName), Toast.LENGTH_LONG); - Tasker.sendTaskerEvent(WppCore.stripJID(raw), "viewed_message"); + Tasker.sendTaskerEvent(contactName, WppCore.stripJID(raw), "viewed_message"); } } } @@ -314,7 +314,7 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { name = TextUtils.isEmpty(name) ? WppCore.stripJID(jid) : name; if (showOnline) Utils.showToast(String.format(Utils.getApplication().getString(ResId.string.toast_online), name), Toast.LENGTH_SHORT); - Tasker.sendTaskerEvent(WppCore.stripJID(jid), "contact_online"); + Tasker.sendTaskerEvent(name, WppCore.stripJID(jid), "contact_online"); } }); } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/SeenTick.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/SeenTick.java index 2d8e05ad..104ebd84 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/SeenTick.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/SeenTick.java @@ -29,6 +29,7 @@ import com.wmods.wppenhacer.xposed.core.Unobfuscator; import com.wmods.wppenhacer.xposed.core.Utils; import com.wmods.wppenhacer.xposed.core.WppCore; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import com.wmods.wppenhacer.xposed.core.db.MessageStore; import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; @@ -50,7 +51,6 @@ public class SeenTick extends Feature { private static final ArraySet messages = new ArraySet<>(); private static Object mWaJobManager; - private static Field fieldMessageKey; private static Class mSendReadClass; private static Method WaJobManagerMethod; private static String currentJid; @@ -68,38 +68,33 @@ public void doHook() throws Throwable { var bubbleMethod = Unobfuscator.loadAntiRevokeBubbleMethod(classLoader); logDebug(Unobfuscator.getMethodDescriptor(bubbleMethod)); - fieldMessageKey = Unobfuscator.loadMessageKeyField(classLoader); - logDebug(Unobfuscator.getFieldDescriptor(fieldMessageKey)); - var messageSendClass = XposedHelpers.findClass("com.whatsapp.jobqueue.job.SendE2EMessageJob", classLoader); - WaJobManagerMethod = Unobfuscator.loadBlueOnReplayWaJobManagerMethod(classLoader); var messageJobMethod = Unobfuscator.loadBlueOnReplayMessageJobMethod(classLoader); mSendReadClass = XposedHelpers.findClass("com.whatsapp.jobqueue.job.SendReadReceiptJob", classLoader); - WppCore.addListenerChat((conv, type) -> { - var jid = WppCore.getCurrentRawJID(); - if (!Objects.equals(jid, currentJid)) { - currentJid = jid; - messages.clear(); + WppCore.addListenerChat((activity, type) -> { + if (activity.getClass().getSimpleName().equals("Conversation") && (type == WppCore.ActivityChangeState.ChangeType.START || type == WppCore.ActivityChangeState.ChangeType.RESUME)) { + var jid = WppCore.getCurrentRawJID(); + if (!Objects.equals(jid, currentJid)) { + currentJid = jid; + messages.clear(); + } + currentScreen = "conversation"; } - currentScreen = "conversation"; }); XposedBridge.hookMethod(bubbleMethod, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { var objMessage = param.args[2]; - var fieldMessageDetails = XposedHelpers.getObjectField(objMessage, fieldMessageKey.getName()); - String messageKey = (String) XposedHelpers.getObjectField(fieldMessageDetails, "A01"); - var userJidClass = XposedHelpers.findClass("com.whatsapp.jid.UserJid", classLoader); - var userJidMethod = ReflectionUtils.findMethodUsingFilter(fieldMessageKey.getDeclaringClass(), me -> me.getReturnType().equals(userJidClass) && me.getParameterCount() == 0); - Object userJid = ReflectionUtils.callMethod(userJidMethod, objMessage); - if (XposedHelpers.getBooleanField(fieldMessageDetails, "A02")) return; - messages.add(new MessageInfo(objMessage, messageKey, userJid)); + var fMessage = new FMessageWpp(objMessage); + var key = fMessage.getKey(); + if (key.isFromMe) return; + messages.add(new MessageInfo(fMessage, key.messageID, fMessage.getUserJid())); } }); @@ -112,8 +107,8 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { var handler = new Handler(Looper.getMainLooper()); if (Objects.equals(currentScreen, "status")) { if (messages.isEmpty()) return; - MessageStore.storeMessageRead(messages.valueAt(0).messageKey); - var view = messageMap.get(messages.valueAt(0).messageKey); + MessageStore.storeMessageRead(messages.valueAt(0).messageId); + var view = messageMap.get(messages.valueAt(0).messageId); if (view != null) { view.post(() -> setSeenButton(view, true)); } @@ -159,20 +154,17 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { var setPageActiveMethod = Unobfuscator.loadStatusActivePage(classLoader); logDebug(Unobfuscator.getMethodDescriptor(setPageActiveMethod)); var fieldList = Unobfuscator.getFieldByType(setPageActiveMethod.getDeclaringClass(), List.class); + XposedBridge.hookMethod(setPageActiveMethod, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { var position = (int) param.args[1]; var list = (List) XposedHelpers.getObjectField(param.args[0], fieldList.getName()); - var message = list.get(position); - var messageKeyObject = fieldMessageKey.get(message); - var messageKey = (String) XposedHelpers.getObjectField(messageKeyObject, "A01"); - var userJidClass = XposedHelpers.findClass("com.whatsapp.jid.UserJid", classLoader); - var userJidMethod = ReflectionUtils.findMethodUsingFilter(fieldMessageKey.getDeclaringClass(), me -> me.getReturnType().equals(userJidClass) && me.getParameterCount() == 0); - var userJid = userJidMethod.invoke(message); - var jid = WppCore.getRawString(userJid); + var fMessage = new FMessageWpp(list.get(position)); + var messageKey = (String) fMessage.getKey().messageID; + var jid = WppCore.getRawString(fMessage.getUserJid()); messages.clear(); - messages.add(new MessageInfo(message, messageKey, null)); + messages.add(new MessageInfo(fMessage, messageKey, null)); currentJid = jid; currentScreen = "status"; } @@ -187,12 +179,10 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { if (!prefs.getBoolean("hidestatusview", false)) return; - var fMessageField = ReflectionUtils.getFieldByExtendType(param.thisObject.getClass(), fieldMessageKey.getDeclaringClass()); - var fMessage = ReflectionUtils.getField(fMessageField, param.thisObject); - var messageKey = ReflectionUtils.getField(fieldMessageKey, fMessage); - var messageId = (String) XposedHelpers.getObjectField(messageKey, "A01"); - var isFromMe = XposedHelpers.getBooleanField(messageKey, "A02"); - if (isFromMe) return; + var fMessageField = ReflectionUtils.getFieldByExtendType(param.thisObject.getClass(), FMessageWpp.TYPE); + var fMessage = new FMessageWpp(ReflectionUtils.getField(fMessageField, param.thisObject)); + var key = fMessage.getKey(); + if (key.isFromMe) return; var view = (View) param.getResult(); var contentView = (LinearLayout) view.findViewById(Utils.getID("bottom_sheet", "id")); var buttonImage = new ImageView(view.getContext()); @@ -209,15 +199,15 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { buttonImage.setBackground(border); contentView.setOrientation(LinearLayout.HORIZONTAL); contentView.addView(buttonImage, 0); - messageMap.put(messageId, buttonImage); + messageMap.put(key.messageID, buttonImage); buttonImage.setOnClickListener(v -> AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { Utils.showToast(view.getContext().getString(ResId.string.sending_read_blue_tick), Toast.LENGTH_SHORT); sendBlueTickStatus(currentJid); - MessageStore.storeMessageRead(messageId); + MessageStore.storeMessageRead(key.messageID); setSeenButton(buttonImage, true); })); AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { - var seen = MessageStore.isReadMessageStatus(messageId); + var seen = MessageStore.isReadMessageStatus(key.messageID); setSeenButton(buttonImage, seen); }); } @@ -303,14 +293,14 @@ private void sendBlueTick(String currentJid) { logDebug("messages: " + Arrays.toString(messages.toArray(new MessageInfo[0]))); if (messages.isEmpty() || currentJid == null || currentJid.contains(Utils.getMyNumber())) return; - var messagekeys = messages.stream().map(item -> item.messageKey).collect(Collectors.toList()); + var messagekeys = messages.stream().map(item -> item.messageId).collect(Collectors.toList()); var listAudios = MessageStore.getAudioListByMessageList(messagekeys); logDebug("listAudios: " + listAudios); for (var messageKey : listAudios) { - var mInfo = messages.stream().filter(messageInfo -> messageInfo.messageKey.equals(messageKey)).findAny(); + var mInfo = messages.stream().filter(messageInfo -> messageInfo.messageId.equals(messageKey)).findAny(); if (mInfo.isPresent()) { messages.remove(mInfo.get()); - sendBlueTickMedia(mInfo.get().fMessage, false); + sendBlueTickMedia(mInfo.get().fMessage.getObject(), false); } } sendBlueTickMsg(currentJid); @@ -325,7 +315,7 @@ private void sendBlueTickMsg(String currentJid) { HashMap> map = new HashMap<>(); for (var messageInfo : messages) { map.computeIfAbsent(messageInfo.userJid, k -> new ArrayList<>()); - Objects.requireNonNull(map.get(messageInfo.userJid)).add(messageInfo.messageKey); + Objects.requireNonNull(map.get(messageInfo.userJid)).add(messageInfo.messageId); } var userJidTarget = WppCore.createUserJid(currentJid); for (var userjid : map.keySet()) { @@ -346,7 +336,7 @@ private void sendBlueTickStatus(String currentJid) { if (messages.isEmpty() || currentJid == null || currentJid.equals("status_me")) return; try { logDebug("sendBlue: " + currentJid); - var arr_s = messages.stream().map(item -> item.messageKey).toArray(String[]::new); + var arr_s = messages.stream().map(item -> item.messageId).toArray(String[]::new); var userJidSender = WppCore.createUserJid("status@broadcast"); var userJid = WppCore.createUserJid(currentJid); WppCore.setPrivBoolean(arr_s[0] + "_rpass", true); @@ -379,11 +369,11 @@ public String getPluginName() { static class MessageInfo { public Object userJid; - public String messageKey; - public Object fMessage; + public String messageId; + public FMessageWpp fMessage; - public MessageInfo(Object fMessage, String messageKey, Object userJid) { - this.messageKey = messageKey; + public MessageInfo(FMessageWpp fMessage, String messageId, Object userJid) { + this.messageId = messageId; this.fMessage = fMessage; this.userJid = userJid; } @@ -391,7 +381,7 @@ public MessageInfo(Object fMessage, String messageKey, Object userJid) { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof MessageInfo messageInfo) { - return messageKey.equals(messageInfo.messageKey) && fMessage.equals(messageInfo.fMessage) && userJid.equals(messageInfo.userJid); + return messageId.equals(messageInfo.messageId) && fMessage.equals(messageInfo.fMessage) && userJid.equals(messageInfo.userJid); } return false; } @@ -399,7 +389,7 @@ public boolean equals(@Nullable Object obj) { @NonNull @Override public String toString() { - return messageKey; + return messageId; } } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java index 3483b2a7..ee5a452c 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java @@ -24,6 +24,7 @@ import com.wmods.wppenhacer.xposed.core.Unobfuscator; import com.wmods.wppenhacer.xposed.core.Utils; import com.wmods.wppenhacer.xposed.core.WppCore; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import com.wmods.wppenhacer.xposed.core.db.MessageHistory; import com.wmods.wppenhacer.xposed.core.db.MessageStore; import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; @@ -55,15 +56,6 @@ public void doHook() throws Throwable { var getEditMessage = Unobfuscator.loadGetEditMessageMethod(classLoader); logDebug(Unobfuscator.getMethodDescriptor(getEditMessage)); - var getFieldIdMessage = Unobfuscator.loadSetEditMessageField(classLoader); - logDebug(Unobfuscator.getFieldDescriptor(getFieldIdMessage)); - - var newMessageMethod = Unobfuscator.loadNewMessageMethod(classLoader); - logDebug(Unobfuscator.getMethodDescriptor(newMessageMethod)); - - var newMessageWithMediaMethod = Unobfuscator.loadNewMessageWithMediaMethod(classLoader); - logDebug(Unobfuscator.getMethodDescriptor(newMessageMethod)); - var editMessageShowMethod = Unobfuscator.loadEditMessageShowMethod(classLoader); logDebug(Unobfuscator.getMethodDescriptor(editMessageShowMethod)); @@ -77,17 +69,14 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { if (editMessage == null) return; long timestamp = XposedHelpers.getLongField(editMessage, "A00"); if (timestamp == 0L) return; - long id = getFieldIdMessage.getLong(param.args[0]); - String newMessage = (String) newMessageMethod.invoke(param.args[0]); + var fMessage = new FMessageWpp(param.args[0]); + long id = fMessage.getRowId(); + String newMessage = fMessage.getMessageStr(); if (newMessage == null) { - if (newMessageWithMediaMethod == null) { - var methods = ReflectionUtils.findAllMethodUsingFilter(param.args[0].getClass(), method -> method.getReturnType() == String.class && ReflectionUtils.isOverridden(method)); - for (var method : methods) { - newMessage = (String) method.invoke(param.args[0]); - if (newMessage != null) break; - } - }else { - newMessage = (String) newMessageWithMediaMethod.invoke(param.args[0]); + var methods = ReflectionUtils.findAllMethodUsingFilter(param.args[0].getClass(), method -> method.getReturnType() == String.class && ReflectionUtils.isOverridden(method)); + for (var method : methods) { + newMessage = (String) method.invoke(param.args[0]); + if (newMessage != null) break; } if (newMessage == null) return; } @@ -110,7 +99,8 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { textView.setOnClickListener((v) -> { try { var messageObj = XposedHelpers.callMethod(param.thisObject, "getFMessage"); - long id = getFieldIdMessage.getLong(messageObj); + var fMesage = new FMessageWpp(messageObj); + long id = fMesage.getRowId(); var msg = new MessageHistory.MessageItem(id, MessageStore.getMessageById(id), 0); var messages = MessageHistory.getInstance().getMessages(id); if (messages == null) { @@ -174,7 +164,7 @@ private void showBottomDialog(ArrayList messages) { LinearLayout.LayoutParams layoutParams4 = new LinearLayout.LayoutParams(Utils.dipToPixels(70), Utils.dipToPixels(8)); layoutParams4.gravity = 17; layoutParams4.setMargins(0, Utils.dipToPixels(5), 0, Utils.dipToPixels(5)); - var bg2 = DesignUtils.createDrawable("rc_dotline_dialog",Color.BLACK); + var bg2 = DesignUtils.createDrawable("rc_dotline_dialog", Color.BLACK); imageView0.setBackground(DesignUtils.alphaDrawable(bg2, DesignUtils.getPrimaryTextColor(), 33)); imageView0.setLayoutParams(layoutParams4); // Button View diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Tasker.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Tasker.java index 3dc2ef27..394604d5 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Tasker.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Tasker.java @@ -14,16 +14,16 @@ import com.wmods.wppenhacer.xposed.core.Unobfuscator; import com.wmods.wppenhacer.xposed.core.Utils; import com.wmods.wppenhacer.xposed.core.WppCore; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import java.util.Objects; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XSharedPreferences; import de.robv.android.xposed.XposedBridge; -import de.robv.android.xposed.XposedHelpers; public class Tasker extends Feature { - private static Object fMessage; + private static FMessageWpp fMessage; private static boolean taskerEnabled; public Tasker(@NonNull ClassLoader classLoader, @NonNull XSharedPreferences preferences) { @@ -49,9 +49,10 @@ private void registerSenderMessage() { ContextCompat.registerReceiver(Utils.getApplication(), new SenderMessageBroadcastReceiver(), filter, ContextCompat.RECEIVER_EXPORTED); } - public static void sendTaskerEvent(String number, String event) { + public static void sendTaskerEvent(String name, String number, String event) { if (!taskerEnabled) return; Intent intent = new Intent("com.wmods.wppenhacer.EVENT"); + intent.putExtra("name", name); intent.putExtra("number", number); intent.putExtra("event", event); Utils.getApplication().sendBroadcast(intent); @@ -60,13 +61,11 @@ public static void sendTaskerEvent(String number, String event) { public void hookReceiveMessage() throws Throwable { var method = Unobfuscator.loadReceiptMethod(classLoader); var method2 = Unobfuscator.loadReceiptOutsideChat(classLoader); - var newMessageMethod = Unobfuscator.loadNewMessageMethod(classLoader); - var fieldMessageKey = Unobfuscator.loadMessageKeyField(classLoader); XposedBridge.hookMethod(method2, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - fMessage = param.args[0]; + fMessage = new FMessageWpp(param.args[0]); } }); @@ -74,12 +73,12 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { if (param.args[4] == "sender" || param.args[1] == null) return; - var messageKey = fieldMessageKey.get(fMessage); - var userJid = XposedHelpers.getObjectField(messageKey, "A00"); + + var userJid = fMessage.getKey().remoteJid; var rawJid = WppCore.getRawString(userJid); var name = WppCore.getContactName(userJid); var number = WppCore.stripJID(rawJid); - var msg = (String) newMessageMethod.invoke(fMessage); + var msg = fMessage.getMessageStr(); if (TextUtils.isEmpty(msg) || TextUtils.isEmpty(number)) return; new Handler(Utils.getApplication().getMainLooper()).post(() -> { Intent intent = new Intent("com.wmods.wppenhacer.MESSAGE_RECEIVED"); diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadProfile.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadProfile.java index ba31d34d..d687087d 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadProfile.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadProfile.java @@ -52,9 +52,9 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { var jidObj = ReflectionUtils.getField(loadProfileInfoField, ReflectionUtils.getField(field, param.thisObject)); var jid = WppCore.stripJID(WppCore.getRawString(jidObj)); var file = WppCore.getContactPhotoFile(jid); - var destPath = Utils.getDestination(prefs, file, "Profile Photo"); - destPath = destPath.endsWith(".jpg") ? destPath : destPath + "pg"; - var error = Utils.copyFile(file, new File(destPath)); + var destPath = Utils.getDestination(prefs, "Profile Photo"); + var name = Utils.generateName(jidObj, "jpg"); + var error = Utils.copyFile(file, new File(destPath, name)); if (TextUtils.isEmpty(error)) { Toast.makeText(Utils.getApplication(), Utils.getApplication().getString(ResId.string.saved_to) + destPath, Toast.LENGTH_LONG).show(); } else { diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadViewOnce.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadViewOnce.java index 31a99f2b..2a1c875b 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadViewOnce.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/DownloadViewOnce.java @@ -12,6 +12,8 @@ import com.wmods.wppenhacer.xposed.core.ResId; import com.wmods.wppenhacer.xposed.core.Unobfuscator; import com.wmods.wppenhacer.xposed.core.Utils; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; +import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; import java.io.File; @@ -50,18 +52,24 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { MenuItem item = menu.add(0, 0, 0, ResId.string.download).setIcon(Utils.getID("btn_download", "drawable")); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); item.setOnMenuItemClickListener(item1 -> { - var i = XposedHelpers.getIntField(param.thisObject, initIntField.getName()); - var message = callMethod.getParameterCount() == 2 ? XposedHelpers.callMethod(param.thisObject, callMethod.getName(), param.thisObject, i) : XposedHelpers.callMethod(param.thisObject, callMethod.getName(), i); - if (message != null) { - var fileData = XposedHelpers.getObjectField(message, "A01"); - var file = (File) XposedHelpers.getObjectField(fileData, fileField.getName()); - var dest = Utils.getDestination(prefs, file, "View Once"); - var error = Utils.copyFile(file, new File(dest)); - if (TextUtils.isEmpty(error)) { - Utils.showToast(Utils.getApplication().getString(ResId.string.saved_to) + dest, Toast.LENGTH_LONG); - } else { - Utils.showToast(Utils.getApplication().getString(ResId.string.error_when_saving_try_again) + ":" + error, Toast.LENGTH_LONG); + try { + var i = XposedHelpers.getIntField(param.thisObject, initIntField.getName()); + var message = callMethod.getParameterCount() == 2 ? XposedHelpers.callMethod(param.thisObject, callMethod.getName(), param.thisObject, i) : XposedHelpers.callMethod(param.thisObject, callMethod.getName(), i); + if (message != null) { + var fileData = XposedHelpers.getObjectField(message, "A01"); + var file = (File) ReflectionUtils.getField(fileField, fileData); + var dest = Utils.getDestination(prefs, "View Once"); + var userJid = new FMessageWpp(message).getUserJid(); + var name = Utils.generateName(userJid, "jpg"); + var error = Utils.copyFile(file, new File(dest, name)); + if (TextUtils.isEmpty(error)) { + Utils.showToast(Utils.getApplication().getString(ResId.string.saved_to) + dest, Toast.LENGTH_LONG); + } else { + Utils.showToast(Utils.getApplication().getString(ResId.string.error_when_saving_try_again) + ":" + error, Toast.LENGTH_LONG); + } } + } catch (Exception e) { + Utils.showToast(e.getMessage(), Toast.LENGTH_LONG); } return true; }); diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java index 0924884f..32ff5e40 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java @@ -3,6 +3,7 @@ import android.content.SharedPreferences; import android.media.MediaScannerConnection; import android.os.Environment; +import android.text.TextUtils; import android.view.Menu; import android.view.View; import android.widget.Toast; @@ -13,6 +14,7 @@ import com.wmods.wppenhacer.xposed.core.ResId; import com.wmods.wppenhacer.xposed.core.Unobfuscator; import com.wmods.wppenhacer.xposed.core.Utils; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import com.wmods.wppenhacer.xposed.utils.MimeTypeUtils; import com.wmods.wppenhacer.xposed.utils.ReflectionUtils; @@ -48,6 +50,8 @@ public void doHook() throws Exception { logDebug("Menu class: " + clazzMenu.getName()); var menuField = Unobfuscator.getFieldByType(clazzSubMenu, clazzMenu); logDebug("Menu field: " + menuField.getName()); + + Class StatusPlaybackBaseFragmentClass = classLoader.loadClass("com.whatsapp.status.playback.fragment.StatusPlaybackBaseFragment"); Class StatusPlaybackContactFragmentClass = classLoader.loadClass("com.whatsapp.status.playback.fragment.StatusPlaybackContactFragment"); var listStatusField = ReflectionUtils.getFieldsByExtendType(StatusPlaybackContactFragmentClass, List.class).get(0); @@ -74,10 +78,18 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { try { var fileData = XposedHelpers.getObjectField(fMessage, "A01"); var file = (File) XposedHelpers.getObjectField(fileData, fieldFile.getName()); - if (copyFile(prefs, file)) { - Utils.showToast(Utils.getApplication().getString(ResId.string.saved_to) + getPathDestination(prefs, file), Toast.LENGTH_SHORT); + var userJid = new FMessageWpp(fMessage).getUserJid(); + var fileType = file.getName().substring(file.getName().lastIndexOf(".") + 1); + var destination = getPathDestination(prefs, file); + var name = Utils.generateName(userJid, fileType); + var destinationFile = new File(destination, name); + var error = Utils.copyFile(file, destinationFile); + Utils.scanFile(destinationFile); + if (TextUtils.isEmpty(error)) { + Utils.showToast(Utils.getApplication().getString(ResId.string.saved_to) + destinationFile.getAbsolutePath(), Toast.LENGTH_SHORT); + log("Saved to: " + destinationFile.getAbsolutePath()); } else { - Utils.showToast(Utils.getApplication().getString(ResId.string.error_when_saving_try_again), Toast.LENGTH_SHORT); + Utils.showToast(Utils.getApplication().getString(ResId.string.error_when_saving_try_again) + ": " + error, Toast.LENGTH_SHORT); } } catch (Exception e) { Utils.showToast(e.getMessage(), Toast.LENGTH_SHORT); @@ -131,7 +143,7 @@ private String getPathDestination(SharedPreferences sharedPreferences, @NonNull if (!mediaPath.exists()) mediaPath.mkdirs(); - return mediaPath + "/" + f.getName(); + return mediaPath + "/"; } @NonNull diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/CallPrivacy.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/CallPrivacy.java index 8bd0efc2..f642a959 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/CallPrivacy.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/CallPrivacy.java @@ -43,7 +43,7 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { var userJid = XposedHelpers.callMethod(callinfo, "getPeerJid"); var callId = XposedHelpers.callMethod(callinfo, "getCallId"); var type = Integer.parseInt(prefs.getString("call_privacy", "0")); - Tasker.sendTaskerEvent(WppCore.stripJID(WppCore.getRawString(userJid)), "call_received"); + Tasker.sendTaskerEvent(WppCore.getContactName(userJid), WppCore.stripJID(WppCore.getRawString(userJid)), "call_received"); var blockCall = checkCallBlock(userJid, type); if (!blockCall) return; var clazzVoip = XposedHelpers.findClass("com.whatsapp.voipcalling.Voip", classLoader); diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/ViewOnce.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/ViewOnce.java index e42d3cae..f7899c18 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/ViewOnce.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/ViewOnce.java @@ -5,11 +5,11 @@ import com.wmods.wppenhacer.xposed.core.Feature; import com.wmods.wppenhacer.xposed.core.Unobfuscator; +import com.wmods.wppenhacer.xposed.core.components.FMessageWpp; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XSharedPreferences; import de.robv.android.xposed.XposedBridge; -import de.robv.android.xposed.XposedHelpers; public class ViewOnce extends Feature { private boolean isFromMe; @@ -25,7 +25,6 @@ public void doHook() throws Exception { logDebug(classViewOnce); var viewOnceStoreMethod = Unobfuscator.loadViewOnceStoreMethod(classLoader); logDebug(Unobfuscator.getMethodDescriptor(viewOnceStoreMethod)); - var messageKeyField = Unobfuscator.loadMessageKeyField(classLoader); XposedBridge.hookMethod(viewOnceStoreMethod, new XC_MethodHook() { @Override @@ -34,8 +33,7 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { isFromMe = false; var messageObject = param.args[0]; if (messageObject == null) return; - var messageKey = messageKeyField.get(messageObject); - isFromMe = XposedHelpers.getBooleanField(messageKey, "A02"); + isFromMe = new FMessageWpp(messageObject).getKey().isFromMe; } }); diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 944737e4..e4aed24a 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -358,7 +358,8 @@ android:padding="?dialogPreferredPadding" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" + android:layout_gravity="center" + android:gravity="center" android:orientation="vertical"> @@ -387,11 +388,21 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_marginLeft="8dp" + android:layout_marginStart="8dp" android:text="@string/export_settings" /> + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 63a5018b..a4127a6c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -271,4 +271,6 @@ Standard Audio note Voice note + Reset Settings + Settings reseted diff --git a/changelog.txt b/changelog.txt index 030ee582..76120882 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,8 +1,21 @@ -[WHATSAPP] -* Fix contact display names +[WA ENHANCER] +* Adicionado botão de resetar as configurações +* Os backups agora vai ter data no nome +* Corrigido erros nos backups para a lista de bloqueios(backups antigos não será suportado) +* Todos os modulos foi atualizados para facilitar a manutenção + +[STATUS DOWNLOADER] +* Os nomes do arquivo salvo agora tera o nome do usuario, numero do telefone e data (Ex: Mary_12345678_20240622-181400.jpg) + +[VIEW ONCE DOWNLOADER] +* Os nomes do arquivo salvo agora tera o nome do usuario, numero do telefone e data (Ex: Mary_12345678_20240622-181400.jpg) -[BLUE TICK] -* The button now turns blue when replying to a status +[PROFILE PICTURE DOWNLOADER] +* Os nomes do arquivo salvo agora tera o nome do usuario, numero do telefone e data (Ex: Mary_12345678_20240622-181400.jpg) + +[TASKER] +* Adicionado variavel %name aos eventos + +[WHATSAPP] +* Adicionado suporte para a versão 2.24.12.78 -[CALL PRIVACY] -* Add white and block contacts for call privacy \ No newline at end of file