Repository navigation
Add the per-keyboard volume E2E run - #140
Open
Slacker-LLC wants to merge 103 commits into
Open
Slacker-LLC wants to merge 103 commits into
Slacker-LLC wants to merge 103 commits into
Conversation
The corner marks were an older scheme of our own (a=~, s=!, d=@ …). They now follow the reference product's map (ficon_text in input_kbd_pinyin26.xml and input_kbd_english26.xml): the same key carries the full-width mark in Chinese and the ASCII mark in English, the top row keeps 1–0, and a, s, z, c, m are the same in both languages. A long press now opens only the letter in both cases, upper first, as the reference does (long_press_bubble_text); the mark stays on the swipe-up gesture (fusiyin_keycode). The comma/period key also commits the mark above it on a swipe up. Co-Authored-By: Claude Code <noreply@anthropic.com>
… reference skin - The 26-key draws A and L half a letter wider (skin weight 15 against 10) and the last row's 分词 / 退格 with the same ratio, instead of nine equal letters. - The nine-key and stroke side column is 删除 / 重输 / 发送 with send twice as tall; the separate zero key goes away and the space bar carries the corner 0 (an up swipe types it, behind the 上滑数字 setting). - Candidate items pad 8dp per side, so more candidates fit on the strip. Co-Authored-By: Claude Code <noreply@anthropic.com>
The rail during composition is now the same flat list the symbols use: one reading per row at one text size, a hairline between rows, and no state drawn on any item — the pre-edit says which reading is current. The list keeps the user's scroll position until the open digits change, instead of re-centring on every keystroke. The reference ships one FilterListLayout for both jobs and gives the reading the symbol item's own style (cls_pinyin9_filter_button inherits cls_vertical_symbol_list_button, style.xml:1023-1032), with syllables one weight heavier at the same size (style.xml:112,121-122). The native-side evidence is recorded in docs/DECISIONS.md. Co-Authored-By: Claude Code <noreply@anthropic.com>
The separate zero key went away with the reference-aligned side column, so the rail case swipes up on the space bar, the way the key works. Co-Authored-By: Claude Code <noreply@anthropic.com>
When this app is the user's input method its service is bound in the test process and its clipboard listener captures every copy — including the fixture these two tests copy — by design, so the queued panel load they check is indistinguishable from the listener. They now hold the precondition they need instead of failing; a system IME active (CI) runs them as before. Co-Authored-By: Claude Code <noreply@anthropic.com>
-PopenimeAppIdSuffix=.dev installs beside the release build (the owner's phone runs the .dev variant); release builds never pass it. Co-Authored-By: Claude Code <noreply@anthropic.com>
Typing "dang" also produced the split da + "ng", and no syllable starts with "ng", so that path can never complete a reading of the input; the words for the settled "da" prefix (打, score 7798) nonetheless entered the candidate set and outranked the complete reading 当 (6899), so the space bar committed 打 and 当地 fell to rank 6 of "dangdi". Candidates now carry a coverage rank: a word whose reading covers the whole input sorts above one that only matches a prefix of it, and frequency decides inside each rank. "dang" -> 当 党 档, "dangdi" -> 当地 荡涤. Co-Authored-By: Claude Code <noreply@anthropic.com>
An address or e-mail field now gets `. / www. .com .cn http wap. ftp:` on the nine-key rail instead of the punctuation marks, and no + cell, because that list belongs to the field. The values are the reference nine-key layout's own `uri_filter_list` attribute; only that layout declares one. Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference's first-item class takes the candidate font one weight heavier and the accent as its text colour, with no background (cls_option_first_canditem, style.xml:551-554; first_cand_font weight 500 against 400; first_cand_text_color rgba(79,132,255,1)). openIME drew it bold on a key-coloured tile. Co-Authored-By: Claude Code <noreply@anthropic.com>
The expanded candidates used to be the key grid itself: one bordered tile per candidate with the first one filled in the accent. The reference's 更多候选 page is a different surface, and its skin file says how it is built. The page now opens with 全部 / 单字 as one option group over the list (input_more_cand.xml:9-13), the list sits in one rounded card (radius 11, 2 edge, cls_morecand_bk), and the backspace floats in that card's bottom-right corner at 25.2% by 20.2% of the list, rounding only that corner with the card's own radius (bkround="0,0,11,0"). Every cell is the same flat label with a hairline edge (cls_morecands_button): the skin gives the expanded list no first-item class, so no cell carries the accent tile. 单字 keeps single characters and 全部 is the page's default, as the options declare. The corner key deletes one letter of the open composition, so the page stays open on the shorter list. The reference's left syllable list (FilterListLayout, 音节过滤) is not in this change: the 26-key path has no syllable-fixing state yet. Co-Authored-By: Claude Code <noreply@anthropic.com>
The URL rail, the first-candidate accent, the candidate ranking fix and the expanded page were user-visible changes without an entry. Co-Authored-By: Claude Code <noreply@anthropic.com>
The 26-key bottom row gains the reference's two symbol keys beside the space bar, in Chinese and English, with the address-field marks in a URL or e-mail field, and each key takes the reference's own weight. The English merged key now leads with the period and carries the comma in its corner, as the skin draws it, instead of the other way round. The nine-key 1 cell becomes the reference's @# key: the label names the symbols it offers, a tap and an up swipe still type the digit, and a long press opens the reference's own seven-symbol bubble. The board has no 分词 key because the reference's has none, and the 26-key 分词 key drops the invented corner mark and popup its class never declares. Co-Authored-By: Claude Code <noreply@anthropic.com>
The open Pinyin string now paints the syllables the user has fixed in the accent and the unconverted tail in the key text colour, as the reference's cls_comp_half / cls_comp_right pair does, and it takes comp_font's own size. A decoder-inserted divider stays in the plain colour: only a syllable the user chose is fixed. Co-Authored-By: Claude Code <noreply@anthropic.com>
The strip now insets the candidate list at both ends, draws the reference's hairline split between the list and the expand key, keeps a 3-unit gap before it, and gives the expand key the reference's pill press shape. Its 48dp touch target stays: that is our own rule. Co-Authored-By: Claude Code <noreply@anthropic.com>
Each idle-toolbar key is now the reference's own 40-unit pill with a press tint, instead of a bare icon stretched by weight across the row, and the slack of the strip sits in a spacer ahead of the hide key. The 48dp touch target stays our own rule. Co-Authored-By: Claude Code <noreply@anthropic.com>
The digits page was a 3x3 grid over a 返回 / 空格 / 0 row with 退格 / . / @ / 发送 down the right. The reference's 26-key 123 key opens input_kbd_number_from26.xml instead: a symbol rail over the return key in the left column, three digit columns closed by 符号 / 0 / . , and a delete / space / send column, at the skin's own weights 66 / 75 / 75 / 75 / 66 and with send twice as tall as the keys above it. The @ key is gone with no number page declaring one; in a phone field the symbol cell carries the dialer's # and the period cell its +, so * / + / # stay reachable. Co-Authored-By: Claude Code <noreply@anthropic.com>
input_kbd_stroke.xml draws three columns of three cells: 一 丨 丿 / 丶 折 通配 / @# :;, each with the skin's own corner digit and an up swipe that types it. The last row was missing from our board, so 通配's digit 6 and the two punctuation marks had no key; the @# cell now opens the reference's own / - _ @ # . 7 list on a long press. The bottom rows of the stroke and nine-key boards take the reference's 45.5 / 134 / 45.5, which fills the 225-unit centre column exactly. Co-Authored-By: Claude Code <noreply@anthropic.com>
…trip The reference's idle row runs clipboard, emoji, board selector, where ours led with the board selector, and its icons sit in a strip that scrolls when they do not fit, with the slack in a spacer at the strip's own end (sliderenable, input_toolbar_idle.xml:14,34). Ours stretched the icons by weight instead, so a narrow screen shrank them, and the spacer sat outside the strip. 收起 stays outside it. Co-Authored-By: Claude Code <noreply@anthropic.com>
input_kbd_symbol.xml ends the page with a row of the return key and the category container, weighted 85 against 13.1, and scrolling. Ours put the categories down a 74dp column at the left edge, which cost the grid a fifth of the page's width. The strip is the chip row the emoji page and the expanded candidate page already use, so the symbol surfaces agree now. Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference's symbol row closes with its 123 key and its backspace at the two ends (input_kbd_symbol.xml:31-41, weight 15 against the cells' 70), so the page reaches the digits and deletes without being left first. Our cells are five to a row, so both keys take the ends of the tab strip's row, the row the reference gives to the page's own return key. Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference fills its symbol board's toolbar with the history of what the user has typed (input_toolbar_quickinput.xml:4-18): a 4-unit lead inset, the scrolling list, the candidate strip's own hairline split, a 3-unit gap, a 40-unit close key and a 4-unit tail. Each cell is 36 units wide with a radius-6 press face over candidate-sized text in the candidate text colour (style.xml:1061-1070), and a tap commits through the same path the board's own cells use, so the list re-reads itself after every symbol. Co-Authored-By: Claude Code <noreply@anthropic.com>
The tools page and the keyboard switcher are one surface in the reference: a container 88.9% of the page wide with its own paddings, tiles filling their cells in a 4-by-2 grid capped at 192 units (style.xml:616-619), each tile a radius-14 card filled with setting_button_bk, its pressed colour, or the theme colour when it is the chosen one, and its name dimmed to keybutton_text_3 (style.xml:626-647, values/colors.xml:15,87-93). Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference fills the toolbar row with a tip while the floating keyboard is up (`input_toolbar_tip.xml:43-50`): one pill across the row, a 3.571% lead space, a left-aligned ellipsized label and a round close key whose width is its own height. Each of those numbers is now a constant with the line it came from, and the close key keeps our 48dp touch target. Ours names our own way back — a tap on the handle — where the reference asks for a drag to the bottom edge, because the docked keyboard is what our handle restores. The tip settles for the stay afloat once its close key is tapped, and the next stay shows it again. Co-Authored-By: Claude Code <noreply@anthropic.com>
The typing toolbar holds the pinyin block in a wrapper of at most half the page (`maxwidth="halfMaxWidth"`, `input_toolbar_typing.xml:7`), with a 5-unit lead of its own and the row's 3-unit top inset; the other half goes to an empty control, the room the reference keeps beside it (line 18). The string scrolls inside that cap, as the reference's own composition container does, and the block carries the container's own press tint (`comp_pushedbk`, black 8% light and white 12% dark). Our pre-edit ran the full width of the row in portrait and stopped at a 160dp cap of our own making in landscape, and it gave no press feedback while it was edited. Co-Authored-By: Claude Code <noreply@anthropic.com>
A fresh copy or a text message is answered by the reference's own quick-input toolbar (`input_toolbar_quickinput.xml`): the text at the candidate font in `canditem_text` with the glyph that names where it came from (lines 39-45), and the row's own close key borrowed from `cls_history_close_button` (line 46) instead of a back control. Our chips were filled pills at the body size behind a back chevron, a shape no reference toolbar draws. The system's autofill chips keep that back control, because they are the platform's own views in the same strip; every row keeps our 48dp touch target. Co-Authored-By: Claude Code <noreply@anthropic.com>
The tip, pre-edit and quick-input comments quoted nearby lines for the container, the lead space, the close key and the composition wrapper. Each now names the line the attribute is actually on. Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference's quick-input row measures both parts against the row (`input_toolbar_quickinput.xml:42,44-45`): the text box is inset 0.055/0.111 of it, and the glyph that names where the text came from is a superscript at the row's top edge, `fi_toolbar_tip_superscript`'s 30 units against `cand_font`'s 56 (`style.xml:138,83`). Our first pass drew the glyph as a fixed 18dp icon centred on the row, which reads as a second key beside the text rather than as the mark of its origin. Co-Authored-By: Claude Code <noreply@anthropic.com>
The strip's container is `input_toolbar_typing.xml:23-32`, not 16-30, in the keyboard's own comment and in DECISIONS.md. Co-Authored-By: Claude Code <noreply@anthropic.com>
The theme pass rescales every text view it meets by the reference scale, so a badge sized from the design token alone drifted from its own label on a device whose scale is not 1. The badge now takes the label's measured size at layout, which also drops the policy helper the view no longer needs. Co-Authored-By: Claude Code <noreply@anthropic.com>
CI failed the same sixteen tests on every API level, in four groups. The tip banner (6b6a199) took the floating toolbar row: the quick-phrase and long-press-drag tests read a row that no longer carries icons, and the banner's own width tests measured before the first layout pass. They now settle the banner as the user does and wait for the row to place itself. The quick-input rows belong to a real editor session, which a keyboard view built by hand has none of, so they now declare the editor options they are drawn for through the new `editorOptionsOverride` seam. The symbol history tests cleared the store inside their own harness, wiping the history they had just arranged; the `@After` cleanup already empties it between tests, so the record stands. The rest follow the reference rather than our earlier guess: - English's merged key commits "." and corners "," , as its layout draws it (`input_kbd_english26.xml:154-161`), and its up swipe types the comma. - The launcher grid packs four tiles per row and leaves the last row short (`input_settings.xml:13-45`); the cells keep the page's one column width. - The tile radius goes through the page's own reference scale, as every other reference unit does. - The handwriting tile follows the strokes table only local builds ship. - The bottom row is measured with the reference's own key widths (123 70.6, merged 37.6, both symbol keys 35.5, space 133.6, 中/英 38.6, 确定 74.6, `style.xml:960-978`), which put a hair more weight on the left than the right, so the space bar sits just left of the centre line. - The font test counts only keys the user can see, and names the key it reports. The merged and symbol keys of the 26-key bottom row now shrink their mark rather than ellipsizing it, as the reference gives them their own fonts for (`text_comma_cn` 72 units against `key_letter` 57, `style.xml:127`, `:4`). Co-Authored-By: Claude Code <noreply@anthropic.com>
updateResponsiveGeometry runs from onMeasure and wrote mainDock's and the
second key row's layout parameters back unconditionally. Assigning
layoutParams always calls requestLayout(), and a request made after
performTraversals has cleared mLayoutRequested schedules another full
layout pass ("Clear this now, so that if anything requests a layout in
the rest of this function we will catch it and re-run a full layout
pass", ViewRootImpl.performTraversals) — while nothing in the chain was
conditional. The keyboard therefore re-measured, re-laid out and redrew
every frame for as long as it was shown, docked or floating.
The three writes now happen only when the value they carry differs.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The floating keyboard's long-press drag only started when the press landed
on a toolbar icon. With no child under the finger, the framework dispatches
the rest of the gesture straight to the zone's own onTouchEvent and never
asks the interceptor again ("intercepted = true" in the else branch,
ViewGroup.dispatchTouchEvent, actionMasked != ACTION_DOWN with no touch
target), and the zone's onTouchEvent returned super's false — so the
long press armed and nothing ever came of it. The zone now claims the
gesture itself once it was going to intercept the press, swallows the
DOWN, and starts the drag on the first move after the long press.
The docked height drag never armed at all. It gates on the press being
inside the toolbar row (ImeTopZone.isInsideToolbar) and compared the row
taken with getLocationInWindow — window-local — against MotionEvent.rawY,
which is "the original location of the event on the screen, before it had
been adjusted for the containing window and views". This keyboard's window
is not the screen (dumpsys window: frame=[0,1731][1080,2400], gravity
BOTTOM), so its toolbar row sits at window y 0 while a finger on the row
reports a raw y of about 1731: the check could not be true on a device.
It now measures the row on screen, the same way the candidate choice strip
tests raw touches (KeyPopupController.trackChoiceTouch).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Dragging the card wrote the window's attributes on every touch sample, including the samples whose rounded delta is zero: at 60Hz that is a relayout of the IME window per frame while a finger jitters on the toolbar, and the drag path also re-read the opacity preference each time. applyLayout now returns early when position, size and alpha all match what the window already carries, and the opacity comes from the value scheduleLayout last applied. A drag that does move the card still writes, so the bounds still clamp and the position is still remembered. Co-Authored-By: Claude Code <noreply@anthropic.com>
hasPressedKey() answers "a key still owns this gesture" by walking the rows for isPressed, and renderModeBody defers to a 40ms poll while it is true. isPressed is not cleared when a view is taken out of the hierarchy, so a gesture whose key was rebuilt away under it — or one a rebuild swallowed — left a key that looked pressed forever: every later rebuild (a keyboard switch, a rotation, closing a panel) silently did nothing and the poll re-posted itself for as long as the keyboard was attached. A touch stream is only live between a DOWN and its UP, and this view already sees every event that reaches the keyboard, so dispatchTouchEvent now tracks whether one is open and hasPressedKey() answers false when none is. The deferral still protects a real gesture, and the rebuild it deferred lands as soon as the finger lifts. Co-Authored-By: Claude Code <noreply@anthropic.com>
The docked height drag went through setKeyboardHeightPercent on every touch sample: each one wrote the preference and rebuilt the whole key surface, so a single drag persisted the height a hundred times and rebuilt the keyboard a hundred times. The drag now previews — the row heights and the wanted window height follow the finger, and the rebuild is posted to the next frame so a frame with several samples rebuilds once — while the commit happens on release, from either the UP or a CANCEL that takes the gesture away (KeyboardHeightDragController.onDragEnd). The keyboard reports and persists the height exactly once, when the user lets go. Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
The zone gives toolbarRow its own full height, so the row reaches the zone's bottom: measuring the band below the row found 0px and the test polled until its 30s timeout. The band is the slack around the 48dp icon strip inside the row, which is where the gesture lands on no child. Co-Authored-By: Claude Code <noreply@anthropic.com>
The stress script covers taps and modes; this one types real text: two thousand random keys, a thousand words, five hundred four-character words and a hundred sentences of fifteen characters or more per Chinese keyboard, on every keyboard the app offers. Words come from the bundled dictionaries, sentences from this repository's own Chinese prose, so the run needs no network and writes nothing into the repository. A word counts as a hit only when the committed text is the expected text; on a miss the harness re-types the word alone and keeps the expected text, the committed text and the candidate list, which is how the ranking defect behind "dang -> 打" was found. The two debug-only read commands (editor-tail64, candidates64) give the harness one round trip per check and stay unreachable in a release build. Co-Authored-By: Claude Code <noreply@anthropic.com>
The word and four-character lists leave 452 of the thousand most common characters untouched, so the run gained a character phase: each character by its own reading (wubi and stroke by their own code), checked the same way, and a --phases filter to run one phase alone. Co-Authored-By: Claude Code <noreply@anthropic.com>
A long per-keyboard run can outlive a foreground change: another app comes to the front, the input view goes away, and the next bounds read raises. The run then dies hours in and loses the whole keyboard. Keys now takes an on_lost callback. When refresh_bounds fails, it calls back once, re-shows the keyboard and re-applies the mode, then reads the bounds again, so the run continues from where it stopped. Co-Authored-By: Claude Code <noreply@anthropic.com>
The run lasts hours. Its recovery already brings the keyboard back when another app takes the foreground (which is what stopped the first full run); on top of that the device now stays awake and lit for the whole run, so a screen timeout can never take the input method away either. Co-Authored-By: Claude Code <noreply@anthropic.com>
phase_rows only kept the wrong rows, so a report could not split a phase by input shape - the word list is two blocks (two-character words first, three-character after) and one rate over both hides the step at word 700. Each row now lands in the phase's results with the text that came out and the rank the expected word got. ensure() also replaces the two inline refresh-and-retry blocks: a lost keyboard is recovered through the same path, and the recovery stops the apps known to take the front of the shared emulator first. Co-Authored-By: Claude Code <noreply@anthropic.com>
The 2026-10-15 run started on a tree 29-43 commits behind HEAD and had its APK swapped 22 minutes in, so the report described an engine nobody would ship. Compare the installed package's lastUpdateTime with the built APK's mtime before the first tap and again at every keyboard switch, and stop with the install command instead of measuring the wrong build. Co-Authored-By: Claude Code <noreply@anthropic.com>
Slacker-LLC
force-pushed
the
test/volume-e2e
branch
from
October 15, 2026 14:42
90e6b80 to
c05f11f
Compare
The reference documents the gesture itself: the subtitle of its own switch (`res/cU.xml`, key `enable_key_enter_send_msg`, default false) reads 「长按「发送」可换行。开关支持App范围」, and its confirm dialog repeats the line. Only the send face is documented, so only that face takes a long press here; a composition reads 确定 on the key and keeps its press-only behaviour, as do the other action faces. `enterKeyLongPressFor` sits next to the other Enter-key policy so the key face, the dispatched action and the long press all resolve from the same EditorInfo bits. `ImeKeyboardView.syncEnterKeyPresentation` wires the listener and says the gesture in the key's contentDescription (「发送,长按换行」), `onEnterNewline` commits a live composition the way the key's own press does and otherwise sends a raw Enter. Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference names all three parts of this feature itself: the clipboard list's tip 「长按列表可进入拆词」 (`string/clipboard_history_word_seg_tip`), the view it opens, titled 「滑动选词」 (`word_segmentation_title`), and its one action, 「添加到常用语」 (`word_segmentation_add_to_common_phrase`), with a colour set that separates a clickable label from an un-clickable one and gives that action a disabled face. This port had nothing behind a long press on a clipboard card. `HanWordSegmenter` takes the longest word the tables carry at each position (they hold up to eight characters, 依法追究刑事责任 being the longest row of `pinyin_phrases.tsv`); `TextWordIndex` is their text side, built once on the panel's own thread. `ClipboardPanelController` opens the split on a long press, selects a run by sliding across the words — the run stays when the finger lifts — and files it into 常用语 (`QuickPhraseRepository`), disabled until something is selected. `WordFlowLayout` is the wrapped list the words are laid out in. Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference ships a poetry grammar (sys_poem_gram, type 11010) whose lines are keyed by the pinyin they are typed with, and its own settings text names poetry among what 联想 recommends (关闭联想后,将不会推荐诗词、 计算结果、emoji表情。). Generate poem/lines.tsv from the decoded table and offer a line as a candidate once the composition spells three of its syllables, behind the engine's own candidates; a line spelled out whole brings the line that follows it in its own poem. The layer follows the 智能联想 switch the reference groups it under. Three syllables is the measured floor: of the 3,000 most frequent pinyin keys, 2 syllables match 380 (12.7%) and 3 match 3 (0.1%). Co-Authored-By: Claude Code <noreply@anthropic.com>
Policies and routing for the 快捷格式输入 batch, whose settings rows and service wiring follow in a separate commit (another session is editing the same files). 数字、英文前后加空格: LetterDigitSpacePolicy (core) and a letterDigitSpace hook in InputConnectionGateway.commitText, the single funnel every commit goes through. The reference's own title and subtitle are the rule (string/letter_digit_space_list_item_title/subtitle, res/xq.xml): a space between Chinese and digits/English, on typing and on voice alike. 双击空格键输入句号: DoubleSpacePeriodPolicy keeps the reference's 200 ms window (InputViewRoot$z.invoke, classes.dex code_off 0x4c1764, const-wide/16 0xc8) and its 31-character punctuation gate. 算式出结果: ArithmeticExpressionPolicy evaluates the expression that ends at the cursor. The reference computes it natively (libkeyboard.so InputModel::Impl::AssociateCalculator 0x26523c, GetCalculatorCandidate 0x255ca4, CommitCalculatorCand 0x264594) and its 智能联想 text lists 计算结果 among what that switch offers (string/associate_close_content). 使用耳机麦克风录音: VoiceInputRoutePolicy decides between a headset and the phone's own microphone, as the reference's enable_bluetooth_input does (string/enable_bluetooth_input_show, res/cU.xml defaultValue=false); VoiceAudioRouteManager and LocalAudioVoiceBackend read the switch per session. Unit tests for all four policies and the gateway spacing, plus an instrumented test for the service-side double space. Co-Authored-By: Claude Code <noreply@anthropic.com>
Second half of the batch, carrying both lanes' wiring: the settings rows for 数字、英文前后加空格 / 首字母自动大写 / 双击空格键输入句号 (the reference's own 快捷格式输入 page, res/xq.xml), 候选栏展示 and 使用耳机麦克风录音, plus 首字母自动大写 and 按键音量 from the other session working this tree. 首字母自动大写 reads the text before the cursor at every text change and raises Shift at a sentence start; it rides the reference's switch (enable_first_letter_capitalization, defaultValue=false) and the Shift key now announces the reference's own guide text (string/caps_lock_guide_text). 按键音量 scales the bundled click samples and the system click with the reference's key_sound_volume (0-100, default 50). 算式出结果 and 候选栏展示 fill the row between words: an expression that ends at the cursor offers its result, and with 候选栏展示 on the clipboard's content is offered as a candidate that writes what was copied. Candidate-bar clipboard display ships off even though the reference defaults it on (enable_clipboard_candidate_bar_show, defaultValue=true), because this batch's personalisation features are off until switched on; the divergence is recorded in the changelog and the decision log. 使用耳机麦克风录音 routes voice input to a headset when one is worn and back to the phone's own microphone when it is not, per the reference's own subtitle 「默认使用手机录音。佩戴耳机时,使用耳机麦克风」. User-data export and import carry all six new settings. The FuzzyRulesInstrumentedTest expectation now matches the shipped fuzzy defaults (z=zh among them, fcae0dd) instead of the pre-fcae0dd behaviour. Co-Authored-By: Claude Code <noreply@anthropic.com>
The reference enumerates the whole open digit tail on every key press and cuts nothing. Its left-list builder (libshell.so 0x5ba1e0) pushes one string per marked syllable id, then the letters of the open head key -- each with its `+0x20` twin (0x5ba6c4) -- and the leading digit item, reserving only (marked + 8) at 0x5ba430; decoding syllable.dat end to end gives 64 -> 10 items, 9426 -> 18, 5426 -> 15. Fuzzy widens the lattice at the digit level rather than selecting a lookup: every data3 record carries the smallest rule mask that reaches its spelling and pass2 (0x5b962c) admits it while `mask` is a subset of the reader's fuzzy set, so node 64 carries `li` (0x0008), 426 carries `fang` (0x0050), and 9426 runs from 19 readings to 32 with every rule on. This port listed syllables only, offered letters for a single key press only, cut the rail at 12 and never used fuzzy while decoding, so those readings could not appear at all. The rail now lists the head key's syllable-capable letters for a tail of any length (i/u/v stay out as dead ends), the rail bound goes 12 -> 48, the reading bound 12 -> 24 and the librime reading count 6 -> 12; the decoder files one fuzzy-variant entry per syllable under its plain spelling's digits carrying the rules it needs, admitted only while all of them are on, while the rail keeps plain spellings the way the reference's left builder does (mask == 0, 0x5ba378). ENGINE-SPEC.md:222 records the 0x6c0508 family as a nine-key fuzzy path; the disassembly places it in the wubi engine, so that line is recorded as wrong and not followed. Co-Authored-By: Claude Code <noreply@anthropic.com>
Keep the input improvements while restoring the five-key bottom row, equal letter widths, nine-key zero and segmentation keys, stroke grid, numeric arrangement, and uniform key gaps. Restore the numeric return key to its original function-key color and cover the layouts and phone symbols. Co-Authored-By: Claude Code <noreply@anthropic.com>
…fficial model packages The keyboard and the app pages now share one accent, the launcher grids stay centred at any window width, and the toolbar keeps our own key order. The voice-model page lists the official download addresses, and its own import takes the tar.bz2 packages those addresses serve. - Unify the accent (light #1668D0, dark #2D6FD6) across the keyboard palette and setup_primary, with white on the accent, and give the toolbar icons the weight they need to read on the strip. A test pins the two together. - Centre the tools and keyboard-switcher grids: the reference's 88.9% width was computed but never applied, so the rows sat left of the window centre. The rows also follow the window when it changes width. - Keep our own toolbar order (切换键盘, 剪贴板, 表情, 文本编辑, 撤销, 更多), in the reference's scrolling strip. docs/DECISIONS.md records that this is deliberate against the reference's own row. - Refresh the SMS code chip from a ContentObserver on Telephony.Sms.CONTENT_URI with a 200 ms debounce, so a code that arrives while the keyboard is open shows up; unregister it when the chip is off, the field is a password or the view detaches. SmsCodeExtractor also reads the layouts real messages use. - Import the official sherpa-onnx tar.bz2 model packages as they arrive, with commons-compress for bzip2 (java.util.zip has zip and gzip only), the application/x-bzip2 MIME type in the picker, and the archive's own traversal and size checks kept. - List the official model addresses on the voice-model page with copy buttons, and centre that page's content and cards. - Hide the handwriting entry (HandwritingFeaturePolicy.ENTRY_OFFERED): the pad is still rough. The provider, the pad and the strokes table stay in the build. - Name the release assets openIME-llm-v<VERSION>.apk (the offline voice models) and openIME-v<VERSION>.apk (the smaller package), and compare the draft's asset names against those two instead of counting them, so a tag run with both APKs attached can publish. Co-Authored-By: Claude Code <noreply@anthropic.com>
Fold [Unreleased] into the 1.0.0 section and set VERSION. No code changes. Co-Authored-By: Claude Code <noreply@anthropic.com>
# Conflicts: # .github/workflows/release.yml
`theDefaultModeWouldLeaveTheCardWithNoTouchableArea` insets a Rect on all four
sides. That overload is hidden in the platform source
(`frameworks/base/graphics/java/android/graphics/Rect.java`, the javadoc block
above `public void inset(int left, int top, int right, int bottom)` carries
`@hide` at android-10.0.0_r1), so the API 29 compatibility job dies with
NoSuchMethodError: No virtual method inset(IIII)V in class android.graphics.Rect
API 26 predates hidden-API enforcement, which is why that job stayed green and
API 29 did not. The test now moves the edge it cares about, which is what the
four-argument call did here.
Co-Authored-By: Claude Code <noreply@anthropic.com>
View.onTouchEvent posts the click on ACTION_UP, and detaching the view cancels that post. The pending-rebuild poll could be due ahead of the post, so a tap on Space during a layout change was swallowed. The poll now yields one turn after it sees the finger lift. The matching test also skips when the main thread ran past the long-press deadline, where the press is a voice hold by design. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The stress script counts taps and mode switches; this run types real text and checks what was committed.
scripts/typing_volume_e2e.py, driven byscripts/build_volume_data.py:Input comes from the bundled dictionaries and this repository's own prose, so no network is needed and nothing is written into the repository. A word is a hit only when the committed text equals the expected text; a sentence is scored by character accuracy. On a miss the harness re-types that word alone and records the expected text, the committed text and the candidate list, which is how it found the ranking defect fixed in #138 (
dangoffered 打 first, and 当地 sat at rank 6 behind single characters).The two debug-only commands the harness needs —
editor-tail64andcandidates64— read the committed text and the candidate bar in one round trip and stay unreachable in a release build, like the rest of the test bridge.docs/TEST_SOP.mdsection 13 records how to run it.🤖 Generated with Claude Code