Detecting Android Soft Keyboard Visibility Changes
Overview
Detecting when the soft keyboard appears or disappears on Android devices can be achieved by monitoring changes in the root view's layout through ViewTreeObserver.OnGlobalLayoutListener. This approach avoids the need for adding custom layout overlays or complex configuration.
Implementation
The core technique involves observing the android.R.id.content view, which represents the window's content area. When the keyboard opens, the available height derceases; when it closes, the height returns to its original value.
import android.app.Activity;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
public class SoftKeyboardDetector implements ViewTreeObserver.OnGlobalLayoutListener {
private static final String LOG_TAG = "KeyboardDetector";
private View rootContent;
private int initialHeight;
private int lastMeasuredHeight;
private KeyboardStateCallback callback;
public interface KeyboardStateCallback {
void onKeyboardStateChanged(boolean visible, int keyboardHeightPx);
}
public void setKeyboardCallback(KeyboardStateCallback callback) {
this.callback = callback;
}
public SoftKeyboardDetector(Activity activity) {
if (activity == null) {
Log.w(LOG_TAG, "Activity reference cannot be null");
return;
}
rootContent = activity.findViewById(android.R.id.content);
if (rootContent != null) {
registerLayoutObserver();
}
}
private void registerLayoutObserver() {
rootContent.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
int currentHeight = rootContent.getHeight();
if (currentHeight == 0) {
return;
}
boolean heightChanged = false;
if (lastMeasuredHeight == 0) {
lastMeasuredHeight = currentHeight;
initialHeight = currentHeight;
} else {
heightChanged = (lastMeasuredHeight != currentHeight);
lastMeasuredHeight = currentHeight;
}
if (heightChanged) {
handleKeyboardTransition(currentHeight);
}
}
private void handleKeyboardTransition(int currentHeight) {
boolean keyboardVisible;
int keyboardHeight = 0;
if (initialHeight == currentHeight) {
keyboardVisible = false;
} else {
keyboardVisible = true;
keyboardHeight = initialHeight - currentHeight;
}
if (callback != null) {
callback.onKeyboardStateChanged(keyboardVisible, keyboardHeight);
}
}
public void cleanup() {
if (rootContent != null) {
ViewTreeObserver observer = rootContent.getViewTreeObserver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
observer.removeOnGlobalLayoutListener(this);
}
}
}
}
Activity Configuration
To enable proper keyboard detection, the Activity must be configured to resize the window when the input method appears. Add the following to your Activity in the manifest:
<activity
android:name=".YourActivity"
android:windowSoftInputMode="adjustResize" />
Usage Example
public class MainActivity extends AppCompatActivity {
private SoftKeyboardDetector keyboardDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
keyboardDetector = new SoftKeyboardDetector(this);
keyboardDetector.setKeyboardCallback((visible, height) -> {
if (visible) {
Log.d("MainActivity", "Keyboard shown, height: " + height + "px");
} else {
Log.d("MainActivity", "Keyboard hidden");
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (keyboardDetector != null) {
keyboardDetector.cleanup();
}
}
}
How It Works
- The listener attaches to the root content view's
ViewTreeObserver - When layout changes occur,
onGlobalLayout()fires - The implementation compares the current view height against the original height
- A reduced height indicates the keyboard is visible; returning to the original height means the keyboard has hidden
- The difference between heights represents the keyboard's pixel height
This method works reliably across most Android versions without requiring system-level permissions or intrusive techniques.