input connection-how to delete selected text? - android

I made a custom keyboard for android. When I press backspace button of my keyboard I use
getCurrentInputConnection().deleteSurroundingText(1, 0);
to delete one letter from the input field. But when I select some text and then press the backspace button, the selected text is not deleted. What method in input connection should I use so that selected text is also deleted from my keyboard when I press the backspace button?

When deleting you need to take into account the following situations:
There is a composing selection.
The editor/user has a cursor selection on the text.
There is no selection of any kind.
If there is a selection then it should be deleted. If there is no selection then the character in front of the cursor should be deleted.
Solution 1
At first I used this method. I like it because it only uses the input connection.
CharSequence selectedText = inputConnection.getSelectedText(0);
if (TextUtils.isEmpty(selectedText)) {
// no selection, so delete previous character
inputConnection.deleteSurroundingText(1, 0);
} else {
// delete the selection
inputConnection.commitText("", 1);
}
As long as the input connection is using the default BaseInputConnection.deleteSurroundingText method, this should be fine. However, it should be noted that the documentation warns
IME authors: please be careful not to delete only half of a surrogate
pair. Also take care not to delete more characters than are in the
editor, as that may have ill effects on the application.
If some custom view is using an input connection that doesn't correctly check for for text length or surrogate pairs, then this could cause a crash. Even though this is an unlikely senario, if you use this solution, then you should add that extra checking code here.
This may be why the sample Android keyboard first checks if there is a composing span, and if there isn't then it using the following solution.
Solution 2
You can also use the input connection to send a KeyEvent with KEYCODE_DEL. In my opinion this is not as good because it is a soft keyboard masquerading as a hard keyboard. But many keyboards do this. When I was making a custom view that accepted keyboard input, I had to handle deletes as a KeyEvent, that is, independently of the input connection (because the input connection was not deleting the text).
So just send the delete message as a KeyEvent (as if you were pressing a hard keyboard key down and then letting it up).
getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DEL));
getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_DEL));
This works as expected. It will delete the selection if there is one, or delete one character behind the cursor if there isn't a selection. (However, you should handle any composing span separately.)
Thanks to this answer for the idea.

Call getCurrentInputConnection().commitText("",1);

Related

Switch InputType from Text to Number on the fly

Canadian postal codes have the following format: A1A1A1, and match the following regex:
[ABCEGHJKLMNPRSTVXY][0-9][A-Z][0-9][A-Z][0-9]
I am setting up an EditText for the user to input their postal code. I would like to display alternatively the text and the number keyboard.
Naively, I use this code in either the TextWatcher or the InputFilter
if (Character.isDigit(s.charAt(s.length() - 1))) {
zipView.setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
| InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
} else {
zipView.setInputType(InputType.TYPE_CLASS_PHONE);
}
However, this result in an exception when the user inputs the first number.
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:464)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:454)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:33)
at android.text.method.NumberKeyListener.onKeyDown(NumberKeyListener.java:121)
at android.widget.TextView.doKeyDown(TextView.java:5787)
at android.widget.TextView.onKeyDown(TextView.java:5600)
at android.view.KeyEvent.dispatch(KeyEvent.java:2609)
... (continues without ever mentionning my classes.)
My guess is that the input type does not like that there are unsupported characters already in the view.
Input type doesn't actually restrict the keys allowed, its a hint to the keyboard as to what will be entered, so the keyboard can decide to change its UI. Nothing prevents you from adding text to a number field. It looks like a problem calling replace in a filter you set (filters are different from input type).
In fact most keyboards wouldn't even trigger this- XXXKeyListener classes are generally only called by hardware keyboards that cause keydown and keyup events. Software keyboards generally don't do that. Did you give this field a NULL input type initially? That's the only thing that would make the average softkeyboard try to pretend to be a hardware one.
Oh one other thing- setting the input mode while the field is active generally doesn't work well. If you don't reset the input connection, most keyboards won't even detect it (there is no change input type API for the keyboard side). If you do reset the input connection, you're likely to hit all sorts of weird behavior with autocorrect and timing (I know Swype had a dozen different rules for debouncing of events that resetting the input connection interfered with). Its not recommended to change an input type, ever.

Disable DONE in soft keyboard until minimum number of characters are typed in edit text

I need to keep the DONE button (imeOptions-->IME_ACTION_DONE) on android's system softboard disabled until the minimum number of characters are entered in the edit text. Any suggestions?
Note: Minimum number of characters is just one such validation that needs to be performed on the edittext user input. So until the user entered text pass through all the validations the DONE needs to be kept disabled preventing user from navigating to the next step.
Thanks
This is the closest I could get to. I couldn't disable the button but quietly consume the event triggered by the DONE button and do nothing.
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)){
if(isValid(mTextView.getText()){
//Permit further operation
}else{
//Do nothing - This will consume the KEYCODE_ENTER action
}
return false; //To let other listeners that this event has already been consumed
}
My suggestion would be not to go down this path. Ultimately you have no control over what a soft keyboard does. Even if you found a method for doing this on the stock keyboard, it would likely not work with the Samsung Keyboard or the Swype Keyboard. Some third-party keyboards even ignore basic controls like inputType, happily showing letters to users for entry into numeric fields. You should treat all keyboard-related api's as advisory and not count on any of them being enforced.

Appropriate way of asking the user for feet and inches on Android?

I'm implementing a form where the user is asked for a measurement. Depending on the locale, the user will be entering either meters or feet/inches.
Naively, my current implementation asks for a decimal point to be used with only feet. e.g., 2.5 feet would equal 2′ 6″ which is fairly misleading from my understanding. I'm not in a country that hasn't adopted to the metric system, so it wasn't obvious to me at the time.
There's a few possibilities and problems I see:
Show two EditText fields, one for feet one for inches. This makes layout design difficult since I'm also allowing the user to enter meters, which will only need one EditText. A possibility is to make one hidden at run time.
Using one EditText, I can't seem to find an android:inputType that allows for number input plus double primes and primes, or double quotes and apostrophes. e.g. 3′ 5″ or 3' 5". It means the EditText would have to use the standard alphabet keyboard which makes it slightly hindering to the user.
Also, with one EditText, I am happy to (and already doing so for just a single entry with meters and feet without inches), to suffix the EditText after the user loses focus, and remove the suffix when being focused again. This does make the code more complex for a simple input field.
Are there any other options for this?
I just realised soon after posting:
Why not create a NumberPicker popup or Spinner when the user focuses on the EditText. This would only show up for imperial measurements.
I'm thinking off the top of my head you can use a TextWatcher to check for when the user types a space. When that occurs, suffix in the ' at the end and let the user type the inches.
Or, always append the suffix to the end and push it down beyond the cursor every time the user types. When the user presses space then jump the cursor over and put " beyond it.
It may or may not be messy from a user flow perspective (I haven't tried or seen it), but it could solve some problems. You can continue to force the user to type only numerical values which keeps the number keyboard up instead of letters. They don't have to swap keyboards or do long-key presses to type a single character. It also shows the intentions to the user as he/she types.
edittext.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getKeyCode() != KeyEvent.KEYCODE_DEL) {
String input = edittext.getText().toString();
if (input.length() == 1) {
input = input + "'";
edittext.setText(input);
int pos = edittext.getText().length();
edittext.setSelection(pos);
}
}
return false;
}
});

Android: How to record keystroke?

I want to make a smart keyboard that can learn and save new words from user. I already made note and keyboard separately, the problem is :
how to read all keystrokes and write it to my note in background?
how to save my note automatically?
thanks for your help
Keep a String or StringBuilder that stores all the text that the user types. All text sent through your soft keyboard will have to pass through the onKey method.
So, I'd do something like this:
1) In onKey, check to make sure primaryCode (the keycode that was pressed) is a letter/number/apostrophe using the corresponding functions. So, something like
Character.isDefined(primaryCode)
2) Concatenate primaryCode onto the end of your StringBuilder/String.
You'll also have to deal with the user moving the cursor/backspacing. In my keyboard, I only store the most recent two words (resetting this whenever the user moves the cursor). That way, the keyboard can learn what the most likely word is given the last word.
You can save your "note" using an ObjectOutputStream or (if it's fairly small) using sharedPreferences.
Send me an email if you run into an more issues: I've been writing a soft keyboard for a while so I'm pretty familiar with it.

Android EditText: Listeners, Newline Characters, and Focus

Currently I have an edittext field that when the user presses enter it does mostly what I want it to, validate an IP Address format and inform the user if it is wrong. How do I make it so when the user presses enter it checks it like it is supposed to be does NOT enter the newline character?
Here is my code for it.
public boolean onEditorAction(TextView arg0, int arg1, KeyEvent arg2) {
if(validateIPaddress(m_etIPAddress.getText().toString()))
{
ConfigData.m_IPAddress = m_etIPAddress.getText().toString();
}
else
{
showAlertDialog("Invalid IP Address\n Example: \n255.255.255.255\n0.0.0.0","Error: ");
m_etIPAddress.setText(ConfigData.m_IPAddress);
m_etIPAddress.requestFocus();
}
return false;
}
Another problem I have is that in the false condition of the validation, that it will not bring up the soft keyboard to allow the user to reedit that text field. If the user clicks on another edit text the window gives it focus, and allows the user to edit the second text field while still maintaining the 'green outline' around the original edittext. Is there a way to fix this?
EDIT:
Thanks for the response. The EditText still creates a newline. I tried calling that when I create the EditText and it shows the dialog then inserts a newline character at the beginning.. which is weird because the
m_etIPAddress.setText(ConfigData.m_IPAddress);
should automatically overwrite anything in that field to the static IP saved within ConfigData. (my settings class) and I think the focus might work, the problem is that after requestFocus, that EditText shows it has focus but is unresponsive.
I can click on other EditText's and modify them, while it still shows the focus outline on the IP EditText. If I click on the IP EditText it doesn't actually do anything. Its kind of strange.
I think for your EditText creating a new line, you can do that by replacing the enter button by a done button like that :
yourEditText.setImeOptions(EditorInfo.IME_ACTION_DONE);
And to go with that, you can put this to your xml file describing your EditText :
android:maxLines="1"

Categories

Resources