mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-19 23:28:31 +01:00
Refactor input method subtype system
This commit is contained in:
parent
ef1860b8d0
commit
7570e4d258
1
java/res/drawable/empty.xml
Normal file
1
java/res/drawable/empty.xml
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/transparent" /> </shape>
|
@ -573,4 +573,43 @@ Tip: You can download and remove dictionaries by going to <b>Languages &
|
||||
This resource is copied from packages/apps/Settings/res/values/strings.xml -->
|
||||
<!-- This resource is corresponding to msgid="5433275485499039199" -->
|
||||
<string name="user_dict_fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
|
||||
|
||||
<string name="layout_arabic">Arabic</string>
|
||||
<string name="layout_armenian_phonetic">Armenian (Phonetic)</string>
|
||||
<string name="layout_azerty">AZERTY</string>
|
||||
<string name="layout_bengali">Bengali</string>
|
||||
<string name="layout_bengali_akkhor">Bengali (Akkhor)</string>
|
||||
<string name="layout_bepo">BÉPO</string>
|
||||
<string name="layout_bulgarian">Bulgarian</string>
|
||||
<string name="layout_bulgarian_bds">Bulgarian (BDS)</string>
|
||||
<string name="layout_colemak">Colemak</string>
|
||||
<string name="layout_dvorak">Dvorak</string>
|
||||
<string name="layout_east_slavic">East Slavic</string>
|
||||
<string name="layout_farsi">Farsi</string>
|
||||
<string name="layout_georgian">Georgian</string>
|
||||
<string name="layout_greek">Greek</string>
|
||||
<string name="layout_hebrew">Hebrew</string>
|
||||
<string name="layout_hindi">Hindi</string>
|
||||
<string name="layout_hindi_compact">Hindi (Compact)</string>
|
||||
<string name="layout_kannada">Kannada</string>
|
||||
<string name="layout_khmer">Khmer</string>
|
||||
<string name="layout_lao">Lao</string>
|
||||
<string name="layout_malayalam">Malayalam</string>
|
||||
<string name="layout_marathi">Marathi</string>
|
||||
<string name="layout_mongolian">Mongolian</string>
|
||||
<string name="layout_nepali_romanized">Nepali (Romanized)</string>
|
||||
<string name="layout_nepali_traditional">Nepali (Traditional)</string>
|
||||
<string name="layout_nordic">Nordic</string>
|
||||
<string name="layout_pcqwerty">PC QWERTY</string>
|
||||
<string name="layout_qwerty">QWERTY</string>
|
||||
<string name="layout_qwertz">QWERTZ</string>
|
||||
<string name="layout_serbian_qwertz">Serbian (QWERTZ)</string>
|
||||
<string name="layout_sinhala">Sinhala</string>
|
||||
<string name="layout_south_slavic">South Slavic</string>
|
||||
<string name="layout_spanish">Spanish</string>
|
||||
<string name="layout_swiss">Swiss</string>
|
||||
<string name="layout_tamil">Tamil</string>
|
||||
<string name="layout_telugu">Telugu</string>
|
||||
<string name="layout_thai">Thai</string>
|
||||
<string name="layout_uzbek">Uzbek</string>
|
||||
</resources>
|
||||
|
21
java/res/xml/kbd_bepo.xml
Normal file
21
java/res/xml/kbd_bepo.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The CyanogenMod Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<Keyboard
|
||||
xmlns:latin="http://schemas.android.com/apk/res-auto"
|
||||
>
|
||||
<include
|
||||
latin:keyboardLayout="@xml/rows_bepo" />
|
||||
</Keyboard>
|
37
java/res/xml/keyboard_layout_set_bepo.xml
Normal file
37
java/res/xml/keyboard_layout_set_bepo.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The CyanogenMod Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<KeyboardLayoutSet
|
||||
xmlns:latin="http://schemas.android.com/apk/res-auto">
|
||||
<Element
|
||||
latin:elementName="alphabet"
|
||||
latin:elementKeyboard="@xml/kbd_bepo"
|
||||
latin:enableProximityCharsCorrection="true" />
|
||||
<Element
|
||||
latin:elementName="symbols"
|
||||
latin:elementKeyboard="@xml/kbd_symbols" />
|
||||
<Element
|
||||
latin:elementName="symbolsShifted"
|
||||
latin:elementKeyboard="@xml/kbd_symbols_shift" />
|
||||
<Element
|
||||
latin:elementName="phone"
|
||||
latin:elementKeyboard="@xml/kbd_phone" />
|
||||
<Element
|
||||
latin:elementName="phoneSymbols"
|
||||
latin:elementKeyboard="@xml/kbd_phone_symbols" />
|
||||
<Element
|
||||
latin:elementName="number"
|
||||
latin:elementKeyboard="@xml/kbd_number" />
|
||||
</KeyboardLayoutSet>
|
@ -1,812 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/**
|
||||
* Copyright (c) 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!-- The attributes in this XML file provide configuration information -->
|
||||
<!-- for the Input Method Manager. -->
|
||||
|
||||
<!-- Supported subtypes
|
||||
keyboard_locale: script_name/keyboard_layout_set
|
||||
af: Afrikaans/qwerty
|
||||
ar: Arabic/arabic
|
||||
az_AZ: Azerbaijani (Azerbaijan)/qwerty
|
||||
be_BY: Belarusian (Belarus)/east_slavic
|
||||
bg: Bulgarian/bulgarian
|
||||
bg: Bulgarian/bulgarian_bds
|
||||
bn_BD: Bengali (Bangladesh)/bengali_akkhor
|
||||
bn_IN: Bengali (India)/bengali
|
||||
ca: Catalan/spanish
|
||||
cs: Czech/qwertz
|
||||
da: Danish/nordic
|
||||
de: German/qwertz
|
||||
de_CH: German (Switzerland)/swiss
|
||||
el: Greek/greek
|
||||
en_IN: English (India)/qwerty
|
||||
en_US: English (United States)/qwerty
|
||||
en_GB: English (Great Britain)/qwerty
|
||||
eo: Esperanto/spanish
|
||||
es: Spanish/spanish
|
||||
es_US: Spanish (United States)/spanish
|
||||
es_419: Spanish (Latin America)/spanish
|
||||
et_EE: Estonian (Estonia)/nordic
|
||||
eu_ES: Basque (Spain)/spanish
|
||||
fa: Persian/farsi
|
||||
fi: Finnish/nordic
|
||||
fr: French/azerty
|
||||
fr_CA: French (Canada)/qwerty
|
||||
fr_CH: French (Switzerland)/swiss
|
||||
gl_ES: Galician (Spain)/spanish
|
||||
hi: Hindi/hindi
|
||||
hi: Hindi/hindi_compact
|
||||
hi_ZZ: Hinglish/qwerty # This is a preliminary keyboard layout.
|
||||
hr: Croatian/qwertz
|
||||
hu: Hungarian/qwertz
|
||||
hy_AM: Armenian (Armenia) Phonetic/armenian_phonetic
|
||||
in: Indonesian/qwerty # "id" is the official language code of Indonesian.
|
||||
is: Icelandic/qwerty
|
||||
it: Italian/qwerty
|
||||
it_CH: Italian (Switzerland)/swiss
|
||||
iw: Hebrew/hebrew # "he" is the official language code of Hebrew.
|
||||
ka_GE: Georgian (Georgia)/georgian
|
||||
kk: Kazakh/east_slavic
|
||||
km_KH: Khmer (Cambodia)/khmer
|
||||
kn_IN: Kannada (India)/kannada
|
||||
ky: Kyrgyz/east_slavic
|
||||
lo_LA: Lao (Laos)/lao
|
||||
lt: Lithuanian/qwerty
|
||||
lv: Latvian/qwerty
|
||||
mk: Macedonian/south_slavic
|
||||
ml_IN: Malayalam (India)/malayalam
|
||||
mn_MN: Mongolian (Mongolia)/mongolian
|
||||
mr_IN: Marathi (India)/marathi
|
||||
ms_MY: Malay (Malaysia)/qwerty
|
||||
nb: Norwegian Bokmål/nordic
|
||||
ne_NP: Nepali (Nepal) Romanized/nepali_romanized
|
||||
ne_NP: Nepali (Nepal) Traditional/nepali_traditional
|
||||
nl: Dutch/qwerty
|
||||
nl_BE: Dutch (Belgium)/azerty
|
||||
pl: Polish/qwerty
|
||||
pt_BR: Portuguese (Brazil)/qwerty
|
||||
pt_PT: Portuguese (Portugal)/qwerty
|
||||
ro: Romanian/qwerty
|
||||
ru: Russian/east_slavic
|
||||
si_LK: Sinhala (Sri Lanka)/sinhala # This is a preliminary keyboard layout.
|
||||
sk: Slovak/qwerty
|
||||
sl: Slovenian/qwerty
|
||||
sr: Serbian/south_slavic
|
||||
sr_ZZ: Serbian (Latin)/serbian_qwertz # This is a preliminary keyboard layout.
|
||||
sv: Swedish/nordic
|
||||
sw: Swahili/qwerty
|
||||
ta_IN: Tamil (India)/tamil
|
||||
ta_LK: Tamil (Sri Lanka)/tamil # Disabled in conjunction with si_LK.
|
||||
ta_SG: Tamil (Singapore)/tamil
|
||||
te_IN: Telugu (India)/telugu
|
||||
th: Thai/thai
|
||||
tl: Tagalog/spanish
|
||||
tr: Turkish/qwerty
|
||||
uk: Ukrainian/east_slavic
|
||||
uz_UZ: Uzbek (Uzbekistan)/uzbek # This is a preliminary keyboard layout.
|
||||
vi: Vietnamese/qwerty
|
||||
zu: Zulu/qwerty
|
||||
zz: QWERTY/qwerty
|
||||
(zz: Emoji/emoji)
|
||||
-->
|
||||
<!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. -->
|
||||
<!-- TODO: Remove "AsciiCapable" from the extra values when we can stop supporting JB-MR1 -->
|
||||
<!-- Note: SupportTouchPositionCorrection extra value is obsolete and maintained for backward
|
||||
compatibility. -->
|
||||
<!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default
|
||||
subtype.-->
|
||||
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:settingsActivity="org.futo.inputmethod.latin.uix.settings.SettingsActivity"
|
||||
android:isDefault="@bool/im_is_default"
|
||||
android:supportsSwitchingToNextInputMethod="true"
|
||||
android:supportsInlineSuggestions="true">
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_en_US"
|
||||
android:subtypeId="0xc9194f98"
|
||||
android:imeSubtypeLocale="en_US"
|
||||
android:languageTag="en-US"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_en_GB"
|
||||
android:subtypeId="0xb045e755"
|
||||
android:imeSubtypeLocale="en_GB"
|
||||
android:languageTag="en-GB"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x6f972360"
|
||||
android:imeSubtypeLocale="af"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x590dde40"
|
||||
android:imeSubtypeLocale="ar"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x70b0f974"
|
||||
android:imeSubtypeLocale="az_AZ"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x1dc3a859"
|
||||
android:imeSubtypeLocale="be_BY"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x0ba9c0e8"
|
||||
android:imeSubtypeLocale="bg"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_bulgarian_bds"
|
||||
android:subtypeId="0x5f51ba9a"
|
||||
android:imeSubtypeLocale="bg"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian_bds,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xa2144b0c"
|
||||
android:imeSubtypeLocale="bn_BD"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=bengali_akkhor,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xbff5986c"
|
||||
android:imeSubtypeLocale="bn_IN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=bengali,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xd2e520d5"
|
||||
android:imeSubtypeLocale="ca"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x2d3d2ed0"
|
||||
android:imeSubtypeLocale="cs"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x2df4605d"
|
||||
android:imeSubtypeLocale="da"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x2e2cbe61"
|
||||
android:imeSubtypeLocale="de"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x7acfd0aa"
|
||||
android:imeSubtypeLocale="de_CH"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x0e7802d3"
|
||||
android:imeSubtypeLocale="el"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=greek,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8d58fc2d"
|
||||
android:imeSubtypeLocale="en_IN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x4090554a"
|
||||
android:imeSubtypeLocale="eo"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x30a6e00e"
|
||||
android:imeSubtypeLocale="es"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_es_US"
|
||||
android:subtypeId="0x84d2efc6"
|
||||
android:imeSubtypeLocale="es_US"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xa23e5d19"
|
||||
android:imeSubtypeLocale="es_419"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xec2d3955"
|
||||
android:imeSubtypeLocale="et_EE"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=nordic,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x070e5c07"
|
||||
android:imeSubtypeLocale="eu_ES"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xbe66c254"
|
||||
android:imeSubtypeLocale="fa"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=farsi,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x31cecda3"
|
||||
android:imeSubtypeLocale="fi"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x324da12c"
|
||||
android:imeSubtypeLocale="fr"
|
||||
android:languageTag="fr"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xeadbb691"
|
||||
android:imeSubtypeLocale="fr_CA"
|
||||
android:languageTag="fr-CA"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xeadc55f5"
|
||||
android:imeSubtypeLocale="fr_CH"
|
||||
android:languageTag="fr-CH"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xb939573c"
|
||||
android:imeSubtypeLocale="gl_ES"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x39753b7f"
|
||||
android:imeSubtypeLocale="hi"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic_compact"
|
||||
android:subtypeId="0xe49c89a1"
|
||||
android:imeSubtypeLocale="hi"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi_compact,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<!-- TODO: This Hinglish keyboard is a preliminary layout.
|
||||
This isn't based on the final specification. -->
|
||||
<!-- Disabled because there is no LM yet, and this layout does not offer anything different.
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_hi_ZZ"
|
||||
android:subtypeId="0x352eb37c"
|
||||
android:imeSubtypeLocale="hi_ZZ"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,KeyboardLayoutSet=qwerty,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
-->
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x35b7526a"
|
||||
android:imeSubtypeLocale="hr"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x35e198ed"
|
||||
android:imeSubtypeLocale="hu"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xe39ac3ca"
|
||||
android:imeSubtypeLocale="hy_AM"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=armenian_phonetic,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<!-- Java uses the deprecated "in" code instead of the standard "id" code for Indonesian. -->
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x7daea460"
|
||||
android:imeSubtypeLocale="in"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x7df519e5"
|
||||
android:imeSubtypeLocale="is"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x37885a0b"
|
||||
android:imeSubtypeLocale="it"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xd914fe1a"
|
||||
android:imeSubtypeLocale="it_CH"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<!-- Java uses the deprecated "iw" code instead of the standard "he" code for Hebrew. -->
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x66fb18bd"
|
||||
android:imeSubtypeLocale="iw"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x6e119e6a"
|
||||
android:imeSubtypeLocale="ka_GE"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=georgian,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x2d73d2f6"
|
||||
android:imeSubtypeLocale="kk"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x1365683a"
|
||||
android:imeSubtypeLocale="km_KH"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=khmer,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8c78064f"
|
||||
android:imeSubtypeLocale="kn_IN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=kannada,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x2e391c04"
|
||||
android:imeSubtypeLocale="ky"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8315772c"
|
||||
android:imeSubtypeLocale="lo_LA"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=lao,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8321bb43"
|
||||
android:imeSubtypeLocale="lt"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x833dea45"
|
||||
android:imeSubtypeLocale="lv"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xaf50ab7c"
|
||||
android:imeSubtypeLocale="mk"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=south_slavic,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xc182ebd4"
|
||||
android:imeSubtypeLocale="ml_IN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=malayalam,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xcdcfc3ab"
|
||||
android:imeSubtypeLocale="mn_MN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=mongolian,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x747b9f03"
|
||||
android:imeSubtypeLocale="mr_IN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=marathi,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x84c87c61"
|
||||
android:imeSubtypeLocale="ms_MY"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x3f12ee14"
|
||||
android:imeSubtypeLocale="nb"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xd80a4cee"
|
||||
android:imeSubtypeLocale="ne_NP"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_romanized,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic_traditional"
|
||||
android:subtypeId="0x5fafea88"
|
||||
android:imeSubtypeLocale="ne_NP"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_traditional,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x3f9fd91e"
|
||||
android:imeSubtypeLocale="nl"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x500ca92c"
|
||||
android:imeSubtypeLocale="nl_BE"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=azerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x43098a5c"
|
||||
android:imeSubtypeLocale="pl"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xcafff4a6"
|
||||
android:imeSubtypeLocale="pt_BR"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xe2fffc5a"
|
||||
android:imeSubtypeLocale="pt_PT"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8d185978"
|
||||
android:imeSubtypeLocale="ro"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x763a8752"
|
||||
android:imeSubtypeLocale="ru"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<!-- TODO: This Sinhala keyboard is a preliminary layout.
|
||||
This isn't based on the final specification. -->
|
||||
<!-- si_LK is currently disabled due to lack of combination rules.
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x5c6b3bde"
|
||||
android:imeSubtypeLocale="si_LK"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=sinhala,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
-->
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8e94d413"
|
||||
android:imeSubtypeLocale="sk"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8ea2eb94"
|
||||
android:imeSubtypeLocale="sl"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x77c5196e"
|
||||
android:imeSubtypeLocale="sr"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<!-- TODO: This Serbian Latin keyboard is a preliminary layout.
|
||||
This isn't based on the final specification. -->
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_sr_ZZ"
|
||||
android:subtypeId="0xf4a5569c"
|
||||
android:imeSubtypeLocale="sr_ZZ"
|
||||
android:languageTag="sr-Latn"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=serbian_qwertz,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x48b4ff43"
|
||||
android:imeSubtypeLocale="sv"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x8f3dee1f"
|
||||
android:imeSubtypeLocale="sw"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x67acea2a"
|
||||
android:imeSubtypeLocale="ta_IN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=tamil,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<!-- TODO: Enabling/Disabling ta_LK subtype must be aligned with si_LK subtype. -->
|
||||
<!-- ta_LK disabled alongside si_LK subtype due to lack of combination rules.
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x6ca12d84"
|
||||
android:imeSubtypeLocale="ta_LK"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=tamil,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
!-->
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x785abbd9"
|
||||
android:imeSubtypeLocale="ta_SG"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=tamil,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x1e177389"
|
||||
android:imeSubtypeLocale="te_IN"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=telugu,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x1f94d5d4"
|
||||
android:imeSubtypeLocale="th"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=thai,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xf08285ef"
|
||||
android:imeSubtypeLocale="tl"
|
||||
android:languageTag="fil"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x4a3179de"
|
||||
android:imeSubtypeLocale="tr"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x3e84492c"
|
||||
android:imeSubtypeLocale="uk"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
<!-- TODO: This Uzbek keyboard is a preliminary layout.
|
||||
This isn't based on the final specification. -->
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0xad5cf7f6"
|
||||
android:imeSubtypeLocale="uz_UZ"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=uzbek,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x93972eee"
|
||||
android:imeSubtypeLocale="vi"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_generic"
|
||||
android:subtypeId="0x9b13ab76"
|
||||
android:imeSubtypeLocale="zu"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_no_language_qwerty"
|
||||
android:subtypeId="0xa239ebad"
|
||||
android:imeSubtypeLocale="zz"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable,EmojiCapable"
|
||||
android:isAsciiCapable="true"
|
||||
/>
|
||||
<!-- Emoji subtype has to be an addtional subtype added at boot time because ICS doesn't
|
||||
support Emoji. -->
|
||||
<!--
|
||||
<subtype android:icon="@drawable/ic_ime_switcher_dark"
|
||||
android:label="@string/subtype_emoji"
|
||||
android:subtypeId="0xc14d88b2"
|
||||
android:imeSubtypeLocale="zz"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="KeyboardLayoutSet=emoji,EmojiCapable"
|
||||
android:isAsciiCapable="false"
|
||||
/>
|
||||
-->
|
||||
android:settingsActivity="org.futo.inputmethod.latin.uix.settings.SettingsActivity"
|
||||
android:isDefault="true"
|
||||
android:supportsSwitchingToNextInputMethod="true"
|
||||
android:supportsInlineSuggestions="true">
|
||||
<subtype android:icon="@drawable/ic_launcher_foreground"
|
||||
android:label="@string/english_ime_name"
|
||||
android:imeSubtypeLocale="xx_YY"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:overridesImplicitlyEnabledSubtype="true" />
|
||||
</input-method>
|
||||
|
66
java/res/xml/rowkeys_bepo1.xml
Normal file
66
java/res/xml/rowkeys_bepo1.xml
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The CyanogenMod Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<merge
|
||||
xmlns:latin="http://schemas.android.com/apk/res-auto"
|
||||
>
|
||||
<Key
|
||||
latin:keySpec="b"
|
||||
latin:keyHintLabel="1"
|
||||
latin:additionalMoreKeys="1"/>
|
||||
<Key
|
||||
latin:keySpec="é"
|
||||
latin:keyHintLabel="2"
|
||||
latin:additionalMoreKeys="2,è" />
|
||||
<Key
|
||||
latin:keySpec="p"
|
||||
latin:keyHintLabel="3"
|
||||
latin:additionalMoreKeys="3" />
|
||||
<Key
|
||||
latin:keySpec="o"
|
||||
latin:keyHintLabel="4"
|
||||
latin:additionalMoreKeys="4"
|
||||
latin:moreKeys="!text/morekeys_o" />
|
||||
<Key
|
||||
latin:keySpec="v"
|
||||
latin:keyHintLabel="5"
|
||||
latin:additionalMoreKeys="5"
|
||||
latin:moreKeys="!text/morekeys_v" />
|
||||
<Key
|
||||
latin:keySpec="d"
|
||||
latin:keyHintLabel="6"
|
||||
latin:additionalMoreKeys="6"
|
||||
latin:moreKeys="!text/morekeys_d" />
|
||||
<Key
|
||||
latin:keySpec="l"
|
||||
latin:keyHintLabel="7"
|
||||
latin:additionalMoreKeys="7"
|
||||
latin:moreKeys="!text/morekeys_l" />
|
||||
<Key
|
||||
latin:keySpec="j"
|
||||
latin:keyHintLabel="8"
|
||||
latin:additionalMoreKeys="8"
|
||||
latin:moreKeys="!text/morekeys_j" />
|
||||
<Key
|
||||
latin:keySpec="z"
|
||||
latin:keyHintLabel="9"
|
||||
latin:additionalMoreKeys="9"
|
||||
latin:moreKeys="!text/morekeys_z" />
|
||||
<Key
|
||||
latin:keySpec="w"
|
||||
latin:keyHintLabel="0"
|
||||
latin:additionalMoreKeys="0"
|
||||
latin:moreKeys="!text/morekeys_w" />
|
||||
</merge>
|
48
java/res/xml/rowkeys_bepo2.xml
Normal file
48
java/res/xml/rowkeys_bepo2.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The CyanogenMod Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<merge
|
||||
xmlns:latin="http://schemas.android.com/apk/res-auto"
|
||||
>
|
||||
<Key
|
||||
latin:keySpec="a"
|
||||
latin:moreKeys="!text/morekeys_a" />
|
||||
<Key
|
||||
latin:keySpec="u"
|
||||
latin:moreKeys="!text/morekeys_u" />
|
||||
<Key
|
||||
latin:keySpec="i"
|
||||
latin:moreKeys="!text/morekeys_i" />
|
||||
<Key
|
||||
latin:keySpec="e"
|
||||
latin:moreKeys="!text/morekeys_e" />
|
||||
<Key
|
||||
latin:keySpec="c"
|
||||
latin:moreKeys="!text/morekeys_c" />
|
||||
<Key
|
||||
latin:keySpec="t"
|
||||
latin:moreKeys="!text/morekeys_t" />
|
||||
<Key
|
||||
latin:keySpec="s"
|
||||
latin:moreKeys="!text/morekeys_s" />
|
||||
<Key
|
||||
latin:keySpec="r"
|
||||
latin:moreKeys="!text/morekeys_r" />
|
||||
<Key
|
||||
latin:keySpec="n"
|
||||
latin:moreKeys="!text/morekeys_n" />
|
||||
<Key
|
||||
latin:keySpec="m" />
|
||||
</merge>
|
38
java/res/xml/rowkeys_bepo3.xml
Normal file
38
java/res/xml/rowkeys_bepo3.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The CyanogenMod Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<merge
|
||||
xmlns:latin="http://schemas.android.com/apk/res-auto"
|
||||
>
|
||||
<Key
|
||||
latin:keySpec="y"
|
||||
latin:moreKeys="!text/morekeys_y" />
|
||||
<Key
|
||||
latin:keySpec="x" />
|
||||
<Key
|
||||
latin:keySpec="k"
|
||||
latin:moreKeys="!text/morekeys_k" />
|
||||
<Key
|
||||
latin:keySpec="q"
|
||||
latin:moreKeys="!text/morekeys_q" />
|
||||
<Key
|
||||
latin:keySpec="g"
|
||||
latin:moreKeys="!text/morekeys_g" />
|
||||
<Key
|
||||
latin:keySpec="h"
|
||||
latin:moreKeys="!text/morekeys_h" />
|
||||
<Key
|
||||
latin:keySpec="f" />
|
||||
</merge>
|
49
java/res/xml/rows_bepo.xml
Normal file
49
java/res/xml/rows_bepo.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The CyanogenMod Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<merge
|
||||
xmlns:latin="http://schemas.android.com/apk/res-auto"
|
||||
>
|
||||
<include
|
||||
latin:keyboardLayout="@xml/key_styles_common" />
|
||||
<Row
|
||||
latin:keyWidth="10%p"
|
||||
>
|
||||
<include
|
||||
latin:keyboardLayout="@xml/rowkeys_bepo1" />
|
||||
</Row>
|
||||
<Row
|
||||
latin:keyWidth="10%p"
|
||||
>
|
||||
<include
|
||||
latin:keyboardLayout="@xml/rowkeys_bepo2" />
|
||||
</Row>
|
||||
<Row
|
||||
latin:keyWidth="10%p"
|
||||
>
|
||||
<Key
|
||||
latin:keyStyle="shiftKeyStyle"
|
||||
latin:keyWidth="15%p"
|
||||
latin:visualInsetsRight="1%p" />
|
||||
<include
|
||||
latin:keyboardLayout="@xml/rowkeys_bepo3" />
|
||||
<Key
|
||||
latin:keyStyle="deleteKeyStyle"
|
||||
latin:keyWidth="fillRight"
|
||||
latin:visualInsetsLeft="1%p" />
|
||||
</Row>
|
||||
<include
|
||||
latin:keyboardLayout="@xml/row_qwerty4" />
|
||||
</merge>
|
@ -28,7 +28,6 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import org.futo.inputmethod.event.Event;
|
||||
import org.futo.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
|
||||
import org.futo.inputmethod.keyboard.emoji.EmojiPalettesView;
|
||||
import org.futo.inputmethod.keyboard.internal.KeyboardState;
|
||||
import org.futo.inputmethod.keyboard.internal.KeyboardTextsSet;
|
||||
import org.futo.inputmethod.latin.InputView;
|
||||
@ -36,6 +35,7 @@ import org.futo.inputmethod.latin.LatinIME;
|
||||
import org.futo.inputmethod.latin.LatinIMELegacy;
|
||||
import org.futo.inputmethod.latin.R;
|
||||
import org.futo.inputmethod.latin.RichInputMethodManager;
|
||||
import org.futo.inputmethod.latin.Subtypes;
|
||||
import org.futo.inputmethod.latin.WordComposer;
|
||||
import org.futo.inputmethod.latin.define.ProductionFlags;
|
||||
import org.futo.inputmethod.latin.settings.Settings;
|
||||
@ -181,8 +181,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
||||
|| !newKeyboard.mId.mSubtype.equals(oldKeyboard.mId.mSubtype);
|
||||
final int languageOnSpacebarFormatType = LanguageOnSpacebarUtils
|
||||
.getLanguageOnSpacebarFormatType(newKeyboard.mId.mSubtype);
|
||||
final boolean hasMultipleEnabledIMEsOrSubtypes = mRichImm
|
||||
.hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */);
|
||||
final boolean hasMultipleEnabledIMEsOrSubtypes = Subtypes.INSTANCE.hasMultipleEnabledSubtypes(mThemeContext);
|
||||
keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType,
|
||||
hasMultipleEnabledIMEsOrSubtypes);
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ import org.futo.inputmethod.latin.uix.deferGetSetting
|
||||
import org.futo.inputmethod.latin.uix.deferSetSetting
|
||||
import org.futo.inputmethod.latin.uix.differsFrom
|
||||
import org.futo.inputmethod.latin.uix.getSetting
|
||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||
import org.futo.inputmethod.latin.uix.getSettingFlow
|
||||
import org.futo.inputmethod.latin.uix.setSetting
|
||||
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||
@ -275,7 +276,21 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
saveSubtypes()
|
||||
val onNewSubtype: (String) -> Unit = {
|
||||
val activeSubtype = it.ifEmpty {
|
||||
getSettingBlocking(SubtypesSetting).firstOrNull()
|
||||
}
|
||||
|
||||
if(activeSubtype != null) {
|
||||
changeInputMethodSubtype(Subtypes.convertToSubtype(activeSubtype))
|
||||
}
|
||||
}
|
||||
|
||||
onNewSubtype(getSetting(ActiveSubtype))
|
||||
|
||||
dataStore.data.collect {
|
||||
onNewSubtype(it[ActiveSubtype.key] ?: ActiveSubtype.default)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,8 +426,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
languageModelFacilitator.saveHistoryLog()
|
||||
}
|
||||
|
||||
override fun onCurrentInputMethodSubtypeChanged(newSubtype: InputMethodSubtype?) {
|
||||
super.onCurrentInputMethodSubtypeChanged(newSubtype)
|
||||
private fun changeInputMethodSubtype(newSubtype: InputMethodSubtype?) {
|
||||
latinIMELegacy.onCurrentInputMethodSubtypeChanged(newSubtype)
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
@ -61,8 +60,6 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.futo.inputmethod.accessibility.AccessibilityUtils;
|
||||
import org.futo.inputmethod.annotations.UsedForTesting;
|
||||
import org.futo.inputmethod.compat.BuildCompatUtils;
|
||||
import org.futo.inputmethod.compat.EditorInfoCompatUtils;
|
||||
import org.futo.inputmethod.compat.ViewOutlineProviderCompatUtils;
|
||||
import org.futo.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
|
||||
import org.futo.inputmethod.dictionarypack.DictionaryPackConstants;
|
||||
@ -90,7 +87,7 @@ import org.futo.inputmethod.latin.settings.SettingsValues;
|
||||
import org.futo.inputmethod.latin.suggestions.SuggestionStripView;
|
||||
import org.futo.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
|
||||
import org.futo.inputmethod.latin.touchinputconsumer.GestureConsumer;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner;
|
||||
import org.futo.inputmethod.latin.uix.actions.SwitchLanguageActionKt;
|
||||
import org.futo.inputmethod.latin.uix.settings.SettingsActivity;
|
||||
import org.futo.inputmethod.latin.utils.ApplicationUtils;
|
||||
import org.futo.inputmethod.latin.utils.DialogUtils;
|
||||
@ -176,7 +173,7 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
private final SuggestionStripController mSuggestionStripController;
|
||||
|
||||
private RichInputMethodManager mRichImm;
|
||||
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
|
||||
public final KeyboardSwitcher mKeyboardSwitcher;
|
||||
private final SubtypeState mSubtypeState = new SubtypeState();
|
||||
private EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector;
|
||||
private StatsUtilsManager mStatsUtilsManager;
|
||||
@ -329,9 +326,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
case MSG_DEALLOCATE_MEMORY:
|
||||
latinImeLegacy.deallocateMemory();
|
||||
break;
|
||||
case MSG_SWITCH_LANGUAGE_AUTOMATICALLY:
|
||||
latinImeLegacy.switchLanguage((InputMethodSubtype)msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,10 +459,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
obtainMessage(MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED, suggestedWords).sendToTarget();
|
||||
}
|
||||
|
||||
public void postSwitchLanguage(final InputMethodSubtype subtype) {
|
||||
obtainMessage(MSG_SWITCH_LANGUAGE_AUTOMATICALLY, subtype).sendToTarget();
|
||||
}
|
||||
|
||||
// Working variables for the following methods.
|
||||
private boolean mIsOrientationChanging;
|
||||
private boolean mPendingSuccessiveImsCallback;
|
||||
@ -589,23 +579,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
mCurrentSubtypeHasBeenUsed = true;
|
||||
}
|
||||
|
||||
public void switchSubtype(final IBinder token, final RichInputMethodManager richImm) {
|
||||
final InputMethodSubtype currentSubtype = richImm.getInputMethodManager()
|
||||
.getCurrentInputMethodSubtype();
|
||||
final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
|
||||
final boolean currentSubtypeHasBeenUsed = mCurrentSubtypeHasBeenUsed;
|
||||
if (currentSubtypeHasBeenUsed) {
|
||||
mLastActiveSubtype = currentSubtype;
|
||||
mCurrentSubtypeHasBeenUsed = false;
|
||||
}
|
||||
if (currentSubtypeHasBeenUsed
|
||||
&& richImm.checkIfSubtypeBelongsToThisImeAndEnabled(lastActiveSubtype)
|
||||
&& !currentSubtype.equals(lastActiveSubtype)) {
|
||||
richImm.setInputMethodAndSubtype(token, lastActiveSubtype);
|
||||
return;
|
||||
}
|
||||
richImm.switchToNextInputMethod(token, true /* onlyCurrentIme */);
|
||||
}
|
||||
}
|
||||
|
||||
// Loading the native library eagerly to avoid unexpected UnsatisfiedLinkError at the initial
|
||||
@ -929,18 +902,7 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
}
|
||||
|
||||
void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) {
|
||||
// If the primary hint language does not match the current subtype language, then try
|
||||
// to switch to the primary hint language.
|
||||
// TODO: Support all the locales in EditorInfo#hintLocales.
|
||||
final Locale primaryHintLocale = EditorInfoCompatUtils.getPrimaryHintLocale(editorInfo);
|
||||
if (primaryHintLocale == null) {
|
||||
return;
|
||||
}
|
||||
final InputMethodSubtype newSubtype = mRichImm.findSubtypeByLocale(primaryHintLocale);
|
||||
if (newSubtype == null || newSubtype.equals(mRichImm.getCurrentSubtype().getRawSubtype())) {
|
||||
return;
|
||||
}
|
||||
mHandler.postSwitchLanguage(newSubtype);
|
||||
|
||||
}
|
||||
|
||||
public void updateMainKeyboardViewSettings() {
|
||||
@ -1374,11 +1336,8 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
if (isShowingOptionDialog()) return false;
|
||||
switch (requestCode) {
|
||||
case Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER:
|
||||
if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
|
||||
mRichImm.getInputMethodManager().showInputMethodPicker();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
((LatinIME)mInputMethodService).getUixManager().showLanguageSwitcher();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1459,13 +1418,8 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
return mOptionsDialog != null && mOptionsDialog.isShowing();
|
||||
}
|
||||
|
||||
public void switchLanguage(final InputMethodSubtype subtype) {
|
||||
final IBinder token = mInputMethodService.getWindow().getWindow().getAttributes().token;
|
||||
mRichImm.setInputMethodAndSubtype(token, subtype);
|
||||
}
|
||||
|
||||
public void switchToNextSubtype() {
|
||||
mRichImm.getInputMethodManager().showInputMethodPicker();
|
||||
SwitchLanguageActionKt.switchToNextLanguage(mInputMethodService);
|
||||
}
|
||||
|
||||
// TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
|
||||
@ -2006,12 +1960,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
|
||||
mDictionaryFacilitator.clearUserHistoryDictionary(mInputMethodService);
|
||||
}
|
||||
|
||||
@UsedForTesting
|
||||
List<InputMethodSubtype> getEnabledSubtypesForTest() {
|
||||
return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList(
|
||||
true /* allowsImplicitlySelectedSubtypes */) : new ArrayList<InputMethodSubtype>();
|
||||
}
|
||||
|
||||
public void dumpDictionaryForDebug(final String dictName) {
|
||||
if (!mDictionaryFacilitator.isActive()) {
|
||||
resetDictionaryFacilitatorIfNecessary();
|
||||
|
@ -102,9 +102,6 @@ public class RichInputMethodManager {
|
||||
|
||||
// Initialize additional subtypes.
|
||||
SubtypeLocaleUtils.init(context);
|
||||
final InputMethodSubtype[] additionalSubtypes = getAdditionalSubtypes();
|
||||
mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
|
||||
getInputMethodIdOfThisIme(), additionalSubtypes);
|
||||
|
||||
// Initialize the current input method subtype and the shortcut IME.
|
||||
refreshSubtypeCaches();
|
||||
@ -122,110 +119,6 @@ public class RichInputMethodManager {
|
||||
return mImmWrapper.mImm;
|
||||
}
|
||||
|
||||
public List<InputMethodSubtype> getMyEnabledInputMethodSubtypeList(
|
||||
boolean allowsImplicitlySelectedSubtypes) {
|
||||
return getEnabledInputMethodSubtypeList(
|
||||
getInputMethodInfoOfThisIme(), allowsImplicitlySelectedSubtypes);
|
||||
}
|
||||
|
||||
public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
|
||||
if (mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme)) {
|
||||
return true;
|
||||
}
|
||||
// Was not able to call {@link InputMethodManager#switchToNextInputMethodIBinder,boolean)}
|
||||
// because the current device is running ICS or previous and lacks the API.
|
||||
if (switchToNextInputSubtypeInThisIme(token, onlyCurrentIme)) {
|
||||
return true;
|
||||
}
|
||||
return switchToNextInputMethodAndSubtype(token);
|
||||
}
|
||||
|
||||
private boolean switchToNextInputSubtypeInThisIme(final IBinder token,
|
||||
final boolean onlyCurrentIme) {
|
||||
final InputMethodManager imm = mImmWrapper.mImm;
|
||||
final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype();
|
||||
final List<InputMethodSubtype> enabledSubtypes = getMyEnabledInputMethodSubtypeList(
|
||||
true /* allowsImplicitlySelectedSubtypes */);
|
||||
final int currentIndex = getSubtypeIndexInList(currentSubtype, enabledSubtypes);
|
||||
if (currentIndex == INDEX_NOT_FOUND) {
|
||||
Log.w(TAG, "Can't find current subtype in enabled subtypes: subtype="
|
||||
+ SubtypeLocaleUtils.getSubtypeNameForLogging(currentSubtype));
|
||||
return false;
|
||||
}
|
||||
final int nextIndex = (currentIndex + 1) % enabledSubtypes.size();
|
||||
if (nextIndex <= currentIndex && !onlyCurrentIme) {
|
||||
// The current subtype is the last or only enabled one and it needs to switch to
|
||||
// next IME.
|
||||
return false;
|
||||
}
|
||||
final InputMethodSubtype nextSubtype = enabledSubtypes.get(nextIndex);
|
||||
setInputMethodAndSubtype(token, nextSubtype);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean switchToNextInputMethodAndSubtype(final IBinder token) {
|
||||
final InputMethodManager imm = mImmWrapper.mImm;
|
||||
final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
|
||||
final int currentIndex = getImiIndexInList(getInputMethodInfoOfThisIme(), enabledImis);
|
||||
if (currentIndex == INDEX_NOT_FOUND) {
|
||||
Log.w(TAG, "Can't find current IME in enabled IMEs: IME package="
|
||||
+ getInputMethodInfoOfThisIme().getPackageName());
|
||||
return false;
|
||||
}
|
||||
final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis);
|
||||
final List<InputMethodSubtype> enabledSubtypes = getEnabledInputMethodSubtypeList(nextImi,
|
||||
true /* allowsImplicitlySelectedSubtypes */);
|
||||
if (enabledSubtypes.isEmpty()) {
|
||||
// The next IME has no subtype.
|
||||
imm.setInputMethod(token, nextImi.getId());
|
||||
return true;
|
||||
}
|
||||
final InputMethodSubtype firstSubtype = enabledSubtypes.get(0);
|
||||
imm.setInputMethodAndSubtype(token, nextImi.getId(), firstSubtype);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int getImiIndexInList(final InputMethodInfo inputMethodInfo,
|
||||
final List<InputMethodInfo> imiList) {
|
||||
final int count = imiList.size();
|
||||
for (int index = 0; index < count; index++) {
|
||||
final InputMethodInfo imi = imiList.get(index);
|
||||
if (imi.equals(inputMethodInfo)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
// This method mimics {@link InputMethodManager#switchToNextInputMethod(IBinder,boolean)}.
|
||||
private static InputMethodInfo getNextNonAuxiliaryIme(final int currentIndex,
|
||||
final List<InputMethodInfo> imiList) {
|
||||
final int count = imiList.size();
|
||||
for (int i = 1; i < count; i++) {
|
||||
final int nextIndex = (currentIndex + i) % count;
|
||||
final InputMethodInfo nextImi = imiList.get(nextIndex);
|
||||
if (!isAuxiliaryIme(nextImi)) {
|
||||
return nextImi;
|
||||
}
|
||||
}
|
||||
return imiList.get(currentIndex);
|
||||
}
|
||||
|
||||
// Copied from {@link InputMethodInfo}. See how auxiliary of IME is determined.
|
||||
private static boolean isAuxiliaryIme(final InputMethodInfo imi) {
|
||||
final int count = imi.getSubtypeCount();
|
||||
if (count == 0) {
|
||||
return false;
|
||||
}
|
||||
for (int index = 0; index < count; index++) {
|
||||
final InputMethodSubtype subtype = imi.getSubtypeAt(index);
|
||||
if (!subtype.isAuxiliary()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class InputMethodInfoCache {
|
||||
private final InputMethodManager mImm;
|
||||
private final String mImePackageName;
|
||||
@ -287,38 +180,6 @@ public class RichInputMethodManager {
|
||||
return getInputMethodInfoOfThisIme().getId();
|
||||
}
|
||||
|
||||
public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
|
||||
return checkIfSubtypeBelongsToList(subtype,
|
||||
getEnabledInputMethodSubtypeList(
|
||||
getInputMethodInfoOfThisIme(),
|
||||
true /* allowsImplicitlySelectedSubtypes */));
|
||||
}
|
||||
|
||||
public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
|
||||
final InputMethodSubtype subtype) {
|
||||
final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
|
||||
final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(subtype,
|
||||
getMyEnabledInputMethodSubtypeList(false /* allowsImplicitlySelectedSubtypes */));
|
||||
return subtypeEnabled && !subtypeExplicitlyEnabled;
|
||||
}
|
||||
|
||||
private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype,
|
||||
final List<InputMethodSubtype> subtypes) {
|
||||
return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
private static int getSubtypeIndexInList(final InputMethodSubtype subtype,
|
||||
final List<InputMethodSubtype> subtypes) {
|
||||
final int count = subtypes.size();
|
||||
for (int index = 0; index < count; index++) {
|
||||
final InputMethodSubtype ims = subtypes.get(index);
|
||||
if (ims.equals(subtype)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return INDEX_NOT_FOUND;
|
||||
}
|
||||
|
||||
public void onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) {
|
||||
updateCurrentSubtype(newSubtype);
|
||||
updateShortcutIme();
|
||||
@ -355,142 +216,9 @@ public class RichInputMethodManager {
|
||||
return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype());
|
||||
}
|
||||
|
||||
public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
|
||||
final List<InputMethodInfo> enabledImis = mImmWrapper.mImm.getEnabledInputMethodList();
|
||||
return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
|
||||
}
|
||||
|
||||
public boolean hasMultipleEnabledSubtypesInThisIme(
|
||||
final boolean shouldIncludeAuxiliarySubtypes) {
|
||||
final List<InputMethodInfo> imiList = Collections.singletonList(
|
||||
getInputMethodInfoOfThisIme());
|
||||
return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList);
|
||||
}
|
||||
|
||||
private boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes,
|
||||
final List<InputMethodInfo> imiList) {
|
||||
// Number of the filtered IMEs
|
||||
int filteredImisCount = 0;
|
||||
|
||||
for (InputMethodInfo imi : imiList) {
|
||||
// We can return true immediately after we find two or more filtered IMEs.
|
||||
if (filteredImisCount > 1) return true;
|
||||
final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList(imi, true);
|
||||
// IMEs that have no subtypes should be counted.
|
||||
if (subtypes.isEmpty()) {
|
||||
++filteredImisCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
int auxCount = 0;
|
||||
for (InputMethodSubtype subtype : subtypes) {
|
||||
if (subtype.isAuxiliary()) {
|
||||
++auxCount;
|
||||
}
|
||||
}
|
||||
final int nonAuxCount = subtypes.size() - auxCount;
|
||||
|
||||
// IMEs that have one or more non-auxiliary subtypes should be counted.
|
||||
// If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
|
||||
// subtypes should be counted as well.
|
||||
if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
|
||||
++filteredImisCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredImisCount > 1) {
|
||||
return true;
|
||||
}
|
||||
final List<InputMethodSubtype> subtypes = getMyEnabledInputMethodSubtypeList(true);
|
||||
int keyboardCount = 0;
|
||||
// imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
|
||||
// both explicitly and implicitly enabled input method subtype.
|
||||
// (The current IME should be LatinIME.)
|
||||
for (InputMethodSubtype subtype : subtypes) {
|
||||
if (KEYBOARD_MODE.equals(subtype.getMode())) {
|
||||
++keyboardCount;
|
||||
}
|
||||
}
|
||||
return keyboardCount > 1;
|
||||
}
|
||||
|
||||
public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString,
|
||||
final String keyboardLayoutSetName) {
|
||||
final InputMethodInfo myImi = getInputMethodInfoOfThisIme();
|
||||
final int count = myImi.getSubtypeCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final InputMethodSubtype subtype = myImi.getSubtypeAt(i);
|
||||
final String layoutName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
|
||||
if (localeString.equals(subtype.getLocale())
|
||||
&& keyboardLayoutSetName.equals(layoutName)) {
|
||||
return subtype;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public InputMethodSubtype findSubtypeByLocale(final Locale locale) {
|
||||
// Find the best subtype based on a straightforward matching algorithm.
|
||||
// TODO: Use LocaleList#getFirstMatch() instead.
|
||||
final List<InputMethodSubtype> subtypes =
|
||||
getMyEnabledInputMethodSubtypeList(true /* allowsImplicitlySelectedSubtypes */);
|
||||
final int count = subtypes.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final InputMethodSubtype subtype = subtypes.get(i);
|
||||
final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
|
||||
if (subtypeLocale.equals(locale)) {
|
||||
return subtype;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final InputMethodSubtype subtype = subtypes.get(i);
|
||||
final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
|
||||
if (subtypeLocale.getLanguage().equals(locale.getLanguage()) &&
|
||||
subtypeLocale.getCountry().equals(locale.getCountry()) &&
|
||||
subtypeLocale.getVariant().equals(locale.getVariant())) {
|
||||
return subtype;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final InputMethodSubtype subtype = subtypes.get(i);
|
||||
final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
|
||||
if (subtypeLocale.getLanguage().equals(locale.getLanguage()) &&
|
||||
subtypeLocale.getCountry().equals(locale.getCountry())) {
|
||||
return subtype;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final InputMethodSubtype subtype = subtypes.get(i);
|
||||
final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
|
||||
if (subtypeLocale.getLanguage().equals(locale.getLanguage())) {
|
||||
return subtype;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) {
|
||||
mImmWrapper.mImm.setInputMethodAndSubtype(
|
||||
token, getInputMethodIdOfThisIme(), subtype);
|
||||
}
|
||||
|
||||
public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) {
|
||||
mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
|
||||
getInputMethodIdOfThisIme(), subtypes);
|
||||
// Clear the cache so that we go read the {@link InputMethodInfo} of this IME and list of
|
||||
// subtypes again next time.
|
||||
refreshSubtypeCaches();
|
||||
}
|
||||
|
||||
private List<InputMethodSubtype> getEnabledInputMethodSubtypeList(final InputMethodInfo imi,
|
||||
final boolean allowsImplicitlySelectedSubtypes) {
|
||||
return mInputMethodInfoCache.getEnabledInputMethodSubtypeList(
|
||||
imi, allowsImplicitlySelectedSubtypes);
|
||||
}
|
||||
|
||||
public void refreshSubtypeCaches() {
|
||||
mInputMethodInfoCache.clear();
|
||||
updateCurrentSubtype(mImmWrapper.mImm.getCurrentInputMethodSubtype());
|
||||
updateCurrentSubtype(Subtypes.INSTANCE.getActiveSubtype(mContext));
|
||||
updateShortcutIme();
|
||||
}
|
||||
|
||||
@ -545,13 +273,7 @@ public class RichInputMethodManager {
|
||||
mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode())));
|
||||
}
|
||||
final RichInputMethodSubtype richSubtype = mCurrentRichInputMethodSubtype;
|
||||
final boolean implicitlyEnabledSubtype = checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
|
||||
richSubtype.getRawSubtype());
|
||||
final Locale systemLocale = mContext.getResources().getConfiguration().locale;
|
||||
LanguageOnSpacebarUtils.onSubtypeChanged(
|
||||
richSubtype, implicitlyEnabledSubtype, systemLocale);
|
||||
LanguageOnSpacebarUtils.setEnabledSubtypes(getMyEnabledInputMethodSubtypeList(
|
||||
true /* allowsImplicitlySelectedSubtypes */));
|
||||
|
||||
// TODO: Update an icon for shortcut IME
|
||||
final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts =
|
||||
|
@ -209,14 +209,7 @@ public class RichInputMethodSubtype {
|
||||
@Nonnull
|
||||
public static RichInputMethodSubtype getNoLanguageSubtype() {
|
||||
RichInputMethodSubtype noLanguageSubtype = sNoLanguageSubtype;
|
||||
if (noLanguageSubtype == null) {
|
||||
final InputMethodSubtype rawNoLanguageSubtype = RichInputMethodManager.getInstance()
|
||||
.findSubtypeByLocaleAndKeyboardLayoutSet(
|
||||
SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY);
|
||||
if (rawNoLanguageSubtype != null) {
|
||||
noLanguageSubtype = new RichInputMethodSubtype(rawNoLanguageSubtype);
|
||||
}
|
||||
}
|
||||
|
||||
if (noLanguageSubtype != null) {
|
||||
sNoLanguageSubtype = noLanguageSubtype;
|
||||
return noLanguageSubtype;
|
||||
@ -230,14 +223,7 @@ public class RichInputMethodSubtype {
|
||||
@Nonnull
|
||||
public static RichInputMethodSubtype getEmojiSubtype() {
|
||||
RichInputMethodSubtype emojiSubtype = sEmojiSubtype;
|
||||
if (emojiSubtype == null) {
|
||||
final InputMethodSubtype rawEmojiSubtype = RichInputMethodManager.getInstance()
|
||||
.findSubtypeByLocaleAndKeyboardLayoutSet(
|
||||
SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI);
|
||||
if (rawEmojiSubtype != null) {
|
||||
emojiSubtype = new RichInputMethodSubtype(rawEmojiSubtype);
|
||||
}
|
||||
}
|
||||
|
||||
if (emojiSubtype != null) {
|
||||
sEmojiSubtype = emojiSubtype;
|
||||
return emojiSubtype;
|
||||
|
@ -1,26 +1,256 @@
|
||||
package org.futo.inputmethod.latin
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.view.inputmethod.InputMethodSubtype
|
||||
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
||||
import okhttp3.internal.toImmutableList
|
||||
import org.futo.inputmethod.latin.common.Constants
|
||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||
import org.futo.inputmethod.latin.uix.setSetting
|
||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||
import org.futo.inputmethod.latin.uix.setSettingBlocking
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItem
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
|
||||
import org.futo.inputmethod.latin.uix.settings.SettingsActivity
|
||||
import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
|
||||
import org.futo.inputmethod.latin.uix.theme.Typography
|
||||
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
|
||||
import java.util.Locale
|
||||
|
||||
val SubtypesSetting = SettingsKey(
|
||||
stringSetPreferencesKey("subtypes"),
|
||||
setOf()
|
||||
)
|
||||
|
||||
suspend fun Context.saveSubtypes() {
|
||||
val inputMethodManager = getSystemService(android.inputmethodservice.InputMethodService.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
val inputMethodList = inputMethodManager.getEnabledInputMethodSubtypeList(
|
||||
RichInputMethodManager.getInstance().inputMethodInfoOfThisIme,
|
||||
true
|
||||
)
|
||||
val ActiveSubtype = SettingsKey(
|
||||
stringPreferencesKey("activeSubtype"),
|
||||
""
|
||||
)
|
||||
|
||||
val encodedSubtypes = inputMethodList.map {
|
||||
it.locale + ":" + (it.extraValue ?: "") + ":" + it.languageTag
|
||||
}.toSet()
|
||||
object Subtypes {
|
||||
fun convertToSubtype(string: String): InputMethodSubtype {
|
||||
val splits = string.split(":")
|
||||
val locale = splits[0]
|
||||
|
||||
setSetting(SubtypesSetting, encodedSubtypes)
|
||||
val extraValue = splits.getOrNull(1) ?: ""
|
||||
val languageTag = splits.getOrNull(2) ?: ""
|
||||
|
||||
return InputMethodSubtypeBuilder()
|
||||
.setSubtypeLocale(locale)
|
||||
.setSubtypeExtraValue(extraValue)
|
||||
.setLanguageTag(languageTag)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun getActiveSubtype(context: Context): InputMethodSubtype {
|
||||
val activeSubtype = context.getSettingBlocking(ActiveSubtype).ifEmpty {
|
||||
context.getSettingBlocking(SubtypesSetting).firstOrNull() ?: "en_US:"
|
||||
}
|
||||
|
||||
return convertToSubtype(activeSubtype)
|
||||
}
|
||||
|
||||
fun hasMultipleEnabledSubtypes(context: Context): Boolean {
|
||||
return context.getSettingBlocking(SubtypesSetting).size > 1
|
||||
}
|
||||
|
||||
fun subtypeToString(subtype: InputMethodSubtype): String {
|
||||
return subtype.locale + ":" + (subtype.extraValue ?: "") + ":" + subtype.languageTag
|
||||
}
|
||||
|
||||
fun removeLanguage(context: Context, entry: InputMethodSubtype) {
|
||||
val value = subtypeToString(entry)
|
||||
val currentSetting = context.getSettingBlocking(SubtypesSetting)
|
||||
|
||||
context.setSettingBlocking(SubtypesSetting.key, currentSetting.filter { it != value && it != value.replace("::", ":") }.toSet())
|
||||
|
||||
if(context.getSettingBlocking(ActiveSubtype) == value) {
|
||||
context.setSettingBlocking(ActiveSubtype.key, currentSetting.find {
|
||||
it != value
|
||||
} ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
fun addLanguage(context: Context, language: Locale, layout: String) {
|
||||
val value = subtypeToString(
|
||||
InputMethodSubtypeBuilder()
|
||||
.setSubtypeLocale(language.toString())
|
||||
.setSubtypeExtraValue("KeyboardLayoutSet=$layout")
|
||||
.build()
|
||||
)
|
||||
val currentSetting = context.getSettingBlocking(SubtypesSetting)
|
||||
|
||||
context.setSettingBlocking(SubtypesSetting.key, currentSetting + setOf(value))
|
||||
}
|
||||
|
||||
fun getName(inputMethodSubtype: InputMethodSubtype): String {
|
||||
return SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(inputMethodSubtype)
|
||||
}
|
||||
|
||||
fun getNameForLocale(locale: String): String {
|
||||
return getName(InputMethodSubtypeBuilder().setSubtypeLocale(locale).build())
|
||||
}
|
||||
|
||||
fun getLocale(locale: String): Locale {
|
||||
return Locale.forLanguageTag(locale.replace("_", "-"))
|
||||
}
|
||||
|
||||
fun getLocale(inputMethodSubtype: InputMethodSubtype): Locale {
|
||||
return getLocale(inputMethodSubtype.locale)
|
||||
}
|
||||
|
||||
fun getLayoutName(context: Context, layout: String): String {
|
||||
val resourceId = context.resources.getIdentifier("layout_$layout", "string", context.packageName)
|
||||
if(resourceId == 0){
|
||||
return layout
|
||||
} else {
|
||||
return context.getString(resourceId)
|
||||
}
|
||||
}
|
||||
|
||||
fun layoutsMappedByLanguage(layouts: Set<String>): Map<String, List<InputMethodSubtype>> {
|
||||
val subtypes = layouts.map {
|
||||
convertToSubtype(it)
|
||||
}
|
||||
|
||||
return HashMap<String, MutableList<InputMethodSubtype>>().apply {
|
||||
subtypes.forEach {
|
||||
val list = this.getOrPut(it.locale) { mutableListOf() }
|
||||
list.add(it)
|
||||
}
|
||||
}.mapValues { it.value.toImmutableList() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun LanguageSwitcherDialog(
|
||||
onDismiss: () -> Unit = { }
|
||||
) {
|
||||
val inspection = LocalInspectionMode.current
|
||||
val context = LocalContext.current
|
||||
val subtypeSet = if(inspection) {
|
||||
setOf("en_US:", "pt_PT:", "lt:", "fr:KeyboardLayoutSet=bepo:")
|
||||
} else {
|
||||
useDataStoreValueBlocking(SubtypesSetting)
|
||||
}
|
||||
|
||||
val subtypes = remember(subtypeSet) {
|
||||
Subtypes.layoutsMappedByLanguage(subtypeSet)
|
||||
}
|
||||
|
||||
val keys = remember(subtypes) { subtypes.keys.toList().sorted() }
|
||||
|
||||
val activeSubtype = if(inspection) {
|
||||
"pt_PT:"
|
||||
} else {
|
||||
useDataStoreValueBlocking(ActiveSubtype)
|
||||
}
|
||||
|
||||
Surface(shape = RoundedCornerShape(48.dp), color = MaterialTheme.colorScheme.background) {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
"Select language",
|
||||
textAlign = TextAlign.Center,
|
||||
style = Typography.titleLarge,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(0.dp, 16.dp)
|
||||
)
|
||||
|
||||
LazyColumn(modifier = Modifier.weight(1.0f)) {
|
||||
items(keys) { locale ->
|
||||
|
||||
subtypes[locale]!!.forEach { subtype ->
|
||||
val layout = Subtypes.getLayoutName(context,
|
||||
subtype.getExtraValueOf(Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET) ?: ""
|
||||
)
|
||||
|
||||
val title = if(inspection) { subtype.locale } else { Subtypes.getName(subtype) }
|
||||
|
||||
val selected = activeSubtype == Subtypes.subtypeToString(subtype)
|
||||
|
||||
val item = @Composable {
|
||||
NavigationItem(
|
||||
title = title,
|
||||
subtitle = layout.ifBlank { null },
|
||||
style = NavigationItemStyle.MiscNoArrow,
|
||||
navigate = {
|
||||
context.setSettingBlocking(ActiveSubtype.key, Subtypes.subtypeToString(subtype))
|
||||
onDismiss()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
Surface(color = MaterialTheme.colorScheme.primary) {
|
||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimary) {
|
||||
item()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(modifier = Modifier.height(64.dp)) {
|
||||
Spacer(modifier = Modifier.weight(1.0f))
|
||||
TextButton(onClick = {
|
||||
val inputMethodManager =
|
||||
context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.showInputMethodPicker()
|
||||
|
||||
onDismiss()
|
||||
}) {
|
||||
Text("Switch Keyboard")
|
||||
}
|
||||
TextButton(onClick = {
|
||||
val intent = Intent()
|
||||
intent.setClass(context, SettingsActivity::class.java)
|
||||
intent.setFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
)
|
||||
intent.putExtra("navDest", "languages")
|
||||
context.startActivity(intent)
|
||||
|
||||
onDismiss()
|
||||
}) {
|
||||
Text("Languages")
|
||||
}
|
||||
Spacer(modifier = Modifier.width(32.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -59,12 +59,6 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
|
||||
final String intentAction = intent.getAction();
|
||||
if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
|
||||
Log.i(TAG, "Package has been replaced: " + context.getPackageName());
|
||||
// Need to restore additional subtypes because system always clears additional
|
||||
// subtypes when the package is replaced.
|
||||
RichInputMethodManager.init(context);
|
||||
final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
|
||||
final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes();
|
||||
richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
|
||||
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
|
||||
Log.i(TAG, "Boot has been completed");
|
||||
} else if (Intent.ACTION_LOCALE_CHANGED.equals(intentAction)) {
|
||||
|
@ -38,7 +38,8 @@ import org.futo.inputmethod.latin.Dictionary
|
||||
import org.futo.inputmethod.latin.LatinIMELegacy
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.ReadOnlyBinaryDictionary
|
||||
import org.futo.inputmethod.latin.RichInputMethodManager
|
||||
import org.futo.inputmethod.latin.Subtypes
|
||||
import org.futo.inputmethod.latin.SubtypesSetting
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItem
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
||||
@ -68,13 +69,16 @@ data class InputLanguage(
|
||||
)
|
||||
|
||||
fun getActiveLanguages(context: Context): List<InputLanguage> {
|
||||
RichInputMethodManager.init(context)
|
||||
|
||||
return RichInputMethodManager.getInstance().getMyEnabledInputMethodSubtypeList(true).map {
|
||||
val name = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(it)
|
||||
|
||||
InputLanguage(it.locale, name, it)
|
||||
}.toList()
|
||||
SubtypeLocaleUtils.init(context)
|
||||
return context.getSettingBlocking(SubtypesSetting)
|
||||
.let { Subtypes.layoutsMappedByLanguage(it) }
|
||||
.map {
|
||||
InputLanguage(
|
||||
it.value.first().locale,
|
||||
Subtypes.getName(it.value.first()),
|
||||
it.value.first()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,6 +46,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.futo.inputmethod.latin.AudioAndHapticFeedbackManager
|
||||
import org.futo.inputmethod.latin.BuildConfig
|
||||
import org.futo.inputmethod.latin.LanguageSwitcherDialog
|
||||
import org.futo.inputmethod.latin.LatinIME
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.SuggestedWords
|
||||
@ -57,6 +58,7 @@ import org.futo.inputmethod.latin.uix.actions.ActionRegistry
|
||||
import org.futo.inputmethod.latin.uix.actions.EmojiAction
|
||||
import org.futo.inputmethod.latin.uix.settings.SettingsActivity
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
import org.futo.inputmethod.latin.uix.theme.UixThemeAuto
|
||||
import org.futo.inputmethod.latin.uix.theme.UixThemeWrapper
|
||||
import org.futo.inputmethod.updates.DISABLE_UPDATE_REMINDER
|
||||
import org.futo.inputmethod.updates.autoDeferManualUpdateIfNeeded
|
||||
@ -66,7 +68,6 @@ import org.futo.inputmethod.updates.openManualUpdateCheck
|
||||
import org.futo.inputmethod.updates.retrieveSavedLastUpdateCheckResult
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
private class LatinIMEActionInputTransaction(
|
||||
private val inputLogic: InputLogic,
|
||||
shouldApplySpace: Boolean,
|
||||
@ -334,13 +335,13 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
}
|
||||
}
|
||||
|
||||
val wordBeingForgotten: MutableState<SuggestedWordInfo?> = mutableStateOf(null)
|
||||
val forgetWordDismissed: MutableState<Boolean> = mutableStateOf(true)
|
||||
private val wordBeingForgotten: MutableState<SuggestedWordInfo?> = mutableStateOf(null)
|
||||
private val forgetWordDismissed: MutableState<Boolean> = mutableStateOf(true)
|
||||
|
||||
@Composable
|
||||
fun BoxScope.ForgetWordDialog() {
|
||||
AnimatedVisibility(
|
||||
visible = forgetWordDismissed.value == false,
|
||||
visible = !forgetWordDismissed.value,
|
||||
modifier = Modifier.matchParentSize(),
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
@ -349,11 +350,13 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
Box(modifier = Modifier.matchParentSize()) {
|
||||
Surface(
|
||||
color = Color.Black.copy(alpha = 0.66f),
|
||||
modifier = Modifier.matchParentSize().pointerInput(Unit) {
|
||||
this.detectTapGestures(onPress = {
|
||||
forgetWordDismissed.value = true
|
||||
})
|
||||
}
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.pointerInput(Unit) {
|
||||
this.detectTapGestures(onPress = {
|
||||
forgetWordDismissed.value = true
|
||||
})
|
||||
}
|
||||
) { }
|
||||
|
||||
Surface(
|
||||
@ -405,6 +408,23 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
}
|
||||
}
|
||||
|
||||
private var languageSwitcherDialog: DialogComposeView? = null
|
||||
fun showLanguageSwitcher() {
|
||||
// Dismiss old dialog
|
||||
languageSwitcherDialog?.dismiss()
|
||||
|
||||
// Create new dialog
|
||||
languageSwitcherDialog = createDialogComposeView(latinIME) {
|
||||
UixThemeAuto {
|
||||
LanguageSwitcherDialog(
|
||||
onDismiss = { it.dismiss() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
languageSwitcherDialog?.show()
|
||||
}
|
||||
|
||||
fun setContent() {
|
||||
composeView?.setContent {
|
||||
UixThemeWrapper(latinIME.colorScheme) {
|
||||
@ -522,6 +542,7 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
|
||||
fun onInputFinishing() {
|
||||
closeActionWindow()
|
||||
languageSwitcherDialog?.dismiss()
|
||||
}
|
||||
|
||||
fun cleanUpPersistentStates() {
|
||||
|
@ -1,8 +1,20 @@
|
||||
package org.futo.inputmethod.latin.uix
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.lifecycle.setViewTreeLifecycleOwner
|
||||
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
||||
import org.futo.inputmethod.latin.LatinIME
|
||||
import org.futo.inputmethod.latin.R
|
||||
import java.net.URLDecoder
|
||||
import java.net.URLEncoder
|
||||
|
||||
@ -29,4 +41,71 @@ fun String.urlEncode(): String {
|
||||
|
||||
fun String.urlDecode(): String {
|
||||
return URLDecoder.decode(this, "utf-8")
|
||||
}
|
||||
|
||||
|
||||
// This ugly workaround is required as Android Compose freaks out when you use a Dialog outside of
|
||||
// an activity (i.e. in an input method service)
|
||||
data class DialogComposeView(
|
||||
val dialog: Dialog,
|
||||
val composeView: ComposeView
|
||||
)
|
||||
|
||||
fun createDialogComposeView(
|
||||
latinIME: LatinIME,
|
||||
maxWidthProportion: Float = 0.9f,
|
||||
maxHeightProportion: Float = 0.75f,
|
||||
dimAmount: Float = 0.5f,
|
||||
onDismiss: () -> Unit = { },
|
||||
content: @Composable (Dialog) -> Unit,
|
||||
): DialogComposeView {
|
||||
val context: Context = latinIME
|
||||
|
||||
val composeView = ComposeView(context)
|
||||
|
||||
val dialog = Dialog(context).apply {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(composeView)
|
||||
|
||||
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
setOnDismissListener {
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
val window = dialog.window
|
||||
window?.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM or WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
||||
window?.attributes?.token = latinIME.latinIMELegacy.mKeyboardSwitcher.mainKeyboardView.windowToken
|
||||
window?.attributes?.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG
|
||||
|
||||
window?.apply {
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
val width = displayMetrics.widthPixels
|
||||
val height = displayMetrics.heightPixels
|
||||
|
||||
val maxWidth = (width * maxWidthProportion).toInt()
|
||||
val maxHeight = (height * maxHeightProportion).toInt()
|
||||
|
||||
setLayout(maxWidth, maxHeight)
|
||||
setGravity(Gravity.CENTER)
|
||||
|
||||
setBackgroundDrawable(AppCompatResources.getDrawable(context, R.drawable.empty))
|
||||
setDimAmount(dimAmount)
|
||||
}
|
||||
|
||||
composeView.setViewTreeLifecycleOwner(latinIME)
|
||||
composeView.setViewTreeSavedStateRegistryOwner(latinIME)
|
||||
|
||||
composeView.setContent { content(dialog) }
|
||||
|
||||
return DialogComposeView(dialog, composeView)
|
||||
}
|
||||
|
||||
fun DialogComposeView.show() {
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
fun DialogComposeView.dismiss() {
|
||||
dialog.dismiss()
|
||||
}
|
@ -20,6 +20,7 @@ val AllActions = listOf(
|
||||
RedoAction,
|
||||
VoiceInputAction,
|
||||
SystemVoiceInputAction,
|
||||
SwitchLanguageAction
|
||||
)
|
||||
|
||||
|
||||
@ -70,7 +71,8 @@ val DefaultActions = listOf(
|
||||
ClipboardAction,
|
||||
SettingsAction,
|
||||
ThemeAction,
|
||||
MemoryDebugAction
|
||||
MemoryDebugAction,
|
||||
SwitchLanguageAction
|
||||
)
|
||||
|
||||
val DefaultActionsString = ActionRegistry.actionsToString(DefaultActions)
|
||||
|
@ -0,0 +1,32 @@
|
||||
package org.futo.inputmethod.latin.uix.actions
|
||||
|
||||
import android.content.Context
|
||||
import org.futo.inputmethod.latin.ActiveSubtype
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.SubtypesSetting
|
||||
import org.futo.inputmethod.latin.uix.Action
|
||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||
import org.futo.inputmethod.latin.uix.setSettingBlocking
|
||||
|
||||
fun switchToNextLanguage(context: Context) {
|
||||
val enabledSubtypes = context.getSettingBlocking(SubtypesSetting).toList()
|
||||
val currentSubtype = context.getSettingBlocking(ActiveSubtype)
|
||||
|
||||
val index = enabledSubtypes.indexOf(currentSubtype)
|
||||
val nextIndex = if(index == -1) {
|
||||
0
|
||||
} else {
|
||||
(index + 1) % enabledSubtypes.size
|
||||
}
|
||||
|
||||
context.setSettingBlocking(ActiveSubtype.key, enabledSubtypes[nextIndex])
|
||||
}
|
||||
|
||||
val SwitchLanguageAction = Action(
|
||||
icon = R.drawable.globe,
|
||||
name = R.string.show_language_switch_key,
|
||||
simplePressImpl = { manager, _ ->
|
||||
switchToNextLanguage(manager.getContext())
|
||||
},
|
||||
windowImpl = null,
|
||||
)
|
@ -23,6 +23,10 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.ArrowForward
|
||||
import androidx.compose.material.icons.filled.Send
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
@ -539,3 +543,64 @@ fun SettingTextField(title: String, placeholder: String, field: SettingsKey<Stri
|
||||
.padding(8.dp, 4.dp),
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun<T> DropDownPicker(
|
||||
label: String,
|
||||
options: List<T>,
|
||||
selection: T?,
|
||||
onSet: (T) -> Unit,
|
||||
getDisplayName: (T) -> String,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = {
|
||||
expanded = !expanded
|
||||
},
|
||||
modifier = modifier
|
||||
) {
|
||||
TextField(
|
||||
readOnly = true,
|
||||
value = selection?.let(getDisplayName) ?: "None",
|
||||
onValueChange = { },
|
||||
label = if (label.isNotBlank()) {
|
||||
{ Text(label) }
|
||||
} else {
|
||||
null
|
||||
},
|
||||
trailingIcon = {
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(
|
||||
expanded = expanded
|
||||
)
|
||||
},
|
||||
colors = ExposedDropdownMenuDefaults.textFieldColors(
|
||||
focusedLabelColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
focusedLeadingIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
focusedIndicatorColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
focusedTrailingIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
),
|
||||
modifier = Modifier.menuAnchor()
|
||||
)
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = {
|
||||
expanded = false
|
||||
}
|
||||
) {
|
||||
options.forEach { selectionOption ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(getDisplayName(selectionOption))
|
||||
},
|
||||
onClick = {
|
||||
onSet(selectionOption)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import androidx.navigation.compose.rememberNavController
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.uix.ErrorDialog
|
||||
import org.futo.inputmethod.latin.uix.InfoDialog
|
||||
import org.futo.inputmethod.latin.uix.settings.pages.AddLanguageScreen
|
||||
import org.futo.inputmethod.latin.uix.settings.pages.AdvancedParametersScreen
|
||||
import org.futo.inputmethod.latin.uix.settings.pages.BlacklistScreen
|
||||
import org.futo.inputmethod.latin.uix.settings.pages.CreditsScreen
|
||||
@ -49,6 +50,7 @@ fun SettingsNavigator(
|
||||
) {
|
||||
composable("home") { HomeScreen(navController) }
|
||||
composable("languages") { LanguagesScreen(navController) }
|
||||
composable("addLanguage") { AddLanguageScreen(navController) }
|
||||
composable("predictiveText") { PredictiveTextScreen(navController) }
|
||||
composable("advancedparams") { AdvancedParametersScreen(navController) }
|
||||
composable("typing") { TypingScreen(navController) }
|
||||
|
@ -0,0 +1,160 @@
|
||||
package org.futo.inputmethod.latin.uix.settings.pages
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import org.futo.inputmethod.latin.Subtypes
|
||||
import org.futo.inputmethod.latin.uix.settings.DropDownPicker
|
||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||
import org.futo.inputmethod.latin.uix.settings.SettingItem
|
||||
|
||||
val QwertyVariants = listOf("qwerty", "qwertz", "dvorak", "azerty", "colemak", "bepo", "pcqwerty")
|
||||
|
||||
val locales = mapOf(
|
||||
"af" to listOf("qwerty"),
|
||||
"ar" to listOf("arabic"),
|
||||
"az_AZ" to listOf("qwerty"),
|
||||
"be_BY" to listOf("east_slavic"),
|
||||
"bg" to listOf("bulgarian"),
|
||||
"bg" to listOf("bulgarian_bds"),
|
||||
"bn_BD" to listOf("bengali_akkhor"),
|
||||
"bn_IN" to listOf("bengali"),
|
||||
"ca" to listOf("spanish"),
|
||||
"cs" to listOf("qwertz"),
|
||||
"da" to listOf("nordic"),
|
||||
"de" to listOf("qwertz"),
|
||||
"de_CH" to listOf("swiss"),
|
||||
"el" to listOf("greek"),
|
||||
"en_IN" to listOf("qwerty"),
|
||||
"en_US" to QwertyVariants,
|
||||
"en_GB" to QwertyVariants,
|
||||
"eo" to listOf("spanish"),
|
||||
"es" to listOf("spanish"),
|
||||
"es_US" to listOf("spanish"),
|
||||
"es_419" to listOf("spanish"),
|
||||
"et_EE" to listOf("nordic"),
|
||||
"eu_ES" to listOf("spanish"),
|
||||
"fa" to listOf("farsi"),
|
||||
"fi" to listOf("nordic"),
|
||||
"fr" to listOf("azerty", "qwerty", "swiss", "bepo"),
|
||||
"fr_CA" to listOf("qwerty", "azerty", "swiss", "bepo"),
|
||||
"fr_CH" to listOf("swiss", "qwerty", "azerty", "bepo"),
|
||||
"gl_ES" to listOf("spanish"),
|
||||
"hi" to listOf("hindi", "hindi_compact"),
|
||||
//"hi_ZZ" to listOf("qwerty"),
|
||||
"hr" to listOf("qwertz"),
|
||||
"hu" to listOf("qwertz"),
|
||||
"hy_AM" to listOf("armenian_phonetic"),
|
||||
"in" to listOf("qwerty"),
|
||||
"is" to listOf("qwerty"),
|
||||
"it" to listOf("qwerty"),
|
||||
"it_CH" to listOf("swiss"),
|
||||
"iw" to listOf("hebrew"),
|
||||
"ka_GE" to listOf("georgian"),
|
||||
"kk" to listOf("east_slavic"),
|
||||
"km_KH" to listOf("khmer"),
|
||||
"kn_IN" to listOf("kannada"),
|
||||
"ky" to listOf("east_slavic"),
|
||||
"lo_LA" to listOf("lao"),
|
||||
"lt" to listOf("qwerty"),
|
||||
"lv" to listOf("qwerty"),
|
||||
"mk" to listOf("south_slavic"),
|
||||
"ml_IN" to listOf("malayalam"),
|
||||
"mn_MN" to listOf("mongolian"),
|
||||
"mr_IN" to listOf("marathi"),
|
||||
"ms_MY" to listOf("qwerty"),
|
||||
"nb" to listOf("nordic"),
|
||||
"ne_NP" to listOf("nepali_romanized", "nepali_traditional"),
|
||||
"nl" to listOf("qwerty"),
|
||||
"nl_BE" to listOf("azerty"),
|
||||
"pl" to listOf("qwerty"),
|
||||
"pt_BR" to listOf("qwerty"),
|
||||
"pt_PT" to listOf("qwerty"),
|
||||
"ro" to listOf("qwerty"),
|
||||
"ru" to listOf("east_slavic"),
|
||||
"si_LK" to listOf("sinhala"),
|
||||
"sk" to listOf("qwerty"),
|
||||
"sl" to listOf("qwerty"),
|
||||
"sr" to listOf("south_slavic"),
|
||||
"sr_ZZ" to listOf("serbian_qwertz"),
|
||||
"sv" to listOf("nordic"),
|
||||
"sw" to listOf("qwerty"),
|
||||
"ta_IN" to listOf("tamil"),
|
||||
"ta_LK" to listOf("tamil"),
|
||||
"ta_SG" to listOf("tamil"),
|
||||
"te_IN" to listOf("telugu"),
|
||||
"th" to listOf("thai"),
|
||||
"tl" to listOf("spanish"),
|
||||
"tr" to listOf("qwerty"),
|
||||
"uk" to listOf("east_slavic"),
|
||||
"uz_UZ" to listOf("uzbek"),
|
||||
"vi" to listOf("qwerty"),
|
||||
"zu" to listOf("qwerty"),
|
||||
"zz" to listOf("qwerty"),
|
||||
)
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AddLanguageScreen(navController: NavHostController = rememberNavController()) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val selectedLocale: MutableState<String> = remember { mutableStateOf(context.resources.configuration.locale.toString()) }
|
||||
val selectedLayout: MutableState<String> = remember { mutableStateOf("qwerty") }
|
||||
|
||||
val keys = remember { locales.keys.toList() }
|
||||
ScrollableList {
|
||||
ScreenTitle("Add Language", showBack = true, navController)
|
||||
|
||||
SettingItem(title = "Language") {
|
||||
DropDownPicker(
|
||||
"",
|
||||
keys,
|
||||
selectedLocale.value,
|
||||
{
|
||||
selectedLocale.value = it
|
||||
selectedLayout.value = locales[it]!!.first()
|
||||
},
|
||||
{
|
||||
Subtypes.getNameForLocale(it)
|
||||
},
|
||||
modifier = Modifier.width(180.dp)
|
||||
)
|
||||
}
|
||||
|
||||
SettingItem(title = "Layout") {
|
||||
DropDownPicker(
|
||||
"",
|
||||
locales[selectedLocale.value] ?: listOf(),
|
||||
selectedLayout.value,
|
||||
{ selectedLayout.value = it },
|
||||
{ Subtypes.getLayoutName(context, it) },
|
||||
modifier = Modifier.width(180.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Button(onClick = {
|
||||
Subtypes.addLanguage(
|
||||
context,
|
||||
Subtypes.getLocale(selectedLocale.value),
|
||||
selectedLayout.value
|
||||
)
|
||||
|
||||
navController.navigateUp()
|
||||
}, modifier = Modifier.fillMaxWidth().padding(16.dp)) {
|
||||
Text("Add")
|
||||
}
|
||||
}
|
||||
}
|
@ -52,6 +52,11 @@ fun CreditsScreen(navController: NavHostController = rememberNavController()) {
|
||||
modifier = Modifier.clickable {
|
||||
context.openURI("https://github.com/gkonovalov/android-vad")
|
||||
})
|
||||
|
||||
ParagraphText("Some keyboard layouts were taken from the CyanogenMod/LineageOS fork of the LatinIME keyboard. Their fork is Apache-2.0 licensed. Copyright (C) 2015 The CyanogenMod Project",
|
||||
modifier = Modifier.clickable {
|
||||
context.openURI("https://github.com/LineageOS/android_packages_inputmethods_LatinIME")
|
||||
})
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
ParagraphText("Note: The authors listed above are not affiliated with us and do not endorse or promote us")
|
||||
|
@ -1,32 +1,39 @@
|
||||
package org.futo.inputmethod.latin.uix.settings.pages
|
||||
|
||||
import android.content.Context
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.internal.toImmutableList
|
||||
import org.futo.inputmethod.latin.BinaryDictionaryGetter
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.RichInputMethodManager
|
||||
import org.futo.inputmethod.latin.saveSubtypes
|
||||
import org.futo.inputmethod.latin.Subtypes
|
||||
import org.futo.inputmethod.latin.SubtypesSetting
|
||||
import org.futo.inputmethod.latin.common.Constants
|
||||
import org.futo.inputmethod.latin.uix.FileKind
|
||||
import org.futo.inputmethod.latin.uix.ResourceHelper
|
||||
import org.futo.inputmethod.latin.uix.getSetting
|
||||
@ -35,10 +42,10 @@ import org.futo.inputmethod.latin.uix.settings.NavigationItem
|
||||
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
|
||||
import org.futo.inputmethod.latin.uix.settings.ScrollableList
|
||||
import org.futo.inputmethod.latin.uix.settings.Tip
|
||||
import org.futo.inputmethod.latin.uix.settings.openLanguageSettings
|
||||
import org.futo.inputmethod.latin.uix.settings.SettingItem
|
||||
import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
|
||||
import org.futo.inputmethod.latin.uix.theme.Typography
|
||||
import org.futo.inputmethod.latin.uix.youAreImporting
|
||||
import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
|
||||
import org.futo.inputmethod.latin.xlm.ModelPaths
|
||||
import org.futo.inputmethod.updates.openURI
|
||||
import java.util.Locale
|
||||
@ -101,27 +108,12 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
||||
val context = LocalContext.current
|
||||
val deleteDialogInfo: MutableState<DeleteInfo?> = remember { mutableStateOf(null) }
|
||||
|
||||
val inputMethodManager = remember { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
|
||||
val inputMethodList = remember { mutableStateOf(
|
||||
inputMethodManager.getEnabledInputMethodSubtypeList(
|
||||
RichInputMethodManager.getInstance().inputMethodInfoOfThisIme,
|
||||
true
|
||||
).toImmutableList()
|
||||
) }
|
||||
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
|
||||
|
||||
LaunchedEffect(lifecycleState) {
|
||||
delay(250L)
|
||||
inputMethodList.value = inputMethodManager.getEnabledInputMethodSubtypeList(
|
||||
RichInputMethodManager.getInstance().inputMethodInfoOfThisIme,
|
||||
true
|
||||
)
|
||||
|
||||
context.saveSubtypes()
|
||||
val inputMethods = useDataStoreValueBlocking(SubtypesSetting)
|
||||
val inputMethodList = remember(inputMethods) {
|
||||
Subtypes.layoutsMappedByLanguage(inputMethods)
|
||||
}
|
||||
|
||||
val inputMethodKeys = remember(inputMethodList) { inputMethodList.keys.toList().sorted() }
|
||||
|
||||
if(deleteDialogInfo.value != null) {
|
||||
val info = deleteDialogInfo.value!!
|
||||
@ -139,17 +131,19 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
||||
ScreenTitle("Languages", showBack = true, navController)
|
||||
|
||||
NavigationItem(
|
||||
title = "Enable/disable languages",
|
||||
title = "Add language",
|
||||
style = NavigationItemStyle.Misc,
|
||||
navigate = { context.openLanguageSettings() },
|
||||
navigate = {
|
||||
navController.navigate("addLanguage")
|
||||
},
|
||||
)
|
||||
|
||||
Tip("Note: This screen is a WIP, use the above option to toggle languages")
|
||||
inputMethodKeys.forEach { localeString ->
|
||||
val subtypes = inputMethodList[localeString]!!
|
||||
|
||||
inputMethodList.value.forEach {
|
||||
val name = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(it)
|
||||
val locale = Subtypes.getLocale(localeString)
|
||||
|
||||
val locale = Locale.forLanguageTag(it.locale.replace("_", "-"))
|
||||
val name = Subtypes.getName(subtypes.first())
|
||||
|
||||
val voiceInputModelName = ResourceHelper.tryFindingVoiceInputModelForLocale(context, locale)?.name?.let { stringResource(it) }
|
||||
val dictionaryName = runBlocking { ResourceHelper.findKeyForLocaleAndKind(context, locale, FileKind.Dictionary) }?.let {
|
||||
@ -170,7 +164,36 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
||||
transformerModel = transformerName
|
||||
)
|
||||
|
||||
ScreenTitle(name)
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
Column(modifier = Modifier.align(Alignment.CenterVertically).padding(0.dp, 16.dp)) {
|
||||
Text(name, style = Typography.titleLarge)
|
||||
if(subtypes.size == 1) {
|
||||
val layout = Subtypes.getLayoutName(context,
|
||||
subtypes.first().getExtraValueOf(Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET) ?: ""
|
||||
)
|
||||
|
||||
Text(layout,
|
||||
style = Typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.outline)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1.0f))
|
||||
|
||||
if(subtypes.size == 1) {
|
||||
IconButton(modifier = Modifier.fillMaxHeight().align(Alignment.CenterVertically), onClick = {
|
||||
Subtypes.removeLanguage(context, subtypes.first())
|
||||
}) {
|
||||
Icon(
|
||||
Icons.Default.Clear,
|
||||
contentDescription = "Remove language",
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NavigationItem(
|
||||
title = options.voiceInputModel ?: "None",
|
||||
@ -208,6 +231,25 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
|
||||
},
|
||||
icon = painterResource(id = R.drawable.cpu)
|
||||
)
|
||||
if(subtypes.size > 1) {
|
||||
subtypes.forEach {
|
||||
val layout = Subtypes.getLayoutName(
|
||||
context,
|
||||
it.getExtraValueOf(Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET)
|
||||
)
|
||||
SettingItem(title = "Layout $layout") {
|
||||
IconButton(modifier = Modifier.fillMaxHeight(), onClick = {
|
||||
Subtypes.removeLanguage(context, it)
|
||||
}) {
|
||||
Icon(
|
||||
Icons.Default.Clear,
|
||||
contentDescription = "Remove layout $layout",
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -574,17 +574,6 @@ public class DictionaryInfoUtils {
|
||||
addOrUpdateDictInfo(dictList, dictionaryInfo);
|
||||
}
|
||||
|
||||
// Generate the dictionary information from the enabled subtypes. This will not
|
||||
// overwrite the real records.
|
||||
RichInputMethodManager.init(context);
|
||||
List<InputMethodSubtype> enabledSubtypes = RichInputMethodManager
|
||||
.getInstance().getMyEnabledInputMethodSubtypeList(true);
|
||||
for (InputMethodSubtype subtype : enabledSubtypes) {
|
||||
Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale());
|
||||
DictionaryInfo dictionaryInfo = createDictionaryInfoFromLocale(locale);
|
||||
addOrUpdateDictInfo(dictList, dictionaryInfo);
|
||||
}
|
||||
|
||||
return dictList;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import android.util.Log;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
|
||||
import org.futo.inputmethod.latin.R;
|
||||
import org.futo.inputmethod.latin.Subtypes;
|
||||
import org.futo.inputmethod.latin.common.LocaleUtils;
|
||||
import org.futo.inputmethod.latin.common.StringUtils;
|
||||
|
||||
@ -286,6 +287,19 @@ public final class SubtypeLocaleUtils {
|
||||
final String replacementString = getReplacementString(subtype, displayLocale);
|
||||
// TODO: rework this for multi-lingual subtypes
|
||||
final int nameResId = subtype.getNameResId();
|
||||
|
||||
if(nameResId == 0) {
|
||||
if(replacementString.isEmpty()) {
|
||||
return StringUtils.capitalizeFirstCodePoint(
|
||||
Subtypes.INSTANCE.getLocale(subtype).getDisplayName(displayLocale),
|
||||
displayLocale);
|
||||
} else {
|
||||
return StringUtils.capitalizeFirstCodePoint(
|
||||
replacementString,
|
||||
displayLocale);
|
||||
}
|
||||
}
|
||||
|
||||
final RunInLocale<String> getSubtypeName = new RunInLocale<String>() {
|
||||
@Override
|
||||
protected String job(final Resources res) {
|
||||
|
Loading…
Reference in New Issue
Block a user