Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
1da6e4e
add parts of passive gathering and review screen
Helium314 Feb 21, 2026
8493c21
Merge branch 'main' into passive_gathering
Helium314 Feb 23, 2026
fddfad4
add ignore-by-default mode for apps
Helium314 Feb 23, 2026
63a3700
improve showing apps
Helium314 Feb 23, 2026
f559ad6
Merge branch 'main' into passive_gathering
Helium314 Mar 1, 2026
91bbc20
move passive gathering settings
Helium314 Mar 1, 2026
fa94b9f
improve display of app inclusion list
Helium314 Mar 1, 2026
93da8b6
some details
Helium314 Mar 1, 2026
8d831bb
some comments on where to grab the suggestions
Helium314 Mar 1, 2026
f40aa94
more comments and how to use passive gathering
Helium314 Mar 3, 2026
0e28a9d
add passive gathering indicator
Helium314 Mar 3, 2026
e9b75b3
add words to some cache to at least coarsely track later corrections
Helium314 Mar 5, 2026
045f13b
store dict index per suggestion
Helium314 Mar 5, 2026
7dc1f59
add some basic cache functionality, and a lot of todo stuff
Helium314 Mar 6, 2026
b3f8cfe
implement some of the cache functionality
Helium314 Mar 6, 2026
4aa8b30
Merge branch 'main' into passive_gathering
Helium314 Mar 10, 2026
579b107
updates after discussion
Helium314 Mar 10, 2026
4e0e4f0
comments, store passive words using coroutine
Helium314 Mar 10, 2026
99f8e11
clear cache when determining passive gathering is not used
Helium314 Mar 10, 2026
c990c40
fix issues with targetWord / usedWord
Helium314 Mar 10, 2026
5c0b292
reload after deleting / exporting
Helium314 Mar 10, 2026
4d20e1b
move gesture data gathering init
Helium314 Mar 11, 2026
3d758b8
some todos
Helium314 Mar 11, 2026
4eede86
comments
Helium314 Mar 15, 2026
d09e2e1
Merge branch 'main' into passive_gathering
Helium314 Mar 19, 2026
93fc5ed
excluded words string
Helium314 Mar 19, 2026
693d9e7
comments
Helium314 Mar 19, 2026
adf64c8
remove duplicate removal of blocked words
Helium314 Mar 19, 2026
028fc4d
improve review screen
Helium314 Mar 19, 2026
083c67a
comments
Helium314 Mar 19, 2026
4d2d63b
details for gesture data
Helium314 Mar 19, 2026
82f302b
clear cache and update icon on switching incognoto mode
Helium314 Mar 22, 2026
c5707d3
cache excluded apps
Helium314 Mar 22, 2026
8e17b45
toolbar expand key should react to incognito setting, not to toolbar key
Helium314 Mar 22, 2026
54aa947
Merge branch 'main' into passive_gathering
Helium314 Mar 22, 2026
35f36c1
no passive gathering for number fields and stuff
Helium314 Mar 22, 2026
01c85d2
toolbar expand key should react to incognito setting, not to toolbar key
Helium314 Mar 22, 2026
38c2718
Merge branch 'main' into passive_gathering
Helium314 Mar 22, 2026
9f9c6ec
add toolbar key to toggle passive gathering
Helium314 Mar 22, 2026
d55f908
switch recording icon depending on cache state
Helium314 Mar 22, 2026
2524464
fix onEdit not being triggered when it should be
Helium314 Mar 22, 2026
e97c297
Merge branch 'main' into passive_gathering
Helium314 Mar 22, 2026
7b33f15
comments / todos
Helium314 Mar 22, 2026
5151b9a
move stuff around to shrink large file
Helium314 Mar 22, 2026
2ac474e
only store used dictionary infos
Helium314 Mar 22, 2026
0de14ab
allow undefined input type class
Helium314 Mar 22, 2026
56c2903
mostly comments
Helium314 Mar 22, 2026
004fc6a
don't save shortcuts
Helium314 Mar 22, 2026
53a7349
add todo
Helium314 Mar 22, 2026
a9e1862
better don't use passive gathering with undefined input type
Helium314 Mar 23, 2026
4a900a2
review screen: move options to dropdown menu
Helium314 Mar 28, 2026
f069058
show word details in dialog
Helium314 Mar 28, 2026
897b516
add missing string
Helium314 Mar 28, 2026
a913391
better deal with excluded words
Helium314 Mar 28, 2026
302da16
remove new exclusions from displayed list immediately
Helium314 Mar 28, 2026
6ea948d
rename to filterExcludedSuggestions, sanity check when deleting
Helium314 Mar 28, 2026
5f32a36
don't save the word when entering inline emoji search
Helium314 Mar 28, 2026
93bb3ed
update checksums when removing suggestions
Helium314 Mar 29, 2026
604a305
add missing text
Helium314 Mar 29, 2026
c03dc8d
clarify when it's for active gathering only
Helium314 Mar 29, 2026
bb010fa
prepare for user editing / deleting selected text
Helium314 Mar 29, 2026
8aa3b84
improve ExcludedWordsDialog
Helium314 Mar 29, 2026
c975edb
add category titles to GestureDataScreen
Helium314 Mar 29, 2026
73acae2
different text for passive gathering switch
Helium314 Mar 29, 2026
a76b3f5
Merge branch 'main' into passive_gathering
Helium314 Mar 29, 2026
298025b
Merge branch 'main' into passive_gathering
Helium314 Mar 30, 2026
ffbd1b6
tune when gesture data should actually be saved
Helium314 Mar 30, 2026
666b763
add painterResourceCompat do deal with non-vector / bitmap drawables …
Helium314 Apr 6, 2026
3434825
Merge branch 'main' into passive_gathering
Helium314 Apr 6, 2026
7fe0859
initial info texts for passive data gathering, WIP
Helium314 Apr 6, 2026
b75cfb0
improve strings
Helium314 Apr 7, 2026
820c448
add strings
Helium314 Apr 7, 2026
eb0617d
update texts
Helium314 Apr 9, 2026
dab6a93
add text showing in how many apps passive gathering is used
Helium314 Apr 10, 2026
718777b
fix problems showing toolbar keys in settings
Helium314 Apr 10, 2026
87b0559
Merge branch 'main' into passive_gathering
Helium314 Apr 10, 2026
16557e7
better deal with editing selected text
Helium314 Apr 10, 2026
ba9f981
deal with undo after (gesture) typing
Helium314 Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ import helium314.keyboard.latin.common.loopOverCodePointsBackwards
import helium314.keyboard.latin.define.ProductionFlags
import helium314.keyboard.latin.inputlogic.InputLogic
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.GestureDataGatheringSettings
import helium314.keyboard.latin.utils.PassiveGatheringCache
import helium314.keyboard.latin.utils.SubtypeSettings
import helium314.keyboard.latin.utils.prefs
import kotlin.math.abs
import kotlin.math.min

Expand Down Expand Up @@ -102,7 +105,24 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
override fun onCodeInput(primaryCode: Int, x: Int, y: Int, isKeyRepeat: Boolean) {
when (primaryCode) {
KeyCode.TOGGLE_AUTOCORRECT -> return settings.toggleAutoCorrect()
KeyCode.TOGGLE_INCOGNITO_MODE -> return settings.toggleAlwaysIncognitoMode()
KeyCode.TOGGLE_PASSIVE_GATHERING -> {
GestureDataGatheringSettings.togglePassiveGatheringEnabled(latinIME.prefs())
PassiveGatheringCache.clear() // clear data from current text field
latinIME.setGestureDataGatheringMode(latinIME.currentInputEditorInfo)
return
}
KeyCode.PASSIVE_GATHERING_TEMP_OFF -> {
GestureDataGatheringSettings.tempDisablePassiveGathering(latinIME.prefs())
PassiveGatheringCache.clear() // clear data from current text field
latinIME.setGestureDataGatheringMode(latinIME.currentInputEditorInfo)
return
}
KeyCode.TOGGLE_INCOGNITO_MODE -> {
settings.toggleAlwaysIncognitoMode()
PassiveGatheringCache.clear() // clear data from current text field
latinIME.setGestureDataGatheringMode(latinIME.currentInputEditorInfo)
return
}
}
val mkv = keyboardSwitcher.mainKeyboardView

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.view.inputmethod.InputMethodSubtype;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
Expand Down Expand Up @@ -595,6 +596,12 @@ private void showFakeToast(final String text, final int timeMillis) {
}, timeMillis);
}

public void setPassiveGatheringIndicator(boolean enabled, boolean hasData) {
ImageView view = mCurrentInputView.findViewById(R.id.passiveGatheringIndicator);
view.setVisibility(enabled ? View.VISIBLE: View.GONE);
view.setImageResource(hasData ? R.drawable.btn_keyboard_key_action_normal_lxx_base : R.drawable.ring);
}

// Implements {@link KeyboardState.SwitchActions}.
@Override
public boolean isInDoubleTapShiftKeyTimeout() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class KeyboardIconsSet private constructor() {
ToolbarKey.PAGE_START -> R.drawable.ic_page_start
ToolbarKey.PAGE_END -> R.drawable.ic_page_end
ToolbarKey.SPLIT -> R.drawable.ic_ime_switcher
ToolbarKey.PASSIVE_GATHERING -> R.drawable.ic_settings_gesture
})
}
} }
Expand Down Expand Up @@ -215,6 +216,7 @@ class KeyboardIconsSet private constructor() {
ToolbarKey.PAGE_START -> R.drawable.ic_page_start
ToolbarKey.PAGE_END -> R.drawable.ic_page_end
ToolbarKey.SPLIT -> R.drawable.ic_ime_switcher
ToolbarKey.PASSIVE_GATHERING -> R.drawable.ic_settings_gesture
})
}
} }
Expand Down Expand Up @@ -276,6 +278,7 @@ class KeyboardIconsSet private constructor() {
ToolbarKey.PAGE_START -> R.drawable.ic_page_start_rounded
ToolbarKey.PAGE_END -> R.drawable.ic_page_end_rounded
ToolbarKey.SPLIT -> R.drawable.ic_ime_switcher
ToolbarKey.PASSIVE_GATHERING -> R.drawable.ic_settings_gesture
})
}
} }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ object KeyCode {
const val META_RIGHT = -10049
const val EMOJI_SEARCH = -10050
const val INLINE_EMOJI_SEARCH_DONE = -10051
const val TOGGLE_PASSIVE_GATHERING = -10052 // will be useless after removal of gesture data gathering, but don't remove for compatibility
const val PASSIVE_GATHERING_TEMP_OFF =-10053 // will be useless after removal of gesture data gathering, but don't remove for compatibility


// Intents
Expand All @@ -201,7 +203,7 @@ object KeyCode {
PAGE_DOWN, META, TAB, ESCAPE, INSERT, SLEEP, MEDIA_PLAY, MEDIA_PAUSE, MEDIA_PLAY_PAUSE, MEDIA_NEXT,
MEDIA_PREVIOUS, VOL_UP, VOL_DOWN, MUTE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, BACK,
TIMESTAMP, CTRL_LEFT, CTRL_RIGHT, ALT_LEFT, ALT_RIGHT, META_LEFT, META_RIGHT, SEND_INTENT_ONE, SEND_INTENT_TWO,
SEND_INTENT_THREE, EMOJI_SEARCH, INLINE_EMOJI_SEARCH_DONE, META_LOCK
SEND_INTENT_THREE, EMOJI_SEARCH, INLINE_EMOJI_SEARCH_DONE, META_LOCK, TOGGLE_PASSIVE_GATHERING, PASSIVE_GATHERING_TEMP_OFF
-> this

// conversion
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/helium314/keyboard/latin/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.LayoutUtilsCustom
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.SubtypeSettings
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.latin.utils.upgradeToolbarPrefs
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand All @@ -36,6 +38,8 @@ class App : Application() {

RichInputMethodManager.init(this)
checkVersionUpgrade(this)
if (BuildConfig.DEBUG) // do this on every debug apk start because we may work on adding a new toolbar key
upgradeToolbarPrefs(prefs())
transferOldPinnedClips(this) // todo: remove in a few months, maybe end 2026
app = this
Defaults.initDynamicDefaults(this)
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/java/helium314/keyboard/latin/AppsManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.graphics.drawable.Drawable

class AppsManager(val context: Context) : BroadcastReceiver() {
private val mPackageManager: PackageManager = context.packageManager
Expand Down Expand Up @@ -49,10 +50,10 @@ class AppsManager(val context: Context) : BroadcastReceiver() {
fun onAppsChanged()
}

fun getPackagesAndNames(): Collection<Pair<String, String>> {
fun getPackagesWithNameAndIcon(): List<Triple<String, String, Drawable?>> {
val filter = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
return mPackageManager.queryIntentActivities(filter, 0).distinctBy { it.activityInfo.packageName }.map {
it.activityInfo.packageName to it.activityInfo.loadLabel(mPackageManager).toString()
Triple(it.activityInfo.packageName, it.activityInfo.loadLabel(mPackageManager).toString(), it.activityInfo.loadIcon(mPackageManager))
}
}
}
27 changes: 19 additions & 8 deletions app/src/main/java/helium314/keyboard/latin/LatinIME.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
import helium314.keyboard.latin.touchinputconsumer.GestureConsumer;
import helium314.keyboard.latin.utils.ColorUtilKt;
import helium314.keyboard.latin.utils.GestureDataGatheringKt;
import helium314.keyboard.latin.utils.GestureDataGatheringSettings;
import helium314.keyboard.latin.utils.InlineAutofillUtils;
import helium314.keyboard.latin.utils.InputMethodPickerKt;
import helium314.keyboard.latin.utils.JniUtils;
Expand Down Expand Up @@ -840,14 +841,7 @@ private void onStartInputInternal(final EditorInfo editorInfo, final boolean res
void onStartInputViewInternal(final EditorInfo editorInfo, final boolean restarting) {
super.onStartInputView(editorInfo, restarting);

// only for active gesture data gathering, remove when data gathering phase is done (end of 2026 latest)
if (GestureDataGatheringKt.isInActiveGatheringMode(editorInfo)) {
mDictionaryFacilitator = GestureDataGatheringKt.getGestureDataActiveFacilitator();
} else {
mDictionaryFacilitator = mOriginalDictionaryFacilitator;
}
GestureDataGatheringKt.showEndNotificationIfNecessary(this); // will do nothing for a long time
mInputLogic.setFacilitator(mDictionaryFacilitator);
setGestureDataGatheringMode(editorInfo);

mDictionaryFacilitator.onStartInput();
// Switch to the null consumer to handle cases leading to early exit below, for which we
Expand Down Expand Up @@ -1842,4 +1836,21 @@ public void onTrimMemory(int level) {
// deallocateMemory always called on hiding, and should not be called when showing
}
}

// remove when data gathering phase is done (end of 2026 latest)
public void setGestureDataGatheringMode(final EditorInfo editorInfo) {
if (GestureDataGatheringKt.isInActiveGatheringMode(editorInfo)) {
mDictionaryFacilitator = GestureDataGatheringKt.getGestureDataActiveFacilitator();
GestureDataGatheringKt.usePassiveGathering = false;
mKeyboardSwitcher.setPassiveGatheringIndicator(false, false);
} else {
mDictionaryFacilitator = mOriginalDictionaryFacilitator;

// no active mode, check for passive mode
boolean usePassive = GestureDataGatheringKt.setUsePassiveGathering(this, editorInfo);
mKeyboardSwitcher.setPassiveGatheringIndicator(usePassive, false);
}
GestureDataGatheringSettings.INSTANCE.showEndNotificationIfNecessary(this); // will do nothing for a long time
mInputLogic.setFacilitator(mDictionaryFacilitator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ public NgramContext getNgramContextFromNthPreviousWord(
*
* @param spacingAndPunctuations the rules for spacing and punctuation
* @param script the script we consider to be writing words, as one of ScriptUtils.SCRIPT_*
* @return a range containing the text surrounding the cursor
* @return a range containing the text surrounding the cursor (does NOT include the current selection)
*/
@Nullable public TextRange getWordRangeAtCursor(final SpacingAndPunctuations spacingAndPunctuations,
final String script) {
Expand Down
31 changes: 21 additions & 10 deletions app/src/main/java/helium314/keyboard/latin/Suggest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import helium314.keyboard.latin.settings.SettingsValuesForSuggestion
import helium314.keyboard.latin.suggestions.SuggestionStripView
import helium314.keyboard.latin.utils.AutoCorrectionUtils
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.PassiveGatheringCache
import helium314.keyboard.latin.utils.SuggestionResults
import helium314.keyboard.latin.utils.WordData
import helium314.keyboard.latin.utils.usePassiveGathering
import java.util.Locale
import kotlin.math.min

Expand Down Expand Up @@ -272,11 +275,11 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) {
wordComposer.composedDataSnapshot, ngramContext, keyboard,
settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle
)
replaceSingleLetterFirstSuggestion(suggestionResults)

// For transforming words that don't come from a dictionary, because it's our best bet
val locale = mDictionaryFacilitator.mainLocale
val suggestionsContainer = ArrayList(suggestionResults)
replaceSingleLetterFirstSuggestion(suggestionsContainer)
val suggestionsCount = suggestionsContainer.size
val keyboardShiftMode = keyboard.mId.keyboardCapsMode
val shouldMakeSuggestionsOnlyFirstCharCapitalized = wordComposer.wasShiftedNoLock()
Expand Down Expand Up @@ -340,6 +343,13 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) {
} else {
suggestionsContainer
}

if (usePassiveGathering && inputStyle == SuggestedWords.INPUT_STYLE_TAIL_BATCH) {
val wordData = WordData(null, suggestionResults, wordComposer.composedDataSnapshot,
ngramContext, keyboard, inputStyle, false, pseudoTypedWordInfo?.mWord)
PassiveGatheringCache.addWord(wordData)
}

return SuggestedWords(suggestionsList, suggestionResults.mRawSuggestions, pseudoTypedWordInfo, true,
false, false, inputStyle, sequenceNumber)
}
Expand Down Expand Up @@ -513,20 +523,21 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) {
}

/** reduces score of the first suggestion if next one is close and has more than a single letter */
private fun replaceSingleLetterFirstSuggestion(suggestionResults: SuggestionResults) {
private fun replaceSingleLetterFirstSuggestion(suggestionResults: MutableList<SuggestedWordInfo>) {
if (suggestionResults.size < 2 || suggestionResults.first().mWord.length != 1) return
// suppress single letter suggestions if next suggestion is close and has more than one letter
val iterator: Iterator<SuggestedWordInfo> = suggestionResults.iterator()
val first = iterator.next()
val second = iterator.next()
val first = suggestionResults[0]
val second = suggestionResults[1]
if (second.mWord.length > 1 && second.mScore > 0.94 * first.mScore) {
suggestionResults.remove(first) // remove and re-add with lower score
suggestionResults.add(
SuggestedWordInfo(
first.mWord, first.mPrevWordsContext, (first.mScore * 0.93).toInt(),
first.mKindAndFlags, first.mSourceDict, first.mIndexOfTouchPointOfSecondWord, first.mAutoCommitFirstWordConfidence
)
val modifiedFirst = SuggestedWordInfo(
first.mWord, first.mPrevWordsContext, (first.mScore * 0.93).toInt(),
first.mKindAndFlags, first.mSourceDict, first.mIndexOfTouchPointOfSecondWord, first.mAutoCommitFirstWordConfidence
)
val insertIndex = suggestionResults.indexOfFirst { it.mScore < modifiedFirst.mScore }
if (insertIndex == -1) suggestionResults.add(modifiedFirst)
else suggestionResults.add(insertIndex, modifiedFirst)

if (DebugFlags.DEBUG_ENABLED)
Log.d(TAG, "reduced score of ${first.mWord} from ${first.mScore}, new first: ${suggestionResults.first().mWord} (${suggestionResults.first().mScore})")
}
Expand Down
Loading