diff --git a/java/src/org/futo/inputmethod/latin/RichInputConnection.java b/java/src/org/futo/inputmethod/latin/RichInputConnection.java index ca1e82100..d61b1e25f 100644 --- a/java/src/org/futo/inputmethod/latin/RichInputConnection.java +++ b/java/src/org/futo/inputmethod/latin/RichInputConnection.java @@ -1178,4 +1178,12 @@ public final class RichInputConnection implements PrivateCommandPerformer { } return steps; } + + public StringBuilder getComposingTextForDebug() { + return mComposingText; + } + + public StringBuilder getCommittedTextBeforeComposingTextForDebug() { + return mCommittedTextBeforeComposingText; + } } diff --git a/java/src/org/futo/inputmethod/latin/uix/Action.kt b/java/src/org/futo/inputmethod/latin/uix/Action.kt index e305ce864..e932e4c8f 100644 --- a/java/src/org/futo/inputmethod/latin/uix/Action.kt +++ b/java/src/org/futo/inputmethod/latin/uix/Action.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.LifecycleCoroutineScope +import org.futo.inputmethod.latin.LatinIME import org.futo.inputmethod.latin.uix.theme.ThemeOption import java.util.Locale @@ -64,6 +65,8 @@ interface KeyboardManagerForAction { fun openInputMethodPicker() fun activateAction(action: Action) fun showActionEditor() + + fun getLatinIMEForDebug(): LatinIME } interface ActionWindow { diff --git a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt index d67d837e1..4e2ab2c10 100644 --- a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt +++ b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt @@ -279,6 +279,8 @@ class UixActionKeyboardManager(val uixManager: UixManager, val latinIME: LatinIM override fun showActionEditor() { uixManager.showActionEditor() } + + override fun getLatinIMEForDebug(): LatinIME = latinIME } data class ActiveDialogRequest( diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/MemDebugAction.kt b/java/src/org/futo/inputmethod/latin/uix/actions/MemDebugAction.kt index f69b0bd4a..421f6c570 100644 --- a/java/src/org/futo/inputmethod/latin/uix/actions/MemDebugAction.kt +++ b/java/src/org/futo/inputmethod/latin/uix/actions/MemDebugAction.kt @@ -1,6 +1,11 @@ package org.futo.inputmethod.latin.uix.actions +import android.os.Build import android.os.Debug +import android.text.InputType +import android.view.inputmethod.EditorInfo +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -8,15 +13,156 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay import org.futo.inputmethod.latin.R import org.futo.inputmethod.latin.uix.Action import org.futo.inputmethod.latin.uix.ActionWindow +import org.futo.inputmethod.latin.uix.settings.ScreenTitle import org.futo.inputmethod.latin.uix.settings.ScrollableList import org.futo.inputmethod.latin.uix.theme.ThemeOptions import org.futo.inputmethod.latin.uix.theme.Typography +val DebugLabel = Typography.labelSmall.copy(fontFamily = FontFamily.Monospace) +val DebugTitle = Typography.titleSmall.copy(fontFamily = FontFamily.Monospace, fontWeight = FontWeight.Bold) + +private fun getInputTypeAsString(inputType: Int): String { + val types = mutableListOf() + + // Classify the base type + when (inputType and InputType.TYPE_MASK_CLASS) { + InputType.TYPE_CLASS_TEXT -> { + types.add("TEXT") + + // Add variations + when (inputType and InputType.TYPE_MASK_VARIATION) { + InputType.TYPE_TEXT_VARIATION_NORMAL -> types.add("NORMAL") + InputType.TYPE_TEXT_VARIATION_URI -> types.add("URI") + InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS -> types.add("EMAIL_ADDRESS") + InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT -> types.add("EMAIL_SUBJECT") + InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE -> types.add("SHORT_MESSAGE") + InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE -> types.add("LONG_MESSAGE") + InputType.TYPE_TEXT_VARIATION_PERSON_NAME -> types.add("PERSON_NAME") + InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS -> types.add("POSTAL_ADDRESS") + InputType.TYPE_TEXT_VARIATION_PASSWORD -> types.add("PASSWORD") + InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD -> types.add("VISIBLE_PASSWORD") + InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT -> types.add("WEB_EDIT_TEXT") + InputType.TYPE_TEXT_VARIATION_FILTER -> types.add("FILTER") + InputType.TYPE_TEXT_VARIATION_PHONETIC -> types.add("PHONETIC") + InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS -> types.add("WEB_EMAIL_ADDRESS") + InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD -> types.add("WEB_PASSWORD") + + } + + // Add flags + if (inputType and InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS != 0) { + types.add("FLAG_CAP_CHARACTERS") + } + if (inputType and InputType.TYPE_TEXT_FLAG_CAP_WORDS != 0) { + types.add("FLAG_CAP_WORDS") + } + if (inputType and InputType.TYPE_TEXT_FLAG_CAP_SENTENCES != 0) { + types.add("FLAG_CAP_SENTENCES") + } + if (inputType and InputType.TYPE_TEXT_FLAG_AUTO_CORRECT != 0) { + types.add("FLAG_AUTO_CORRECT") + } + if (inputType and InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE != 0) { + types.add("FLAG_AUTO_COMPLETE") + } + if (inputType and InputType.TYPE_TEXT_FLAG_MULTI_LINE != 0) { + types.add("FLAG_MULTI_LINE") + } + if (inputType and InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE != 0) { + types.add("FLAG_IME_MULTI_LINE") + } + if (inputType and InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS != 0) { + types.add("FLAG_NO_SUGGESTIONS") + } + if (inputType and InputType.TYPE_TEXT_FLAG_ENABLE_TEXT_CONVERSION_SUGGESTIONS != 0) { + types.add("FLAG_ENABLE_TEXT_CONVERSION_SUGGESTIONS") + } + } + InputType.TYPE_CLASS_NUMBER -> { + types.add("NUMBER") + + // Add variations + when (inputType and InputType.TYPE_MASK_VARIATION) { + InputType.TYPE_NUMBER_VARIATION_NORMAL -> types.add("NORMAL") + InputType.TYPE_NUMBER_VARIATION_PASSWORD -> types.add("PASSWORD") + } + + // Add flags + if (inputType and InputType.TYPE_NUMBER_FLAG_SIGNED != 0) { + types.add("FLAG_SIGNED") + } + if (inputType and InputType.TYPE_NUMBER_FLAG_DECIMAL != 0) { + types.add("FLAG_DECIMAL") + } + } + InputType.TYPE_CLASS_PHONE -> { + types.add("PHONE") + } + InputType.TYPE_CLASS_DATETIME -> { + types.add("DATETIME") + + // Add variations + when (inputType and InputType.TYPE_MASK_VARIATION) { + InputType.TYPE_DATETIME_VARIATION_NORMAL -> types.add("NORMAL") + InputType.TYPE_DATETIME_VARIATION_DATE -> types.add("DATE") + InputType.TYPE_DATETIME_VARIATION_TIME -> types.add("TIME") + } + } + } + + return types.joinToString(" | ") +} + + +private fun getImeOptionsString(imeOptions: Int): String { + val options = mutableListOf() + + // Add action + when (imeOptions and EditorInfo.IME_MASK_ACTION) { + EditorInfo.IME_ACTION_NONE -> options.add("IME_ACTION_NONE") + EditorInfo.IME_ACTION_GO -> options.add("IME_ACTION_GO") + EditorInfo.IME_ACTION_SEARCH -> options.add("IME_ACTION_SEARCH") + EditorInfo.IME_ACTION_SEND -> options.add("IME_ACTION_SEND") + EditorInfo.IME_ACTION_NEXT -> options.add("IME_ACTION_NEXT") + EditorInfo.IME_ACTION_DONE -> options.add("IME_ACTION_DONE") + EditorInfo.IME_ACTION_PREVIOUS -> options.add("IME_ACTION_PREVIOUS") + } + + // Add flags + if (imeOptions and EditorInfo.IME_FLAG_NO_FULLSCREEN != 0) { + options.add("IME_FLAG_NO_FULLSCREEN") + } + if (imeOptions and EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS != 0) { + options.add("IME_FLAG_NAVIGATE_PREVIOUS") + } + if (imeOptions and EditorInfo.IME_FLAG_NAVIGATE_NEXT != 0) { + options.add("IME_FLAG_NAVIGATE_NEXT") + } + if (imeOptions and EditorInfo.IME_FLAG_NO_EXTRACT_UI != 0) { + options.add("IME_FLAG_NO_EXTRACT_UI") + } + if (imeOptions and EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION != 0) { + options.add("IME_FLAG_NO_ACCESSORY_ACTION") + } + if (imeOptions and EditorInfo.IME_FLAG_NO_ENTER_ACTION != 0) { + options.add("IME_FLAG_NO_ENTER_ACTION") + } + if (imeOptions and EditorInfo.IME_FLAG_FORCE_ASCII != 0) { + options.add("IME_FLAG_FORCE_ASCII") + } + + return options.joinToString(" | ") +} + val MemoryDebugAction = Action( icon = R.drawable.code, @@ -24,6 +170,7 @@ val MemoryDebugAction = Action( simplePressImpl = null, canShowKeyboard = true, windowImpl = { manager, _ -> + val latinIme = manager.getLatinIMEForDebug() object : ActionWindow { @Composable override fun windowName(): String { @@ -44,9 +191,47 @@ val MemoryDebugAction = Action( } ScrollableList { + Text("Editor Info", style = DebugTitle) + latinIme.currentInputEditorInfo?.let { info -> + Text("packageName = ${info.packageName}", style = DebugLabel) + Text("inputType = ${info.inputType} (${getInputTypeAsString(info.inputType)})", style = DebugLabel) + Text("imeOptions = ${info.imeOptions} (${getImeOptionsString(info.imeOptions)})", style = DebugLabel) + Text("privateImeOptions = ${info.privateImeOptions}", style = DebugLabel) + Text("actionId = ${info.actionId}", style = DebugLabel) + Text("actionLabel = ${info.actionLabel}", style = DebugLabel) + Text("extras = ${info.extras}", style = DebugLabel) + Text("fieldId = ${info.fieldId}", style = DebugLabel) + Text("fieldName = ${info.fieldName}", style = DebugLabel) + Text("hintLocales = ${info.hintLocales}", style = DebugLabel) + Text("hintText = ${info.hintText}", style = DebugLabel) + Text("initialCapsMode = ${info.initialCapsMode}", style = DebugLabel) + Text("initialSelEnd = ${info.initialSelEnd}", style = DebugLabel) + Text("initialSelStart = ${info.initialSelStart}", style = DebugLabel) + Text("label = ${info.label}", style = DebugLabel) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + Text("contentMimeTypes = ${info.contentMimeTypes?.joinToString(",")}", style = DebugLabel) + } + + info + } ?: run { + Text("editor info is null", style = DebugLabel) + } + + Spacer(modifier = Modifier.height(8.dp)) + + Text("Keyboard State", style = DebugTitle) + Text("composingText = ${latinIme.inputLogic.mConnection.composingTextForDebug}", style = DebugLabel) + Text("committedTextBeforeComposingText = ${latinIme.inputLogic.mConnection.committedTextBeforeComposingTextForDebug}", style = DebugLabel) + Text("LM.shouldPassThroughToLegacy = ${latinIme.languageModelFacilitator.shouldPassThroughToLegacy()}", style = DebugLabel) + Text("LM.isTransformerDisabledDueToTimeout = ${latinIme.languageModelFacilitator.isTransformerDisabled()}", style = DebugLabel) + + Spacer(modifier = Modifier.height(8.dp)) + + Text("Memory Use", style = DebugTitle) state.value.forEach { val value = it.value.toInt().toFloat() / 1000.0f - Text("${it.key}: ${String.format("%.2f", value)}MB", style = Typography.labelSmall) + Text("${it.key}: ${String.format("%.2f", value)}MB", style = DebugLabel) } Button(onClick = { diff --git a/java/src/org/futo/inputmethod/latin/xlm/LanguageModelFacilitator.kt b/java/src/org/futo/inputmethod/latin/xlm/LanguageModelFacilitator.kt index d8abd73a6..5c48002d2 100644 --- a/java/src/org/futo/inputmethod/latin/xlm/LanguageModelFacilitator.kt +++ b/java/src/org/futo/inputmethod/latin/xlm/LanguageModelFacilitator.kt @@ -649,6 +649,8 @@ public class LanguageModelFacilitator( ignoringNextUpdate = false } + public fun isTransformerDisabled(): Boolean = transformerDisabled + var ignoringNextUpdate = false fun ignoreNextUpdate() { ignoringNextUpdate = true