Getting notified when virtual keyboard shown / dismissed for an EditText? - android

I'd like to get notified when the virtual keyboard is shown / dismissed. This does not seem to be possible, other than by using some layout resizing listener tricks:
How to check visibility of software keyboard in Android?
My activity has a single EditText. I could make it not have focus at activity startup, then add a focuschangelistener to it. When it gains focus, I can do my onVirtualKeyboardShown() stuff. If I could just listen for the back key being pressed in the EditText, I could then interpret that as the virtual keyboard being hidden. Something like:
EditText et = ...;
et.setOnFocusChangedListener(new OnFocusChangedListener() {
public void onFocusChanged(boolean focused) {
if (focused) {
// virtual keyboard probably showing.
}
}
});
et.setKeyListener(new KeyListener() {
public void onKeyPressed(int code) {
if (code == BACK_KEY) [
if (et.isFocused()) {
// virtual keyboard probably hiding.
// lose focus to set up for next time.
et.setFocused(false);
}
}
}
});
Seems like any approach is fraught with problems given all the differences between virtual keyboards, then we also have to deal with physical keyboards too,
Thanks

This does not seem to be possible, other than by using some layout resizing listener tricks
Correct.
I want to be notified so I can show my own suggestions ribbon above the virtual keyboard.
Not all Android devices use virtual keyboards. Some have physical keyboards. Since you need to support both types of devices, you need to come up with a UI design that does not assume that everyone has a virtual keyboard.

// Catch the keyboard height
final LinearLayout masterView = (LinearLayout) findViewById(R.id.conversation_prent);
masterView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
Rect r = new Rect();
masterView.getWindowVisibleDisplayFrame(r);
int result = 0;
int resourceId = getResources().getIdentifier(
"status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(
resourceId);
}
int heightDiff = masterView.getRootView().getHeight()
- masterView.getHeight();
heightDiff = heightDiff - (ab.getHeight() + result);
Log.e("Keyboard Size", "Size: " + heightDiff);
if (heightDiff > 200) {
// The keyboard is shown
} else {
// The keyboard is hidden
}
}
});
if your app is running on android < 3 (HoneyComb) delete the parts of the code that are related to the actionbar.

Related

Detect "Show virtual keyboard" setting programatically in Android

There's a setting in Android called "Show virtual keyboard", which in my phone is located in:
Settings > Languages & input > Physical keyboard. It controls whether to keep the virtual keyboard on the screen while a physical keyboard is active.
Is there a way of programatically querying whether it is enabled or disabled? I can't find it in the Settings.System list in Android developers.
I don't know exactly if you can query that information but if it helps you, there is a way to programatically detect if the keyboard is opened or not.
private boolean isKeyboardShowing = false;
private void detectKeyboard() {
rootView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
int screenHeight = rootView.getRootView().getHeight();
int keypadHeight = screenHeight - r.bottom;
if (keypadHeight > screenHeight * 0.15) {
// keyboard is opened
if (!isKeyboardShowing) {
isKeyboardShowing = true;
}
}
else {
// keyboard is closed
if (isKeyboardShowing) {
isKeyboardShowing = false;
}
}
}
});
}

How to validate virtual keyboard visibility?

I want to show a button when the virtual keyboard is open and hide this button if the virtual keyboard visibility is off.But I could not find any listeners to perform this activity.
Anybody knows how to do this?
As found here, you'll need to instantiate the SoftkeyBoard and add a listener.
/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use your root layout
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);
/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
#Override
public void onSoftKeyboardHide()
{
// Code here
}
#Override
public void onSoftKeyboardShow()
{
// Code here
}
});
/*
Open or close the soft keyboard programatically
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();
/*
SoftKeyboard can catch keyboard events when an EditText gains focus and keyboard appears
*/
/* Prevent memory leaks:
*/
#Override
public void onDestroy()
{
super.onDestroy();
softKeyboard.unRegisterSoftKeyboardCallback();
}
In his post, you will also find more information about bug fixes and possible problems.
add onGlobalLayoutListener to your parent view of activity/fragment and make your button visibility accordingly
final View parentView= findViewById(R.id.myrootview);
parentView.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---button visible
}else{
//Soft KeyBoard Shown---button hide
}
}
});
There is no direct event for keyboard open and close. but you can create observer on your full layout and then display buttons or whatever you want to do.
For Observer code check this - Hide part of activity_main.xml if keyboard is open (Android)

Styled text lost in Android IME

I'm developing an IME for Android, which includes some highlighting of the text input by the user with a background colour (using SpannableString).
When the device is rotated and the keyboard is redrawn, the text remains in the input box as entered by the user, however, all styling (i.e. background colour) is lost.
Any ideas why this might be happening and how to circumvent it?
I have found a solution, which is not perfect, but it works.
Set up an ExtractedText variable in the IME service class.
In the OnConfigurationChanged method, get the extracted text. Then in the onStartInputView method, delete the text in the bound editor, and replace it with the extracted text.
#Override
public void onConfigurationChanged (Configuration newConfig)
{
//get what's been input so far
ExtractedTextRequest req = new ExtractedTextRequest();
req.token = 0;
req.flags = InputConnection.GET_TEXT_WITH_STYLES;
extractedText = ic.getExtractedText(req, 0);
super.onConfigurationChanged(newConfig);
}
#Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
...
if(extractedText!=null)
{
if(ic.deleteSurroundingText(9999, 0))
{
ic.commitText(extractedText.text, 1);
Log.i("onStartInputView", "Text Replaced");
}
else
{
Log.i("onStartInputView", "IC not valid");
}
}
super.onStartInputView(attribute, restarting);
}

Showing dropdown of AutoComplete below

I have a layout in which I have autoComplete edit text with some suggestions.
The image below is its normal behaviour until keyboard slides in.
after the keyboard comes the dropdown goes above the field which hides my TO: field. As shown below.
What should I do to get the dropdown below even when the keyboard slides up.
I want the result to be like this.
Thanks...
I resolved this by hiding the upper layout when key board is shown and focus is on this edit text. As soon as the keyboard is slided_out the upper layout is visible again which bring back the original screen.
For detecting the keyboard slide_in/slide_out i used something like this.
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 > 100) { // if more than 100 pixels, its
// probably a keyboard...
if (searchText.isFocused()) {
//keyboard is shown
}
} else {
if (searchText.isFocused()) {
//Keyboard is hidden.
}
}
}
});

Popup Keyboard issue in android, when column limits are specified

Im working on an input method for android and one of the tasks is to implement a custom popup keyboard for hard keyboard key presses. Usually input methods let the editor handle that but the thing is I need to add more symbols than android supports.
So I implemented the popup keyboard and even have it displaying well when a hard key (character key) is long pressed.
The steps I've followed are:
Create popup window.
Inflate a linear layout which contains a keyboardview and a close button and save it to a view object
bind the keyboardview and close buttons to the relevant objects
Create a keyboard for the popup characters and set it as the keyboard for the keyboard view. The keyboard has a column limit of 5.
set the linear layout as the content view for the popup window
Display the popup window
THE ISSUE: If there are multiple rows in the popup keyboard I am only able to select key in the last row for the column. Even if I click on the key in the first row of that column, the key in the last row gets selected.
If anyone could explain why this is happening and how do I fix it, Id appreciate it.
THE CODE:
PopupWindow mPopupKeyboard = new PopupWindow(this.getBaseContext());
mPopupKeyboard.setBackgroundDrawable(null);
if(mPopupKeyboard != null)
{
this.dismissPopupKeyboard();
View mMiniKeyboardContainer = null;
KeyboardView mMiniKeyboard = null;
View closeButton = null;
mMiniKeyboardContainer = getLayoutInflater().inflate(R.layout.keyboard_popup_keyboard, null);
mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(R.id.popup_keyboardView);
closeButton = mMiniKeyboardContainer.findViewById(R.id.closeButton);
if (closeButton != null)
{
closeButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
mPopupKeyboard.dismiss();
});
}
mMiniKeyboard.setOnKeyboardActionListener(this);
String resourcestring = "abcdefghi";
mMiniKeyboard.setKeyboard(new Keyboard(this.getBaseContext(), R.xml.kbd_popup_template, alternates, 3, 0));
mMiniKeyboard.setPopupParent(mCandidateView);
mPopupKeyboard.setContentView(mMiniKeyboardContainer);
mPopupKeyboard.setWidth(LayoutParams.WRAP_CONTENT);
mPopupKeyboard.setHeight(LayoutParams.WRAP_CONTENT);
mPopupKeyboard.showAtLocation(mCandidateView, Gravity.TOP, 0, 0);
}
I had a similar problem with popup keyboards. I found that it was a problem only with Android 2.3. My only workaround was to avoid popup keyboards with more than one row.
The reason this occurs is because KeyboardView sends off the MotionEvent. MotionEvent.getRawX() and getRawY() only return coordinates within the bounds of KeyboardView. If the MotionEvent happens above KeyboardView, it returns the closest absolute coordinates in KeyboardView.
One solution is to create an invisible View above KeyboardView. It will have to detect the MotionEvent and then pass the MotionEvent back to KeyboardView and then your multirow popup keyboard will work
For the starting code look at CandidateViews above the KeyboardView. For example look at this project:
https://github.com/blackcj/AndroidCustomKeyboard
In the
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
(https://github.com/blackcj/AndroidCustomKeyboard/blob/master/app/src/main/java/com/blackcj/customkeyboard/CandidateView.java)
method add 200 to desiredHeight in this statement:
setMeasuredDimension(measuredWidth, resolveSize(desiredHeight, heightMeasureSpec));
Notice how this will cause the motionEvent.getRawY() to work for an extra 200p in height

Categories

Resources