Skip to content

fix(YouTube - Settings): Back button/gesture closes search instead of exiting #5418

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.app.Activity;
import android.content.Context;
import android.preference.PreferenceFragment;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toolbar;
Expand All @@ -24,12 +25,15 @@
* This class is responsible for injecting our own fragment by replacing the LicenseActivity.
*/
@SuppressWarnings("unused")
public class LicenseActivityHook {
public class LicenseActivityHook extends Activity {

private static int currentThemeValueOrdinal = -1; // Must initially be a non-valid enum ordinal value.

private static ViewGroup.LayoutParams toolbarLayoutParams;

@SuppressLint("StaticFieldLeak")
public static SearchViewController searchViewController;

public static void setToolbarLayoutParams(Toolbar toolbar) {
if (toolbarLayoutParams != null) {
toolbar.setLayoutParams(toolbarLayoutParams);
Expand Down Expand Up @@ -126,12 +130,13 @@ private static void createToolbar(Activity activity, PreferenceFragment fragment
view -> view instanceof TextView);
if (toolbarTextView != null) {
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
}
setToolbarLayoutParams(toolbar);

// Add Search Icon and EditText for ReVancedPreferenceFragment only.
// Add Search bar only for ReVancedPreferenceFragment.
if (fragment instanceof ReVancedPreferenceFragment) {
SearchViewController.addSearchViewComponents(activity, toolbar, (ReVancedPreferenceFragment) fragment);
searchViewController = SearchViewController.addSearchViewComponents(activity, toolbar, (ReVancedPreferenceFragment) fragment);
}

toolBarParent.addView(toolbar, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.util.Pair;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
Expand Down Expand Up @@ -51,6 +52,7 @@ public class SearchViewController {
private final Deque<String> searchHistory;
private final AutoCompleteTextView autoCompleteTextView;
private final boolean showSettingsSearchHistory;
private int currentOrientation;

/**
* Creates a background drawable for the SearchView with rounded corners.
Expand Down Expand Up @@ -83,8 +85,8 @@ public static int getSearchViewBackground() {
/**
* Adds search view components to the activity.
*/
public static void addSearchViewComponents(Activity activity, Toolbar toolbar, ReVancedPreferenceFragment fragment) {
new SearchViewController(activity, toolbar, fragment);
public static SearchViewController addSearchViewComponents(Activity activity, Toolbar toolbar, ReVancedPreferenceFragment fragment) {
return new SearchViewController(activity, toolbar, fragment);
}

private SearchViewController(Activity activity, Toolbar toolbar, ReVancedPreferenceFragment fragment) {
Expand Down Expand Up @@ -115,6 +117,9 @@ private SearchViewController(Activity activity, Toolbar toolbar, ReVancedPrefere
searchView.getContext().getResources().getIdentifier(
"android:id/search_src_text", null, null));

// Disable fullscreen keyboard mode.
autoCompleteTextView.setImeOptions(autoCompleteTextView.getImeOptions() | EditorInfo.IME_FLAG_NO_EXTRACT_UI);

// Set background and query hint.
searchView.setBackground(createBackgroundDrawable(toolbar.getContext()));
searchView.setQueryHint(str("revanced_settings_search_hint"));
Expand Down Expand Up @@ -197,12 +202,14 @@ public boolean onQueryTextChange(String newText) {
if (isSearchActive) {
closeSearch();
} else {
activity.onBackPressed();
activity.finish();
}
} catch (Exception ex) {
Logger.printException(() -> "navigation click failure", ex);
}
});

monitorOrientationChanges();
}

/**
Expand Down Expand Up @@ -285,6 +292,21 @@ private void updateSearchHistoryAdapter() {
}
}

private void monitorOrientationChanges() {
currentOrientation = activity.getResources().getConfiguration().orientation;

searchView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
int newOrientation = activity.getResources().getConfiguration().orientation;
if (newOrientation != currentOrientation) {
currentOrientation = newOrientation;
if (autoCompleteTextView != null) {
autoCompleteTextView.dismissDropDown();
Logger.printDebug(() -> "Orientation changed, search history dismissed");
}
}
});
}

/**
* Opens the search view and shows the keyboard.
*/
Expand Down Expand Up @@ -313,7 +335,7 @@ private void openSearch() {
/**
* Closes the search view and hides the keyboard.
*/
private void closeSearch() {
public void closeSearch() {
isSearchActive = false;
toolbar.getMenu().findItem(getResourceIdentifier(
"action_search", "id")).setVisible(true);
Expand All @@ -326,6 +348,19 @@ private void closeSearch() {
imm.hideSoftInputFromWindow(searchView.getWindowToken(), 0);
}

public static boolean handleBackPress() {
if (LicenseActivityHook.searchViewController != null
&& LicenseActivityHook.searchViewController.isSearchExpanded()) {
LicenseActivityHook.searchViewController.closeSearch();
return true;
}
return false;
}

public boolean isSearchExpanded() {
return isSearchActive;
}

/**
* Custom ArrayAdapter for search history.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.BackgroundColorSpan;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
Expand Down Expand Up @@ -248,7 +249,15 @@ private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
v.setPadding(0, statusInsets.top, 0, navInsets.bottom);
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());

// Apply padding for display cutout in landscape.
int leftPadding = cutoutInsets.left;
int rightPadding = cutoutInsets.right;
int topPadding = statusInsets.top;
int bottomPadding = navInsets.bottom;

v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
return insets;
});
}
Expand All @@ -265,10 +274,16 @@ private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
true, TextView.class::isInstance);
if (toolbarTextView != null) {
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
}

LicenseActivityHook.setToolbarLayoutParams(toolbar);

if (LicenseActivityHook.searchViewController != null
&& LicenseActivityHook.searchViewController.isSearchExpanded()) {
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
}

rootView.addView(toolbar, 0);
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,15 @@ import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.overrideThemeColors
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.InputType
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.*
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.misc.settings.preference.TextPreference
import app.revanced.patches.shared.misc.settings.settingsPatch
import app.revanced.patches.youtube.misc.check.checkEnvironmentPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.fix.playbackspeed.fixPlaybackSpeedWhilePlayingPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.copyResources
import app.revanced.util.copyXmlNode
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.inputStreamFromBundledResource
import app.revanced.util.insertLiteralOverride
import app.revanced.util.*
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
Expand Down Expand Up @@ -152,15 +136,24 @@ private val settingsResourcePatch = resourcePatch {
}
}

// Modify the manifest and add a data intent filter to the LicenseActivity.
// Some devices freak out if undeclared data is passed to an intent,
// and this change appears to fix the issue.
// Modify the manifest to enhance LicenseActivity behavior:
// 1. Add a data intent filter with MIME type "text/plain".
// Some devices crash if undeclared data is passed to an intent,
// and this change appears to fix the issue.
// 2. Add android:configChanges="orientation|screenSize|keyboardHidden".
// This prevents the activity from being recreated on configuration changes
// (e.g., screen rotation), preserving its current state and fragment.
document("AndroidManifest.xml").use { document ->
val licenseElement = document.childNodes.findElementByAttributeValueOrThrow(
"android:name",
"com.google.android.libraries.social.licenses.LicenseActivity",
)

licenseElement.setAttribute(
"android:configChanges",
"orientation|screenSize|keyboardHidden"
)

val mimeType = document.createElement("data")
mimeType.setAttribute("android:mimeType", "text/plain")

Expand Down Expand Up @@ -267,6 +260,32 @@ val settingsPatch = bytecodePatch(
methods.add(attachBaseContext)
}

licenseActivityOnCreateFingerprint.classDef.apply {
val onBackPressed = ImmutableMethod(
type,
"onBackPressed",
emptyList(),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(3)
).toMutable().apply {
addInstructions(
"""
invoke-static {}, Lapp/revanced/extension/youtube/settings/SearchViewController;->handleBackPress()Z
move-result v0
if-nez v0, :search_handled
invoke-virtual { p0 }, Landroid/app/Activity;->finish()V
:search_handled
return-void
"""
)

};
methods.add(onBackPressed);
};

// Update shared dark mode status based on YT theme.
// This is needed because YT allows forcing light/dark mode
// which then differs from the system dark mode status.
Expand Down Expand Up @@ -338,20 +357,18 @@ object PreferenceScreen : BasePreferenceScreen() {
icon = "@drawable/revanced_settings_screen_05_player",
layout = "@layout/preference_with_icon",
)

val SHORTS = Screen(
key = "revanced_settings_screen_06_shorts",
summaryKey = null,
icon = "@drawable/revanced_settings_screen_06_shorts",
layout = "@layout/preference_with_icon",
)

val SEEKBAR = Screen(
key = "revanced_settings_screen_07_seekbar",
summaryKey = null,
icon = "@drawable/revanced_settings_screen_07_seekbar",
layout = "@layout/preference_with_icon",
)
)
val SWIPE_CONTROLS = Screen(
key = "revanced_settings_screen_08_swipe_controls",
summaryKey = null,
Expand Down
Loading