From 191aa7987a76ce8cec678b272852175bc0558679 Mon Sep 17 00:00:00 2001 From: mkx173 Date: Thu, 11 Apr 2024 03:41:55 -0700 Subject: [PATCH] feat: fix transition animation for android 14+ --- .../java/gm/tieba/tabswitch/XposedInit.java | 6 +- .../tieba/tabswitch/hooker/TSPreference.java | 12 +- .../gm/tieba/tabswitch/hooker/add/Ripple.java | 82 ---------- .../hooker/auto/TransitionAnimation.java | 151 ++++++++++++++++++ 4 files changed, 165 insertions(+), 86 deletions(-) delete mode 100644 app/src/main/java/gm/tieba/tabswitch/hooker/add/Ripple.java create mode 100644 app/src/main/java/gm/tieba/tabswitch/hooker/auto/TransitionAnimation.java diff --git a/app/src/main/java/gm/tieba/tabswitch/XposedInit.java b/app/src/main/java/gm/tieba/tabswitch/XposedInit.java index 2903ea67..70b6bbeb 100644 --- a/app/src/main/java/gm/tieba/tabswitch/XposedInit.java +++ b/app/src/main/java/gm/tieba/tabswitch/XposedInit.java @@ -30,7 +30,6 @@ import gm.tieba.tabswitch.hooker.Obfuscated; import gm.tieba.tabswitch.hooker.TSPreference; import gm.tieba.tabswitch.hooker.add.HistoryCache; -import gm.tieba.tabswitch.hooker.add.Ripple; import gm.tieba.tabswitch.hooker.add.SaveImages; import gm.tieba.tabswitch.hooker.add.SelectClipboard; import gm.tieba.tabswitch.hooker.auto.AgreeNum; @@ -40,6 +39,7 @@ import gm.tieba.tabswitch.hooker.auto.NotificationDetect; import gm.tieba.tabswitch.hooker.auto.OpenSign; import gm.tieba.tabswitch.hooker.auto.OriginSrc; +import gm.tieba.tabswitch.hooker.auto.TransitionAnimation; import gm.tieba.tabswitch.hooker.deobfuscation.DeobfuscationHelper; import gm.tieba.tabswitch.hooker.deobfuscation.DeobfuscationHooker; import gm.tieba.tabswitch.hooker.deobfuscation.Matcher; @@ -141,7 +141,6 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { new ContentFilter(), new FrsPageFilter(), new HistoryCache(), - new Ripple(), new SaveImages(), new AutoSign(), new OpenSign(), @@ -157,7 +156,8 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { new NotificationDetect(), new PurgeVideo(), new SelectClipboard(), - new UserFilter() + new UserFilter(), + new TransitionAnimation() ); final var matchers = new ArrayList(hookers.size() + 2); matchers.add(new TbToast()); diff --git a/app/src/main/java/gm/tieba/tabswitch/hooker/TSPreference.java b/app/src/main/java/gm/tieba/tabswitch/hooker/TSPreference.java index 7827879b..8aae1bc6 100644 --- a/app/src/main/java/gm/tieba/tabswitch/hooker/TSPreference.java +++ b/app/src/main/java/gm/tieba/tabswitch/hooker/TSPreference.java @@ -5,6 +5,7 @@ import android.app.Dialog; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Process; import android.text.TextUtils; @@ -199,7 +200,6 @@ private LinearLayout createRootPreference(final Activity activity) { preferenceLayout.addView(TSPreferenceHelper.createTextView(isPurgeEnabled ? "别出新意" : "增加功能")); preferenceLayout.addView(new SwitchButtonHolder(activity, "浏览历史增加搜索", "history_cache", SwitchButtonHolder.TYPE_SWITCH)); - preferenceLayout.addView(new SwitchButtonHolder(activity, "楼层增加点按效果", "ripple", SwitchButtonHolder.TYPE_SWITCH)); preferenceLayout.addView(new SwitchButtonHolder(activity, "长按下载保存全部图片", "save_images", SwitchButtonHolder.TYPE_SWITCH)); preferenceLayout.addView(new SwitchButtonHolder(activity, "弹窗自由复制", "select_clipboard", SwitchButtonHolder.TYPE_SWITCH)); @@ -290,6 +290,16 @@ private LinearLayout createModifyTabPreference(final Activity activity) { preferenceLayout.addView(new SwitchButtonHolder(activity, "隐藏进吧", "enter_forum", SwitchButtonHolder.TYPE_SWITCH)); preferenceLayout.addView(new SwitchButtonHolder(activity, "隐藏发帖", "write_thread", SwitchButtonHolder.TYPE_SWITCH)); preferenceLayout.addView(new SwitchButtonHolder(activity, "隐藏消息", "im_message", SwitchButtonHolder.TYPE_SWITCH)); + preferenceLayout.addView(TSPreferenceHelper.createTextView("其他")); + SwitchButtonHolder transitionAnimation = new SwitchButtonHolder(activity, "修复过渡动画", "transition_animation", SwitchButtonHolder.TYPE_SWITCH); + transitionAnimation.setOnButtonClickListener(v -> { + if (!(Build.VERSION.SDK_INT >= 34 && DeobfuscationHelper.isTbSatisfyVersionRequirement("12.58.2.1", DeobfuscationHelper.getTbVersion(getContext())))) { + TbToast.showTbToast("当前贴吧版本不支持此功能", TbToast.LENGTH_SHORT); + } else { + transitionAnimation.bdSwitch.changeState(); + } + }); + preferenceLayout.addView(transitionAnimation); return preferenceLayout; } diff --git a/app/src/main/java/gm/tieba/tabswitch/hooker/add/Ripple.java b/app/src/main/java/gm/tieba/tabswitch/hooker/add/Ripple.java deleted file mode 100644 index 9ea0b481..00000000 --- a/app/src/main/java/gm/tieba/tabswitch/hooker/add/Ripple.java +++ /dev/null @@ -1,82 +0,0 @@ -package gm.tieba.tabswitch.hooker.add; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.StateListDrawable; -import android.util.AttributeSet; -import android.util.SparseArray; -import android.view.View; -import android.widget.RelativeLayout; - -import androidx.annotation.NonNull; - -import java.lang.reflect.Method; - -import de.robv.android.xposed.XC_MethodHook; -import de.robv.android.xposed.XposedBridge; -import de.robv.android.xposed.XposedHelpers; -import gm.tieba.tabswitch.XposedContext; -import gm.tieba.tabswitch.hooker.IHooker; -import gm.tieba.tabswitch.util.DisplayUtils; -import gm.tieba.tabswitch.util.ReflectUtils; - -public class Ripple extends XposedContext implements IHooker { - - @NonNull - @Override - public String key() { - return "ripple"; - } - - public void hook() throws Throwable { - final var subPbLayoutClass = XposedHelpers.findClass("com.baidu.tieba.pb.pb.sub.SubPbLayout", sClassLoader); - // 楼中楼 - try { - Method md; - try { - md = subPbLayoutClass.getDeclaredFields()[4].getType().getDeclaredMethod("createView"); - } catch (final NoSuchMethodException e) { - md = subPbLayoutClass.getDeclaredFields()[4].getType().getDeclaredMethod("b"); - } - XposedBridge.hookMethod(md, new XC_MethodHook() { - @Override - protected void afterHookedMethod(final MethodHookParam param) throws Throwable { - final var newSubPbListItem = (View) param.getResult(); - final var tag = (SparseArray) newSubPbListItem.getTag(); - final var b = tag.valueAt(0); - // R.id.new_sub_pb_list_richText - final var view = (View) ReflectUtils.getObjectField(b, "com.baidu.tbadk.widget.richText.TbRichTextView"); - view.setBackground(createSubPbBackground()); - } - }); - } catch (final NoSuchMethodException e) { - XposedBridge.log(e); - } - // 查看全部回复 - XposedHelpers.findAndHookConstructor(subPbLayoutClass, Context.class, AttributeSet.class, new XC_MethodHook() { - @Override - protected void afterHookedMethod(final MethodHookParam param) throws Throwable { - final var view = ReflectUtils.getObjectField(param.thisObject, RelativeLayout.class); - view.setBackground(createSubPbBackground()); - } - }); - } - - private StateListDrawable createBackground() { - final StateListDrawable sld = new StateListDrawable(); - sld.addState(new int[]{android.R.attr.state_pressed}, - new ColorDrawable(ReflectUtils.getColor("CAM_X0204"))); - return sld; - } - - private StateListDrawable createSubPbBackground() { - if (!DisplayUtils.getTbSkin(getContext()).equals("")) { - return createBackground(); - } else { - final StateListDrawable sld = new StateListDrawable(); - sld.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(Color.WHITE)); - return sld; - } - } -} diff --git a/app/src/main/java/gm/tieba/tabswitch/hooker/auto/TransitionAnimation.java b/app/src/main/java/gm/tieba/tabswitch/hooker/auto/TransitionAnimation.java new file mode 100644 index 00000000..59dbb64b --- /dev/null +++ b/app/src/main/java/gm/tieba/tabswitch/hooker/auto/TransitionAnimation.java @@ -0,0 +1,151 @@ +package gm.tieba.tabswitch.hooker.auto; + +import android.app.Activity; + +import androidx.annotation.NonNull; + +import de.robv.android.xposed.XC_MethodReplacement; +import de.robv.android.xposed.XposedHelpers; +import gm.tieba.tabswitch.XposedContext; +import gm.tieba.tabswitch.hooker.IHooker; + +public class TransitionAnimation extends XposedContext implements IHooker { + + private Class activityPendingTransitionFactory; + private int CHAT_SQUARE_FADE_IN; + private int CHAT_SQUARE_FADE_OUT; + private int RES_BIG_IMAGE_IN_FROM_RIGHT; + private int RES_BIG_IMAGE_OUT_TO_RIGHT; + private int RES_CUSTOM_FADE_IN; + private int RES_CUSTOM_FADE_OUT; + private int RES_CUSTOM_IN_FROM_RIGHT; + private int RES_CUSTOM_OUT_TO_RIGHT; + private int RES_FADE_OUT; + private int RES_NFADE_IN; + private int RES_NORMAL_IN_FROM_BOTTOM; + private int RES_NORMAL_IN_FROM_LEFT; + private int RES_NORMAL_IN_FROM_RIGHT; + private int RES_NORMAL_OUT_TO_BOTTOM; + private int RES_NORMAL_OUT_TO_LEFT; + private int RES_NORMAL_OUT_TO_RIGHT; + + @NonNull + @Override + public String key() { + return "transition_animation"; + } + + @Override + public void hook() throws Throwable { + activityPendingTransitionFactory = XposedHelpers.findClass("com.baidu.tbadk.ActivityPendingTransitionFactory", sClassLoader); + + CHAT_SQUARE_FADE_IN = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "CHAT_SQUARE_FADE_IN"); + CHAT_SQUARE_FADE_OUT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "CHAT_SQUARE_FADE_OUT"); + RES_BIG_IMAGE_IN_FROM_RIGHT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_BIG_IMAGE_IN_FROM_RIGHT"); + RES_BIG_IMAGE_OUT_TO_RIGHT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_BIG_IMAGE_OUT_TO_RIGHT"); + RES_CUSTOM_FADE_IN = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_CUSTOM_FADE_IN"); + RES_CUSTOM_FADE_OUT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_CUSTOM_FADE_OUT"); + RES_CUSTOM_IN_FROM_RIGHT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_CUSTOM_IN_FROM_RIGHT"); + RES_CUSTOM_OUT_TO_RIGHT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_CUSTOM_OUT_TO_RIGHT"); + RES_FADE_OUT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_FADE_OUT"); + RES_NFADE_IN = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_NFADE_IN"); + RES_NORMAL_IN_FROM_BOTTOM = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_NORMAL_IN_FROM_BOTTOM"); + RES_NORMAL_IN_FROM_LEFT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_NORMAL_IN_FROM_LEFT"); + RES_NORMAL_IN_FROM_RIGHT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_NORMAL_IN_FROM_RIGHT"); + RES_NORMAL_OUT_TO_BOTTOM = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_NORMAL_OUT_TO_BOTTOM"); + RES_NORMAL_OUT_TO_LEFT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_NORMAL_OUT_TO_LEFT"); + RES_NORMAL_OUT_TO_RIGHT = XposedHelpers.getStaticIntField(activityPendingTransitionFactory, "RES_NORMAL_OUT_TO_RIGHT"); + + XposedHelpers.findAndHookMethod( + activityPendingTransitionFactory, + "enterExitAnimation", + "com.baidu.tbadk.TbPageContext", int.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + enterExitAnimation(param.args[0], (int) param.args[1]); + return null; + } + } + ); + + XposedHelpers.findAndHookMethod( + activityPendingTransitionFactory, + "closeAnimation", + "com.baidu.tbadk.TbPageContext", int.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + closeAnimation(param.args[0], (int) param.args[1]); + return null; + } + } + ); + } + + private void enterExitAnimation(Object tbPageContext, int i) { + Activity pageActivity = (Activity) XposedHelpers.callMethod(tbPageContext, "getPageActivity"); + if (XposedHelpers.getStaticBooleanField(activityPendingTransitionFactory, "IS_CUSTOM_FROM_THIRD_PARTY")) { + i = 3; + } + switch (i) { + case 0: + pageActivity.overridePendingTransition(0, 0); + return; + case 1: + pageActivity.overridePendingTransition(RES_NORMAL_IN_FROM_RIGHT, RES_FADE_OUT); + return; + case 2: + pageActivity.overridePendingTransition(RES_BIG_IMAGE_IN_FROM_RIGHT, RES_FADE_OUT); + return; + case 3: + pageActivity.overridePendingTransition(RES_CUSTOM_IN_FROM_RIGHT, RES_CUSTOM_FADE_OUT); + return; + case 4: + pageActivity.overridePendingTransition(RES_NORMAL_IN_FROM_BOTTOM, RES_FADE_OUT); + return; + case 5: + pageActivity.overridePendingTransition(CHAT_SQUARE_FADE_IN, CHAT_SQUARE_FADE_OUT); + return; + case 6: + pageActivity.overridePendingTransition(RES_NORMAL_IN_FROM_LEFT, RES_FADE_OUT); + return; + default: + pageActivity.overridePendingTransition(RES_NORMAL_IN_FROM_RIGHT, RES_FADE_OUT); + return; + } + } + + private void closeAnimation(Object tbPageContext, int i) { + Activity pageActivity = (Activity) XposedHelpers.callMethod(tbPageContext, "getPageActivity"); + if (XposedHelpers.getStaticBooleanField(activityPendingTransitionFactory, "IS_CUSTOM_FROM_THIRD_PARTY")) { + i = 3; + } + switch (i) { + case 0: + pageActivity.overridePendingTransition(0, 0); + return; + case 1: + pageActivity.overridePendingTransition(RES_NFADE_IN, RES_NORMAL_OUT_TO_RIGHT); + return; + case 2: + pageActivity.overridePendingTransition(RES_NFADE_IN, RES_BIG_IMAGE_OUT_TO_RIGHT); + return; + case 3: + pageActivity.overridePendingTransition(RES_CUSTOM_FADE_IN, RES_CUSTOM_OUT_TO_RIGHT); + return; + case 4: + pageActivity.overridePendingTransition(RES_NFADE_IN, RES_NORMAL_OUT_TO_BOTTOM); + return; + case 5: + pageActivity.overridePendingTransition(CHAT_SQUARE_FADE_IN, CHAT_SQUARE_FADE_OUT); + return; + case 6: + pageActivity.overridePendingTransition(RES_NFADE_IN, RES_NORMAL_OUT_TO_LEFT); + return; + default: + pageActivity.overridePendingTransition(RES_NFADE_IN, RES_NORMAL_OUT_TO_RIGHT); + return; + } + } +}