How to check visibility of software keyboard in Android? How to check visibility of software keyboard in Android? android android

How to check visibility of software keyboard in Android?


NEW ANSWER added Jan 25th 2012

Since writing the below answer, someone clued me in to the existence of ViewTreeObserver and friends, APIs which have been lurking in the SDK since version 1.

Rather than requiring a custom Layout type, a much simpler solution is to give your activity's root view a known ID, say @+id/activityRoot, hook a GlobalLayoutListener into the ViewTreeObserver, and from there calculate the size diff between your activity's view root and the window size:

final View activityRootView = findViewById(R.id.activityRoot);activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {    @Override    public void onGlobalLayout() {        int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();        if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard...            // ... do something here        }     }});

Using a utility such as:

public static float dpToPx(Context context, float valueInDp) {    DisplayMetrics metrics = context.getResources().getDisplayMetrics();    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);}

Easy!

Note:Your application must set this flag in Android Manifest android:windowSoftInputMode="adjustResize" otherwise above solution will not work.

ORIGINAL ANSWER

Yes it's possible, but it's far harder than it ought to be.

If I need to care about when the keyboard appears and disappears (which is quite often) then what I do is customize my top-level layout class into one which overrides onMeasure(). The basic logic is that if the layout finds itself filling significantly less than the total area of the window, then a soft keyboard is probably showing.

import android.app.Activity;import android.content.Context;import android.graphics.Rect;import android.util.AttributeSet;import android.widget.LinearLayout;/* * LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when  * the soft keyboard is shown and hidden (something Android can't tell you, weirdly).  */public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {    public LinearLayoutThatDetectsSoftKeyboard(Context context, AttributeSet attrs) {        super(context, attrs);    }    public interface Listener {        public void onSoftKeyboardShown(boolean isShowing);    }    private Listener listener;    public void setListener(Listener listener) {        this.listener = listener;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int height = MeasureSpec.getSize(heightMeasureSpec);        Activity activity = (Activity)getContext();        Rect rect = new Rect();        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);        int statusBarHeight = rect.top;        int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();        int diff = (screenHeight - statusBarHeight) - height;        if (listener != null) {            listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high        }        super.onMeasure(widthMeasureSpec, heightMeasureSpec);           }    }

Then in your Activity class...

public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ...        LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);        mainLayout.setListener(this);        ...    }    @Override    public void onSoftKeyboardShown(boolean isShowing) {        // do whatever you need to do here    }    ...}


So hopefully this helps someone out.

The new answer that Reuben Scratton gave is great and really efficient, but it really only works if you set your windowSoftInputMode to adjustResize. If you set it to adjustPan, it's still not possible to detect whether or not the keyboard is visible using his code snippet. To work around this, I made this tiny modification to the code above.

final View activityRootView = findViewById(R.id.activityRoot);activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {    Rect r = new Rect();    //r will be populated with the coordinates of your view that area still visible.    activityRootView.getWindowVisibleDisplayFrame(r);       int heightDiff = activityRootView.getRootView().getHeight() - r.height();    if (heightDiff > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...        ... do something here    } }}); 


It has been forever in terms of computer but this question is still unbelievably relevant!

So I've taken the above answers and have combined and refined them a bit...

public interface OnKeyboardVisibilityListener {    void onVisibilityChanged(boolean visible);}public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {    final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {        private boolean wasOpened;        private final int DefaultKeyboardDP = 100;        // From @nathanielwolf answer...  Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff        private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);        private final Rect r = new Rect();        @Override        public void onGlobalLayout() {            // Convert the dp to pixels.            int estimatedKeyboardHeight = (int) TypedValue                    .applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());            // Conclude whether the keyboard is shown or not.            activityRootView.getWindowVisibleDisplayFrame(r);            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);            boolean isShown = heightDiff >= estimatedKeyboardHeight;            if (isShown == wasOpened) {                Log.d("Keyboard state", "Ignoring global layout change...");                return;            }            wasOpened = isShown;            listener.onVisibilityChanged(isShown);        }    });}

Works for me :)

NOTE: If you notice that the DefaultKeyboardDP does not fit your device play with the value and post a comment for everyone to know what should be the value... eventually we will get the correct value to fit all devices!

For more details, check out the implementation on Cyborg