12/11/2014 UPDATE: The patch area has been changed so as not to limit & lt; API level 19, because on a third-party keyboard the error still exceeds 19.
1/9/2014 UPDATE: I developed a code approach to solve all the problems of Google Keyboard (LatinIME) KEYCODE_DEL, in particular releases 42904 and 62306.
The Turix response enhancement has been included, with permission, in my own code here . In Turix remote enhancements, you need to enter garbage characters into an editable buffer, instead finding an incremental way to ensure that only one character is always in that buffer.
I used (similar) code for this in a deployed application that you can test:
https://play.google.com/store/apps/details?id=com.goalstate.WordGames.FullBoard.trialsuite]
INTRODUCTION
The workaround below is for all versions of the Google keyboard, both past and future, regarding these two errors. This workaround does not require the application to remain stuck, focusing on API level 15 or lower, which some applications have limited to take advantage of the compatibility code that bypasses issue 42904.
These problems are present only as errors for the view that implemented the override for onCreateInputConnection () and which returns TYPE_NULL to the calling IME (in the inputType element of the EditorInfo argument passed to this IME method). Only by doing this, the view can reasonably expect that key events (including KEYCODE_DEL) will be returned to it from the soft keyboard. Therefore, the workaround presented here requires a TYPE_NULL InputType.
For applications that do not use TYPE_NULL, there are various overrides in the BaseInputConnection-derived object returned by the view from its override onCreateInputConnection (), which are called by the IME when the user is editing, instead of the IME generating key events. This approach (not TYPE_NULL) is usually better, because the capabilities of the soft keyboard now go far beyond just keystrokes, for things like voice input, termination, etc. Key events are an older method, and those who implement LatinIME on Google have stated that they would like to stop using TYPE_NULL (and key events).
If stopping using TYPE_NULL is an option, then I would strongly recommend that you continue with the recommended approach using InputConnection overriding methods instead of key events (or, more simply, using a class derived from EditText that does this for you).
However, the behavior of TYPE_NULL does not officially end, and thus LatinIME's failure to generate KEYCODE_DEL events is, under certain circumstances, really an error. I suggest the following workaround to solve this problem.
OVERVIEW:
The problems that applications encountered while retrieving KEYCODE_DEL from LatinIME are due to TWO known errors reported here :
https://code.google.com/p/android/issues/detail?id=42904 (indicated as WorkingAsIntended, but the problem, I claim, is an error, because it leads to a failure in the support of generating KEYCODE_DEL events for applications oriented to APIs of level 16 and above that specifically specify InputType of type TYPE_NULL.The problem has been fixed in the latest version of LatinIME, but there are previous releases that still demonstrate this error, and therefore applications that use TYPE_NULL and are designed for API level 16 or higher, you still need a workaround that can be executed from within the application.
and here :
http://code.google.com/p/android/issues/detail?id=62306 (currently listed as fixed but not yet released - FutureRelease - but even after its release we still need a workaround that can run from the app to deal with past releases that will be preserved "in the wild").
In accordance with this thesis (that problems with KEYCODE_DEL events are related to errors in LatinIME), I found that when using an external hardware keyboard, as well as using a third-party SwiftKey soft keyboard, these problems do not occur until they actually occur for certain versions of LatinIME.
One or the other (but not both) of these issues is present in some releases of LatinIME. Therefore, it is difficult for developers to find out during testing whether they worked on all the KEYCODE_DEL problems, and sometimes when updating for Android (or Google keyboards), the problem will no longer be reproduced during testing. However, the LatinIME versions causing the problem will be present on many devices used. This made me delve into the AOSP LatinIME git repository to determine the exact scope of each of the two problems (i.e., the specific LatinIME and Android, versions for which each of the two problems may be present). The crawl code below is limited to these specific versions.
The workaround below includes extensive comments that should help you understand what it is trying to achieve. After the presentation of the code, I will hold an additional discussion that will include specific Android Open Source Project (AOSP) commits, in which each of the two errors was presented and in which it disappeared, as well as Android versions that could include the affected releases of Google Keyboard .
I would warn anyone who is thinking of using this approach to do their own testing to make sure it works for their particular application. I think that it will work in general, and tested it on several devices and versions of LatinIME, but the reasoning is complicated, so proceed with caution. If you find any problems, please leave a comment below.
CODE :
Here is my workaround for both issues, with explanations in the code comments:
First, include the following class (edited to taste) in your application in its own source file InputConnectionAccomodatingLatinIMETypeNullIssues.java:
import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.BaseInputConnection; public class InputConnectionAccomodatingLatinIMETypeNullIssues extends BaseInputConnection {
Then take each View-derived class that should receive key events from the LatinIME soft keyboard and edit it as follows:
First, create an override for onCreateInputConnection () in the view that you want to receive key events as follows:
@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { //Passing FALSE as the SECOND ARGUMENT (fullEditor) to the constructor // will result in the key events continuing to be passed in to this // view. Use our special BaseInputConnection-derived view InputConnectionAccomodatingLatinIMETypeNullIssues baseInputConnection = new InputConnectionAccomodatingLatinIMETypeNullIssues(this, false); //In some cases an IME may be able to display an arbitrary label for a // command the user can perform, which you can specify here. A null value // here asks for the default for this key, which is usually something // like Done. outAttrs.actionLabel = null; //Special content type for when no explicit type has been specified. // This should be interpreted (by the IME that invoked // onCreateInputConnection())to mean that the target InputConnection // 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. This disables the more // sophisticated kinds of editing that use a text buffer. outAttrs.inputType = InputType.TYPE_NULL; //This creates a Done key on the IME keyboard if you need one outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE; return baseInputConnection; }
Second, make the following changes to your onKey () handler to represent:
this.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if(event.getAction() != KeyEvent.ACTION_DOWN) { //We only look at ACTION_DOWN in this code, assuming that ACTION_UP is redundant. // If not, adjust accordingly. return false; } else if(event.getUnicodeChar() == (int)EditableAccomodatingLatinIMETypeNullIssues.ONE_UNPROCESSED_CHARACTER.charAt(0)) { //We are ignoring this character, and we want everyone else to ignore it, too, so // we return true indicating that we have handled it (by ignoring it). return true; } //Now, just do your event handling as usual... if(keyCode == KeyEvent.KEYCODE_ENTER) { //Trap the Done key and close the keyboard if it is pressed (if that what you want to do) InputMethodManager imm = (InputMethodManager) mainActivity.getSystemService(Context.INPUT_METHOD_SERVICE)); imm.hideSoftInputFromWindow(LetterRack.this.getWindowToken(), 0); return true; } else if(keyCode == KeyEvent.KEYCODE_DEL) { //Backspace key processing goes here... return true; } else if((keyCode >= KeyEvent.KEYCODE_A) && (keyCode <= KeyEvent.KEYCODE_Z)) { //(Or, use event.getUnicodeChar() if preferable to key codes). //Letter processing goes here... return true; } //Etc. } };
Finally, we need to define a class for our editable one, which ensures that there is always at least one character in our editable buffer:
import android.text.SpannableStringBuilder; public class EditableAccomodatingLatinIMETypeNullIssues extends SpannableStringBuilder { EditableAccomodatingLatinIMETypeNullIssues(CharSequence source) { super(source); }
This completes the original changes, which, as I discovered, solve both problems.
ADDITIONAL NOTES :
The issue described in release 42904 was introduced in the version of LatinIME that ships with API level 16. Prior to this, KEYCODE_DEL events were generated regardless of whether TYPE_NULL was used. In LatinIME released with Jelly Bean, this generation was discontinued, but no exception was made for TYPE_NULL, and therefore the behavior of TYPE_NULL was effectively disabled for applications targeting API level 16. However, a compatibility code was added that allows applications that have targetSdkVersion & lt ; 16 to continue to receive KEYCODE_DEL events, even without TYPE_NULL. See this AOSP commit on line 1493:
https://android.googlesource.com/platform/packages/inputmethods/LatinIME/+/android-4.1.1_r1/java/src/com/android/inputmethod/latin/LatinIME.java
Therefore, you can work around this problem by setting targetSdkVersion in your application to 15 or lower.
In commit 4.4_r0.9 (just before 4.4), this problem was fixed by adding the test isTypeNull () to the conditions protecting the generation of KEYCODE_DEL. Unfortunately, it was at this moment that a new error was introduced (62306), due to which the whole sentence around the KEYCODE_DEL generation was missed if the user entered the Backspace key as many times as he entered other characters. This led to a KEYCODE_DEL generation error under such circumstances, even with TYPE_NULL and even with targetSdkVersion & lt; = 15. This led to applications that could previously obtain the correct KEYCODE_DEL behavior using the compatibility code (targetSdkVersion & lt; = 15) unexpectedly This problem occurs when users update their copies of the Google keyboard (or run an OTA containing a new Google keyboard version). See this git AOSP file on line 2146 (the item includes "NOT_A_CODE"):
https://android.googlesource.com/platform/packages/inputmethods/LatinIME/+/android-4.4_r0.9/java/src/com/android/inputmethod/latin/LatinIME.java
This problem has persisted in released versions of Google Keyboard to date (01/07/2014). This was fixed in the repo, but at the time of writing, the article was not released.
This unreleased commit can be found here (the git commit containing this commit combines the commit called "Send backspace as an event when TYPE_NULL"), on line 2110 (you can see that the sentence is NOT_A_CODE, which was used to prevent our achievement of the sentence generates KEYCODE_DEL has been deleted):
https://android.googlesource.com/platform/packages/inputmethods/LatinIME/+/b41bea65502ce7339665859d3c2c81b4a29194e4/java/src/com/android/inputmethod/latin/LatinIME.java
When this hotfix is released, this version of the Google keyboard will no longer have either of these two issues affecting TYPE_NULL. However, over time, older versions will be installed on certain devices. Therefore, the problem still needs a workaround. In the end, as more people move to a higher level than the last, not including corrections, this workaround will be required less and less. But it is already intended for a gradual abandonment of yourself (as soon as you make the specified changes to establish the final limit for the area when the final correction will be really released, so that you know what it really is).