Skip to content

Commit f994264

Browse files
authored
fix(YouTube - Settings): Back button/gesture closes search instead of exiting (#5418)
1 parent eb61c1f commit f994264

File tree

4 files changed

+104
-32
lines changed

4 files changed

+104
-32
lines changed

extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/LicenseActivityHook.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import android.app.Activity;
77
import android.content.Context;
88
import android.preference.PreferenceFragment;
9+
import android.util.TypedValue;
910
import android.view.ViewGroup;
1011
import android.widget.TextView;
1112
import android.widget.Toolbar;
@@ -24,12 +25,15 @@
2425
* This class is responsible for injecting our own fragment by replacing the LicenseActivity.
2526
*/
2627
@SuppressWarnings("unused")
27-
public class LicenseActivityHook {
28+
public class LicenseActivityHook extends Activity {
2829

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

3132
private static ViewGroup.LayoutParams toolbarLayoutParams;
3233

34+
@SuppressLint("StaticFieldLeak")
35+
public static SearchViewController searchViewController;
36+
3337
public static void setToolbarLayoutParams(Toolbar toolbar) {
3438
if (toolbarLayoutParams != null) {
3539
toolbar.setLayoutParams(toolbarLayoutParams);
@@ -126,12 +130,13 @@ private static void createToolbar(Activity activity, PreferenceFragment fragment
126130
view -> view instanceof TextView);
127131
if (toolbarTextView != null) {
128132
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
133+
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
129134
}
130135
setToolbarLayoutParams(toolbar);
131136

132-
// Add Search Icon and EditText for ReVancedPreferenceFragment only.
137+
// Add Search bar only for ReVancedPreferenceFragment.
133138
if (fragment instanceof ReVancedPreferenceFragment) {
134-
SearchViewController.addSearchViewComponents(activity, toolbar, (ReVancedPreferenceFragment) fragment);
139+
searchViewController = SearchViewController.addSearchViewComponents(activity, toolbar, (ReVancedPreferenceFragment) fragment);
135140
}
136141

137142
toolBarParent.addView(toolbar, 0);

extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/SearchViewController.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.util.Pair;
1111
import android.view.MenuItem;
1212
import android.view.View;
13+
import android.view.inputmethod.EditorInfo;
1314
import android.view.inputmethod.InputMethodManager;
1415
import android.widget.ArrayAdapter;
1516
import android.widget.AutoCompleteTextView;
@@ -51,6 +52,7 @@ public class SearchViewController {
5152
private final Deque<String> searchHistory;
5253
private final AutoCompleteTextView autoCompleteTextView;
5354
private final boolean showSettingsSearchHistory;
55+
private int currentOrientation;
5456

5557
/**
5658
* Creates a background drawable for the SearchView with rounded corners.
@@ -83,8 +85,8 @@ public static int getSearchViewBackground() {
8385
/**
8486
* Adds search view components to the activity.
8587
*/
86-
public static void addSearchViewComponents(Activity activity, Toolbar toolbar, ReVancedPreferenceFragment fragment) {
87-
new SearchViewController(activity, toolbar, fragment);
88+
public static SearchViewController addSearchViewComponents(Activity activity, Toolbar toolbar, ReVancedPreferenceFragment fragment) {
89+
return new SearchViewController(activity, toolbar, fragment);
8890
}
8991

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

120+
// Disable fullscreen keyboard mode.
121+
autoCompleteTextView.setImeOptions(autoCompleteTextView.getImeOptions() | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
122+
118123
// Set background and query hint.
119124
searchView.setBackground(createBackgroundDrawable(toolbar.getContext()));
120125
searchView.setQueryHint(str("revanced_settings_search_hint"));
@@ -197,12 +202,14 @@ public boolean onQueryTextChange(String newText) {
197202
if (isSearchActive) {
198203
closeSearch();
199204
} else {
200-
activity.onBackPressed();
205+
activity.finish();
201206
}
202207
} catch (Exception ex) {
203208
Logger.printException(() -> "navigation click failure", ex);
204209
}
205210
});
211+
212+
monitorOrientationChanges();
206213
}
207214

208215
/**
@@ -285,6 +292,21 @@ private void updateSearchHistoryAdapter() {
285292
}
286293
}
287294

295+
private void monitorOrientationChanges() {
296+
currentOrientation = activity.getResources().getConfiguration().orientation;
297+
298+
searchView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
299+
int newOrientation = activity.getResources().getConfiguration().orientation;
300+
if (newOrientation != currentOrientation) {
301+
currentOrientation = newOrientation;
302+
if (autoCompleteTextView != null) {
303+
autoCompleteTextView.dismissDropDown();
304+
Logger.printDebug(() -> "Orientation changed, search history dismissed");
305+
}
306+
}
307+
});
308+
}
309+
288310
/**
289311
* Opens the search view and shows the keyboard.
290312
*/
@@ -313,7 +335,7 @@ private void openSearch() {
313335
/**
314336
* Closes the search view and hides the keyboard.
315337
*/
316-
private void closeSearch() {
338+
public void closeSearch() {
317339
isSearchActive = false;
318340
toolbar.getMenu().findItem(getResourceIdentifier(
319341
"action_search", "id")).setVisible(true);
@@ -326,6 +348,19 @@ private void closeSearch() {
326348
imm.hideSoftInputFromWindow(searchView.getWindowToken(), 0);
327349
}
328350

351+
public static boolean handleBackPress() {
352+
if (LicenseActivityHook.searchViewController != null
353+
&& LicenseActivityHook.searchViewController.isSearchExpanded()) {
354+
LicenseActivityHook.searchViewController.closeSearch();
355+
return true;
356+
}
357+
return false;
358+
}
359+
360+
public boolean isSearchExpanded() {
361+
return isSearchActive;
362+
}
363+
329364
/**
330365
* Custom ArrayAdapter for search history.
331366
*/

extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import android.text.SpannableStringBuilder;
1818
import android.text.TextUtils;
1919
import android.text.style.BackgroundColorSpan;
20+
import android.util.TypedValue;
2021
import android.view.ViewGroup;
2122
import android.view.Window;
2223
import android.view.WindowInsets;
@@ -248,7 +249,15 @@ private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
248249
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
249250
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
250251
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
251-
v.setPadding(0, statusInsets.top, 0, navInsets.bottom);
252+
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());
253+
254+
// Apply padding for display cutout in landscape.
255+
int leftPadding = cutoutInsets.left;
256+
int rightPadding = cutoutInsets.right;
257+
int topPadding = statusInsets.top;
258+
int bottomPadding = navInsets.bottom;
259+
260+
v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
252261
return insets;
253262
});
254263
}
@@ -265,10 +274,16 @@ private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
265274
true, TextView.class::isInstance);
266275
if (toolbarTextView != null) {
267276
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
277+
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
268278
}
269279

270280
LicenseActivityHook.setToolbarLayoutParams(toolbar);
271281

282+
if (LicenseActivityHook.searchViewController != null
283+
&& LicenseActivityHook.searchViewController.isSearchExpanded()) {
284+
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
285+
}
286+
272287
rootView.addView(toolbar, 0);
273288
return false;
274289
}

patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,15 @@ import app.revanced.patches.shared.misc.mapping.get
1212
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
1313
import app.revanced.patches.shared.misc.mapping.resourceMappings
1414
import app.revanced.patches.shared.misc.settings.overrideThemeColors
15-
import app.revanced.patches.shared.misc.settings.preference.BasePreference
16-
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
17-
import app.revanced.patches.shared.misc.settings.preference.InputType
18-
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
19-
import app.revanced.patches.shared.misc.settings.preference.ListPreference
20-
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
21-
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
22-
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
15+
import app.revanced.patches.shared.misc.settings.preference.*
2316
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
24-
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
25-
import app.revanced.patches.shared.misc.settings.preference.TextPreference
2617
import app.revanced.patches.shared.misc.settings.settingsPatch
2718
import app.revanced.patches.youtube.misc.check.checkEnvironmentPatch
2819
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
2920
import app.revanced.patches.youtube.misc.fix.playbackspeed.fixPlaybackSpeedWhilePlayingPatch
3021
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
3122
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
32-
import app.revanced.util.ResourceGroup
33-
import app.revanced.util.addInstructionsAtControlFlowLabel
34-
import app.revanced.util.copyResources
35-
import app.revanced.util.copyXmlNode
36-
import app.revanced.util.findElementByAttributeValueOrThrow
37-
import app.revanced.util.findInstructionIndicesReversedOrThrow
38-
import app.revanced.util.inputStreamFromBundledResource
39-
import app.revanced.util.insertLiteralOverride
23+
import app.revanced.util.*
4024
import com.android.tools.smali.dexlib2.AccessFlags
4125
import com.android.tools.smali.dexlib2.Opcode
4226
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
@@ -152,15 +136,24 @@ private val settingsResourcePatch = resourcePatch {
152136
}
153137
}
154138

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

152+
licenseElement.setAttribute(
153+
"android:configChanges",
154+
"orientation|screenSize|keyboardHidden"
155+
)
156+
164157
val mimeType = document.createElement("data")
165158
mimeType.setAttribute("android:mimeType", "text/plain")
166159

@@ -267,6 +260,32 @@ val settingsPatch = bytecodePatch(
267260
methods.add(attachBaseContext)
268261
}
269262

263+
licenseActivityOnCreateFingerprint.classDef.apply {
264+
val onBackPressed = ImmutableMethod(
265+
type,
266+
"onBackPressed",
267+
emptyList(),
268+
"V",
269+
AccessFlags.PUBLIC.value,
270+
null,
271+
null,
272+
MutableMethodImplementation(3)
273+
).toMutable().apply {
274+
addInstructions(
275+
"""
276+
invoke-static {}, Lapp/revanced/extension/youtube/settings/SearchViewController;->handleBackPress()Z
277+
move-result v0
278+
if-nez v0, :search_handled
279+
invoke-virtual { p0 }, Landroid/app/Activity;->finish()V
280+
:search_handled
281+
return-void
282+
"""
283+
)
284+
285+
};
286+
methods.add(onBackPressed);
287+
};
288+
270289
// Update shared dark mode status based on YT theme.
271290
// This is needed because YT allows forcing light/dark mode
272291
// which then differs from the system dark mode status.
@@ -338,20 +357,18 @@ object PreferenceScreen : BasePreferenceScreen() {
338357
icon = "@drawable/revanced_settings_screen_05_player",
339358
layout = "@layout/preference_with_icon",
340359
)
341-
342360
val SHORTS = Screen(
343361
key = "revanced_settings_screen_06_shorts",
344362
summaryKey = null,
345363
icon = "@drawable/revanced_settings_screen_06_shorts",
346364
layout = "@layout/preference_with_icon",
347365
)
348-
349366
val SEEKBAR = Screen(
350367
key = "revanced_settings_screen_07_seekbar",
351368
summaryKey = null,
352369
icon = "@drawable/revanced_settings_screen_07_seekbar",
353370
layout = "@layout/preference_with_icon",
354-
)
371+
)
355372
val SWIPE_CONTROLS = Screen(
356373
key = "revanced_settings_screen_08_swipe_controls",
357374
summaryKey = null,

0 commit comments

Comments
 (0)