Keep the search bar from holding the keyboard focus on the home screen
Returning to the launcher from another app left the search bar's text field focused, with the on-screen keyboard up. Typing on the physical keyboard then went into the search bar - the IME commits characters to the focused text field - while the search results never appeared, because the key event handler deliberately leaves keys alone while the text field has the focus. Coming home looked like the launcher had stopped responding to the keyboard; it happens with a freshly started launcher and a plain app switch, with no search ever opened. Give that focus up again one frame after the launcher is resumed, and hide the on-screen keyboard, as long as the home screen is what is shown. Only on a resume (pauseTime > 0), so that a search component used as the home screen can still focus itself when the launcher starts. Also set isSearchBarFocused back to false when the text field loses the focus, like upstream does. LauncherSearchBar requests focus whenever that flag is true, so only ever setting it to true made the text field focus itself again after it had been unfocused - which is what kept the on-screen keyboard around. Clear the search query before resetting the page in the resume path, so that a stale query is gone even if the page transition is interrupted. Note: the focus fix is a workaround for the framework/IME handing the focus back to the text field; it is not verified on the device yet.
This commit is contained in:
@@ -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) }
|
||||
|
||||
Reference in New Issue
Block a user