diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/scaffold/LauncherScaffold.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/scaffold/LauncherScaffold.kt index f43c8cd2e..4ee10e18a 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/scaffold/LauncherScaffold.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/scaffold/LauncherScaffold.kt @@ -63,6 +63,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.listSaver import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.runtime.withFrameNanos import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.composed @@ -79,6 +80,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalViewConfiguration @@ -988,6 +990,7 @@ internal fun LauncherScaffold( val lifecycleOwner = LocalLifecycleOwner.current val activity = LocalActivity.current as AppCompatActivity val view = LocalView.current + val focusManager = LocalFocusManager.current val wallpaperManager = remember(activity) { WallpaperManager.getInstance(activity) } @@ -1136,10 +1139,27 @@ internal fun LauncherScaffold( // The search does not survive leaving the launcher, not even for a short app // switch: coming back should always show a fresh search. if (!state.isLocked) { + // Clear the query first: the page transition below animates and must not + // be what keeps a stale query around. + searchVM.reset() if (state.currentComponent?.survivesPause != true) { state.reset() } - searchVM.reset() + } + } + // The framework hands the keyboard focus - and with it the on-screen keyboard - + // back to the search bar's text field whenever the launcher's window regains + // focus, even though no search is open. The home screen would then sit behind an + // on-screen keyboard and the physical keyboard would type into the search bar + // without the search results ever opening, because the characters are delivered + // to the focused text field instead of the key event handler. Give that focus up + // again, one frame after the resume, so that it also works when the framework + // grants the focus while the window is coming back. + if (activity.pauseTime > 0L) { + withFrameNanos { } + if (state.currentComponent !is SearchComponent) { + focusManager.clearFocus() + activity.hideSoftKeyboard() } } awaitCancellation() @@ -1409,8 +1429,11 @@ internal fun LauncherScaffold( // as usual from now on. state.isTypingSearch = false scope.launch { state.onSearchBarTap() } - state.isSearchBarFocused = true } + // Keep this in sync with the real focus state. It must go back to false when + // the text field loses focus, otherwise the launcher keeps asking for it + // (LauncherSearchBar requests focus whenever this is true). + state.isSearchBarFocused = it }, onKeyboardActionGo = if (launchOnEnter) { { searchVM.launchBestMatchOrAction(activity) }