Skip to content

Commit

Permalink
fix(YouTube/Shorts components): even if Hide navigation bar is turn…
Browse files Browse the repository at this point in the history
…ed on, the navigation bar will reappear when the user opens the comments or description panel in Shorts
  • Loading branch information
inotia00 committed Sep 25, 2024
1 parent 6c060c5 commit 2cdc05a
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -1,71 +1,83 @@
package app.revanced.patches.youtube.shorts.components

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patches.youtube.shorts.components.fingerprints.BottomNavigationBarFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.RenderBottomNavigationBarFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.SetPivotBarFingerprint
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.youtube.shorts.components.fingerprints.BottomBarContainerHeightFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.ReelWatchPagerFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.SHORTS_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.navigation.fingerprints.InitializeButtonsFingerprint
import app.revanced.patches.youtube.utils.navigation.NavigationBarHookPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.BottomBarContainer
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelWatchPlayer
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.fingerprint.MultiMethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
import app.revanced.util.injectLiteralInstructionViewCall
import app.revanced.util.patch.MultiMethodBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference

object ShortsNavigationBarPatch : BytecodePatch(
setOf(
BottomNavigationBarFingerprint,
InitializeButtonsFingerprint,
RenderBottomNavigationBarFingerprint
)
/**
* Up to YouTube 19.28.42, there are two Methods with almost the same pattern.
*
* In certain YouTube versions, the hook should be done not on the first matching Method, but also on the last matching Method.
*
* 'Multiple fingerprint search' feature is not yet implemented in ReVanced Patcher,
* So I just implement it via [MultiMethodFingerprint].
*
* Related Issues:
* https://github.com/ReVanced/revanced-patcher/issues/74
* https://github.com/ReVanced/revanced-patcher/issues/308
*/
@Patch(dependencies = [NavigationBarHookPatch::class])
object ShortsNavigationBarPatch : MultiMethodBytecodePatch(
fingerprints = setOf(ReelWatchPagerFingerprint),
multiFingerprints = setOf(BottomBarContainerHeightFingerprint)
) {
override fun execute(context: BytecodeContext) {
super.execute(context)

InitializeButtonsFingerprint.resultOrThrow().let { parentResult ->
SetPivotBarFingerprint.also { it.resolve(context, parentResult.classDef) }
.resultOrThrow().let {
it.mutableMethod.apply {
val startIndex = it.scanResult.patternScanResult!!.startIndex
val register = getInstruction<OneRegisterInstruction>(startIndex).registerA
// region patch for set navigation bar height.

addInstruction(
startIndex + 1,
"invoke-static {v$register}, $SHORTS_CLASS_DESCRIPTOR->setNavigationBar(Ljava/lang/Object;)V"
)
}
}
}

RenderBottomNavigationBarFingerprint.resultOrThrow().let {
val walkerMethod =
it.getWalkerMethod(context, it.scanResult.patternScanResult!!.endIndex)

walkerMethod.addInstruction(
0,
"invoke-static {}, $SHORTS_CLASS_DESCRIPTOR->hideShortsNavigationBar()V"
)
}

BottomNavigationBarFingerprint.result?.let {
BottomBarContainerHeightFingerprint.resultOrThrow().forEach {
it.mutableMethod.apply {
val targetIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "findViewById"
val constIndex = indexOfFirstWideLiteralInstructionValue(BottomBarContainer)

val targetIndex = indexOfFirstInstructionOrThrow(constIndex) {
getReference<MethodReference>()?.name == "getHeight"
} + 1
val insertRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA

val heightRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA

addInstructions(
targetIndex + 1, """
invoke-static {v$insertRegister}, $SHORTS_CLASS_DESCRIPTOR->hideShortsNavigationBar(Landroid/view/View;)Landroid/view/View;
move-result-object v$insertRegister
invoke-static {v$heightRegister}, $SHORTS_CLASS_DESCRIPTOR->overrideNavigationBarHeight(I)I
move-result v$heightRegister
"""
)
}
}

NavigationBarHookPatch.addBottomBarContainerHook("$SHORTS_CLASS_DESCRIPTOR->setNavigationBar(Landroid/view/View;)V")

// endregion.

// region patch for addOnAttachStateChangeListener.

val smaliInstruction = """
invoke-static {v$REGISTER_TEMPLATE_REPLACEMENT}, $SHORTS_CLASS_DESCRIPTOR->onShortsCreate(Landroid/view/View;)V
"""

ReelWatchPagerFingerprint.injectLiteralInstructionViewCall(
ReelWatchPlayer,
smaliInstruction
)

// endregion.

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package app.revanced.patches.youtube.shorts.components.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.BottomBarContainer
import app.revanced.util.containsWideLiteralInstructionValue
import app.revanced.util.fingerprint.MultiMethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

internal object BottomBarContainerHeightFingerprint : MultiMethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/View;", "Landroid/os/Bundle;"),
strings = listOf("r_pfvc"),
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionValue(BottomBarContainer)
},
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.revanced.patches.youtube.shorts.components.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelWatchPlayer
import app.revanced.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

internal object ReelWatchPagerFingerprint : LiteralValueFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Landroid/view/View;",
literalSupplier = { ReelWatchPlayer }
)

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ object SharedResourceIdPatch : ResourcePatch() {
var ReelRightLikeIcon = -1L
var ReelTimeBarPlayedColor = -1L
var ReelVodTimeStampsContainer = -1L
var ReelWatchPlayer = -1L
var RelatedChipCloudMargin = -1L
var RightComment = -1L
var ScrimOverlay = -1L
Expand Down Expand Up @@ -204,6 +205,7 @@ object SharedResourceIdPatch : ResourcePatch() {
ReelRightLikeIcon = getId(DRAWABLE, "reel_right_like_icon")
ReelTimeBarPlayedColor = getId(COLOR, "reel_time_bar_played_color")
ReelVodTimeStampsContainer = getId(ID, "reel_vod_timestamps_container")
ReelWatchPlayer = getId(ID, "reel_watch_player")
RelatedChipCloudMargin = getId(LAYOUT, "related_chip_cloud_reduced_margins")
RightComment = getId(DRAWABLE, "ic_right_comment_32c")
ScrimOverlay = getId(ID, "scrim_overlay")
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/app/revanced/util/BytecodeUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableField
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.fingerprint.MultiMethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
Expand All @@ -38,6 +39,8 @@ fun MethodFingerprint.isDeprecated() =

fun MethodFingerprint.resultOrThrow() = result ?: throw exception

fun MultiMethodFingerprint.resultOrThrow() = result.ifEmpty { throw exception }

/**
* The [PatchException] of failing to resolve a [MethodFingerprint].
*
Expand All @@ -46,6 +49,9 @@ fun MethodFingerprint.resultOrThrow() = result ?: throw exception
val MethodFingerprint.exception
get() = PatchException("Failed to resolve ${this.javaClass.simpleName}")

val MultiMethodFingerprint.exception
get() = PatchException("Failed to resolve ${this.javaClass.simpleName}")

fun MethodFingerprint.alsoResolve(context: BytecodeContext, fingerprint: MethodFingerprint) =
also { resolve(context, fingerprint.resultOrThrow().classDef) }.resultOrThrow()

Expand Down
Loading

0 comments on commit 2cdc05a

Please sign in to comment.