From c38d719dd5dd310fb5cc32b5eb63f9c93261f595 Mon Sep 17 00:00:00 2001 From: firesun Date: Sun, 22 Apr 2018 00:57:45 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AA=81=E7=A0=B49=E5=BC=A0=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/firesun/wechat/enhancement/Main.java | 4 +- .../wechat/enhancement/PreferencesUtils.java | 6 +- .../wechat/enhancement/plugin/Limits.java | 259 ++++++++++++++++++ .../wechat/enhancement/util/HookParams.java | 3 + .../enhancement/util/SearchClasses.java | 16 +- app/src/main/res/values/strings.xml | 1 - app/src/main/res/xml/pref_setting.xml | 8 +- 7 files changed, 285 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/me/firesun/wechat/enhancement/plugin/Limits.java diff --git a/app/src/main/java/me/firesun/wechat/enhancement/Main.java b/app/src/main/java/me/firesun/wechat/enhancement/Main.java index b7e4e6c..feeffb0 100644 --- a/app/src/main/java/me/firesun/wechat/enhancement/Main.java +++ b/app/src/main/java/me/firesun/wechat/enhancement/Main.java @@ -5,8 +5,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import java.util.List; - import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; @@ -17,6 +15,7 @@ import me.firesun.wechat.enhancement.plugin.AutoLogin; import me.firesun.wechat.enhancement.plugin.HideModule; import me.firesun.wechat.enhancement.plugin.IPlugin; +import me.firesun.wechat.enhancement.plugin.Limits; import me.firesun.wechat.enhancement.plugin.LuckMoney; import me.firesun.wechat.enhancement.util.HookParams; import me.firesun.wechat.enhancement.util.SearchClasses; @@ -33,6 +32,7 @@ public class Main implements IXposedHookLoadPackage { new AutoLogin(), new HideModule(), new LuckMoney(), + new Limits(), }; @Override diff --git a/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java b/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java index 44c9c6b..5b16c00 100644 --- a/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java +++ b/app/src/main/java/me/firesun/wechat/enhancement/PreferencesUtils.java @@ -77,9 +77,9 @@ public static boolean isAutoLogin() { return getInstance().getBoolean("is_auto_login", false); } -// public static boolean isBreakLimit() { -// return getInstance().getBoolean("is_break_limit", false); -// } + public static boolean isBreakLimit() { + return getInstance().getBoolean("is_break_limit", false); + } } diff --git a/app/src/main/java/me/firesun/wechat/enhancement/plugin/Limits.java b/app/src/main/java/me/firesun/wechat/enhancement/plugin/Limits.java new file mode 100644 index 0000000..b37485d --- /dev/null +++ b/app/src/main/java/me/firesun/wechat/enhancement/plugin/Limits.java @@ -0,0 +1,259 @@ +package me.firesun.wechat.enhancement.plugin; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.HeaderViewListAdapter; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedHelpers; +import de.robv.android.xposed.callbacks.XC_LoadPackage; +import me.firesun.wechat.enhancement.PreferencesUtils; +import me.firesun.wechat.enhancement.util.HookParams; + +import static de.robv.android.xposed.XposedBridge.log; + + +public class Limits implements IPlugin { + @Override + public void hook(XC_LoadPackage.LoadPackageParam lpparam) { + + XposedHelpers.findAndHookMethod(android.app.Activity.class, "onCreate", android.os.Bundle.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) { + try { + if (!PreferencesUtils.isBreakLimit()) + return; + Activity activity = (Activity) param.thisObject; + String className = activity.getClass().getName(); + if (className.equals(HookParams.getInstance().AlbumPreviewUIClassName)) { + Intent intent = activity.getIntent(); + if (intent == null) { + return; + } + int oldLimit = intent.getIntExtra("max_select_count", 9); + int newLimit = 1000; + if (oldLimit <= 9) { + intent.putExtra("max_select_count", oldLimit + newLimit - 9); + } + } + + if (className.equals(HookParams.getInstance().SelectContactUIClassName)) { + Intent intent = activity.getIntent(); + if (intent == null) { + return; + } + + if (intent.getIntExtra("max_limit_num", -1) == 9) { + intent.putExtra("max_limit_num", Integer.MAX_VALUE); + } + } + + } catch (Error | Exception e) { + log("error:" + e); + } + } + }); + + XposedHelpers.findAndHookMethod(HookParams.getInstance().MMActivityClassName, lpparam.classLoader, "onCreateOptionsMenu", Menu.class, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) { + + try { + if (!PreferencesUtils.isBreakLimit()) + return; + + + final Activity activity = (Activity) param.thisObject; + Menu menu = (Menu) param.args[0]; + if (!activity.getClass().getName().equals(HookParams.getInstance().SelectContactUIClassName)) { + return; + } + + Intent intent = activity.getIntent(); + if (intent == null) + return; + boolean checked = intent.getBooleanExtra("select_all_checked", false); + + MenuItem selectAll = menu.add(0, 2, 0, ""); + selectAll.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + TextView btnText = new TextView(activity); + btnText.setTextColor(Color.WHITE); + btnText.setText("全选"); + + LayoutParams layoutParams = new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + Context context = btnText.getContext(); + float scale = context.getResources().getDisplayMetrics().density; + layoutParams.setMarginEnd((int) ((float) 4 * scale + 0.5F)); + btnText.setLayoutParams(layoutParams); + + CheckBox btnCheckbox = new CheckBox(activity); + btnCheckbox.setChecked(checked); + btnCheckbox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + onSelectContactUISelectAll(activity, isChecked); + } + + }); + + layoutParams = new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + + context = btnCheckbox.getContext(); + scale = context.getResources().getDisplayMetrics().density; + layoutParams.setMarginEnd((int) ((float) 6 * scale + 0.5F)); + btnCheckbox.setLayoutParams(layoutParams); + + + LinearLayout actionView = new LinearLayout(activity); + actionView.addView(btnText); + actionView.addView(btnCheckbox); + actionView.setOrientation(LinearLayout.HORIZONTAL); + selectAll.setActionView(actionView); + } catch (Error | Exception e) { + } + } + }); + + XposedHelpers.findAndHookMethod(HookParams.getInstance().SelectContactUIClassName, lpparam.classLoader, "onActivityResult", int.class, int.class, Intent.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) { + try { + if (!PreferencesUtils.isBreakLimit()) + return; + int requestCode = (int) param.args[0]; + int resultCode = (int) param.args[1]; + Intent data = (Intent) param.args[2]; + + if (requestCode == 5) { + Activity activity = (Activity) param.thisObject; + activity.setResult(resultCode, data); + activity.finish(); + param.setResult(null); + } + } catch (Error | Exception e) { + } + } + }); + + XposedHelpers.findAndHookMethod(HookParams.getInstance().SelectConversationUIClassName, lpparam.classLoader, HookParams.getInstance().SelectConversationUICheckLimitMethod, boolean.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) { + try { + if (!PreferencesUtils.isBreakLimit()) + return; + param.setResult(false); + } catch (Error | Exception e) { + + } + + + } + }); + } + + private final void onSelectContactUISelectAll(Activity activity, boolean isChecked) { + try { + Intent intent = activity.getIntent(); + if (intent == null) { + return; + } + intent.putExtra("select_all_checked", isChecked); + intent.putExtra("already_select_contact", ""); + if (isChecked) { + ListView listView = (ListView) XposedHelpers.findFirstFieldByExactType(activity.getClass(), ListView.class).get(activity); + if (listView == null) { + return; + } + + ListAdapter adapter = listView.getAdapter(); + if (adapter == null) { + return; + } + + adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); + + Field contactField = null; + Field usernameField = null; + List userList = new ArrayList(); + + for (int i = 0; i < adapter.getCount(); ++i) { + Object item = adapter.getItem(i); + if (contactField == null) { + Field[] fileds = item.getClass().getFields(); + + for (int j = 0; j < fileds.length; j++) { + Field field = fileds[j]; + field.getType().getName(); + if (field.getType().getName().equals(HookParams.getInstance().ContactInfoClassName)) { + contactField = field; + break; + } + } + + if (contactField == null) { + continue; + } + } + + Object contact = contactField.get(item); + if (contact != null) { + if (usernameField == null) { + Field[] fields = contact.getClass().getFields(); + + for (int j = 0; j < fields.length; j++) { + Field field = fields[j]; + if (field.getName().equals("field_username")) { + usernameField = field; + } + } + + if (usernameField == null) { + continue; + } + } + + Object username = usernameField.get(contact); + if (username != null) { + userList.add((String) username); + } + } + } + intent.putExtra("already_select_contact", stringJoin(",", userList)); + } + activity.startActivityForResult(intent, 5); + } catch (Error | Exception e) { + } + + } + + private static String stringJoin(String join, List strAry) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < strAry.size(); i++) { + if (i == (strAry.size() - 1)) { + sb.append(strAry.get(i)); + } else { + sb.append(strAry.get(i)).append(join); + } + } + + return new String(sb); + } +} diff --git a/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java b/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java index fbb7e5c..33a9c5b 100644 --- a/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java +++ b/app/src/main/java/me/firesun/wechat/enhancement/util/HookParams.java @@ -11,12 +11,15 @@ public class HookParams { public String SQLiteDatabaseInsertMethod = "insert"; public String SQLiteDatabaseDeleteMethod = "delete"; public String ContactInfoUIClassName = "com.tencent.mm.plugin.profile.ui.ContactInfoUI"; + + public String ContactInfoClassName; public String ChatroomInfoUIClassName = "com.tencent.mm.plugin.chatroom.ui.ChatroomInfoUI"; public String WebWXLoginUIClassName = "com.tencent.mm.plugin.webwx.ui.ExtDeviceWXLoginUI"; public String AlbumPreviewUIClassName = "com.tencent.mm.plugin.gallery.ui.AlbumPreviewUI"; public String SelectContactUIClassName = "com.tencent.mm.ui.contact.SelectContactUI"; public String MMActivityClassName = "com.tencent.mm.ui.MMActivity"; public String SelectConversationUIClassName = "com.tencent.mm.ui.transmit.SelectConversationUI"; + public String SelectConversationUICheckLimitMethod; public String LuckyMoneyReceiveUIClassName = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI"; public String XMLParserClassName; public String XMLParserMethod; diff --git a/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java b/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java index 6751593..3357a24 100644 --- a/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java +++ b/app/src/main/java/me/firesun/wechat/enhancement/util/SearchClasses.java @@ -23,7 +23,7 @@ import static de.robv.android.xposed.XposedBridge.log; public class SearchClasses { - private static List wxClasses = new ArrayList(); + private static List wxClasses = new ArrayList(); private static XSharedPreferences preferencesInstance = null; public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam, String versionName) { @@ -153,10 +153,22 @@ public static void init(Context context, XC_LoadPackage.LoadPackageParam lpparam .firstOrNull() .getName(); + + Class SelectConversationUIClass = XposedHelpers.findClass(hp.SelectConversationUIClassName, lpparam.classLoader); + hp.SelectConversationUICheckLimitMethod = ReflectionUtil.findMethodsByExactParameters(SelectConversationUIClass, + boolean.class, boolean.class) + .getName(); + + hp.ContactInfoClassName = ReflectionUtil.findClassesFromPackage(lpparam.classLoader, wxClasses, "com.tencent.mm.storage", 0) + .filterByMethod(String.class, "getCityCode") + .filterByMethod(String.class, "getCountryCode") + .firstOrNull() + .getName(); + saveConfig(context); } - public static int getVersionNum(String version) { + private static int getVersionNum(String version) { String[] v = version.split("\\."); if (v.length == 3) return Integer.valueOf(v[0]) * 100 * 100 + Integer.valueOf(v[1]) * 100 + Integer.valueOf(v[2]); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e1e70b..da64b66 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -18,7 +18,6 @@ 过滤朋友圈广告 电脑微信自动登录 突破9张图片限制 - 全选 消息防撤回 朋友圈防删除 显示图标 diff --git a/app/src/main/res/xml/pref_setting.xml b/app/src/main/res/xml/pref_setting.xml index d41ec7f..a59aaac 100644 --- a/app/src/main/res/xml/pref_setting.xml +++ b/app/src/main/res/xml/pref_setting.xml @@ -81,10 +81,10 @@ android:defaultValue="false" android:key="is_auto_login" android:title="@string/pref_enable_autologin" /> - - - - +