feat(YouTube - Navigation bar components): Add missing resource for Cairo notification icon (YouTube 19.34.42+) https://github.com/inotia00/ReVanced_Extended/issues/2553

This commit is contained in:
inotia00 2024-12-16 12:55:12 +09:00
parent 2fce2f7139
commit 831d2a1e76
9 changed files with 119 additions and 2 deletions

View File

@ -197,6 +197,8 @@ public class GeneralPatch {
// region [Hide navigation bar components] patch // region [Hide navigation bar components] patch
private static final int fillBellCairoBlack = ResourceUtils.getDrawableIdentifier("yt_fill_bell_cairo_black_24");
private static final Map<NavigationButton, Boolean> shouldHideMap = new EnumMap<>(NavigationButton.class) { private static final Map<NavigationButton, Boolean> shouldHideMap = new EnumMap<>(NavigationButton.class) {
{ {
put(NavigationButton.HOME, Settings.HIDE_NAVIGATION_HOME_BUTTON.get()); put(NavigationButton.HOME, Settings.HIDE_NAVIGATION_HOME_BUTTON.get());
@ -216,6 +218,18 @@ public class GeneralPatch {
return Settings.ENABLE_TRANSLUCENT_NAVIGATION_BAR.get(); return Settings.ENABLE_TRANSLUCENT_NAVIGATION_BAR.get();
} }
/**
* @noinspection ALL
*/
public static void setCairoNotificationFilledIcon(EnumMap enumMap, Enum tabActivityCairo) {
if (fillBellCairoBlack != 0) {
// It's very unlikely, but Google might fix this issue someday.
// If so, [fillBellCairoBlack] might already be in enumMap.
// That's why 'EnumMap.putIfAbsent()' is used instead of 'EnumMap.put()'.
enumMap.putIfAbsent(tabActivityCairo, Integer.valueOf(fillBellCairoBlack));
}
}
public static boolean switchCreateWithNotificationButton(boolean original) { public static boolean switchCreateWithNotificationButton(boolean original) {
return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get() || original; return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get() || original;
} }

View File

@ -1,10 +1,14 @@
package app.revanced.patches.youtube.general.navigation package app.revanced.patches.youtube.general.navigation
import app.revanced.patches.youtube.utils.resourceid.ytFillBell
import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal const val ANDROID_AUTOMOTIVE_STRING = "Android Automotive"
internal const val TAB_ACTIVITY_CAIRO_STRING = "TAB_ACTIVITY_CAIRO"
internal val autoMotiveFingerprint = legacyFingerprint( internal val autoMotiveFingerprint = legacyFingerprint(
name = "autoMotiveFingerprint", name = "autoMotiveFingerprint",
opcodes = listOf( opcodes = listOf(
@ -13,7 +17,13 @@ internal val autoMotiveFingerprint = legacyFingerprint(
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_EQZ Opcode.IF_EQZ
), ),
strings = listOf("Android Automotive") strings = listOf(ANDROID_AUTOMOTIVE_STRING)
)
internal val imageEnumConstructorFingerprint = legacyFingerprint(
name = "imageEnumConstructorFingerprint",
returnType = "V",
strings = listOf(TAB_ACTIVITY_CAIRO_STRING)
) )
internal val pivotBarChangedFingerprint = legacyFingerprint( internal val pivotBarChangedFingerprint = legacyFingerprint(
@ -59,6 +69,11 @@ internal val pivotBarStyleFingerprint = legacyFingerprint(
} }
) )
internal val setEnumMapFingerprint = legacyFingerprint(
name = "setEnumMapFingerprint",
literals = listOf(ytFillBell),
)
internal val translucentNavigationBarFingerprint = legacyFingerprint( internal val translucentNavigationBarFingerprint = legacyFingerprint(
name = "translucentNavigationBarFingerprint", name = "translucentNavigationBarFingerprint",
literals = listOf(45630927L), literals = listOf(45630927L),

View File

@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.navigation.addBottomBarContainerHook import app.revanced.patches.youtube.utils.navigation.addBottomBarContainerHook
@ -11,20 +12,54 @@ import app.revanced.patches.youtube.utils.navigation.hookNavigationButtonCreated
import app.revanced.patches.youtube.utils.navigation.navigationBarHookPatch import app.revanced.patches.youtube.utils.navigation.navigationBarHookPatch
import app.revanced.patches.youtube.utils.patch.PatchList.NAVIGATION_BAR_COMPONENTS import app.revanced.patches.youtube.utils.patch.PatchList.NAVIGATION_BAR_COMPONENTS
import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_28_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.patches.youtube.utils.settings.settingsPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.matchOrThrow
import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow import app.revanced.util.indexOfFirstStringInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private val navigationBarComponentsResourcePatch = resourcePatch(
description = "navigationBarComponentsResourcePatch"
) {
dependsOn(versionCheckPatch)
execute {
if (is_19_28_or_greater) {
// Since I couldn't get the Cairo notification filled icon anywhere,
// I just made it as close as possible.
arrayOf(
"xxxhdpi",
"xxhdpi",
"xhdpi",
"hdpi",
"mdpi"
).forEach { dpi ->
copyResources(
"youtube/navigationbuttons",
ResourceGroup(
"drawable-$dpi",
"yt_fill_bell_cairo_black_24.png"
)
)
}
}
}
}
@Suppress("unused") @Suppress("unused")
val navigationBarComponentsPatch = bytecodePatch( val navigationBarComponentsPatch = bytecodePatch(
NAVIGATION_BAR_COMPONENTS.title, NAVIGATION_BAR_COMPONENTS.title,
@ -33,7 +68,9 @@ val navigationBarComponentsPatch = bytecodePatch(
compatibleWith(COMPATIBLE_PACKAGE) compatibleWith(COMPATIBLE_PACKAGE)
dependsOn( dependsOn(
navigationBarComponentsResourcePatch,
settingsPatch, settingsPatch,
sharedResourceIdPatch,
navigationBarHookPatch, navigationBarHookPatch,
versionCheckPatch, versionCheckPatch,
) )
@ -90,7 +127,7 @@ val navigationBarComponentsPatch = bytecodePatch(
// region patch for hide navigation buttons // region patch for hide navigation buttons
autoMotiveFingerprint.methodOrThrow().apply { autoMotiveFingerprint.methodOrThrow().apply {
val insertIndex = indexOfFirstStringInstructionOrThrow("Android Automotive") - 1 val insertIndex = indexOfFirstStringInstructionOrThrow(ANDROID_AUTOMOTIVE_STRING) - 1
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions( addInstructions(
@ -122,6 +159,51 @@ val navigationBarComponentsPatch = bytecodePatch(
// endregion // endregion
// region fix for cairo notification icon
/**
* The Cairo navigation bar was widely rolled out in YouTube 19.28.42.
*
* Unlike Home, Shorts, and Subscriptions, which have Cairo icons,
* Notifications does not have a Cairo icon.
*
* This led to an issue <a href="https://github.com/ReVanced/revanced-patches/issues/4046">revanced-patches#4046</a>,
* Which was closed as not planned because it was a YouTube issue and not a ReVanced issue.
*
* It was not too hard to fix, so it was implemented as a patch.
*/
if (is_19_28_or_greater) {
val cairoNotificationEnumReference = with (imageEnumConstructorFingerprint.methodOrThrow()) {
val stringIndex = indexOfFirstStringInstructionOrThrow(TAB_ACTIVITY_CAIRO_STRING)
val cairoNotificationEnumIndex = indexOfFirstInstructionOrThrow(stringIndex) {
opcode == Opcode.SPUT_OBJECT
}
getInstruction<ReferenceInstruction>(cairoNotificationEnumIndex).reference
}
setEnumMapFingerprint.methodOrThrow().apply {
val enumMapIndex = indexOfFirstInstructionReversedOrThrow {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.definingClass == "Ljava/util/EnumMap;" &&
reference.name == "put" &&
reference.parameterTypes.firstOrNull() == "Ljava/lang/Enum;"
}
val (enumMapRegister, enumRegister) = getInstruction<FiveRegisterInstruction>(enumMapIndex).let {
Pair(it.registerC, it.registerD)
}
addInstructions(
enumMapIndex + 1, """
sget-object v$enumRegister, $cairoNotificationEnumReference
invoke-static {v$enumMapRegister, v$enumRegister}, $GENERAL_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V
"""
)
}
}
// endregion
// Hook navigation button created, in order to hide them. // Hook navigation button created, in order to hide them.
hookNavigationButtonCreated(GENERAL_CLASS_DESCRIPTOR) hookNavigationButtonCreated(GENERAL_CLASS_DESCRIPTOR)

View File

@ -216,6 +216,8 @@ var youTubeControlsOverlaySubtitleButton = -1L
private set private set
var youTubeLogo = -1L var youTubeLogo = -1L
private set private set
var ytFillBell = -1L
private set
var ytOutlinePictureInPictureWhite = -1L var ytOutlinePictureInPictureWhite = -1L
private set private set
var ytOutlineVideoCamera = -1L var ytOutlineVideoCamera = -1L
@ -638,6 +640,10 @@ internal val sharedResourceIdPatch = resourcePatch(
ID, ID,
"youtube_logo" "youtube_logo"
] ]
ytFillBell = resourceMappings[
DRAWABLE,
"yt_fill_bell_black_24"
]
ytOutlinePictureInPictureWhite = resourceMappings[ ytOutlinePictureInPictureWhite = resourceMappings[
DRAWABLE, DRAWABLE,
"yt_outline_picture_in_picture_white_24" "yt_outline_picture_in_picture_white_24"

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB