diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/attributes/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/attributes/Fingerprints.kt new file mode 100644 index 000000000..fe681928e --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/attributes/Fingerprints.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.youtube.utils.fix.attributes + +import app.revanced.patches.youtube.utils.resourceid.ytOutlineMoonZ +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +/** + * Tested on YouTube 19.25.xx ~ YouTube 20.02.xx. + */ +internal val setSleepTimerDrawableFingerprint = legacyFingerprint( + name = "setSleepTimerDrawableFingerprint", + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Z", "Ljava/lang/String;"), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, // Context.getResources() + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, // R.drawable.yt_outline_moon_z_vd_theme_24 + Opcode.INVOKE_VIRTUAL, // Resources.getDrawable(int) + ), + literals = listOf(ytOutlineMoonZ), +) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/attributes/ThemeAttributesPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/attributes/ThemeAttributesPatch.kt new file mode 100644 index 000000000..7f3e98af6 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/attributes/ThemeAttributesPatch.kt @@ -0,0 +1,67 @@ +package app.revanced.patches.youtube.utils.fix.attributes + +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater +import app.revanced.patches.youtube.utils.playservice.versionCheckPatch +import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch +import app.revanced.util.fingerprint.matchOrThrow +import app.revanced.util.referenceMatchesOrThrow +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction + +val themeAttributesPatch = bytecodePatch( + description = "themeAttributesPatch" +) { + dependsOn( + sharedResourceIdPatch, + versionCheckPatch, + ) + + execute { + if (!is_19_25_or_greater) { + return@execute + } + + /** + * There is a warning in the logcat of an unpatched YouTube 19.25.39+: + * + * Drawable com.google.android.youtube:drawable/yt_outline_moon_z_vd_theme_24 has unresolved theme attributes! Consider using Resources.getDrawable(int, Theme) or Context.getDrawable(int). + * java.lang.RuntimeException + * at android.content.res.Resources.getDrawable(Resources.java:857) + * + * According to [stackoverflow](https://stackoverflow.com/questions/28932306/logcat-says-resource-has-unresolved-theme-attributes), + * Replace [Resources.getDrawable(int)] with [Context.getDrawable(int)]. + */ + setSleepTimerDrawableFingerprint.matchOrThrow().let { + it.method.apply { + val getResourcesIndex = it.patternMatch!!.startIndex + val getDrawableIndex = it.patternMatch!!.endIndex + + // Verify that the correct pattern has been found. + referenceMatchesOrThrow( + getResourcesIndex, + "Landroid/content/Context;->getResources()Landroid/content/res/Resources;" + ) + referenceMatchesOrThrow( + getDrawableIndex, + "Landroid/content/res/Resources;->getDrawable(I)Landroid/graphics/drawable/Drawable;" + ) + + val contextRegister = + getInstruction(getResourcesIndex).registerC + val identifierRegister = + getInstruction(getDrawableIndex).registerD + + replaceInstruction( + getDrawableIndex, + "invoke-virtual {v$contextRegister, v$identifierRegister}, " + + "Landroid/content/Context;->getDrawable(I)Landroid/graphics/drawable/Drawable;" + ) + removeInstructions(getResourcesIndex, 2) + } + } + + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt index ddbf22d3d..b2e4a1e4d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt @@ -222,6 +222,8 @@ var youTubeLogo = -1L private set var ytFillBell = -1L private set +var ytOutlineMoonZ = -1L + private set var ytOutlinePictureInPictureWhite = -1L private set var ytOutlineVideoCamera = -1L @@ -656,6 +658,10 @@ internal val sharedResourceIdPatch = resourcePatch( DRAWABLE, "yt_fill_bell_black_24" ] + ytOutlineMoonZ = resourceMappings[ + DRAWABLE, + "yt_outline_moon_z_vd_theme_24" + ] ytOutlinePictureInPictureWhite = resourceMappings[ DRAWABLE, "yt_outline_picture_in_picture_white_24" diff --git a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index cd58c6e34..18edf0a80 100644 --- a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -529,6 +529,11 @@ fun Method.findInstructionIndicesReversedOrThrow(opcode: Opcode): List { return instructions } +fun Method.referenceMatchesOrThrow(targetIndex: Int, reference: String) { + val targetReference = getInstruction(targetIndex).reference.toString() + if (reference != targetReference) throw PatchException("References do not match. Expected: '$reference', Found: '$targetReference'") +} + /** * Called for _all_ instructions with the given literal value. */