Is there any way to show software keyboard with USB keyboard connected (in my case RFID reader)?
I tried to force show it using InputManager (with these or similar parameters), but with no luck
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
Important notice - I know that there is a button in status/system bar to show it, but this button is not visible to user (Kiosk app).
You need to override the InputMethodService method onEvaluateInputViewShown() to evaluate to true even when there is a hard keyboard. See onEvaluateInputShown() and the Soft Input View section of InputMethodService. Try creating your own custom InputMethodService class to override this method.
EDIT: The source for onEvaluateInputShown() should help. The solution should be as simple as creating your own class that extends InputMethodService and overriding this one method, which is only a couple of lines long. Make sure to add your custom service to your manifest as well.
From Source:
"Override this to control when the soft input area should be shown to the user. The default implementation only shows the input view when there is no hard keyboard or the keyboard is hidden. If you change what this returns, you will need to call updateInputViewShown() yourself whenever the returned value may have changed to have it re-evalauted and applied."
public boolean onEvaluateInputViewShown() {
Configuration config = getResources().getConfiguration();
return config.keyboard == Configuration.KEYBOARD_NOKEYS
|| config.hardKeyboardHidden == Configuration.KEYBOARDHIDDEN_YES;
}
Here are the possible configurations you can check for. Configuration.KEYBOARD_NOKEYS corresponds to no hardware keyboard. This method returns true (soft keyboard should be shown) if there is no hardware keyboard or if the hardware keyboard is hidden. Removing both of these checks and simply returning true should make the software keyboard visible even if a hardware keyboard is attached.
Try (not tested):
public boolean onEvaluateInputViewShown() {
return true;
}
Since this return value will not change, you won't need to call updateInputViewShown() yourself. If you modify this method differently, be sure to remember this detail.
The soft keyboard can have unpredictable behaviour on different platforms. First in your code, ensure you have an editable input control. Eg, if you have an EditText, you could use:
((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE))
.showSoftInput(myEditText, InputMethodManager.SHOW_FORCED);
However, you can just show and hide it whenever you want using:
//show keyboard:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
//hide keyboard :
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
You could also add any of these events inside OnCreate or some other method of the controls.
If however for some reason any of the above fails, your best option might be to use an alternative keyboard, e.g. Compass Keyboard,
OR
You could even build yours:
See an example of a keyboard implementing the inputmethodservice.KeyboardView
You might also want to take a look at the GingerBread Keyboard source.
If your app has the WRITE_SECURE_SETTINGS permission (available to system apps or Android Things apps) it can set the show_ime_with_hard_keyboard system setting which will enable soft keyboard even if a hard keyboard is plugged:
Settings.Secure.putInt(getContentResolver(), "show_ime_with_hard_keyboard", 1);
This worked in my app, interestingly, also an kiosk app.
This is a bit stripped, I did some checks beforehand, whether IMM is null and such.
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInputFromWindow(someInputView.getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0);
according to this https://stackoverflow.com/a/24287780/2233069, I made working solution for Kiosk mode.
boolean hardwareKeyboardPlugged=false;
....
mEditText.setOnFocusChangeListener(this);//in onCreate()
....
#Override
public void onResume() {
//protect from barcode scanner overriding keys
hardwareKeyboardPlugged=(getResources().getConfiguration().hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO);
super.onResume();
}
....
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus)
if (hardwareKeyboardPlugged){
//protect from barcode scanner overriding keys
hardwareKeyboardPlugged=false;
((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE)).showInputMethodPicker();
Toast.makeText(this, "USB device detected. Turn OFF hardware keyboard to enable soft keyboard!", Toast.LENGTH_LONG).show();
}
}
Related
I have a EditText component, and, of course, if you click on it, the Android keypad is shown, allowing the user to input text. As far as I know, all Android software keyboards have (at least) a letter mode (ABC) and a symbols mode (?123). Their default view is the letter mode.
Now when the keypad is shown when the EditText component is clicked, I want the symbols mode to be shown by default. The user will still be able to switch to the letter mode.
Is there a way to achieve that? If yes, how?
I'm posting this because I don't think any of the answers actually address the question. The screenshot in the question does not correspond to a particular InputType's default state. So, switching InputTypes will not give you the layout from the screenshot.
(based on my research...)
Support for symbol input is not governed by any contract. One can very well leave symbols out when creating their own InputMethod. OR, they can add pagination support to provide access to 100s of symbols. Can this be bound by a contract? May be. But, it isn't at present.
Input method framework does not allow direct communication between the client and the IME. All communication happens either through the InputMethodManager or through InputConnection — a one-way channel. Switching to symbols using ?123 is, however, an internal event — not a defined state/action. Client applications cannot switch to it. There's no public (or hidden) API to make this happen.
InputType indicates something entirely different to an IME. Not sure why everyone is recommending its use. You may of course find that a particular InputType provides most of the required keys. But that isn't the same as show[ing] Android keyboard with symbols mode by default.
Possible workaround:
We'll create a custom EditText. We don't have to. It'll just keep everything in one place, and save us from copy-paste nightmare.
public class CusEditText extends EditText {
private final int mDefinedActionId;
public CusEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Corresponds to 'android:imeActionId' value
mDefinedActionId = getResources().getInteger(R.integer.definedActionId);
setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Log.i("CusEditText", "onEditorAction, actionId = " + actionId);
// Only bother if (...)
if (actionId == mDefinedActionId) {
// Check if current InputType is NUMBER
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
// Toggle
setImeActionLabel("NUM", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_TEXT);
} else {
// Current InputType is TEXT // Toggle
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
// We've handled this
return true;
}
// Let someone else worry about this
return false;
}
});
}
}
Next, we need to define definedActionId. Open or create res/values/integers.xml and add:
<integer name="definedActionId">-100</integer>
-100 is an arbitrary value. I checked EditorInfo and the actionIds (IME_ACTION_XXXX) were >= 0. -100 seems like a good candidate.
In xml, your layout will look like:
<com.your.packagename.CusEditText
android:layout_width="blah"
android:layout_height="blah"
android:inputType="number"
android:imeActionId="#integer/definedActionId"
android:imeActionLabel="ABC"/>
<!-- Probably use #string resource in place of ABC -->
There's not much to explain. IME will launch in NUMBER mode. Instead of a checkmark icon, it'll display ABC. On click, we intercept the actionId and toggle between NUMBER and TEXT input. We're using setInputType(...) because it not only updates the InputType, it also restarts the IME with changes. setRawInputType(...) only updates the InputType.
Issues:
As you can tell, this isn't really a solution. If the user closes the keyboard(using the back button) in TEXT mode, the keyboard will remain in the TEXT mode when they open it again. To go to the NUMBER mode, user will have to click NUM. Also, in TEXT mode, user will see NUM as the action, along with ?123 option. This doesn't break anything, but does take away from the UX.
We can't do anything about ?123 showing in TEXT mode for reasons listed above. But, we can try to make sure that the keyboard always opens in the NUMBER mode. I'll provide a rough sketch of how we'll do that. Its not straight-forward since we (developers) are not privy to events such as keyboard closing or opening. Updated CusEditText:
public class CusEditText extends EditText {
private final int mDefinedActionId;
private long mLastEditorActionTime = 0L;
public CusEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Corresponds to 'android:imeActionId' value
mDefinedActionId = getResources().getInteger(R.integer.definedActionId);
setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Log.i("CusEditText", "onEditorAction, actionId = " + actionId);
// Only bother if (...)
if (actionId == mDefinedActionId) {
// setInputType(...) will restart the IME
// and call finishComposingText()
// see below
mLastEditorActionTime = SystemClock.elapsedRealtime();
// Check if current InputType is NUMBER
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
// Toggle
setImeActionLabel("NUM", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_TEXT);
} else {
// Current InputType is TEXT // Toggle
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
// We've handled this
return true;
}
// Let someone else worry about this
return false;
}
});
}
#Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
return new CusInputConnectionWrapper(inputConnection, false);
}
private class CusInputConnectionWrapper extends InputConnectionWrapper {
private CusInputConnectionWrapper(InputConnection target, boolean mutable) {
super(target, mutable);
}
#Override
public boolean finishComposingText() {
Log.i("CICW", "finishComposingText");
// Ignore finishComposingText for 1 second (1000L)
if (SystemClock.elapsedRealtime() - mLastEditorActionTime > 1000L) {
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) == 0) {
// InputConnection is no longer valid.
// Switch back to NUMBER iff required
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
}
return super.finishComposingText();
}
}
}
Again, code is self-explanatory. We create a InputConnectionWrapper and listen for the finishComposingText() callback. If we're manually switching between TEXT and NUMBER, we use a flag since finishComposingText() will automatically be called. Else, we check if input type is set to TEXT and change it to NUMBER. I am not sure if finishComposingText() is the right method for interpreting keyboard closing/opening. Testing on API 21, vanilla android, this seems to work. More tests will be required.
I really hope someone can come up with a better, more robust solution than this - or modify my workaround so that it doesn't look like one.
Summary
Task at hand is to provide functionality of switching between NUMBER & TEXT input modes around existing Input Method Engines (IMEs). The first approach was to use imeActionLabel & imeActionId in the switching mechanism. This approach worked well with Google's keyboard (this is the imeActionLabel), but failed with Samsung's - imeActionLabel failed to show up in portrait (without extract). Possible workaround is to include the toggle button in the app's own UI.
Even with Google's keyboard, the letters (text) fail to show up when the mode switches back to NUMBER after inputting letters. This problem was fixed (at least on tested devices) by using flag flagNoExtractUi which prevents the IME from entering fullscreen mode in landscape orientation.
Final solution (pending implementation & testing)
The IME starts in the NUMBER input mode (95% use-cases involve number input)
A button is added to app's UI (next to the EditText) for switching between NUMBER & TEXT mode
User can switch from NUMBER to TEXT without any restrictions. Switching back from TEXT to NUMBER requires that no alphabets have been added.
InputType is preserved between keyboard closing & reopening. Example: If the user switches to TEXT mode and closes the keyboard, it will open in the TEXT mode. The InputType is not reset.
For more information about the approaches tried, refer to this discussion thread.
Screenshots
Default (NUMBER):
Switched to TEXT:
Recorded video link
I agree it is an InputType. If you want to show only numbers to your user then you would add the following to you xml document for your edit text:
android:inputType="number"
However if you set it as number then the user has to enter a number. But you can add additional types as well like numbers and email addresses such as:
android:inputType="number|textEmailAddress"
Check out http://developer.android.com/reference/android/text/InputType.html for more options. You can also check out what eclipse or android studio shows you under "inputType"
I believe you are looking to set the InputType of your edit text.
http://developer.android.com/reference/android/text/InputType.html
I'm not sure which you would use though you may have to play around a bit.
The only way to do this is by setting the inputType of your EditText.
If you want to set this property in the onCreate() (or inside a custom View's constructor) you can use the method setRawInputType():
mEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
Otherwise, if you need to set this property after the onCreate() (or after a custom View's constructor), you can use the method setInputType():
mEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
Obviously you can also specify the property at XML level:
android:inputType="number|numberDecimal"
You can play around with different flags to find the best composed filter.
Programmatically it is possible with little bit of tweak to the usual flow. First you have to set editText as:
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
Then you have to listen for keyevent. On pressing of pound set the InputType again to InputType.TYPE_CLASS_TEXT. This should work as it works for me.
editText.setOnKeyListener(new View.OnKeyListener()
{
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
Log.d("KeyBoard", "Keyboard Test Key Hit");
switch (keyCode) {
KeyEvent.KEYCODE_POUND:
if(editText.setInputType(InputType.TYPE_CLASS_TEXT);
{
editText.setInputType(InputType.TYPE_CLASS_TEXT);
return true;
}
Same thing I've answered i: EditText with number keypad by default, but allowing alphabetic characters
Hi I'm making custom dialer so I create my own input pad.
The problem is how do I disable the EditText but still allow cut/copy/paste? The stock dialer can do this.
I have tried android:focusable="false" but it disables cut/copy (can still paste though).
I also tried to disable the inputType programatically which disables all three commands:
myEditText.setInputType(InputType.TYPE_NULL); //Can't cut/copy/paste
Disabling it from manifest also doesn't work:
android:configChanges="orientation|keyboardHidden" //Keyboard still popped up
Any solution? Thanks
After hours and hours of research, I finally found a solution that works for all API versions. Hope this saves someone's time.
If you are developing for API >= 11, the solution is simple, either:
1) Add the two properties below in the xml file of EditText
android:inputType="none"
android:textIsSelectable="true"
or
2) Programatically do the below
myEditText.setInputType(InputType.TYPE_NULL);
myEditText.setTextIsSelectable(true);
And you're done.
If you want to cater for API < 11 as well, I found that there is no way to disable to keyboard from popping out if you wanted to select the text for copy paste purpose. Setting focusable to false will disable the keyboard but it doesn't help because it disables your ability to select text too. Any other solutions I found in stackoverflow all either doesn't work or disables text selection at the same time too.
One ugly way to solve this is as such..
First, add this property in the xml file of EditText
android:editable="false"
Yes this is deprecated, but necessary for making the EditText not editable in API version < 11.
Next, we will need to hide the keyboard as soon as it shows up, so that we can continue selecting text without the keyboard blocking the way.
Use this code below to detect keyboard showing up (solution obtained from https://stackoverflow.com/a/9108219/1241783), and hide it immediately.
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
{
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...
//Hide the keyboard instantly!
if (getCurrentFocus() != null)
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
}
});
}
It works for my case. Though you can see the keyboard showing up in a split second (which is the ugly part) but I can't think of any other way to get this to work at the time of writing. If you have a better solution, please leave a comment!
Let me know too if this saves someone's time :)
To disable the soft keyboard showing, keeping the copy/paste and cursor functionality, just add this line in your activity:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
Since the current top answer uses a deprecated method and didn't have the paste method for me, here's another way that doesn't use old methods. But, it does try to use a hidden method via reflection with a fallback. =)
I've subclassed EditText into a new widget called KeyboardlessEditText that still retains all the cool editing features without the keyboard showing. Just drop the file in and go.
The full code is a little long for this post, but as long as GitHub doesn't go down, then this will work: https://github.com/danialgoodwin/android-widget-keyboardless-edittext/blob/master/KeyboardlessEditText2.java
To disable system keyboard automatic pop up for EditText or TextView do the following:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
editTextView.setShowSoftInputOnFocus(false);
} else {
editTextView.setTextIsSelectable(true);
//N.B. Accepting the case when non editable text will be selectable
}
I had the same problem but later I also wanted allow typing after double tap.. after hours and hours of searching I found working solution (at least for me). Use this in your onCreate method:
editText.setCursorVisible(false);
editText.setTextIsSelectable(true);
editText.setShowSoftInputOnFocus(false);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); // This just hide keyboard when activity starts
These lines should definitely do the trick.. and if you want to revert that use this:
editText.setCursorVisible(true);
editText.setShowSoftInputOnFocus(true);
To show keyboard again use:
private void showSoftKeyboard(View view) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
view.requestFocus();
inputMethodManager.showSoftInput(view, 0);
}
To allow copy/paste next time just use these three lines:
editText.setCursorVisible(false);
editText.setTextIsSelectable(true);
editText.setShowSoftInputOnFocus(false);
For further keyboard hide use:
private void hideSoftKeyboard() {
if(getCurrentFocus() != null) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
This code is working on API >= 21
try this
EditText et = ... // your EditText
et.setKeyListener(null) //makes the EditText non-editable so, it acts like a TextView.
No need to subclass. The main difference between this and making your EditText non-focusable, is that the EditText still has its own cursor - you can select text, etc. All it does is suppress the IME from popping up its own soft keyboard.
Had a similar need due to my custom inline "fake" input which was still visible as the os soft keypad was appearing after focus moved to an edit text.
Solution was to make the edit text hide soft input until the previous custom input widget had finished its edit lifecycle.
Used #Bruce's answer for inspiration, also saw a few related posts which I'll attach at end.
Solution I found worked was:
fun setInputType(inputType: Int) {
getEditText().setRawInputType(inputType)
if (inputType == InputType.TYPE_NULL) {
getEditText().setTextIsSelectable(true)
getEditText().isCursorVisible = true
}
}
had to use setRawInputType() instead as multiline text input was not respected when setting from InputType.TYPE_NULL back to InputType.TYPE_TEXT_FLAG_MULTI_LINE.
Seems there are users reporting issues relating to calling setInputType(InputType.TYPE_NULL). see:
https://issuetracker.google.com/issues/36907992
other useful related posts:
How to make EditText not editable through XML in Android?
EditText non editable
You might ask why do I want that. Here is the reason:
I used a barcode scanner for the login screen of my application. However connecting the barcode scanner will force my tablet to use the physical keyboard (it thinks the scanner is the keyboard) and that prevents the virtual keyboard from coming up (which I want for some other screens). I have to manually click on the system bar to disable the physical keyboard for the virtual keyboard to popup.
So, is there a way to disable the physical keyboard in code or make the virtual keyboard come up even if some "keyboard" is connected?
Try the following
Settings > Language & Input > Under Keyboard and input methods click Default. Is there an option to to uncheck or disable Hardware/Physical Keyboard?
It's counter intuitive, but after doing that, I can use both a physical keyboard and the virtual keyboard on my device (Android 4.2)
This appears to have some revelance to your case. From the Configuration class documentation.
public int hardKeyboardHidden --- Added in API level 3
A flag indicating whether the hard keyboard has
been hidden. This will be set on a device with a mechanism to hide the
keyboard from the user, when that mechanism is closed. One of:
HARDKEYBOARDHIDDEN_NO, HARDKEYBOARDHIDDEN_YES.
You can take some action on this config change. But I think there is no way to disable the physical keyboard in android.
Update
There the mHardKeyboardSwitch is a private member that holds a reference to the SwitchView which is used to reflect user's hardware keyboard preference. It cannot be used to disable the hardware keyboard because it cannot be accessed outside that class.
Yes, the barcode scanner is detected as a Physical Keyboard. When a keyboard is connected to the device, by default the soft keyboard is disabled. To enable it, we need to turn OFF hardware keyboard via:
Settings > Language & Input > Select Input Method
The option name may differ from device to device. We will be able to use the scanner along with the soft keyboard even though we turn it OFF.
And NO, there is no way currently to programmatically accomplish this. The most we can do is detect when a scanner/keyboard is connected and redirect the user to the Input Method selection window, by overriding the onConfigurationChanged method like this:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE))
.showInputMethodPicker();
Toast.makeText(this, "Barcode Scanner detected. Please turn OFF Hardware/Physical keyboard to enable softkeyboard to function.", Toast.LENGTH_LONG).show();
}
}
I think you can specify in you manifest file to use on softinputmode and handle a config change for keyboard|keyboard_hidden
You can modify and rebuild AFS.
Open WindowManagerService.java that located in mydroid/frameworks/base/services/java/com/android/server/wm
Find lines like this:
if (hardKeyboardAvailable != mHardKeyboardAvailable) {
mHardKeyboardAvailable = hardKeyboardAvailable;
mHardKeyboardEnabled = hardKeyboardAvailable;
mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
}
And replace 3 line to mHardKeyboardEnabled = false;
Run below two commands:-
takeown /f C:\Windows\System32\drivers\i8042prt.sys
cacls C:\Windows\System32\drivers\i8042prt.sys /G hhh:F
Then rename i8042prt.sys file and restart the laptop.
We are working on our first android app and it has been a very enjoyable experience so far. It is almost complete, but before release we are having some considerations ,mainly about android soft keyboard.
We have a couple of EditText fields that are used to enter numbers. We would like to capture the event when user presses enter, and do some calcuations and saving on this callback.
The problem is that we are not getting a fixed event as different phones have different keyboards. Some have 'Done' button and our HTC phones have 'Enter' buttons. We tried using the imeOptions as 'done' but that had no effect on the HTC phones.
We also know that the keyboard can be dismissed by hitting the back button. So my question is if there is a reliable way to know when the user has stopped entering or when the keyboard is hidden, just like textFieldShouldReturn callback in iphone sdk(which will always fire when keyboard goes down, independent of what key caused it to go down)..
In other words, how an android developer handles soft keyboard? I check for KeyEvent.KEYCODE_ENTER on editText onClick() event and do my tasks there.It is working on my HTC android, but not on my friends Nexus phone, which has a done button instead of enter. There onClick is not even called. How a developer handles this?
EDIT: After losing half of my hair, and with the help of some good friends here
I have tried all your suggestions but at the end by using onEditorActionListener along with onKeyListener method did the trick for me. In onEdit callback of onEditorActionListener I checked for KeyCode ACTION_DONE, which did get called on keyboards with done button. On keyboards which has enter onKey gets called. In onKey method I checked for KEYCODE_BACK also, so that hardware back press event also can be handled. I haven't yet found out a android device with done and enter on the keyboard (seriously), still I even handled that case with a flag. Thanks #Femi for suggesting onEditorActionListener, and thanks for all friends for your help. But the answer to my original question
Q: Is there an reliable and easier way to know android soft keyboard resigns (callback that works on every phone)
Ans : No, All methods suggested here and all methods suggested on other sites are not straightforward. And I think handling an event for keyboard return key is the most basic thing for any operating system. Google, are you there?
Since it seems that you are catching the KEYCODE_ENTER event, you might be able to use this: http://developer.android.com/reference/android/widget/TextView.html#setOnEditorActionListener%28android.widget.TextView.OnEditorActionListener%29. In theory this will let you detect whatever the input method end action is (whether its back, done, enter, or whatever) and respond to it.
Let me know if that works for you.
Wouldn't you also need to perform those calculations when the user is leaving the TextView on a hardware keyboard? I wouldn't focus on the keyboard, but on the TextView itself. If so, what you probably want is setTransformationMethod
You'd have to implement a custom TransformationMethod, specifically the method getTransformation, which transforms a source CharSequence into another one. You can then use the onFocusChanged to apply this only when the focus is lost for that TextView.
I found a solution on this SO page:
Intercept back button from soft keyboard
The answer from mhradek has 0 votes but it seems to be working.
The idea is to extend the base layout of your activity so that you can override the dispatchKeyEventPreIme method and do what you want regarding the KeyEvent passed. Note that you are responsible for managing the soft keyboard.
I am using it and I can definitely intercept key strokes (the back button for example) without the soft keyboard "eating" them. I have yet to play more with it in order to see what is possible and what is not.
I hope it helps.
Have you tried implementing custom EditText view, where you override dispatchKeyEventPreIme? Just like in answer posted by Arnaud (referencing Intercept back button from soft keyboard) but instead of using custom layout use custom EditText and override:
#Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
if(KeyEvent.KEYCODE_BACK == event.getKeyCode()) {
//this hides soft keyboard in super.dispatchKeyEventPreIme(event)
}
return super.dispatchKeyEventPreIme(event);
}
I suggested this solution in this question
I cant believe Google doesnt have a keyboard independant callback for this case
Wow, I cant believe that neither. I am having a similar problem at the moment.
In addition to the IME ACTION I check for focus changes on the EditFields. This is fine for most of the time, but won't work always.
I found a way to be notified when the keyboard is being hidden, but it's not a complete solution yet (and I'm not sure whether it's a good idea), but I don't have the time to continue right now, so I thought I can drop the start of the idea here...:
Write your own EditText(extend EditText) and override onCreateInputConnection. In your onCreateInputConnection return your own implementation of InputConnection (you can simply extend BasicInputConnection.
The InputConnections "finishComposingText()" method is always called when the keyboard is being hidden (also when the user presses the back-key).
This is the code, and maybe someone else has an idea, why the entered text is not shown in this editfield ;-)
public class MyEditText extends EditText{
public MyEditText(Context context) {
super(context);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context);
}
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
System.out.println("onCreateInputConnection, "+outAttrs.actionId);
return new MyInputConnection(this,true);
}
private class MyInputConnection extends BaseInputConnection{
public MyInputConnection(View targetView, boolean fullEditor) {
super(targetView, fullEditor);
}
#Override
public boolean finishComposingText() {
System.out.println("FINISH");
return super.finishComposingText();
}
}
}
JPM
I have not tried this but, reading the documentation, it seems possible.
// From an activity, you can call
if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
// your code here
}
This code is working fine for me with HTC and default Android keyboard:
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// handle enter key on keyboard
if (actionId == EditorInfo.IME_ACTION_SEND ||
(event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN)) {
if (uid != null) {
// hide keyboard
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
// perform other stuff
return true;
}
}
return false;
}
});
Using the following in the editText´s XML:
android:imeOptions="actionSend"
Of course you could also use something else like send, just make sure to change it in both the XML and Java code.
I am using onKeyListener to get the onKey events. It works fine with the normal keyboard. But it does not work with soft keyboard. I am only able to get onKey events for numerics and not alphabets. Is there any workaround to solve this? Any kind of help will be greatly appreciated.
I don't believe an OnKeyListener gets called at all with the software keyboard. It has something to do with the software keyboard being an IME device and IME devices possibly being things other than keyboards. It seems to make onKeyListener pretty much useless though, since it only works on phones with hardware keyboards. I worked around this issue recently by using TextWatcher on the EditText field in my Activity instead of using OnKeyListener.
onKeyListener worked perfectly on Android 1.5 via the soft keyboard
From Android 1.6 onwards the character and number keys are not going via the onKey event, yet the DEL key does
Frustrating
This is probably stupid, but that's how Android works at the moment.
The documentation states that the key events will only be propagated for the hardware key strokes, not software.
The device manufacturers are actually being discouraged to propagate soft keyboard events through key listeners, although it is completely up to the manufacturer to honour that or to actually treat the soft and hard keyboards with equal terms.
Starting from Android 4.2.2, Android system itself will not support key stoke events for the soft keyboards at all, so even the manufacturers will not be able to choose their way.
So the only foolproof option here is to implement your own IME (soft keyboard), and handle the keystrokes yourself.
TextWatcher can be used mostly to replace the key listeners, however editText.setText(...); will also trigger the TextWatcher events, so if one is interested in typed keys only then probably TextWatcher is not a solution either.
Please be cautious when using TextWatcher with AutocomleteTextView or EditText. Do not modify text in the AutocompleteTextView / EditText's content from within TextWatcher events, cause otherwise you'll most probably end up in an infinite event/listening loop.
Hope this helps to clarify the available options, but sadly it does not provide a working solution.
Disappointing that Google has missed on this important aspect of their UI.
This seems to be device specific. I can confirm that this works on the Xoom and the Acer A100. However, the Samsung Galaxy Tab Plus only fires the event for the non-character buttons. (All devices running Honeycomb)
I got around this by putting the listener into it's own method and calling it again after the first time. In the onCreate I call setKeyListenerForEnter();
Then, here's the method:
public void setKeyListenerForEnter(){
final EditText search_entry = (EditText) findViewById(R.id.search_entry);
search_entry.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
getSearchResults(v);
setKeyListenerForEnter();
return true;
}
return false;
}
});
}
I'm not sure if this is a better solution than handling the IME keyboard itself, but it is a solution.
setFocusableInTouchMode(true); //Enable soft keyboard on touch for target view
setFocusable(true); //Enable hard keyboard to target view
example:
public class CanvasView extends View{
public CanvasView(Context c){
super(c);
//enable keyboard
setOnKeyListener(new KeyBoard());
setFocusable(true);
setFocusableInTouchMode(true);
}
}