ListPopupWindow closes soft keyboard - android

Working on a lockscreen app I see a very strange behaviour: showing a ListPopupWindow forces the soft keyboard to close. This happens only on a "lockscreen" activity (activity window flags are set to FLAG_SHOW_WHEN_LOCKED|FLAG_DISMISS_KEYGUARD) and only if keyguard pin/password is set.
Here is a code example:
editText.setOnFocusChangeListener((v, hasFocus) -> {
ListPopupWindow popupWindow = new ListPopupWindow(getContext());
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
popupWindow.setAdapter(new ArrayAdapter(
getContext(), android.R.layout.simple_dropdown_item_1line, Arrays.asList("aaa", "bbb", "ccc")));
popupWindow.setAnchorView(editText);
popupWindow.show();
});
When popup list appears the keyboards immediately disappears.
Note that at the same time PopupWindow works ok:
editText.setOnFocusChangeListener((v, hasFocus) -> {
PopupWindow popupWindow = new PopupWindow(getContext());
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
popupWindow.setContentView(new TextClock(getContext()));
popupWindow.showAsDropDown(editText);
});
Both the popup window and the keyboard are visible.
Any idea of how to avoid this keyboard disappearance? Finally I need a SearchView (it displays suggestions in a ListPopupWindow) to work properly on a lockscreen.

I found that the keyboard is not closed if the popup window input method mode is
INPUT_METHOD_FROM_FOCUSABLE.
SearchView contains AutoCompleteTextView that changes its suggestions popup input method mode to INPUT_METHOD_NEEDED or INPUT_METHOD_NOT_NEEDED. So the workaround is to keep PopupWindow.mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE.
I solved this by creating a custom PopupWindow with setInputMethodMode() overridden:
public class SearchSuggestionPopupWindow extends PopupWindow {
SearchSuggestionPopupWindow(final Context context, final PopupWindow original) {
super(context);
setElevation(original.getElevation());
setAnimationStyle(original.getAnimationStyle());
setBackgroundDrawable(original.getBackground());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setOverlapAnchor(original.getOverlapAnchor());
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setEnterTransition(original.getEnterTransition());
setExitTransition(original.getExitTransition());
}
}
#Override
public void setInputMethodMode(final int mode) {
super.setInputMethodMode(PopupWindow.INPUT_METHOD_FROM_FOCUSABLE);
}
}
Then it's necessary to get AutoCompleteTextView from SearchView:
final AutoCompleteTextView textView = searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
and to substitute the custom popup window:
final Field listPopupField = AutoCompleteTextView.class.getDeclaredField("mPopup");
listPopupField.setAccessible(true);
final ListPopupWindow listPopup = (ListPopupWindow) listPopupField.get(textView);
final Field popupField = ListPopupWindow.class.getDeclaredField("mPopup");
popupField.setAccessible(true);
final PopupWindow popup = (PopupWindow) popupField.get(listPopup);
final PopupWindow customPopup = new SearchSuggestionPopupWindow(textView.getContext(), popup);
popupField.set(listPopup, customPopup);

Related

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)

How to show PopupWindow above keyboard?

I want to show a PopupWindow above virtual keyboard like Google Keep did when creating a reminder:
I believe, what you are looking for is combination of:
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
It's basically how native SearchView works:
https://android.googlesource.com/platform/frameworks/support/+/android-6.0.1_r31/v7/appcompat/src/android/support/v7/widget/SearchView.java#1695
which basically calls AutocompleteTextView.ensureImeVisible()
public void ensureImeVisible(boolean visible) {
mPopup.setInputMethodMode(visible
? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
if (mPopup.isDropDownAlwaysVisible() || (mFilter != null && enoughToFilter())) {
showDropDown();
}
}
This would resize Popup window to be shown exactly between Anchor and Keyboard.
use the following code. Change the location of the popup window in the method "showAtLocation".
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
PopupWindow pw = new PopupWindow(inflater.inflate(R.layout.popup_layout, null, false), ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT, true);
findViewById(R.id.activity_layout).post(new Runnable() {
#Override
public void run() {
pw.showAtLocation(findViewById(R.id.activity_layout), Gravity.CENTER, 0, 0); //set location here
}
});
To make a PopupWindow display above (on top of, or in front of) the on-screen keyboard, and make it dismiss when clicked outside, use this:
popupWindow = new PopupWindow(context);
popupWindow.setFocusable(true);
popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
Sample code: https://github.com/lorensiuswlt/NewQuickAction3D
To make a ListPopupWindow display in front of the keyboard, and make it automatically close when clicked outside, use this:
listPopupWindow = new ListPopupWindow(context);
listPopupWindow.setModal(true);
listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
Sample code: Custom PopupMenu (layout)

POPUP window showing in android

i have created a button in android and when clicking it would show the popup window..but the code doesnot work like that..it has no errors but not showing popup window...please helpme..here is my code
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RelativeLayout objrl = (RelativeLayout) findViewById(R.id.myrl);
final Button objButton = (Button) findViewById(R.id.mybutton);
objButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
PopupWindow objPopupWindow = new PopupWindow(objrl, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true);
objPopupWindow.setAnimationStyle(R.drawable.background2);
objPopupWindow.showAtLocation(objButton, Gravity.CENTER_HORIZONTAL, 10, 10);
}
});
}
have you tried this : objPopupWindow.showAsDropDown(popupButton, 0, 0);
or try this http://rajeshandroiddeveloper.blogspot.in/2013/07/android-popupwindow-example-in-listview.html
PopupWindow popupWindowDogs = popupWindowDogs();
called below function where they want ::-
public PopupWindow popupWindowDogs() {
// initialize a pop up window type
PopupWindow popupWindow = new PopupWindow(this);
// the drop down list is a list view
ListView listViewDogs = new ListView(this);
// set our adapter and pass our pop up window contents
listViewDogs.setAdapter(dogsAdapter(popUpContents));
// set the item click listener
listViewDogs.setOnItemClickListener(new DogsDropdownOnItemClickListener());
// some other visual settings
popupWindow.setFocusable(true);
popupWindow.setWidth(250);
popupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
// set the list view as pop up window content
popupWindow.setContentView(listViewDogs);
return popupWindow;
}
I've found some strange stuff in your codes
You've specified WRAP_CONTENT but haven't specified its content at all
Pass a drawable as animation style to the setAnimationStyle method.
In my opinion if you specify a valid animation style and a content view, It should appear.
I think you missed this code inside the OnClickListener
objPopupWindow.setContentView(objrl);

How to prevent windowpopup displacement after showing soft keyboard?

I'm created WindowPopup, with edittext. And when i focused on it, soft keyboard show and displace this popup above the top bounds, so i can't see what i'm typing. I want to show keyboard without any displace of views, just above them.
I read that i can change softInputMode for it, so i'm created class which extends from EditText, and tried to change inputMode in onFocusListener, but it didn't help.
setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View veiw, boolean has_focus) {
if (has_focus) {
//Try to change input mode to prevent displacing
((Activity) getContext()).getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
} else {
//.. return back previous input mode
}
});
I did so, because i need such behavior only in this popup, but i even try to change action attribute in my manifets file
android:windowSoftInputMode="adjustNothing"
or
android:windowSoftInputMode="stateHidden"
Can i show keyboard without any displacing of view?
P.S. i'm using Android API 15
When PopupWindow creates popup view, it sets to it new WindowManager.LayoutParams with softInputMode, which is overwrites behavior of Window.softInputMode. Here piece of code from PopupWindow
private WindowManager.LayoutParams createPopupLayout(IBinder token) {
WindowManager.LayoutParams p = new WindowManager.LayoutParams();
p.gravity = Gravity.LEFT | Gravity.TOP;
p.width = mLastWidth = mWidth;
p.height = mLastHeight = mHeight;
if (mBackground != null) {
p.format = mBackground.getOpacity();
} else {
p.format = PixelFormat.TRANSLUCENT;
}
p.flags = computeFlags(p.flags);
p.type = mWindowLayoutType;
p.token = token;
/*mSoftInputMode is the private field which is by default equals
to WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
*/
p.softInputMode = mSoftInputMode;
}
So to change softInputMode you need just to call public method of PopupWindow
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
And there is no need to remember previous soft input method, because this behavior will be only for this PopupWindow

Issue dismissing popup window

I have a popup menu implemented , which shows up on click of a button. This is my onclick method.
public void showOverflow(View view) {
boolean click = true;
Button action = (Button) findViewById(R.id.btbAction);
LayoutInflater inflater = (LayoutInflater) main.this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View popupView = inflater.inflate(R.layout.overflow_layout, null);
final PopupWindow pw = new PopupWindow(popupView,
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
pw.setOutsideTouchable(true);
if (click) {
pw.showAsDropDown(action, 0, 0);
click = false;
} else {
pw.dismiss();
click = true;
}
}
The popup window shows up when the button is clicked. Now, the problem is that the window is not dismissed when i touch outside the popup window.
I tried setting this property to the popup window
pw.setOutsideTouchable(true);
Things remain the same. Please help me fix this
You should change the setOutsideTouchable call's parameter to true:
pw.setOutsideTouchable(false);
Controls whether the pop-up will be informed of touch events outside
of its window. This only makes sense for pop-ups that are touchable
but not focusable, which means touches outside of the window will be
delivered to the window behind. The default is false.
If the popup is showing, calling this method will take effect only the
next time the popup is shown or through a manual call to one of the
update() methods.
Parameters: touchable true if the popup should receive outside touch
events, false otherwise
On the other hand, what is the click local variable supposed to do? It is set to true, so it will always force the pw to pop up, whenever the showOverflow method is called, and for no reason it is set to false later, because it's life cycle ends as you leave that method.
Your code should look something like this:
private LayoutInflater inflater;
private Button action;
private PopupWindow pw;
private View popupView;
/*
* (non-Javadoc)
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
popupView = inflater.inflate(R.layout.overflow_layout, null, false);
action = (Button) findViewById(R.id.action);
action.setOnClickListener(this);
}
public void showOverflow()
{
pw = new PopupWindow(getApplicationContext());
pw.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
pw.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
pw.setOutsideTouchable(true);
pw.setContentView(popupView);
pw.showAsDropDown(action, 0, 0);
}
The getApplicationContext() shoud be used in case you are inside an Activity class. Otherwise you should get the Context as a parameter.
change pw.setOutsideTouchable(true); to pw.setOutsideTouchable(false);
I know this is an old question but this is what I have done to fix it
The problem is:
You are creating a new instance of popupwindow everytime you call showOverFlow() thats why after you close the popupwindow another popup window will show
What will you do is initialize popupview in OnCreate
Then call popupwindow.showAsDropDown(view) in showOverFlow() method
And lastly you can check whether is it showing below code
Put this code in your button onclick
if(popupwindow.isShowing()){
popup.dismiss() }
else{
ShowOverflow()}

Categories

Resources