diff --git a/app/src/main/java/io/github/sspanak/tt9/hacks/AppHacks.java b/app/src/main/java/io/github/sspanak/tt9/hacks/AppHacks.java index 5a1f78d7..4cb4070c 100644 --- a/app/src/main/java/io/github/sspanak/tt9/hacks/AppHacks.java +++ b/app/src/main/java/io/github/sspanak/tt9/hacks/AppHacks.java @@ -1,7 +1,6 @@ package io.github.sspanak.tt9.hacks; import android.view.KeyEvent; -import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import androidx.annotation.NonNull; @@ -11,30 +10,26 @@ import io.github.sspanak.tt9.ime.modes.InputMode; import io.github.sspanak.tt9.preferences.settings.SettingsStore; public class AppHacks { - private final ConnectedAppInfo appInfo; private final InputConnection inputConnection; + private final InputType inputType; private final SettingsStore settings; private final TextField textField; - public AppHacks(SettingsStore settings, InputConnection inputConnection, EditorInfo inputField, TextField textField) { + public AppHacks(SettingsStore settings, InputConnection inputConnection, InputType inputType, TextField textField) { this.inputConnection = inputConnection; + this.inputType = inputType; this.settings = settings; this.textField = textField; - appInfo = new ConnectedAppInfo(inputConnection, inputField); } - public ConnectedAppInfo getAppInfo() { - return appInfo; - } - /** * setComposingTextWithHighlightedStem * A compatibility function for text fields that do not support SpannableString. Effectively disables highlighting. */ public void setComposingTextWithHighlightedStem(@NonNull String word, InputMode inputMode) { - if (appInfo.isKindleInvertedTextField()) { + if (inputType.isKindleInvertedTextField()) { textField.setComposingText(word); } else { textField.setComposingTextWithHighlightedStem(word, inputMode); @@ -48,9 +43,9 @@ public class AppHacks { * returned, you must not attempt to delete text. This function has already done everything necessary. */ public boolean onBackspace(InputMode inputMode) { - if (appInfo.isKindleInvertedTextField()) { + if (inputType.isKindleInvertedTextField()) { inputMode.clearWordStem(); - } else if (appInfo.isTermux()) { + } else if (inputType.isTermux()) { return false; } @@ -65,7 +60,7 @@ public class AppHacks { * Returns "true" if the action was handled, "false" otherwise. */ public boolean onAction(int action) { - if (appInfo.isSonimSearchField(action)) { + if (inputType.isSonimSearchField(action)) { return sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER); } @@ -80,11 +75,11 @@ public class AppHacks { * it does nothing and return "false", signaling the system we have ignored the key press. */ public boolean onEnter() { - if (settings.getFbMessengerHack() && appInfo.isMessenger()) { + if (settings.getFbMessengerHack() && inputType.isMessenger()) { return onEnterFbMessenger(); - } else if (settings.getGoogleChatHack() && appInfo.isGoogleChat()) { + } else if (settings.getGoogleChatHack() && inputType.isGoogleChat()) { return onEnterGoogleChat(); - } else if (appInfo.isTermux() || appInfo.isMultilineTextInNonSystemApp()) { + } else if (inputType.isTermux() || inputType.isMultilineTextInNonSystemApp()) { // Termux supports only ENTER, so we convert DPAD_CENTER for it. // Any extra installed apps are likely not designed for hardware keypads, so again, // we don't want to send DPAD_CENTER to them. diff --git a/app/src/main/java/io/github/sspanak/tt9/hacks/ConnectedAppInfo.java b/app/src/main/java/io/github/sspanak/tt9/hacks/InputType.java similarity index 52% rename from app/src/main/java/io/github/sspanak/tt9/hacks/ConnectedAppInfo.java rename to app/src/main/java/io/github/sspanak/tt9/hacks/InputType.java index f04382d3..ff05800b 100644 --- a/app/src/main/java/io/github/sspanak/tt9/hacks/ConnectedAppInfo.java +++ b/app/src/main/java/io/github/sspanak/tt9/hacks/InputType.java @@ -3,20 +3,23 @@ package io.github.sspanak.tt9.hacks; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; -import io.github.sspanak.tt9.ime.helpers.InputType; +import io.github.sspanak.tt9.ime.helpers.StandardInputType; -public class ConnectedAppInfo { - final EditorInfo editorInfo; - final InputType inputType; - - - ConnectedAppInfo(InputConnection inputConnection, EditorInfo inputField) { - this.editorInfo = inputField; - this.inputType = new InputType(inputConnection, inputField); +public class InputType extends StandardInputType { + public InputType(InputConnection inputConnection, EditorInfo inputField){ + super(inputConnection, inputField); } - /** + boolean isGoogleChat() { + return isAppField( + "com.google.android.apps.dynamite", + EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT + ); + } + + + /** * isKindleInvertedTextField * When sharing a document to the Amazon Kindle app. It displays a screen where one could edit the title and the author of the * document. These two fields do not support SpannableString, which is used for suggestion highlighting. When they receive one @@ -30,29 +33,22 @@ public class ConnectedAppInfo { return isAppField("com.amazon.kindle", EditorInfo.TYPE_CLASS_TEXT) && ( - editorInfo.imeOptions == titleImeOptions - || editorInfo.imeOptions == titleAlternativeImeOptions - || editorInfo.imeOptions == authorImeOptions + field.imeOptions == titleImeOptions + || field.imeOptions == titleAlternativeImeOptions + || field.imeOptions == authorImeOptions ); } - /** - * isTermux - * Termux is a terminal emulator and it naturally has a text input, but it incorrectly introduces itself as having a NULL input, - * instead of a plain text input. However NULL inputs are usually, buttons and dropdown menus, which indeed can not read text - * and are ignored by TT9 by default. In order not to ignore Termux, we need this. - */ - public boolean isTermux() { - return isAppField("com.termux", EditorInfo.TYPE_NULL) && editorInfo.fieldId > 0; + public boolean isLgX100SDialer() { + int imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_ENTER_ACTION | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS; + return + DeviceInfo.isLgX100S() + && isAppField("com.android.contacts", EditorInfo.TYPE_CLASS_PHONE) + && field.imeOptions == imeOptions; } - /** - * isMessenger - * Facebook Messenger has flaky support for sending messages. To fix that, we detect the chat input field and send the appropriate - * key codes to it. See "onFbMessengerEnter()" for info how the hack works. - */ boolean isMessenger() { return isAppField( "com.facebook.orca", @@ -61,16 +57,12 @@ public class ConnectedAppInfo { } + /** + * Third-party apps are usually designed for a touch screen, so the least we can do is convert + * DPAD_CENTER to ENTER for typing new lines, regardless of the implementation of the OK key. + */ boolean isMultilineTextInNonSystemApp() { - return editorInfo != null && !editorInfo.packageName.contains("android") && inputType.isMultilineText(); - } - - - boolean isGoogleChat() { - return isAppField( - "com.google.android.apps.dynamite", - EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT - ); + return field != null && !field.packageName.contains("android") && isMultilineText(); } @@ -83,24 +75,57 @@ public class ConnectedAppInfo { boolean isSonimSearchField(int action) { return DeviceInfo.isSonim() && - editorInfo != null && (editorInfo.packageName.startsWith("com.android") || editorInfo.packageName.startsWith("com.sonim")) - && (editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION) == action + field != null && (field.packageName.startsWith("com.android") || field.packageName.startsWith("com.sonim")) + && (field.imeOptions & EditorInfo.IME_MASK_ACTION) == action && ( - inputType.isText() + isText() // in some apps, they forgot to set the TEXT type, but fortunately, they did set the NO_SUGGESTIONS flag. - || ((editorInfo.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) == EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) + || ((field.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) == EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) ); } + /** + * isTermux + * Termux is a terminal emulator and it naturally has a text input, but it incorrectly introduces itself as having a NULL input, + * instead of a plain text input. However NULL inputs are usually, buttons and dropdown menus, which indeed can not read text + * and are ignored by TT9 by default. In order not to ignore Termux, we need this. + */ + public boolean isTermux() { + return isAppField("com.termux", EditorInfo.TYPE_NULL) && field.fieldId > 0; + } + + + /** + * isSpecialNumeric + * Calculator and Dialer fields seem to take care of numbers and backspace on their own, + * so we need to be aware of them. + *

+ * NOTE: A Dialer field is not the same as Phone field. Dialer is where you + * actually dial and call a phone number. While the Phone field is a text + * field in any app or a webpage, intended for typing phone numbers. + *

+ * More info (chronological order of bug fixing): + * the initial GitHub issue about Qin F21 Pro+ + * the PR about calculators + * Dialer not detected correctly on LG X100S + */ + protected boolean isSpecialNumeric() { + return + field.packageName.contains("com.android.calculator") // there is "calculator2", hence the contains() + || field.packageName.equals("com.android.dialer") + || isLgX100SDialer(); + } + + /** * isAppField * Detects a particular input field of a particular application. */ boolean isAppField(String appPackageName, int fieldSpec) { return - editorInfo != null - && ((editorInfo.inputType & fieldSpec) == fieldSpec) - && editorInfo.packageName.equals(appPackageName); + field != null + && ((field.inputType & fieldSpec) == fieldSpec) + && field.packageName.equals(appPackageName); } } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java index c40f55e3..76d59f5c 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java @@ -12,8 +12,8 @@ import java.util.ArrayList; import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.db.DictionaryLoader; import io.github.sspanak.tt9.hacks.AppHacks; +import io.github.sspanak.tt9.hacks.InputType; import io.github.sspanak.tt9.ime.helpers.InputModeValidator; -import io.github.sspanak.tt9.ime.helpers.InputType; import io.github.sspanak.tt9.ime.helpers.TextField; import io.github.sspanak.tt9.ime.modes.InputMode; import io.github.sspanak.tt9.ime.modes.ModePredictive; @@ -80,7 +80,7 @@ public abstract class TypingHandler extends KeyPadHandler { textField = new TextField(currentInputConnection, field); // changing the TextField and notifying all interested classes is an atomic operation - appHacks = new AppHacks(settings, connection, field, textField); + appHacks = new AppHacks(settings, connection, inputType, textField); suggestionOps.setTextField(textField); } @@ -229,7 +229,7 @@ public abstract class TypingHandler extends KeyPadHandler { * We do not want to handle any of these, hence we pass through all input to the system. */ protected int getInputModeId() { - if (!inputType.isValid() || (inputType.isLimited() && !appHacks.getAppInfo().isTermux())) { + if (!inputType.isValid() || (inputType.isLimited() && !inputType.isTermux())) { return InputMode.MODE_PASSTHROUGH; } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/InputType.java b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/StandardInputType.java similarity index 83% rename from app/src/main/java/io/github/sspanak/tt9/ime/helpers/InputType.java rename to app/src/main/java/io/github/sspanak/tt9/ime/helpers/StandardInputType.java index a115a2e1..0357c8ba 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/InputType.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/StandardInputType.java @@ -8,14 +8,14 @@ import java.util.ArrayList; import io.github.sspanak.tt9.ime.modes.InputMode; -public class InputType { +abstract public class StandardInputType { private static final int TYPE_MULTILINE_TEXT = EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; - private final InputConnection connection; - private final EditorInfo field; + protected final InputConnection connection; + protected final EditorInfo field; - public InputType(InputConnection inputConnection, EditorInfo inputField) { + protected StandardInputType(InputConnection inputConnection, EditorInfo inputField) { connection = inputConnection; field = inputField; } @@ -38,27 +38,6 @@ public class InputType { } - /** - * isSpecialNumeric - * Calculator and Dialer fields seem to take care of numbers and backspace on their own, - * so we need to be aware of them. - *

- * NOTE: A Dialer field is not the same as Phone field. Dialer is where you - * actually dial and call a phone number. While the Phone field is a text - * field in any app or a webpage, intended for typing phone numbers. - *

- * More info (chronological order of bugfixing): - * in this Github issue - * the PR about calculators - * Dialer not detected correctly on LG X100S - */ - private boolean isSpecialNumeric() { - return - field.packageName.contains("com.android.calculator") // there is "calculator2", hence the contains() - || field.packageName.equals("com.android.dialer"); - } - - public boolean isPhoneNumber() { return field != null @@ -85,6 +64,9 @@ public class InputType { } + abstract protected boolean isSpecialNumeric(); + + public boolean isEmail() { if (field == null) { return false; diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java index 5cbc1049..a64add5e 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java @@ -10,6 +10,7 @@ import android.view.inputmethod.InputConnection; import androidx.annotation.NonNull; +import io.github.sspanak.tt9.hacks.InputType; import io.github.sspanak.tt9.ime.modes.InputMode; import io.github.sspanak.tt9.languages.Language; import io.github.sspanak.tt9.languages.LanguageKind; diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java b/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java index ce1dec16..9f027839 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java @@ -4,7 +4,7 @@ import androidx.annotation.NonNull; import java.util.ArrayList; -import io.github.sspanak.tt9.ime.helpers.InputType; +import io.github.sspanak.tt9.hacks.InputType; import io.github.sspanak.tt9.ime.helpers.TextField; import io.github.sspanak.tt9.languages.Language; import io.github.sspanak.tt9.languages.NaturalLanguage; diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/modes/Mode123.java b/app/src/main/java/io/github/sspanak/tt9/ime/modes/Mode123.java index 3efcc9e7..b99a259b 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/modes/Mode123.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/modes/Mode123.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import io.github.sspanak.tt9.ime.helpers.InputType; +import io.github.sspanak.tt9.hacks.InputType; import io.github.sspanak.tt9.languages.Language; import io.github.sspanak.tt9.languages.NaturalLanguage; import io.github.sspanak.tt9.util.Characters; diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java b/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java index 29a30c7c..91bf6d01 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java @@ -5,7 +5,7 @@ import androidx.annotation.NonNull; import java.util.ArrayList; import io.github.sspanak.tt9.db.WordStoreAsync; -import io.github.sspanak.tt9.ime.helpers.InputType; +import io.github.sspanak.tt9.hacks.InputType; import io.github.sspanak.tt9.ime.helpers.TextField; import io.github.sspanak.tt9.ime.modes.helpers.AutoSpace; import io.github.sspanak.tt9.ime.modes.helpers.AutoTextCase; diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java b/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java index 50258e34..d8bb98fc 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java @@ -1,6 +1,6 @@ package io.github.sspanak.tt9.ime.modes.helpers; -import io.github.sspanak.tt9.ime.helpers.InputType; +import io.github.sspanak.tt9.hacks.InputType; import io.github.sspanak.tt9.ime.helpers.TextField; import io.github.sspanak.tt9.preferences.settings.SettingsStore; import io.github.sspanak.tt9.util.Text;