536

I need to do a very simple thing - find out if the software keyboard is shown. Is this possible in Android?

Harshad Pansuriya
  • 17,218
  • 7
  • 58
  • 86
fhucho
  • 31,862
  • 40
  • 125
  • 178

44 Answers44

689

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
    }

    ...
}
Shahab Rauf
  • 2,629
  • 27
  • 34
Reuben Scratton
  • 37,934
  • 8
  • 74
  • 84
  • 63
    This wasn't working for me until I realized that you must set the following attribute on your activity: android:windowSoftInputMode="adjustResize" – ajh158 May 13 '11 at 19:28
  • I cant do the cast to LinearLayoutThatDetectsSoftKeyboard from my LinearLayout – Dayerman Jul 08 '11 at 07:03
  • +1, but what a pain... (I'm using the check in a functional test) – Peter Ajtai Dec 06 '11 at 19:39
  • This might be a stupid question, but how do I specify that my XML layout should be using this custom LinearLayout class?? – Spencer Ruport Dec 09 '11 at 20:53
  • 9
    Seems to be doing the trick. Also, if you don't know the root view's ID, here's how you can get the view: `((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)` – Goldsmith Jan 26 '12 at 13:20
  • Thanks for the update Reuben. This was indeed very useful. I will be posting an example project for this that will link to your answer and your profile. – Nelson Ramirez Feb 01 '12 at 17:08
  • Thanks Reuben, i did try your way and it worked for me too but it does not work when i remove the title bar... any suggestion pls – cavallo Feb 06 '12 at 12:49
  • 1
    Hi, Your answer to this post helped me greatly but however, since listener gets called everytime(I don't know why.....) I can't do anything with the layout. For example, I inserted a Toast when Keyboard is showing then the Toast keeps on popping up which means listener is getting called all the time.... Is there anyway to stop this? Is this because I implemented listener on the activity not like the way you created it? – Jae Mar 06 '12 at 00:15
  • 1
    Hi, if your original answer is based on this answer from 2010 { http://stackoverflow.com/questions/3409737/android-soft-keyboard-how-to-manipulate-views-on-keyboard-on-off/3422453#3422453 } then a credit is due. If not, then great minds think alike :) – OferR Mar 17 '12 at 07:56
  • 3
    increased if (heightDiff > 200) to 200... 100 didnt work for me tested it on QVGA (wildfire etc) devices, works as well .. :) – cV2 Apr 14 '12 at 23:56
  • 8
    If you try this using the **actual** root view (`android.R.id.content`) you will be able to more confidently say that the `System` rather than your application is the entity changing it's height. Would be much safer for the Android team to give us a break and let us know at least basic things about the SoftKeyboard input. – Graeme Jul 30 '12 at 10:06
  • Setting android:windowSoftInputMode="adjustResize" hides the EditText where the user is writing in some situations, so I couldn't use this approach. – mrcaramori Aug 14 '12 at 13:59
  • @Jae You're right the listener is called every time. Check out the answer here to solve it: http://stackoverflow.com/questions/7300497/adjust-layout-when-soft-keyboard-is-on?lq=1 – Zaheer Aug 30 '12 at 23:17
  • Make sure you add the listener back to the view tree each time the view is attached to the displayed view hierarchy. The listener is removed each time it is detached. – Sky Kelsey Nov 14 '12 at 20:44
  • 14
    Beware that `heightDiff` will always include the height of the action bar. In the new answer that has been ignored by testing if that height is greater than some constant, but 100 pixels is not sufficient for xxhdpi devices such as the Nexus 4. Consider converting that value to DPs if you really want to use this hacky work-around. – Paul Lammertsma Jan 03 '13 at 10:41
  • Pardon the typo. The Nexus 4 is xhdpi, not xxhdpi. (Presently there are no xxhdpi devices; that qualifier [is currently only used for the Nexus 10's launcher](https://plus.google.com/118292708268361843293/posts/ePQya3KsTjW).) – Paul Lammertsma Jan 03 '13 at 11:18
  • 2
    At the time this answer was written there was no such thing as an ActionBar. – Reuben Scratton Jan 03 '13 at 16:46
  • The Droid DNA should be xxhdpi – Tom anMoney Jan 17 '13 at 07:25
  • 1
    @Reuben I have a dialog with EditText need to do the same trick, but when I hide the soft keyboard with the key on it, can't get the global layout event(because the dialog size is not change? ), how could I detect this keyboard hide event? I know the position of the dialog on the screen will change, is it possible to catch that? – Lei Guo May 24 '13 at 03:40
  • 2
    Note that this has nothing really to do with the soft keyboard. Hiding and showing of the system bar equivalent on a Kindle Fire will cause changes in heights as well. I would not be surprised if this caused problems on other vendor-specific scenarios, such as Samsung's multi-window mode. It also makes gross assumptions regarding the size of soft keyboards, which can and do vary (and cannot readily be determined ahead of time by the app). Hence, this reports about UI changes that may or may not be caused by the soft keyboard. – CommonsWare Jul 10 '13 at 19:43
  • All true of course. I imagine those wanting this hack don't care about their UI being constrained by the keyboard particularly, just that their UI is being constrained at all. I wonder if the act of showing or hiding the keyboard shouldn't ideally trigger a resource config change, i.e. loading a layout suited to the reduced window size. Perhaps it'd make sense for windowSoftInputMode to have an option for that. – Reuben Scratton Jul 11 '13 at 14:23
  • This works, but it seems that the listener is only called when the activity is still running. Is there a way to do it outside the activity in which this is implemented in? If I were to minimize my main app, and perhaps bring up the keyboard through a google search? – jimmyC Jul 13 '13 at 00:47
  • You could manually invoke the listener from Activity.onResume() ? – Reuben Scratton Jul 15 '13 at 12:15
  • I mean the listener is only called on your application's activity; doesn't seem that the listener is invoked when another activity brings up a keyboard. – jimmyC Jul 15 '13 at 21:55
  • 1
    It doesn't work for android:windowSoftInputMode="adjustPan". I wanted that my screen shouldn't get shrinked after soft keyboard appears. Can you please tell any fix so that it works even for adjustPan – Shirish Herwade Aug 22 '13 at 05:37
  • 1
    I use a similar set up - but your setup doesn't allow for Chinese and Japenese keyboards who's "suggestion" rulers (which are required) make the screen area grow and shrink by more than 100 (Nexus 10). Instead, where possible, try and use ScreenHeight / 4 as the "fudge" value, as in all instances we've found a keyboard takes up at *least* 1/4 of the screen and any "suggestion bars" take up less than 1/4. (Remember to add an onOrientationChange method to reset the 1/4 value). – Graeme Nov 07 '13 at 11:53
  • 1
    I suggest you use dp and not pixels. I personally use >100dp. – cprcrack Dec 12 '13 at 19:37
  • But it's not working with me. i have 4 edittext on my activity. if i click on any edittext then it scrolling up but i want to scroll up screen when i click on any specific edittext – Sandip Armal Patil Jan 09 '14 at 10:57
  • @ReubenScratton can you take a look at it. http://stackoverflow.com/questions/20885086/screen-scrolling-up-when-clicking-on-any-edittext – Sandip Armal Patil Jan 09 '14 at 11:13
  • 9
    Notice: not working with WindowManager.LayoutParams.FLAG_FULLSCREEN and with a full screen theme. – VAV Mar 06 '14 at 13:23
  • 2
    @PaulLammertsma And even with DP, 100 is too small — 200 may be more safe choice. – Display Name Mar 12 '14 at 15:30
  • 2
    Use (height > 200) for keyboard open even and (height < 200) for keyboard close event :) – geekoraul Apr 21 '14 at 00:23
  • I think solution needs some kind of mechanism to check whether keyboard is opening or closing because of layout will change in both cases! – Fatih Türker Apr 24 '14 at 19:35
  • @PaulLammertsma you can get the height of the action bar in pixels instead: http://stackoverflow.com/questions/7165830/what-is-the-size-of-actionbar-in-pixels So you can remove the action bar height from the height diff. – Yoel Gluschnaider May 20 '14 at 10:54
  • 1
    In reply to Reuben Scratton's new answer. When using a viewpager you should use: activityRootView = mContext.mViewPager.getRootView(); – Tinus81 Feb 22 '13 at 21:07
  • @Reuben Scratton hi sir. my root linearLayout name is main and after using your code i get this error: `android.widget.LinearLayout cannot be cast to com.sample.Class.LinearLayoutThatDetectsSoftKeyboard` –  Dec 15 '14 at 08:11
  • FYI: I have a Scroll View, and I used `android:windowSoftInputMode="stateHidden|adjustPan"` which I set in `` part of the manifest file, works fine. It does re-size my scrollview so I can scroll to the bottom while the keyboard is shown, perhaps a quick tip: `scrollView.smoothScrollTo(0,70);` to make it scroll down (or to specific `Y`) – CularBytes Jul 19 '15 at 22:46
  • How about detecting hide soft keyboard event? You can't be sure by checking whether there is no height difference because there might be something else triggering `GlobalLayoutListener` which i am not fully in knowledge of. – Buddy Aug 13 '15 at 15:16
  • 1
    How about `android:windowSoftInputMode="adjustNothing" ` ? Thanks. I need to set `android:windowSoftInputMode` to `adjustNothing `. – Jerikc XIONG Aug 19 '15 at 09:12
  • Please do use 215 and above for XXHDPI (Similar to HTC One) . – JR Tan Sep 09 '15 at 10:38
  • This does not work if you enabled the KitKat immersive mode. – androidyue Sep 15 '15 at 06:27
  • Don't forget to remove the listener when done with it: activityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); – Bolling Oct 19 '15 at 08:43
  • This solution was too memory consuming. As soon as I implemented this, Kernel usage increased from 0 to 2% and User usage raised by 4%. – Shubham A. Oct 26 '15 at 09:51
  • I logged it. And onSoftKeyboardShown calling 3 times when keyboard is opened and 2 time when keyboard is closed. Can you explain why it calls many times? – AEMLoviji Jan 08 '16 at 15:32
  • for hi resolution devices use heightDiff > root.getRootView().getHeight() / 4 – Melbourne Lopes Apr 14 '16 at 09:01
  • Edited the "new answer" to use a DP value, so that it has a chance of working on newer devices too (as commented earlier by Paul Lammertsma and Sarge Borsch). – Jonik Jun 16 '16 at 11:43
  • actually the (heightdifference > screenHeight / 3) worked for me. i.e if the height difference is greater than that, I am taking keyboard as shown. – aravindkanna Jun 22 '16 at 11:56
  • It doesn't cover all devices. This answer is not generic. – hkaraoglu Jun 24 '16 at 09:47
  • @Reuben Scratton what is COMPLEX_UNIT_DIP? i meant what is the value of that object? – Sagar Chavada Sep 19 '16 at 05:57
  • @SagarChavada TypedValue.COMPLEX_UNIT_DIP – Shahab Rauf Sep 20 '16 at 07:53
  • @VAV, possibly this will work for a full screen: http://stackoverflow.com/a/19494006/2914140 (I mean adjusting a size of layout). – CoolMind Nov 02 '16 at 20:39
  • Just wondering, shouldn't you remove the global layout listener at some point to avoid memory leaks? (onDestroy for example) – Rafag Mar 29 '17 at 09:31
  • Why not `android.R.id.content` in findViewById – Faisal Naseer Apr 22 '17 at 10:05
  • Is there still no simple way of finding this out? :C – ZooMagic May 02 '18 at 12:08
  • Thanks for the answer. It's 2019 and I created a more neat solution: https://stackoverflow.com/a/54761109/5730321 – Leo Droidcoder Feb 19 '19 at 07:53
  • This solution is not working for coordinator layout root – Urchboy Jan 26 '20 at 23:09
  • Hi Reuben how are you? i have a question : why else{} that you did not write it has multiple action?(when keyboard comes up if{} run just once but else{} run multi time) – milad salimi Sep 16 '20 at 07:40
307

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() {
@Override
public 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
    }
 }
}); 
Omar Aflak
  • 2,588
  • 16
  • 36
Kachi
  • 3,539
  • 2
  • 21
  • 17
  • 1
    This is the one that worked for me. I was attempting to detect keyboard state from a custom `TwoDScrollerView` similar to http://stackoverflow.com/a/5224088/530513 although with zooming too. The child was not a simple `ImageView` but a custom layout (extends `RelativeLayout`) but was unable to detect the keyboard using the recommended solution despite setting `android:windowSoftInputMode="adjustResize"`. Thanks! – David O'Meara Aug 20 '12 at 05:15
  • 1
    Thank you thank you thank you! adjustResize just isn't viable for my app and your solution worked perfectly. – dwemthy Sep 28 '12 at 15:06
  • 1
    Works with `ActionBar` and `ActionBarSherlock`. Thanks a lot! By the way, there is a method `r.height()` :) – Dmitry Zaytsev Nov 26 '12 at 08:29
  • 1
    I'll attach a bounty here within 23 hours to mark this answer somehow. – Dmitry Zaytsev Nov 26 '12 at 08:30
  • I was using adjustPan due to scrolling views on my tabhost so this was a big help. I was spawning the Android mail client in one tabhost and hitting "Discard" would leave the keyboard up. Since none of my views need a keyboard (no EditText widgets), I just call imm.toggleSoftInput (InputMethodManager.SHOW_FORCED,0) directly in onGlobalLayou() when heightDiff > 100. – wufoo Nov 26 '12 at 15:36
  • It doesn't work for android:windowSoftInputMode="adjustPan". I wanted that my screen shouldn't get shrinked after soft keyboard appears. Can you please tell any fix so that it works even for adjustPan – Shirish Herwade Aug 22 '13 at 05:39
  • Works very nice... though I've just learned that the condition should have an extra else, if (heightDiff == 0) {\\*Too many times called and it has nothing to do with the keyboard...*\}, at least on my S4 it does... – TacB0sS Sep 23 '13 at 22:28
  • Worked for me nicely on S4, Android OS v4.2.2. – Dragan Marjanović Oct 09 '13 at 08:39
  • 1
    I use a similar set up - but your setup doesn't allow for Chinese and Japenese keyboards who's "suggestion" rulers (which are required) make the screen area grow and shrink by more than 100 (Nexus 10). Instead, where possible, try and use ScreenHeight / 4 as the "fudge" value, as in all instances we've found a keyboard takes up at least 1/4 of the screen and any "suggestion bars" take up less than 1/4. (Remember to add an onOrientationChange method to reset the 1/4 value). – Graeme Nov 07 '13 at 11:55
  • Thanks kachi..u r genious works for me. After trying n trying i got solution. – shripal Jan 02 '14 at 11:05
  • This solution worked the most consistently for me on several devices and emulators running v3.2 - v4.4.2. I first tried Reuben Scratton's updated answer on devices and emulators listed above, but there were instances where the height difference didn't update the first time the keyboard displayed, but on subsequent tries, it did. Note that I didn't need to set windowSoftInputMode (in manifest or in Java). I just placed the code in my main activity's onCreate. Just to be safe, I also used a higher height difference value in my test. Thank you, Kachi. – h-bomb Feb 06 '14 at 17:52
  • Thank you works perfectly, and it's more efficient than @Reuben's method. I've added an else to the condition to catch when the keyboard isn't show :) Thanks again ;) – Ektos974 Mar 03 '14 at 10:17
  • for both open-close states: if (heightDiff > 100 && !keyBoardOpen) { // if more than 100 pixels, its probably a keyboard... keyBoardOpen = true; onKeyBoardOpen(); } else if (heightDiff < 100 && keyBoardOpen) { keyBoardOpen = false; onKeyBoardClosed(); } – Mihaela Romanca Oct 13 '14 at 08:18
  • Thank you! I used this on my messages for the list to auto scroll to bottom when the keyboard pops up! – Petro Mar 18 '15 at 17:44
  • 9
    `heightDiff > root.getRootView().getHeight() / 4` is good value to work with high resolution device. 100px is to short. in Nexus 5 with 1080x1920 res, 1920 - (996-75) >? 100 = 999 1920 - (1776-75) >? 100 = 219 // keyboard is up in galaxy s2 with 480x800 res, 800 - (800-38) >? 100 = 38 800 - (410-38) >? 100 = 428 // keyboard is up so, magic number 100px is not good enough. – Flask_KR Apr 17 '15 at 07:39
  • How about `android:windowSoftInputMode="adjustNothing" ` ? Thanks. I need to set `android:windowSoftInputMode` to `adjustNothing `. – Jerikc XIONG Aug 19 '15 at 09:12
  • Flask_KR's proposal is good - I used (diff > 200) and it worked on Nexus 4, but not on Nexus 5. – khusrav Jan 13 '16 at 20:14
  • Agree with @Flask_KR, on my LG G4 the heightDiff is 168 when the keyboard is not shown, so 100px does not apply to all phones, I am currently using heightDiff > root.getRootView().getHeight() / 4 too. The solution works perfectly though! – Bruce Oct 01 '16 at 09:29
  • 2
    This is broken on newer phone such as the Pixel 3 XL – Nick Oct 18 '18 at 17:49
  • @Graeme I use this way to detect the keyboard, but onGlobalLayout not called sometimes, it is not reliable. Have you encounter this issue? – dragonfly May 02 '19 at 04:08
  • For split view this solution doesn't work fine. For normal full screen, it serves the purpose. – Dhaval Shah May 13 '20 at 14:23
  • Hi kachi how are you? i have a question : why else{} that you did not write it has multiple action?(when keyboard comes up if{} run just once but else{} run multi time) – milad salimi Sep 16 '20 at 07:38
54

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

TacB0sS
  • 9,456
  • 11
  • 66
  • 111
  • 2
    +1 Thank you so much!! I was trying the other answers, but they don't work. Then I found yours and it works like a charm. Awesome code! :D – Kevin van Mierlo Jan 29 '14 at 09:46
  • this works only if you add : android:windowSoftInputMode="stateHidden|adjustPan" or android:windowSoftInputMode="stateHidden|adjustResize" Thank you !!!! – Lena Bru Mar 03 '14 at 10:24
  • Are you sure? If memory servers, I got the events properly also when the android:windowSoftInputMode had its default value... the only thing that didn't work out is the behavior of the screen, so I manually shrank it... – TacB0sS Mar 03 '14 at 21:58
  • If all you want to know is if the keyboard has been opened... use this! – EGHDK Mar 08 '14 at 22:54
  • 2
    a small correction : private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0); – binaryKarmic Dec 25 '14 at 07:55
  • I recommend to handle default keyboard heigh this way : final int defKeyboardDp = getResources().getDimensionPixelSize(R.dimen.default_keyboard_dp); whete default_keyboard_dp have value 100dp – Michal Mar 15 '15 at 12:18
  • Works perfect on a Nexus 5, Android 5.1.1 with a webview + keyboard. – david Jun 30 '15 at 15:49
  • The only solution which works. Tested on APIs 16, 21, 22, 23. – azizbekian Jan 08 '16 at 14:25
  • This solution work perfectly even on device rotation. If you are using Cordova webviews then you should use View activityRootView = activity.findViewById(android.R.id.content); – Hitesh Sahu Apr 05 '16 at 06:35
  • Thanks! I made a similar solution in a fragment, then opened another fragment. In this case I got an exception that `activityRootView == null`. If probably you will have this exception, check `if (activityRootView != null) ...` inside `public void onGlobalLayout()`. – CoolMind Nov 28 '18 at 09:17
  • @CoolMind Perhaps you called the listener too early, before the fragment was attached to the activity.. (BTW I do not use fragments they are badly architected, and hold the potential to numerous bugs) – TacB0sS Nov 30 '18 at 19:06
  • @TacB0sS, I agree with you. It is interesting that some programmers can use only activities without fragments. – CoolMind Dec 03 '18 at 06:59
  • @CoolMind.. funny you say that.. I also barely use Activities as well ;) https://github.com/nu-art/cyborg-core – TacB0sS Dec 03 '18 at 07:21
  • @Lena Bru I didn't use your "inputmode", but it also works~ – Zhou Hongbo Dec 17 '18 at 06:08
  • 2
    Excellent!! No matter the "windowSoftInputMode" is set to"adjustPan" / "adjustResize" / "adjustPan|stateHidden" / "adjustResize|stateHidden", or even without this option, it always works! Tested on XiaoMi 8. – Zhou Hongbo Dec 17 '18 at 06:29
51

Sorry for the late answer, but I had created a little helper class to handle open/close events with notifying listeners and other useful things, may be someone would find it helpful:

import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;

import java.util.LinkedList;
import java.util.List;

public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {

    public interface SoftKeyboardStateListener {
        void onSoftKeyboardOpened(int keyboardHeightInPx);
        void onSoftKeyboardClosed();
    }

    private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
    private final View activityRootView;
    private int        lastSoftKeyboardHeightInPx;
    private boolean    isSoftKeyboardOpened;

    public SoftKeyboardStateWatcher(View activityRootView) {
        this(activityRootView, false);
    }

    public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
        this.activityRootView     = activityRootView;
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        final Rect r = new Rect();
        //r will be populated with the coordinates of your view that area still visible.
        activityRootView.getWindowVisibleDisplayFrame(r);

        final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
            isSoftKeyboardOpened = true;
            notifyOnSoftKeyboardOpened(heightDiff);
        } else if (isSoftKeyboardOpened && heightDiff < 100) {
            isSoftKeyboardOpened = false;
            notifyOnSoftKeyboardClosed();
        }
    }

    public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
    }

    public boolean isSoftKeyboardOpened() {
        return isSoftKeyboardOpened;
    }

    /**
     * Default value is zero {@code 0}.
     *
     * @return last saved keyboard height in px
     */
    public int getLastSoftKeyboardHeightInPx() {
        return lastSoftKeyboardHeightInPx;
    }

    public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.add(listener);
    }

    public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.remove(listener);
    }

    private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
        this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;

        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardOpened(keyboardHeightInPx);
            }
        }
    }

    private void notifyOnSoftKeyboardClosed() {
        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardClosed();
            }
        }
    }
}

Usage example:

final SoftKeyboardStateWatcher softKeyboardStateWatcher 
    = new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);

// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
Artem Zinnatullin
  • 4,057
  • 25
  • 41
  • 2
    The class isnt little but the implementation surely is :). Thanks I will try this :) – Atul O Holic Mar 10 '14 at 13:41
  • 1
    Ping me if you got problems with it :) I successfully used it in 2 projects – Artem Zinnatullin Mar 11 '14 at 05:12
  • After trying many examples above and running into minor issues, this one was the one that worked best for me across many different devices (including xxhdpi). Plus it's in its own nice reusable class. I converted it over to be used in mono droid. – kheit Jun 13 '14 at 20:54
  • Some keyboards, some of the time, have an extra row of custom keys on top (for instance, predicted words). These are apparently not part of the keyboard itself, since using the `getLastKeyboardHeightInPx()` does not include the height of that row. Do you know of a way to take it into account as well? – ygesher Jul 24 '14 at 12:39
  • This only works if u r ready to compromise Layout height change when keyboard appears. right? – M. Usman Khan Sep 19 '14 at 10:43
  • Clear solution, Thanks. – Cüneyt Jun 27 '15 at 22:28
  • The most elegant one IMHO. Unobtrusive code. what manifest fields does it require? configChanges="orientation|screenSize|keyboardHidden" are the ones that worked for me. Thanks! – voghDev Jul 06 '15 at 05:56
  • On my Nexus 5 heightDiff = 216 in portret mode without a soft keyboard opened. Maybe because of the bottom bar. On a samsung heightDiff < 100 when no soft keyboard is shown. – Roel May 06 '16 at 14:43
  • I solved this by first determining the normal difference (without soft keyboard). – Roel May 06 '16 at 14:51
  • i am using this solution in fragments based app, and when i replaced the fragment it is getting crashed – sunil kushwah Sep 04 '17 at 12:07
  • This should be the best answer. working like charm :) – param Sep 20 '17 at 12:19
34

Some improvements to avoid wrongly detect the visibility of soft keyboard on high density devices:

  1. Threshold of height difference should be defined as 128 dp, not 128 pixels.
    Refer to Google design doc about Metrics and Grid, 48 dp is comfortable size for touch object and 32 dp is minimum for buttons. Generic soft keyboard should include 4 rows of key buttons, so minimum keyboard height should be: 32 dp * 4 = 128 dp, that means threshold size should transfer to pixels by multiply device density. For xxxhdpi devices (density 4), the soft keyboard height threshold should be 128 * 4 = 512 pixels.

  2. Height difference between root view and its visible area:
    root view height - status bar height - visible frame height = root view bottom - visible frame bottom, since status bar height equal to the top of root view visible frame.

    private final String TAG = "TextEditor";
    private TextView mTextEditor;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_editor);
        mTextEditor = (TextView) findViewById(R.id.text_editor);
        mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                isKeyboardShown(mTextEditor.getRootView());
            }
        });
    }
    
    private boolean isKeyboardShown(View rootView) {
        /* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
        final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;
    
        Rect r = new Rect();
        rootView.getWindowVisibleDisplayFrame(r);
        DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
        /* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
        int heightDiff = rootView.getBottom() - r.bottom;
        /* Threshold size: dp to pixels, multiply with display density */
        boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;
    
        Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
                + "root view height:" + rootView.getHeight() + ", rect:" + r);
    
        return isKeyboardShown;
    }
    
Orchard Cafe
  • 349
  • 3
  • 3
13

Wow, We have Good news Android Geeks. And its time to say goodbye to the old way. First I will add official release note to read and know more about these methods/ classes, and then we will see these amazing methods/ classes

Breaking Note: Do not add these into your release apps, until these classes/ methods are released

How to check keyboard visibility

val insets = ViewCompat.getRootWindowInsets(view)
val isKeyboardVisible = insets.isVisible(Type.ime())

Few other utilities

How to get the height of Keyboard

val insets = ViewCompat.getRootWindowInsets(view)
val keyboardHeight = insets.getInsets(Type.ime()).bottom

How to show/ hide the keyboard

val controller = view.windowInsetsController

// Show the keyboard
controller.show(Type.ime())

// Hide the keyboard
controller.hide(Type.ime())

Note: WindowInsetsController added in API-30, so wait till backward compatible class is not available.

How to listen to keyboard hide/ show event

ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
    val isKeyboardVisible = insets.isVisible(Type.ime())
    if (isKeyboardVisible) {
        // Do it when keyboard is being shown
    } else {
        // Do it when keyboard is hidden
    }

    // Return the insets to keep going down this event to the view hierarchy
    insets
}
Pankaj Kumar
  • 78,055
  • 25
  • 161
  • 180
  • 2
    I have a problem, it says: "Unresolved reference isVisible()", please help – Andrew Sep 13 '20 at 12:58
  • @Andrew Are you using https://developer.android.com/jetpack/androidx/releases/core#1.5.0-alpha02 ? – Pankaj Kumar Sep 13 '20 at 16:44
  • See https://medium.com/androiddevelopers/animating-your-keyboard-fb776a8fb66d and amazing post for more details – Pankaj Kumar Sep 13 '20 at 16:44
  • Ok, now it found the isVisible function. Unfortunately this does not work because it does nothing.. I am using API 21 and adjustresize. I've but the above code in a function and I am calling it from my fragments onViewCreated() – Andrew Sep 13 '20 at 16:54
  • @Andrew Could you please add code somewhere so I can look into, or can add a new question, so other can also help? – Pankaj Kumar Sep 13 '20 at 17:32
  • I did: https://stackoverflow.com/questions/63874010/android-viewcompat-setonapplywindowsinsetslistener-gets-never-called – Andrew Sep 13 '20 at 18:07
  • @PankajKumar how can I get the keyboard height by using Android jetpack Compose. – Asad Yasin Apr 06 '21 at 17:08
7

The idea is, if you need to hide your keyboard and check soft input state at the same time, use the following solution:

public boolean hideSoftInput() {
    InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
    return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}

This method returns true if keyboard was shown before hiding.

George Maisuradze
  • 1,654
  • 17
  • 16
  • This is the one works without using height and all... Thanks... u saved my time... – Vji Aug 03 '15 at 11:00
  • This should be the accepted answer. All these hacks... smh. The api does not say what the boolean is, so is this a safe method? – John Glen Feb 28 '21 at 04:05
  • You can pass a ResultReceiver to hideSoftInptFromWindow, and it will give you an explicit answer – John Glen Feb 28 '21 at 04:11
7

I used a little time to figure this out... I ran it some CastExceptions, but figured out that you can replace you LinearLayout in the layout.xml with the name of the class.

Like this:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
    xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">

<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:id="@+id/rlMaster" >
    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>

          ....

</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>    


</LinearLayout>

That way you do not run into any cast issues.

... and if you don't want to do this on every page, I recommend that you use "MasterPage in Android". See the link here: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx

  • Wow be careful about pasting this into your XML if you don't have the same package/class name. Eclipse just decides to freeze and you have to shut it down. Such a professional product. /s – Spencer Ruport Dec 09 '11 at 20:58
  • 5
    @SpencerRuport, that's why it's free. – Cody Feb 09 '12 at 18:57
  • @DoctorOreo - get IntelliJ. It's free and doesn't suck. – Mark Jul 26 '13 at 21:37
  • @Mark - a few months after I posted this I did indeed try out IntelliJ. It's much better, IMO, than Eclipse. All of their products (for the most part) I think are excellent. I've even bought a few. – Cody Jul 27 '13 at 21:49
  • Sorry for reviving such an old comment thread. I am glad you are using it and enjoying it. I love using IntelliJ as well as AppCode for iOS and PyCharm for Python work. Cheers! – Mark Jul 29 '13 at 18:37
6

Checking the height of elements is not reliable because some keyboards like WifiKeyboard have zero height.

Instead, you can use the callback result of showSoftInput() and hideSoftInput() to check for the status of the keyboard. Full details and example code at

https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android

Undo
  • 25,204
  • 37
  • 102
  • 124
Roger Keays
  • 2,798
  • 1
  • 27
  • 22
4

Instead of assuming the difference coding I did something like this, as I dint had menu options in my application.

final View root= findViewById(R.id.myrootview); 
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
    public void onGlobalLayout() {
        int heightDiff = root.getRootView().getHeight() - root.getHeight();

        Rect rectgle= new Rect();
        Window window= getWindow();
        window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
        int contentViewTop=                     
          window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
        if(heightDiff <= contentViewTop){
            //Soft KeyBoard Hidden
        }else{
            //Soft KeyBoard Shown
        }
     }
});
Yaron
  • 8,814
  • 8
  • 40
  • 53
Santhosh Shettigar
  • 6,840
  • 6
  • 32
  • 41
  • It doesn't work for android:windowSoftInputMode="adjustPan". I wanted that my screen shouldn't get shrinked after soft keyboard appears. Can you please tell any fix so that it works even for adjustPan – Shirish Herwade Aug 22 '13 at 05:40
4

You can observe softkeyboard's hide by using activity's decorView.

public final class SoftKeyboardUtil {
    public static final String TAG = "SoftKeyboardUtil";
    public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
        final View decorView = activity.getWindow().getDecorView();
        decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect rect = new Rect();
                decorView.getWindowVisibleDisplayFrame(rect);
                int displayHight = rect.bottom - rect.top;
                int hight = decorView.getHeight();
                boolean hide = (double)displayHight / hight > 0.8 ;
                if(Log.isLoggable(TAG, Log.DEBUG)){
                    Log.d(TAG ,"DecorView display hight = "+displayHight);
                    Log.d(TAG ,"DecorView hight = "+ hight);
                    Log.d(TAG, "softkeyboard visible = " + !hide);
                }

                listener.onSoftKeyBoardVisible(!hide);

            }
        });
    }



    public interface OnSoftKeyBoardHideListener{
        void onSoftKeyBoardVisible(boolean visible);
    }
}
Zebulon Li
  • 510
  • 2
  • 20
4

There is also solution with system insets, but it works only with API >= 21 (Android L). Say you have BottomNavigationView, which is child of LinearLayout and you need to hide it when keyboard is shown:

> LinearLayout
  > ContentView
  > BottomNavigationView

All you need to do is to extend LinearLayout in such way:

public class KeyboardAwareLinearLayout extends LinearLayout {
    public KeyboardAwareLinearLayout(Context context) {
        super(context);
    }

    public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public KeyboardAwareLinearLayout(Context context,
                                     @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
                                     int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        int childCount = getChildCount();
        for (int index = 0; index < childCount; index++) {
            View view = getChildAt(index);
            if (view instanceof BottomNavigationView) {
                int bottom = insets.getSystemWindowInsetBottom();
                if (bottom >= ViewUtils.dpToPx(200)) {
                    // keyboard is shown
                    view.setVisibility(GONE);
                } else {
                    // keyboard is hidden
                    view.setVisibility(VISIBLE);
                }
            }
        }
        return insets;
    }
}

The idea is that when keyboard is shown, system insets are changed with pretty big .bottom value.

nikis
  • 10,833
  • 2
  • 32
  • 45
4

There's a hidden method can help for this, InputMethodManager.getInputMethodWindowVisibleHeight. But I don't know why it's hidden.

import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager

class SoftKeyboardStateWatcher(private val ctx: Context) {
  companion object {
    private const val DELAY = 10L
  }

  private val handler = Handler()
  private var isSoftKeyboardOpened: Boolean = false

  private val height: Int
    get() {
      val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
      val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
      method.isAccessible = true
      return method.invoke(imm) as Int
    }

  private val task: Runnable by lazy {
    Runnable {
      start()
      if (!isSoftKeyboardOpened && height > 0) {
        isSoftKeyboardOpened = true
        notifyOnSoftKeyboardOpened(height)
      } else if (isSoftKeyboardOpened && height == 0) {
        isSoftKeyboardOpened = false
        notifyOnSoftKeyboardClosed()
      }
    }
  }

  var listener: SoftKeyboardStateListener? = null

  interface SoftKeyboardStateListener {
    fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
    fun onSoftKeyboardClosed()
  }

  fun start() {
    handler.postDelayed(task, DELAY)
  }

  fun stop() {
    handler.postDelayed({
      if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
    }, DELAY * 10)
  }

  private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
    listener?.onSoftKeyboardOpened(keyboardHeightInPx)
  }

  private fun notifyOnSoftKeyboardClosed() {
    listener?.onSoftKeyboardClosed()
  }
}
Kevin Du
  • 41
  • 5
  • If someone would need this - it works in Xamarin as well, name of the method is exactly the same and needs to be accessed in the same way - through the Class property on the InputMethodManager. – Konstantin Severy Nov 21 '18 at 11:38
  • Be careful using this, it is unsupported API (it's hidden for a reason) and for starters it doesn't work on KitKat. – Daniele Ricci Mar 17 '20 at 14:17
3

I used a slight variant of Reuban's answer, which proved to be more helpful in certain circumstances, especially with high resolution devices.

final View activityRootView = findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightView = activityRootView.getHeight();
                int widthView = activityRootView.getWidth();
                if (1.0 * widthView / heightView > 3) {
                    //Make changes for Keyboard not visible
                } else {
                    //Make changes for keyboard visible
                }
            }
        });
PearsonArtPhoto
  • 35,989
  • 16
  • 107
  • 136
3

None of these solutions will work for Lollipop as is. In Lollipop activityRootView.getRootView().getHeight() includes the height of the button bar, while measuring the view does not. I've adapted the best/simplest solution above to work with Lollipop.

    final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public 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.bottom - r.top);
    Resources res = getResources();
    // The status bar is 25dp, use 50dp for assurance
    float maxDiff =
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());

    //Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      float buttonBarHeight =
          TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
      maxDiff += buttonBarHeight;
    }
    if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
      ...do something here
    }
  }
});
Ali Mehrpour
  • 563
  • 7
  • 16
nathanielwolf
  • 557
  • 6
  • 19
  • Why didn't a similar solution from https://stackoverflow.com/a/18992807/2914140 work for you and how does your solution differ? – CoolMind Mar 20 '19 at 09:29
3

I have just encountered a bug while using most of the solutions above that suggest adding a fixed number.

S4 is has a high dpi which resulted in the navigation bar's height being 100px thus my app thinking that the keyboard is open all the time.

So with all the new high res phones being released i believe using a hard coded value is not a good idea for long term.

A better approach that i found after some testing on various screens and devices was to use percentage. Get the difference between decorView and ur app content and afterwards check what is the percentage of that difference. From the stats that i got, most nav bar(regardless of the size, resolution etc..) will take between 3% to 5% of the screen. Where as if the keyboard is open it was taking between 47% to 55% of the screen.

As a conclusion my solution was to check if the diff is more than 10% then i assume its a keyboard open.

N Jay
  • 1,706
  • 1
  • 17
  • 34
3

It has been forever in terms of the 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 Rect r = new Rect();

        @Override
        public void onGlobalLayout() {
            activityRootView.getWindowVisibleDisplayFrame(r);

            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            boolean isOpen = heightDiff > 100;
            if (isOpen == wasOpened) {
                logDebug("Ignoring global layout change...");
                return;
            }

            wasOpened = isOpen;
            listener.onVisibilityChanged(isOpen);
        }
    });
}

It works for me.

TejaDroid
  • 5,600
  • 3
  • 27
  • 33
3

Try this:

final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public 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.bottom - r.top);
        if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
             // ... do something here ... \\
        }
    }
});
Ofek Ashery
  • 66
  • 1
  • 3
3

I found that a combination of @Reuben_Scratton's method along with @Yogesh's method seems to work best. Combining their methods would yield something like this:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
       // ... do something here
    }
  }
});
cbradley
  • 131
  • 2
  • 5
2

My answer is basically the same as Kachi's answer, but I wrapped it into a nice helper class to clean up the way it's used throughout my app.

import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

/**
 * Detects Keyboard Status changes and fires events only once for each change
 */
public class KeyboardStatusDetector {
    KeyboardVisibilityListener visibilityListener;

    boolean keyboardVisible = false;

    public void registerFragment(Fragment f) {
        registerView(f.getView());
    }

    public void registerActivity(Activity a) {
        registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
    }

    public KeyboardStatusDetector registerView(final View v) {
        v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                v.getWindowVisibleDisplayFrame(r);

                int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
                    /** Check this variable to debounce layout events */
                    if(!keyboardVisible) {
                        keyboardVisible = true;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
                    }
                } else {
                    if(keyboardVisible) {
                        keyboardVisible = false;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
                    }
                }
            }
        });

        return this;
    }

    public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
        visibilityListener = listener;
        return this;
    }

    public static interface KeyboardVisibilityListener {
        public void onVisibilityChanged(boolean keyboardVisible);
    }
}

You can use this to detect keyboard changes anywhere throughout the app like this:

    new KeyboardStatusDetector()
            .registerFragment(fragment)  //register to a fragment 
            .registerActivity(activity)  //or register to an activity
            .registerView(view)          //or register to a view
            .setVisibilityListener(new KeyboardVisibilityListener() {
                @Override
                public void onVisibilityChanged(boolean keyboardVisible) {
                    if(keyboardVisible) {
                       //Do stuff for keyboard visible
                    }else {
                       //Do stuff for keyboard hidden
                    }
                }
            });

Note: only use one of the "register" calls. They all work the same and are only there for convenience

2

you can try this, work great for me:

InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);

if (imm.isAcceptingText()) {
    //Software Keyboard was shown..
} else {
    //Software Keyboard was not shown..
}
IRvanFauziE
  • 715
  • 9
  • 15
2

I was having difficulty maintaining keyboard state when changing orientation of fragments within a viewpager. I'm not sure why, but it just seems to be wonky and acts differently from a standard Activity.

To maintain keyboard state in this case, first you should add android:windowSoftInputMode = "stateUnchanged" to your AndroidManifest.xml. You may notice, though, that this doesn't actually solve the entire problem -- the keyboard didn't open for me if it was previously opened before orientation change. In all other cases, the behavior seemed to be correct.

Then, we need to implement one of the solutions mentioned here. The cleanest one I found was George Maisuradze's--use the boolean callback from hideSoftInputFromWindow:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);

I stored this value in my Fragment's onSaveInstanceState method and retrieved it onCreate. Then, I forcibly showed the keyboard in onCreateView if it had a value of true (it returns true if the keyboard is visible before actually hiding it prior to the Fragment destruction).

Quantum Dot
  • 395
  • 1
  • 5
  • 12
2

according to the doc.. https://developer.android.com/reference/androidx/core/view/WindowInsetsCompat

check release note.. https://developer.android.com/jetpack/androidx/releases/core#1.5.0-alpha02

To get the current keyboard visibility, you can use getRootWindowInsets, and then call the isVisible() function, passing in the IME type.

val windowinsetscompat = ViewCompat.getRootWindowInsets(view)
val imeVisible = windowinsetscompat.isVisible(Type.ime())

there is also listener for changes OnApplyWindowInsetsListener

ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
    val imeVisible = insets.isVisible(Type.ime())
}
Jaydeep chatrola
  • 1,583
  • 5
  • 13
1

Here's my solution, and it works. Instead of looking for pixel size just check that the height of the content view has changed or not:

// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        private int oldHeight;

        @Override
        public void onGlobalLayout() {
            int newHeight = commentsContent.getMeasuredHeight();
            if (newHeight < oldHeight) {
                // Check for the keyboard showing in case the height difference
                // is a result of orientation change
                if (isSoftKeyboardShowing(CommentsActivity.this)) {
                    // Keyboard is showing so scroll to the latest comment
                    scrollToLatestComment();
                }
            }
            oldHeight = newHeight;
        }

    });


public static boolean isSoftKeyboardShowing(Activity activity) {
    InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    return inputMethodManager.isActive();
}
Meanman
  • 1,363
  • 18
  • 16
  • inputMethodManager.isActive() is always returning true for me, regardless of whether the keyboard is up or not – EionRobb Aug 19 '14 at 05:19
1

Don't make any hard code. Best way is you have to resize your views while on Get Focus on EditText with KeyBord Show. You can do this adding resize property on activity into Manifest file using below code.

android:windowSoftInputMode="adjustResize"

Rahul Mandaliya
  • 709
  • 1
  • 10
  • 35
1

There is a direct method to find this out. And, it does not require any Layout changes.
So, it works in immersive fullscreen mode, too.

The trick is that you try to hide or show the soft keyboard and capture the result of that try.
No panic, this does not really show or hide the keyboard. We just ask for the state.

To stay up-to-date, you can simply repeat the operation, e.g. every 200 milliseconds, using a Handler.

You find an implementation here: https://stackoverflow.com/a/27567074/2525452

Community
  • 1
  • 1
fies
  • 53
  • 7
1

i think this method will help you to find out is keybord is visible or not.

 public Boolean isSoftKeyBoardVisible(){
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
        return true;
    } else {
        Log.d(TAG,"Software Keyboard was not shown");
        return false;
    }

}
John smith
  • 1,671
  • 14
  • 27
1

99% of solutions here are based on probability of IME WINDOW SIZE and each such solution is a sh... worth!

because:

  1. OVERLAYS - from User apps or System apps
  2. IME have no MINIMUM SIZE it can take 100% of window size and can be so thin as imagination of developer implementation :)
  3. MODAL windows / MULTI windows
  4. and many many more like no knowledge of IPC (eg: foreign window or its content detection)

so guessing it's IME is always wrong - don't guess be sure !!!

@kevin-du is best solution wright now as its query IMM for IME height - but as it said the method is hidden API so using it could be dangerous in the way of getting wrong "false negative results" - by wrong dev usage.

Community
  • 1
  • 1
ceph3us
  • 6,591
  • 2
  • 34
  • 39
0

Reuben Scratton's new answer (calculate the HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight(); ) will not work in activity if you set the translucent status bar mode.

if you use translucent status bar , activityRootView.getHeight() will never change weather the soft keyboard is visible. it will always return the height of activity and status bar.

For example, Nexus 4, Android 5.0.1, set android:windowTranslucentStatus to true, it will return 1184 forever, even the ime have opend. If you set android:windowTranslucentStatus to false, it will return Height correctly, if ime invisible,it return 1134(not include the status bar)。close the ime, it will return 5xx maybe (depends on ime's height)

I don't know weather this is a bug, I've try on 4.4.4 and 5.0.1, the result is same.

So, up to now, the second most agreed answer, Kachi's solution will be the most safe way to calcute the height of ime. Here's a copy:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new        OnGlobalLayoutListener() {
@Override
public 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.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
    ... do something here
    }
 }
}); 
Loyea
  • 2,520
  • 1
  • 15
  • 19
0

A method that doesn't need a LayoutListener

In my case, I would like to save the state of the keyboard before replacing my Fragment. I call the method hideSoftInputFromWindow from onSaveInstanceState, which closes the keyboard and returns me whether the keyboard was visible or not.

This method is straightforward but may change the state of your keyboard.

Gordak
  • 1,958
  • 19
  • 28
0

This solution may re-opens the keyboard but it works.

InputMethodManager inputManager = ( (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE) );

private boolean isKeyboardShowing() {

    boolean isKeyboardShowing = inputManager.hideSoftInputFromWindow(irrelevantView.getWindowToken(), 0);
    if (isKeyboardShowing) {
        inputManager.showSoftInput(this.getCurrentFocus(), 0);
    }
    return isKeyboardShowing;
}
bapho
  • 633
  • 6
  • 11
0

I know that this is a old post but I think this is the simplest approach that I know and my test device is Nexus 5. I haven't tried it in other devices. Hope that others will share their approach if they find my code is not good :)

public static boolean isKeyboardShown(Context context, View view) {
        if (context == null || view == null) {
            return false;
        }
        InputMethodManager imm = (InputMethodManager) context
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        return imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 
}

imm.hideSoftInputFromWindow returns boolean.

Thanks,

Fran Ceriu
  • 221
  • 2
  • 5
0
if (keyopen())
{
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);            
}

The above function is what I use to check if a Keyboard is visible. If it is, then I close it.

Below shows the two methods required.

First, define the workable Window height in onCreate.

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

//  add to onCreate method
    Rect rectgle= new Rect();
    Window window= getWindow();
    window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
    sheight= rectgle.bottom;
//

} 

Then, add a boolean method that gets the Window height at that instance. If it does not match the original (assuming you are not changing it along the way...) then, the keyboard is open.

public boolean keyopen()
{
    Rect rectgle= new Rect();
    Window window= getWindow();
    window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
    int curheight= rectgle.bottom;

    if (curheight!=sheight)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Frotz!

Belboz
  • 25
  • 4
0

I know how exact you can determine if keyboard is hidden or not.

public int getStatusBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

public int getNavigationBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

public boolean isKeyboardHidden() {
    int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
            - getSupportActionBar().getHeight();
    return delta <= 0;
}

This works for tablets. When navigationbar is shown horizontally.

Valentin Baryshev
  • 2,155
  • 3
  • 12
  • 23
0

Think has a easy way, like this:

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.isActive();

You can also see if him is active in a specific view:

imm.isActive(View v);
Ricardo A.
  • 586
  • 2
  • 7
  • 32
0

The solution provided by Reuben Scratton and Kachi seems to rely on the pixel density of the devices, if you have a high density device the height difference can be bigger than 100 even with the keyboard down. A little work around that would be to see the initial height difference (with keyboard down) and then compare with the current difference.

boolean isOpened = false;
int firstHeightDiff = -1;

public void setListenerToRootView(){
    final View activityRootView = getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
    Rect r = new Rect();
    activityRootView.getWindowVisibleDisplayFrame(r);
    firstHeightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (isAdded()) {
                Rect r = new Rect();
                activityRootView.getWindowVisibleDisplayFrame(r);
                int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
                isOpened = heightDiff>firstHeightDiff+100;
                if (isAdded())
                    if(isOpened) {
                        //TODO stuff for when it is up
                    } else {
                        //TODO stuf for when it is down
                    }
            }
        }
    });
}
0

Here is a workaround to know if softkeyboard is visible.

  1. Check for running services on the system using ActivityManager.getRunningServices(max_count_of_services);
  2. From the returned ActivityManager.RunningServiceInfo instances, check clientCount value for soft keyboard service.
  3. The aforementioned clientCount will be incremented every time, the soft keyboard is shown. For example, if clientCount was initially 1, it would be 2 when the keyboard is shown.
  4. On keyboard dismissal, clientCount is decremented. In this case, it resets to 1.

Some of the popular keyboards have certain keywords in their classNames:

Google AOSP = IME
Swype = IME
Swiftkey = KeyboardService
Fleksy = keyboard
Adaptxt = IME (KPTAdaptxtIME)
Smart = Keyboard (SmartKeyboard)

From ActivityManager.RunningServiceInfo, check for the above patterns in ClassNames. Also, ActivityManager.RunningServiceInfo's clientPackage=android, indicating that the keyboard is bound to system.

The above mentioned information could be combined for a strict way to find out if soft keyboard is visible.

Satishkumar
  • 85
  • 1
  • 8
0

After understanding some of the issues with different resolutions, I decided to use a relative size. As I noticed the difference between visible and hidden states is about 30%. So I decided to replace 128 PX with 0.3.

And I added this class listener to notify of any change.

Here is my version

import android.app.*;
import android.graphics.*;
import android.view.*;

public class SoftKeyboardState {
  public static final int HIDDEN = 0, VISIBLE = 1;
  private OnKeyboardStateChangedListener listener;
  private View decorView;

  public SoftKeyboardState(Activity activity) {
    this.decorView = activity.findViewById(android.R.id.content);
    initKeyboardListener();
  }

  private void initKeyboardListener() {
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(
      new ViewTreeObserver.OnGlobalLayoutListener(){
        private final Rect windowVisibleDisplayFrame = new Rect();
        private int lastVisibleDecorViewHeight;

        @Override
        public void onGlobalLayout() {
          decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
          final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();

          if (lastVisibleDecorViewHeight != 0) {
            if ((lastVisibleDecorViewHeight > visibleDecorViewHeight) && (lastVisibleDecorViewHeight / visibleDecorViewHeight >= 0.3f)) {
              // visible
              if (listener != null)listener.onKeyboardStateChanged(VISIBLE);
            } else if ((lastVisibleDecorViewHeight < visibleDecorViewHeight) && (visibleDecorViewHeight / lastVisibleDecorViewHeight >= 0.3f)) {
              // hidden
              if (listener != null)listener.onKeyboardStateChanged(HIDDEN);
            }
          }
          lastVisibleDecorViewHeight = visibleDecorViewHeight;
        }
      });
  }

  public void setOnKeyboardStateChangedListener(OnKeyboardStateChangedListener listener) {
    this.listener = listener;
  }

  public interface OnKeyboardStateChangedListener {
    public void onKeyboardStateChanged(int state);
  }
}
0

This code works great nice

use this class for root view:

public class KeyboardConstraintLayout extends ConstraintLayout {

private KeyboardListener keyboardListener;
private EditText targetEditText;
private int minKeyboardHeight;
private boolean isShow;

public KeyboardConstraintLayout(Context context) {
    super(context);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (!isInEditMode()) {
        Activity activity = (Activity) getContext();
        @SuppressLint("DrawAllocation")
        Rect rect = new Rect();
        getWindowVisibleDisplayFrame(rect);

        int statusBarHeight = rect.top;
        int keyboardHeight = activity.getWindowManager().getDefaultDisplay().getHeight() - (rect.bottom - rect.top) - statusBarHeight;

        if (keyboardListener != null && targetEditText != null && targetEditText.isFocused()) {
            if (keyboardHeight > minKeyboardHeight) {
                if (!isShow) {
                    isShow = true;
                    keyboardListener.onKeyboardVisibility(true);
                }
            }else {
                if (isShow) {
                    isShow = false;
                    keyboardListener.onKeyboardVisibility(false);
                }
            }
        }
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

public boolean isShowKeyboard() {
    return isShow;
}

public void setKeyboardListener(EditText targetEditText, KeyboardListener keyboardListener) {
    this.targetEditText = targetEditText;
    this.keyboardListener = keyboardListener;
}

public interface KeyboardListener {
    void onKeyboardVisibility (boolean isVisible);
}

}

and set keyboard listener in activity or fragment:

    rootLayout.setKeyboardListener(targetEditText, new KeyboardConstraintLayout.KeyboardListener() {
    @Override
    public void onKeyboardVisibility(boolean isVisible) {

    }
});
saleh gholamian
  • 113
  • 2
  • 8
0

Maybe this will help you:

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
adiga
  • 28,937
  • 7
  • 45
  • 66
  • 1
    While this code snippet may solve the question, [including an explanation](//s.tk/meta/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations! – Shree Mar 07 '19 at 10:29
0

Referring to this answer by @TacB0sS I have developed one class in Kotlin. Hope this will be helpful. Let me know if it requires some improvement.

class KeyboardVisibilityObserver(val layRootContainer: View?, val keyboardVisibilityListener: KeyboardVisibilityListener?) {
    var isKeyboardOpen = false
        private set

    private var keyBoardObserver = object : ViewTreeObserver.OnGlobalLayoutListener {

        private val DefaultKeyboardDP = 100

        // Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
        private val EstimatedKeyboardDP = DefaultKeyboardDP + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 48 else 0

        private val r = Rect()

        override fun onGlobalLayout() {
            if (layRootContainer != null) {
                // Convert the dp to pixels.
                val estimatedKeyboardHeight = TypedValue
                        .applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP.toFloat(), layRootContainer.resources.displayMetrics).toInt()

                // Conclude whether the keyboard is shown or not.
                layRootContainer.getWindowVisibleDisplayFrame(r)
                val heightDiff = layRootContainer.rootView.height - (r.bottom - r.top)
                val isShown = heightDiff >= estimatedKeyboardHeight

                if (isShown == isKeyboardOpen) {
                    //  Log.d("Keyboard state", "Ignoring global layout change...");
                    return
                }

                isKeyboardOpen = isShown

                keyboardVisibilityListener?.onKeyboardVisibilityChanged(isKeyboardOpen)
            }
        }
    }

    init {
        layRootContainer?.viewTreeObserver?.addOnGlobalLayoutListener(keyBoardObserver)
    }

    // call this in onDestroy
    fun removeObserver(){
        layRootContainer?.viewTreeObserver?.removeOnGlobalLayoutListener(keyBoardObserver)
    }

    interface KeyboardVisibilityListener {
        fun onKeyboardVisibilityChanged(isKeyboardOpen: Boolean)
    }
}
Chitrang
  • 4,840
  • 1
  • 31
  • 49
0

In addition to the correct answer I had to add this at the end of the onCreateView when using a webview inside a fragment.

getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

May be is because I am running a Webview inside a fragment or maybe a new behavior on API 30, my issue was that the height of the fragment was never altered even if the keyboard was being shown.

So for Fragment the entire code should be

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = super.onCreateView(inflater, container, savedInstanceState);
    //mWebView.postUrl("https://www.google.com/");
    final View activityRootView = view;
    layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Rect r = new Rect();
            //r will be populated with the coordinates of your view that area still visible.
            activityRootView.getWindowVisibleDisplayFrame(r);
            // This variable was created only for Debug purposes and 
            // to see the height change when clicking on a field inside mWebView
            int screenHeight = activityRootView.getRootView().getHeight();
            Log.d("onGlobalLayout", "rect: " + r.toString());
            Log.d("onGlobalLayout", "screenHeight: " + screenHeight);

            //The difference on the heights from bottom to top and on the root height
            int heightDiff = screenHeight - (r.bottom - r.top);
            Log.d("onGlobalLayout", "heightDiff: " + heightDiff);

            //I suggest to put 250 on resources to have better order
            float dpx = dpToPx(getActivity(), 250);

            if (previousHeightDiff != heightDiff) {
                if (heightDiff > dpx) {
                    isSoftKeyboardPresent = true;
                } else {
                    isSoftKeyboardPresent = false;
                }
                previousHeightDiff = heightDiff;
            }
        }
    };
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
    getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
    return view;
}

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

This is probably not suitable for production because it will open the keyboard. Note that the boolean returned by similar functions is not specified in the API and are therefore unreliable. Refer to the documentation here...

https://developer.android.com/reference/android/view/inputmethod/InputMethodManager#showSoftInput(android.view.View,%20int,%20android.os.ResultReceiver)

public boolean showSoftInput (View view, 
            int flags, 
            ResultReceiver resultReceiver)

Note that this method takes a ResultReceiver. It can get the results: RESULT_UNCHANGED_SHOWN, RESULT_UNCHANGED_HIDDEN, RESULT_SHOWN, or RESULT_HIDDEN. If you get RESULT_UNCHANGED_SHOWN, the keyboard was visible. If you need it to stay closed if it was closed, you will need to close it.

John Glen
  • 445
  • 2
  • 14
-2

The InputMethodManager has information about the soft keyboard. You get it from an activity via:

((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))

You might play around with that to see what it can tell you. You can use it to show or hide the soft input...

Cheryl Simon
  • 44,959
  • 14
  • 91
  • 82
  • 6
    I have looked at InputMethodManager before and unfortunately I couldn't find anything that could tell me if keyb. is open or hidden. – fhucho Jan 28 '10 at 11:38