Set composing text on an EditText from a custom keyboard in Android - android

Explanation of what I am trying to do
I'm making a custom in-app keyboard that works on the same principle of this example. However, in my keyboard I'm using popup windows to display extra letter forms. In traditional Mongolian letters have different forms depending on if they are located at the beginning, middle, or end of a word. Usually these can be determined from the context, but sometimes a user needs to choose an alternate form explicitly from the popup key candidates.
Lets say that a user starts typing a word (where - represent letters):
---
Then they chose a from the popup (I'm only using a to represent the concept of choosing a special Mongolian glyph form). The Unicode for this letter will be rendered as follows if they continue typing:
---a--
However, the Unicode is rendered as
---A
at the end of words. (a and A have the same code in Unicode.) So the user is confused why they chose a from the popup key but it gets rendered as A in the editor. If they would just keep typing, though, it will be fine since it gets rendered as a in middle of words.
What I want to do it set some sort of temporary span on the a of ---a so that it doesn't get rendered as ---A before they type the next letter. But if they add a space or move the cursor to a different location, then it will revert back to the default ---A form for final letters. (That is, the temporary span will be cancelled.)
Real example
If the abstract a and A are too confusing, here is a real example. The user wants to type a Mongolian UE form (Unicode \u1826\u180c) in this word
But since \u1826\u180c gets rendered like this at the end of words
the user is confused until they continue typing. I want the span to make it look like this
which can be temporarily rendered with \u1826\u180c\u200d.
Documentation
The documentation says
If your IME does text prediction or requires multiple steps to compose
a glyph or word, you can show the progress in the text field until the
user commits the word, and then you can replace the partial
composition with the completed text.
And it gives this example and image:
InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
ic.setComposingText("Composin", 1);
ic.commitText("Composing ", 1);
Problem
I was going to describe why it wasn't working in this section, but in the process of setting up my question here, I discovered that it actually works. So I will add my answer below as an example for other people are who doing something similar.

The following code sets a temporary composing span when the string in question is returned by the popup window
if (selectedItem.equals("a")) {
inputConnection.setComposingText("a", 1);
}
where selectedItem is the string chosen by the user from the key popup window candidates.
Note that the a has an underline indicating that it is a composing span. (This is a contrived example from the question where a would be rendered as A if the text were committed immediately.)
This also works for the real example in the question
if (selectedItem.equals("\u1826\u180c")) {
inputConnection.setComposingText("\u1826\u180c\u200d", 1);
}
Committing the composing span
When it is confirmed that the user wants to keep the composing span (ie, they keep typing more letters in the word), it can be committed with
inputConnection.commitText("\u1826\u180c", 1);
Abandoning the composing span
If the user clicks somewhere else, the composing span is not cancelled. But this is a different question.
Your keyboard can override onUpdateSelection to listen for cursor changes there. Then call
inputConnection.finishComposingText();
to keep whatever text was in the composing region. Or
ic.commitText("", 1);
to get rid of it. See this answer for more.

Related

Losing spans on EditText with Google Keyboard as input

I'm trying to apply ForegroundColorSpan with Spannable.EXCLUSIVE_INCLUSIVE flag when using TextWatcher at a specific index range.
With my device's default input (Samsung Keyboard) there are no issues and everything works as expected, however when using Google Keyboard as input that's a different story.
From my debugging I found that Google Keyboard places whole words, even if you change one character - I guess that's because of the word correction feature. As a result, if the Span was applied at some point in the word (even at the end), and a user enters more text, the span disappears.
The only exception is when the span is applied to the last character in the word, and the user enters a space ("ends" the word).
The workaround I found is to simply check if the input is a whole word, and whenever it is - apply the Span again. While that does work, it's not a very good solution since I need to set the caret at the end every time, and the fact that I have to re-apply the spin when it could be avoided (that's why I use Spannable.EXCLUSIVE_INCLUSIVE flag).
P.S. I tried other flags such as INCLUSIVE_INCLUSIVE and it sorta works - however it applies the span backwards as-well, resulting the Span to be applied to the entire word, rather than the index I specified.
Are there better solutions to this issue?
Okay so I found a different solution - turning off keyboard's input suggestion. Doing so prevents the input from being whole word and instead just a single character every time.
To do so I had to add textNoSuggestions flag to EditText's inputType attribute.
android:inputType="textNoSuggestions|<other_flags>"
I found more information about this inputType here: Turn off autosuggest for EditText?

How to make an edit text start out numeric but accept text also

In my application I have an EditText (Actually it's an implementation of MultiAutoCompleteTextView, but I don't think that matters) in which the user can enter a formula to be calculated, although generally they will want to just enter an integer.
What I would really like is for the keyboard to open with the numeric keyboard showing, but allow them to change to text if they want.
As standard of course it shows the letters and allwos them to change to numbers, which is OK, but 90% of the time they will want the numbers.
I tried doing:
operandEditText.setInputType(InputType.TYPE_CLASS_NUMBER|
InputType.TYPE_NUMBER_FLAG_SIGNED|InputType.TYPE_CLASS_TEXT);
But the result was a numeric keypad with letters written on the number keys (like a phone keypad), and it didn't write letters anyway.
I'm also aware that I could add a button, spinner or something that changed the input mode of the widget, but the aim of this is to make the interface easier to use, and I'm not sure adding another control will achieve that.
Is there a way to make it do what I want?

What are the semantics of each InputType constant?

You can set a TextView's inputType to one of the values from InputType to hint that the typed-in text should be a person's name, phone number, &c. Even if the input method doesn't respect this hint, the TextView uses a KeyListener and/or TransformationMethod to ensure that only relevant characters can be entered, or to have effects like masking the password. Even the flags are more than just hints: they can change the behaviour of the TextView significantly (the most obvious example being EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE).
Google's documentation is very vague about the actual effect of each inputType. What characters are actually permitted in each case? How does this vary by locale, if at all? Even if there is no documented answer, and it's liable to change between versions, I'd still like to know the expected behaviour.
You can find this out by inspecting the source of the *KeyListener classes, though of course this may be changed in different versions or by manufacturer or carrier customizations. The below is based on the AOSP 4.3 source. These are only the effects that each type has on Android itself: input methods also use the types as hints to better predict what the user is likely to type. For example, although TYPE_TEXT_VARIATION_PERSON_NAME only has the effect of disabling spell-check, the IM might respond to this type by auto-completing from a dictionary of common names instead of from a language dictionary.
To experiment with input types and IME options, I hacked up a quick app that lets you select them from a list in a GUI, so you don't have to edit an XML layout and rebuild an app to do it. If you want to find out more, or check how they interact with a given IM app, download IM prove free from Google Play.
TYPE_NULL
This one is actually documented:
This should be interpreted to mean that the target input connection is not rich, it can not process and show things like candidate text nor retrieve the current text, so the input method will need to run in a limited "generate key events" mode, if it supports it. Note that some input methods may not support it, for example a voice-based input method will likely not be able to generate key events even if this flag is set.
This makes it sounds like it's for cases where you're not editing text, but pressing a key on the IM will do some action directly. But in fact it hides the IM completely. From the app's point of view, you almost never want this: set it if you only want a hardware keyboard to be able to enter text.
From the IM's point of view, you'll get this type passed to onStartInput a lot, usually when Android is about to hide the IM because a different activity is coming to the foreground. You want responding to this input type to be fast. There could be two reasons why it works this way, but someone involved with the design would have to confirm why:-
It could be to let the IM know that editing is completely finished in that window (unlike onFinishInput, which merely means the IM is being hidden), so it can free memory used for dictionaries and the like until editing restarts.
It could be part of what allows a hardware keyboard to use arrow keys for scrolling, menu accelerator keys, and so on, even when no text input is taking place.
Classes
Numeric types
TYPE_CLASS_NUMBER gives you the digits 0-9. In addition, adding TYPE_NUMBER_FLAG_SIGNED lets you have + or -, but only as the first character. Adding TYPE_NUMBER_FLAG_DECIMAL lets you have . in any position, but only once. You can have both signed and decimal. As far as I can tell, this isn't localized, so the allowed characters are the same even for locales where . is the thousands separator and , is the decimal point, or for locales with different number characters.
TYPE_CLASS_PHONE lets you have the digits 0-9, as well as any of #*+-(),/N.; and space. You can have those characters in any order and any number of times: there's no formatting check.
TYPE_CLASS_DATETIME | TYPE_DATETIME_VARIATION_DATE lets you have the digits 0-9 as well as any of /-.. Again, there's no extra check for formatting, so you can have them in any order.
TYPE_CLASS_DATETIME | TYPE_DATETIME_VARIATION_TIME lets you have the digits 0-9 as well as : and any of amp (for writing "am" or "pm", but you can use them in any order and position). Slightly perversely, you can't have space or . for "3 pm" or "2 p.m." or even "2.30". Again, it doesn't seem to be localized.
TYPE_CLASS_DATETIME | TYPE_DATETIME_VARIATION_NORMAL gets you 0-9 as well as :/-, space, and amp. This notably doesn't include . even though it's allowed in a date.
Based on the above observations, I can't say I'd recommend using any of the above classes. They all seem to have major absences and prevent localization. The above are the only classes with character restrictions.
TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_PASSWORD does as you'd expect: it uses a TransformationMethod to obscure the typed characters.
Text types
In TYPE_CLASS_TEXT, setting TYPE_TEXT_VARIATION_EMAIL_ADDRESS or TYPE_TEXT_VARIATION_EMAIL_SUBJECT makes a press of the enter key move focus to the next field instead of inserting a newline.
TYPE_TEXT_VARIATION_FILTER will prevent the input method going to full-screen (extract) mode.
TYPE_TEXT_VARIATION_PASSWORD has the obvious effect: it uses a TransformationMethod to obscure the typed characters. TYPE_TEXT_VARIATION_VISIBLE_PASSWORD still uses the TransformationMethod to prevent the text being copied
All of the following text variations allow spell-checking if TYPE_TEXT_FLAG_NO_SUGGESTIONS is not set. That is, using an class that is not TYPE_CLASS_TEXT or a variation that is not in this list has the same effect as setting TYPE_TEXT_FLAG_NO_SUGGESTIONS (which is described later).
TYPE_TEXT_VARIATION_NORMAL
TYPE_TEXT_VARIATION_EMAIL_SUBJECT
TYPE_TEXT_VARIATION_LONG_MESSAGE
TYPE_TEXT_VARIATION_SHORT_MESSAGE
TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
Flags
The presence or absence of InputType.TYPE_TEXT_FLAG_MULTI_LINE has non-obvious side-effects. If the type class is not TYPE_CLASS_TEXT, it is always as if the flag were not set, and the TextView goes into single-line mode. Setting lines or maxLines to 1 only affects the way the text is displayed: it does not start single-line mode.
In single-line mode:-
the ellipsize option defaults to end
pressing enter performs the "editor action" or moves focus to the next field (just as for email addresses or subjects, above); otherwise, it inserts a newline
pressing tab moves focus to the next field, only if TYPE_TEXT_FLAG_IME_MULTI_LINE is not set; otherwise it inserts a tab character
the imeOptions can include an "editor action" to replace the enter key on a soft keyboard; in multi-line mode, TextView will add IME_FLAG_NO_ENTER_ACTION to the imeOptions
maxLines is automatically set to 1
adding a newline to the field (e.g. using setText) has no effect, and a carriage return is replaced with a zero-width space (U+FEFF)
TYPE_TEXT_FLAG_CAP_* use TextUtils.getCapsMode to decide whether to capitalize each character. The rules are a little baroque and are not locale-sensitive. AFAICT, this only takes effect if the corresponding setting is enabled in the default keyboard.
When TYPE_TEXT_FLAG_AUTO_CORRECT is set, space, tab, newline, any Unicode "end punctuation" character, or any of ,.!?" will trigger auto-correction of the preceding word (in this context, that's the longest sequence of Unicode letters and apostrophes). If the whole word doesn't have a correction, it continues to retry with shorter subsequences. The corrections come from a fixed system resource com.android.internal.R.xml.autotext and are separate from any configured spell-checker.
TYPE_TEXT_FLAG_NO_SUGGESTIONS (or the text variations listed earlier) stops the text being spell-checked. This prevents the spell-check suggestions list being shown, and also stops misspelled words being highlighted. The input method can still provide completions if it chooses.
Other oddities
Long-tapping a TextView usually selects the tapped word, but if the input type is one of the following, it selects all of the text instead:-
TYPE_CLASS_NUMBER
TYPE_CLASS_PHONE
TYPE_CLASS_DATETIME (any variation)
TYPE_TEXT_VARIATION_URI
TYPE_TEXT_VARIATION_EMAIL_ADDRESS
TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS
TYPE_TEXT_VARIATION_FILTER

Best GUI to let the user edit a list of strings in Android?

Suppose, I need the user to be able to input a list of strings somewhere in the settings of the app. Say, it's a list of URLs. The strings are not supposed to have any spaces, commas or semicolons inside.
The easiest thing I thought of so far is to make a big multi-line EditText with a hint to the user "Separate strings by spaces" and each time the user presses OK, use split(" ") to extract the array of strings.
The problem with that simple solution is that sometimes strings are not long enough to fill the whole EditText width, and >1 strings appear visually in 1 line. Sometimes the URLs are too long, so "www." remains on one line, and the rest of the address appears on the next line. It all looks messy and the user looses track where separate URLs start and end in the line.
Another easy solution: a long single-liner where all strings are separated by ; with optional spaces after. VisualStudio uses that in settings, I find it bad as well since you don't see all the strings at once and have to move in this long line a lot (even harder with the clumsy touch screen).
A more expensive solution: a vertically scrollable list of single-line EditTexts, which are generated programmatically each time the settings screen is opened. Would also need a "+" button which creates a new EditText and a "-" button next to each of the existing EditText's.
EDIT: Another idea: show all the strings in a plain ListView with a "+" button in the last row. When you tap "+", it turns into an EditText with 2 buttons to the right: "OK", "Cancel". "OK" would save the newly added string.
If the user taps any of the items in the list, the line turns into an EditText with "OK" and "Delete" button. "OK" saves edits, "Delete" deletes the item. "OK" and "Delete" buttons better should have images instead of words.
Or, well, all strings can be shown in a ListView, and each time the user taps on an item, an additional popup is shown with EditText for editing the string and 3 buttons below: "OK", "Cancel" and "Delete".
Am I thinking along the right lines? Do you know any existing patterns/libraries/solutions which solve this problem efficiently on touch screens?
It would be better, to have only a single editText, where user can set values in list one by one, and can see added values in listView, There may be some provision for a button to save all entered data, onve. See following link once,
http://www.mubasheralam.com/tutorials/android/listview-transcript-mode
IMHO touch screens are not made for extensive writing since the touch keyboards are awful for writing stuff too long or with too much symbols (e.g. programming language or URL). Do not think about touch apps like old desktop apps/systems. Maybe you should rethink your design and try to avoid this data input.
If it's something your app cannot live without, or you simply do want to do it that way anyway:
I think a newline separator is way more clear than a space or a ";" (assuming the URLs cannot contain ";" btw...).
What about one EditText for each URL, generating EditTexts programatically as the previous one is filled.

Cursor movement and text retrieval in input methods

I'm designing my first Android IME and am a bit overwhelmed. My goals are accessibility-related, and as such I wonder if perhaps I'm trying things with the IME framework that just aren't possible. I've taken the default softkeyboard example and have it working along with some of my modifications, so I've definitely understood at least some of this, but there isn't a whole lot of documentation on some of the things I'm attempting. Here's what I mean:
Currently, Android phones with touchscreen-only keyboards are inaccessible. I currently have an accessible touchscreen keyboard using methods similar to those used in IOS/VoiceOver, so that part of the project is done and fairly straight-forward to accomplish in the IME framework.
Currently, Android's accessibility API doesn't provide accessible feedback for navigating text fields. That is, with an Android screen reader loaded, if you type the word "this", you'll hear individual characters spoken as you type them, but if you then try left-arrowing over the "s", that isn't spoken. So I want to trap movements and provide spoken feedback for the elements navigated past. Here's where I start encountering problems.
I currently have speech feedback for left and right arrowing, using getCurrentInputConnection.getTextBeforeCursor(1, 0) for arrowing left, and a similar call for arrowing right. This gets the character currently under the cursor after the movement is processed, and all is good.
My challenge, though, comes when arrowing up and down between lines. Ideally, I'd like to grab the current line of text and speak that, but I don't see any way to do that. The only thing I can think of is some combination of getTextBefore/AfterCursor(Integer.MAX_VALUE, 0) and combining those values, determining the current line by filtering for the previous and next \n. Is there another way--getting the entire text content of the field as a single block of text and using the cursor position to determine which piece of that text represents the current line? I'm seeing something about extracted text in the various input method classes, and it seems like there may be a way to monitor that, but I don't know if that is at all useful to me (I.e. would that return the entire field content?)
My next goal is providing standard text navigation capabilities. Android accessibility doesn't currently include touchscreen exploration, so it is impossible to otherwise scroll a large block of text. I don't necessarily expect folks to write novels on their phones, but I'd like to provide quick gestures or commands to move up/down paragraphs, and to the top/bottom of longer fields. Does the IMF provide methods for cursor movement, or is that outside of its authority?
Honestly, I didn't get the first part :(
For your second question, you will need to handle it by hand.
For instance, to add a key with a down drawable and make it work you will need to:
In the onKey method check for the code.
If it's 20, you should do a sendDownUpKeyEvents of that key event.

Categories

Resources