diff --git a/src/main/kotlin/app/revanced/patches/music/utils/fix/accessibility/AccessibilityNodeInfoPatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/fix/accessibility/AccessibilityNodeInfoPatch.kt new file mode 100644 index 000000000..15d6d84ad --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/utils/fix/accessibility/AccessibilityNodeInfoPatch.kt @@ -0,0 +1,57 @@ +package app.revanced.patches.music.utils.fix.accessibility + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patches.music.utils.fix.accessibility.fingerprints.TouchExplorationHoverEventFingerprint +import app.revanced.util.containsMethodReferenceNameInstructionIndex +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +object AccessibilityNodeInfoPatch : BytecodePatch( + setOf(TouchExplorationHoverEventFingerprint) +) { + override fun execute(context: BytecodeContext) { + + /** + * The "getTouchDelegateInfo" method has been implemented in YT Music v6.44.52. + * For some reason this method sometimes returns null, which throws [IllegalArgumentException]. + * This is considered unimplemented code, so remove all methods associated with it. + */ + TouchExplorationHoverEventFingerprint.result?.let { + it.mutableMethod.apply { + // Target instruction is invoke-static, but can also be invoke-virtual. + // Therefore, the opcode is not checked. + val touchExplorationHoverEventMethodIndex = implementation!!.instructions.indexOfFirst { instruction -> + val reference = ((instruction as? ReferenceInstruction)?.reference as? MethodReference) + ((instruction as? ReferenceInstruction)?.reference as? MethodReference)?.definingClass == definingClass + && reference?.returnType == "Z" + } + + // Doesn't raise an exception, even if the target instruction is not found in this method + val touchExplorationHoverEventMethodName = if (touchExplorationHoverEventMethodIndex > -1) + (getInstruction(touchExplorationHoverEventMethodIndex).reference as MethodReference).name + else + "UNDEFINED" + + val methods = it.mutableClass.methods + + methods.find { method -> + method.name == "getTouchDelegateInfo" + }?.apply { + if (!containsMethodReferenceNameInstructionIndex("isEmpty")) { + arrayOf( + "getTouchDelegateInfo", + name, + touchExplorationHoverEventMethodName + ).forEach { methodName -> + methods.removeIf { method -> + method.name == methodName + } + } + } + } + } + } // If this method has not been added, there is no need to remove it, so it will not raise any exceptions. + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/utils/fix/accessibility/fingerprints/TouchExplorationHoverEventFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/utils/fix/accessibility/fingerprints/TouchExplorationHoverEventFingerprint.kt new file mode 100644 index 000000000..1d96fe08a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/utils/fix/accessibility/fingerprints/TouchExplorationHoverEventFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.music.utils.fix.accessibility.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object TouchExplorationHoverEventFingerprint : MethodFingerprint( + returnType = "Z", + customFingerprint = { methodDef, _ -> methodDef.name == "onTouchExplorationHoverEvent" } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt index 159abbc17..cb0ca26c9 100644 --- a/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt @@ -3,6 +3,7 @@ package app.revanced.patches.music.utils.settings import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.music.utils.fix.accessibility.AccessibilityNodeInfoPatch import app.revanced.patches.music.utils.intenthook.IntentHookPatch import app.revanced.patches.music.utils.settings.ResourceUtils.YOUTUBE_MUSIC_SETTINGS_KEY import app.revanced.patches.music.utils.settings.ResourceUtils.addMusicPreference @@ -24,6 +25,7 @@ import java.util.concurrent.TimeUnit name = "Settings", description = "Adds ReVanced Extended settings to YouTube Music.", dependencies = [ + AccessibilityNodeInfoPatch::class, IntentHookPatch::class, SettingsBytecodePatch::class ], @@ -49,6 +51,13 @@ import java.util.concurrent.TimeUnit object SettingsPatch : AbstractSettingsResourcePatch( "music/settings" ), Closeable { + private val THREAD_COUNT = Runtime.getRuntime().availableProcessors() + private val threadPoolExecutor = Executors.newFixedThreadPool(THREAD_COUNT) + + lateinit var contexts: ResourceContext + internal var upward0636: Boolean = false + internal var upward0642: Boolean = false + override fun execute(context: ResourceContext) { contexts = context @@ -142,13 +151,6 @@ object SettingsPatch : AbstractSettingsResourcePatch( } - private val THREAD_COUNT = Runtime.getRuntime().availableProcessors() - private val threadPoolExecutor = Executors.newFixedThreadPool(THREAD_COUNT) - - lateinit var contexts: ResourceContext - internal var upward0636: Boolean = false - internal var upward0642: Boolean = false - internal fun addMusicPreference( category: CategoryType, key: String,