Skip to content

Instantly share code, notes, and snippets.

@andrewmunn
Last active June 29, 2021 16:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save andrewmunn/af4c15210dd376f69990eca672d2d0e7 to your computer and use it in GitHub Desktop.
Save andrewmunn/af4c15210dd376f69990eca672d2d0e7 to your computer and use it in GitHub Desktop.
Android Keyboard Status Observable
/**
* Manages access to the Android soft keyboard.
*/
class KeyboardManager @Inject constructor(private val activity: Activity) {
/**
* Observable of the status of the keyboard. Subscribing to this creates a
* Global Layout Listener which is automatically removed when this
* observable is disposed.
*/
fun status() = Observable.create<KeyboardStatus> { emitter ->
val rootView = activity.findViewById<View>(android.R.id.content)
// why are we using a global layout listener? Surely Android
// has callback for when the keyboard is open or closed? Surely
// Android at least lets you query the status of the keyboard?
// Nope! https://stackoverflow.com/questions/4745988/
val globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
val rect = Rect().apply { rootView.getWindowVisibleDisplayFrame(this) }
val screenHeight = rootView.height
// rect.bottom is the position above soft keypad or device button.
// if keypad is shown, the rect.bottom is smaller than that before.
val keypadHeight = screenHeight - rect.bottom
// 0.15 ratio is perhaps enough to determine keypad height.
if (keypadHeight > screenHeight * 0.15) {
emitter.onNext(KeyboardStatus.OPEN)
} else {
emitter.onNext(KeyboardStatus.CLOSED)
}
}
rootView.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
emitter.setCancellable {
rootView.viewTreeObserver.removeOnGlobalLayoutListener(globalLayoutListener)
}
}.distinctUntilChanged()
}
enum class KeyboardStatus {
OPEN, CLOSED
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment