diff options
66 files changed, 866 insertions, 698 deletions
diff --git a/dictionaries/es_wordlist.combined.gz b/dictionaries/es_wordlist.combined.gz Binary files differindex 181a958c0..c0a5264fc 100644 --- a/dictionaries/es_wordlist.combined.gz +++ b/dictionaries/es_wordlist.combined.gz diff --git a/java/res/layout/dictionary_line.xml b/java/res/layout/dictionary_line.xml index 7268cd468..bb1843d6c 100644 --- a/java/res/layout/dictionary_line.xml +++ b/java/res/layout/dictionary_line.xml @@ -42,7 +42,7 @@ android:orientation="vertical"> <TextView - android:id="@+android:id/title" + android:id="@android:id/title" android:layout_marginLeft="5dip" android:layout_marginStart="5dip" android:layout_width="wrap_content" @@ -59,7 +59,7 @@ android:layout_marginLeft="5dip"> <TextView - android:id="@+android:id/summary" + android:id="@android:id/summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" @@ -77,14 +77,14 @@ </LinearLayout> <com.android.inputmethod.dictionarypack.ButtonSwitcher - android:id="@+android:id/wordlist_button_switcher" + android:id="@+id/wordlist_button_switcher" android:layout_weight="0" android:layout_marginStart="13dip" android:layout_marginLeft="13dip" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button - android:id="@+android:id/dict_install_button" + android:id="@+id/dict_install_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right|center_vertical" @@ -92,7 +92,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/install_dict" /> <Button - android:id="@+android:id/dict_cancel_button" + android:id="@+id/dict_cancel_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right|center_vertical" @@ -100,7 +100,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/cancel_download_dict" /> <Button - android:id="@+android:id/dict_delete_button" + android:id="@+id/dict_delete_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right|center_vertical" diff --git a/java/res/layout/key_preview.xml b/java/res/layout/key_preview.xml deleted file mode 100644 index 16d4c72c3..000000000 --- a/java/res/layout/key_preview.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2013, 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. -*/ ---> - -<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minWidth="32dp" - android:gravity="center" - style="?attr/keyPreviewTextViewStyle" -/> diff --git a/java/res/raw/main_es.dict b/java/res/raw/main_es.dict Binary files differindex 83eefe4f6..0911b70f1 100644 --- a/java/res/raw/main_es.dict +++ b/java/res/raw/main_es.dict diff --git a/java/res/values-km-rKH/strings-emoji-descriptions.xml b/java/res/values-km-rKH/strings-emoji-descriptions.xml index 757df50e7..9f1d9973e 100644 --- a/java/res/values-km-rKH/strings-emoji-descriptions.xml +++ b/java/res/values-km-rKH/strings-emoji-descriptions.xml @@ -25,16 +25,16 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="spoken_emoji_00A9" msgid="2859822817116803638">"សញ្ញារក្សាសិទ្ធ"</string> + <string name="spoken_emoji_00A9" msgid="2859822817116803638">"សញ្ញារក្សាសិទ្ធ"</string> <string name="spoken_emoji_00AE" msgid="7708335454134589027">"សញ្ញាចុះបញ្ជី"</string> <string name="spoken_emoji_203C" msgid="153340916701508663">"សញ្ញាឧទានពីរ"</string> - <string name="spoken_emoji_2049" msgid="4877256448299555371">"សញ្ញាឧទានសញ្ញាសួរ"</string> + <string name="spoken_emoji_2049" msgid="4877256448299555371">"សញ្ញាឧទានសញ្ញាសួរ"</string> <string name="spoken_emoji_2122" msgid="9188440722954720429">"សញ្ញានិក្ខិត្តសញ្ញា"</string> <string name="spoken_emoji_2139" msgid="9114342638917304327">"ប្រភពព័ត៌មាន"</string> <string name="spoken_emoji_2194" msgid="8055202727034946680">"ព្រួញឆ្វេងស្ដាំ"</string> <string name="spoken_emoji_2195" msgid="8028122253301087407">"ព្រួញឡើងលើចុះក្រោម"</string> <string name="spoken_emoji_2196" msgid="4019164898967854363">"ព្រួញទិសពាយព្យ"</string> - <string name="spoken_emoji_2197" msgid="4255723717709017801">"ព្រួញទិសឥសាន្តឦសាន្ត"</string> + <string name="spoken_emoji_2197" msgid="4255723717709017801">"ព្រួញទិសឥសាន្តឦសាន្ត"</string> <string name="spoken_emoji_2198" msgid="1452063451313622090">"ព្រួញទិសអាគ្នេយ៍"</string> <string name="spoken_emoji_2199" msgid="6942722693368807849">"ព្រួញទិសនិរតី"</string> <string name="spoken_emoji_21A9" msgid="5204750172335111188">"ព្រួញទៅឆ្វេងមានទំពក់"</string> @@ -45,7 +45,7 @@ <string name="spoken_emoji_23EA" msgid="2251396938087774944">"ត្រីកោណខ្មៅពីរចង្អុលទៅឆ្វេង"</string> <string name="spoken_emoji_23EB" msgid="3746885195641491865">"ត្រីកោណខ្មៅពីរចង្អុលឡើងលើ"</string> <string name="spoken_emoji_23EC" msgid="7852372752901163416">"ត្រីកោណខ្មៅពីរចង្អុលចុះក្រោម"</string> - <string name="spoken_emoji_23F0" msgid="8474219588750627870">"នាឡិការោទ៍"</string> + <string name="spoken_emoji_23F0" msgid="8474219588750627870">"នាឡិការោទ៍"</string> <string name="spoken_emoji_23F3" msgid="166900119581024371">"កែវពិសោធន៍មានខ្សាច់ហូរ"</string> <string name="spoken_emoji_24C2" msgid="3948348737566038470">"អក្សរអឹមធំក្នុងរង្វង់"</string> <string name="spoken_emoji_25AA" msgid="7865181015100227349">"ការ៉េតូចពណ៌ខ្មៅ"</string> @@ -195,7 +195,7 @@ <string name="spoken_emoji_1F312" msgid="4458575672576125401">"ព្រះចន្ទមួយចំណិតស្ដាំ"</string> <string name="spoken_emoji_1F313" msgid="7599181787989497294">"ព្រះចន្ទពាក់កណ្ដាល"</string> <string name="spoken_emoji_1F314" msgid="4898293184964365413">"ព្រះចន្ទមួយចំណិតឆ្វេង"</string> - <string name="spoken_emoji_1F315" msgid="3218117051779496309">"ព្រះចន្ទពេញវង់"</string> + <string name="spoken_emoji_1F315" msgid="3218117051779496309">"ព្រះចន្ទពេញវង់"</string> <string name="spoken_emoji_1F316" msgid="2061317145777689569">"ព្រះចន្ទភ្លឺមួយចំហៀង"</string> <string name="spoken_emoji_1F317" msgid="2721090687319539049">"ព្រះចន្ទភ្លឺពាក់កណ្ដាល"</string> <string name="spoken_emoji_1F318" msgid="3814091755648887570">"ព្រះចន្ទភ្លឺមួយចំណិតឆ្វេង"</string> @@ -262,7 +262,7 @@ <string name="spoken_emoji_1F365" msgid="4963815540953316307">"នំត្រីរាងមូល"</string> <string name="spoken_emoji_1F366" msgid="7862401745277049404">"ការ៉េមបំពង់"</string> <string name="spoken_emoji_1F367" msgid="7447972978281980414">"ការ៉េមកែវ"</string> - <string name="spoken_emoji_1F368" msgid="7790003146142724913">"ការ៉េម"</string> + <string name="spoken_emoji_1F368" msgid="7790003146142724913">"ការ៉េម"</string> <string name="spoken_emoji_1F369" msgid="7383712944084857350">"ដូណាត់"</string> <string name="spoken_emoji_1F36A" msgid="2726271795913042295">"ខូគី"</string> <string name="spoken_emoji_1F36B" msgid="6342163604299875931">"សូកូឡា"</string> @@ -280,7 +280,7 @@ <string name="spoken_emoji_1F377" msgid="1762398562314172075">"កែវស្រា"</string> <string name="spoken_emoji_1F378" msgid="5528234560590117516">"កែវស្រាក្រឡុក"</string> <string name="spoken_emoji_1F379" msgid="790581290787943325">"ភេសជ្ជៈត្រូពិក"</string> - <string name="spoken_emoji_1F37A" msgid="391966822450619516">"កែវស្រាបៀ"</string> + <string name="spoken_emoji_1F37A" msgid="391966822450619516">"កែវស្រាបៀ"</string> <string name="spoken_emoji_1F37B" msgid="9015043286465670662">"ជល់កែវស្រាបៀ"</string> <string name="spoken_emoji_1F37C" msgid="2532113819464508894">"ដបទឹកដោះគោ"</string> <string name="spoken_emoji_1F380" msgid="3487363857092458827">"ខ្សែបូ"</string> @@ -313,7 +313,7 @@ <string name="spoken_emoji_1F3A7" msgid="837856608794094105">"កាស"</string> <string name="spoken_emoji_1F3A8" msgid="2332260356509244587">"ក្ដារលាយពណ៌វិចិត្រករ"</string> <string name="spoken_emoji_1F3A9" msgid="9045869366525115256">"មួកសម្ដែងសិល្បៈ"</string> - <string name="spoken_emoji_1F3AA" msgid="5728760354237132">"តង់សៀក"</string> + <string name="spoken_emoji_1F3AA" msgid="5728760354237132">"តង់សៀក"</string> <string name="spoken_emoji_1F3AB" msgid="1657997517193216284">"សំបុត្រ"</string> <string name="spoken_emoji_1F3AC" msgid="4317366554314492152">"បន្ទះកណ្ដឹង"</string> <string name="spoken_emoji_1F3AD" msgid="607157286336130470">"សម្ដែងសិល្បៈ"</string> @@ -334,10 +334,10 @@ <string name="spoken_emoji_1F3BC" msgid="1608424748821446230">"និមិត្តសញ្ញាតន្ត្រី"</string> <string name="spoken_emoji_1F3BD" msgid="5490786111375627777">"អាវកីឡាមានខ្សែឆៀង"</string> <string name="spoken_emoji_1F3BE" msgid="1851613105691627931">"រ៉ាកែត និងបាល់"</string> - <string name="spoken_emoji_1F3BF" msgid="6862405997423247921">"ជិះស្គី និងក្ដារស្គី"</string> + <string name="spoken_emoji_1F3BF" msgid="6862405997423247921">"ជិះស្គី និងក្ដារស្គី"</string> <string name="spoken_emoji_1F3C0" msgid="7421420756115104085">"បាល់បោះ និងវណ្ណមូល"</string> <string name="spoken_emoji_1F3C1" msgid="6926537251677319922">"ទង់ជាតិប្រណាំងម៉ូតូ"</string> - <string name="spoken_emoji_1F3C2" msgid="5708596929237987082">"អ្នកជិះក្ដាររំអិលលើព្រិល"</string> + <string name="spoken_emoji_1F3C2" msgid="5708596929237987082">"អ្នកជិះក្ដាររំអិលលើព្រិល"</string> <string name="spoken_emoji_1F3C3" msgid="5850982999510115824">"អ្នករត់"</string> <string name="spoken_emoji_1F3C4" msgid="8468355585994639838">"អ្នកជិះទូករអិលលើទឹក"</string> <string name="spoken_emoji_1F3C6" msgid="9094474706847545409">"ពានរង្វាន់"</string> @@ -354,7 +354,7 @@ <string name="spoken_emoji_1F3E6" msgid="342132788513806214">"ធនាគារ"</string> <string name="spoken_emoji_1F3E7" msgid="6322352038284944265">"ម៉ាស៊ីនអេធីអឹម"</string> <string name="spoken_emoji_1F3E8" msgid="5864918444350599907">"សណ្ឋាគារ"</string> - <string name="spoken_emoji_1F3E9" msgid="7830416185375326938">"សណ្ឋាគារក្ដីស្រឡាញ់"</string> + <string name="spoken_emoji_1F3E9" msgid="7830416185375326938">"សណ្ឋាគារក្ដីស្រឡាញ់"</string> <string name="spoken_emoji_1F3EA" msgid="5081084413084360479">"ហាងទំនិញ ២៤ម៉ោង"</string> <string name="spoken_emoji_1F3EB" msgid="7010966528205150525">"សាលារៀន"</string> <string name="spoken_emoji_1F3EC" msgid="4845978861878295154">"ហាងទំនិញធំៗ"</string> @@ -439,12 +439,12 @@ <string name="spoken_emoji_1F44D" msgid="6182553970602667815">"មេដៃឡើងលើ"</string> <string name="spoken_emoji_1F44E" msgid="8030851867365111809">"មេដៃចុះក្រោម"</string> <string name="spoken_emoji_1F44F" msgid="5148753662268213389">"ទះដៃ"</string> - <string name="spoken_emoji_1F450" msgid="1012021072085157054">"លាដៃ"</string> + <string name="spoken_emoji_1F450" msgid="1012021072085157054">"លាដៃ"</string> <string name="spoken_emoji_1F451" msgid="8257466714629051320">"មកុដ"</string> <string name="spoken_emoji_1F452" msgid="4567394011149905466">"មួកស្ត្រី"</string> <string name="spoken_emoji_1F453" msgid="5978410551173163010">"វ៉ែនតា"</string> - <string name="spoken_emoji_1F454" msgid="348469036193323252">"ក្រវ៉ាត់ករ"</string> - <string name="spoken_emoji_1F455" msgid="5665118831861433578">"អាវយឺត"</string> + <string name="spoken_emoji_1F454" msgid="348469036193323252">"ក្រវ៉ាត់ករ"</string> + <string name="spoken_emoji_1F455" msgid="5665118831861433578">"អាវយឺត"</string> <string name="spoken_emoji_1F456" msgid="1890991330923356408">"ខោខោវប៊យ"</string> <string name="spoken_emoji_1F457" msgid="3904310482655702620">"សំលៀកបំពាក់"</string> <string name="spoken_emoji_1F458" msgid="5704243858031107692">"គីម៉ូណូ"</string> @@ -463,8 +463,8 @@ <string name="spoken_emoji_1F465" msgid="4461307702499679879">"គណនី"</string> <string name="spoken_emoji_1F466" msgid="1938873085514108889">"ក្មេងប្រុស"</string> <string name="spoken_emoji_1F467" msgid="8237080594860144998">"ក្មេងស្រី"</string> - <string name="spoken_emoji_1F468" msgid="6081300722526675382">"បុរស"</string> - <string name="spoken_emoji_1F469" msgid="1090140923076108158">"ស្ត្រី"</string> + <string name="spoken_emoji_1F468" msgid="6081300722526675382">"បុរស"</string> + <string name="spoken_emoji_1F469" msgid="1090140923076108158">"ស្ត្រី"</string> <string name="spoken_emoji_1F46A" msgid="5063570981942606595">"គ្រួសារ"</string> <string name="spoken_emoji_1F46B" msgid="6795882374287327952">"បុរស និងស្ត្រីកាន់ដៃគ្នា"</string> <string name="spoken_emoji_1F46C" msgid="6844464165783964495">"បុរសពីរនាក់កាន់ដៃគ្នា"</string> @@ -490,16 +490,16 @@ <string name="spoken_emoji_1F480" msgid="3696253485164878739">"លលាដ៍ក្បាល"</string> <string name="spoken_emoji_1F481" msgid="320408708521966893">"អ្នកផ្ដល់ព័ត៌មាន"</string> <string name="spoken_emoji_1F482" msgid="3424354860245608949">"អ្នកយាម"</string> - <string name="spoken_emoji_1F483" msgid="3221113594843849083">"អ្នករាំ"</string> + <string name="spoken_emoji_1F483" msgid="3221113594843849083">"អ្នករាំ"</string> <string name="spoken_emoji_1F484" msgid="7348014979080444885">"ក្រេមលាបបបូរមាត់"</string> <string name="spoken_emoji_1F485" msgid="6133507975565116339">"ថ្នាំលាបក្រចក"</string> <string name="spoken_emoji_1F486" msgid="9085459968247394155">"ម៉ាស្សាមុខ"</string> <string name="spoken_emoji_1F487" msgid="1479113637259592150">"កាត់សក់"</string> <string name="spoken_emoji_1F488" msgid="6922559285234100252">"ស្លាកសញ្ញាកាត់សក់"</string> <string name="spoken_emoji_1F489" msgid="8114863680950147305">"ស៊ីរ៉ាំង"</string> - <string name="spoken_emoji_1F48A" msgid="8526843630145963032">"ថ្នាំគ្រាប់"</string> + <string name="spoken_emoji_1F48A" msgid="8526843630145963032">"ថ្នាំគ្រាប់"</string> <string name="spoken_emoji_1F48B" msgid="2538528967897640292">"ស្នាមថើប"</string> - <string name="spoken_emoji_1F48C" msgid="1681173271652890232">"លិខិតស្នេហា"</string> + <string name="spoken_emoji_1F48C" msgid="1681173271652890232">"លិខិតស្នេហា"</string> <string name="spoken_emoji_1F48D" msgid="8259886164999042373">"រោទ៍"</string> <string name="spoken_emoji_1F48E" msgid="8777981696011111101">"ត្បូងថ្ម"</string> <string name="spoken_emoji_1F48F" msgid="741593675183677907">"ថើប"</string> @@ -525,7 +525,7 @@ <string name="spoken_emoji_1F4A3" msgid="6378351742957821735">"គ្រាប់បែក"</string> <string name="spoken_emoji_1F4A4" msgid="7217736258870346625">"និមិត្តសញ្ញាដេក"</string> <string name="spoken_emoji_1F4A5" msgid="5401995723541239858">"និមិត្តសញ្ញាប៉ះទង្គិចគ្នា"</string> - <string name="spoken_emoji_1F4A6" msgid="3837802182716483848">"និមិត្តសញ្ញាស្រក់ញើស"</string> + <string name="spoken_emoji_1F4A6" msgid="3837802182716483848">"និមិត្តសញ្ញាស្រក់ញើស"</string> <string name="spoken_emoji_1F4A7" msgid="5718438987757885141">"ដំណក់ទឹក"</string> <string name="spoken_emoji_1F4A8" msgid="4472108229720006377">"និមិត្តសញ្ញាដកឃ្លា"</string> <string name="spoken_emoji_1F4A9" msgid="1240958472788430032">"គំនរធូលី"</string> @@ -539,7 +539,7 @@ <string name="spoken_emoji_1F4B1" msgid="8339494003418572905">"ប្ដូររូបិយប័ណ្ណ"</string> <string name="spoken_emoji_1F4B2" msgid="3179159430187243132">"សញ្ញាដុល្លារ"</string> <string name="spoken_emoji_1F4B3" msgid="5375412518221759596">"កាតឥណទាន"</string> - <string name="spoken_emoji_1F4B4" msgid="1068592463669453204">"ក្រដាសប្រាក់ធនាគារមានសញ្ញាយ៉េន"</string> + <string name="spoken_emoji_1F4B4" msgid="1068592463669453204">"ក្រដាសប្រាក់ធនាគារមានសញ្ញាយ៉េន"</string> <string name="spoken_emoji_1F4B5" msgid="1426708699891832564">"លុយដុល្លារ"</string> <string name="spoken_emoji_1F4B6" msgid="8289249930736444837">"ក្រដាសប្រាក់ធនាគារមានសញ្ញាអឺរ៉ូ"</string> <string name="spoken_emoji_1F4B7" msgid="5245100496860739429">"ក្រដាសប្រាក់ធនាគារមានសញ្ញាផោន"</string> @@ -547,7 +547,7 @@ <string name="spoken_emoji_1F4B9" msgid="647509393536679903">"ក្រាហ្វិកនិន្នាការឡើងមានសញ្ញាយ៉េន"</string> <string name="spoken_emoji_1F4BA" msgid="1269737854891046321">"កៅអី"</string> <string name="spoken_emoji_1F4BB" msgid="6252883563347816451">"កុំព្យូទ័រផ្ទាល់ខ្លួន"</string> - <string name="spoken_emoji_1F4BC" msgid="6182597732218446206">"វ៉ាលី"</string> + <string name="spoken_emoji_1F4BC" msgid="6182597732218446206">"វ៉ាលី"</string> <string name="spoken_emoji_1F4BD" msgid="5820961044768829176">"ឌីសតូច"</string> <string name="spoken_emoji_1F4BE" msgid="4754542485835379808">"ថាសទន់"</string> <string name="spoken_emoji_1F4BF" msgid="2237481756984721795">"ថាស"</string> @@ -557,7 +557,7 @@ <string name="spoken_emoji_1F4C3" msgid="3727274466173970142">"ទំព័រកោង"</string> <string name="spoken_emoji_1F4C4" msgid="4382570710795501612">"ទំព័របញ្ឈរ"</string> <string name="spoken_emoji_1F4C5" msgid="8693944622627762487">"ប្រតិទិន"</string> - <string name="spoken_emoji_1F4C6" msgid="8469908708708424640">"ហែកប្រតិទិន"</string> + <string name="spoken_emoji_1F4C6" msgid="8469908708708424640">"ហែកប្រតិទិន"</string> <string name="spoken_emoji_1F4C7" msgid="2665313547987324495">"កាតរៀបតាមអក្សរ"</string> <string name="spoken_emoji_1F4C8" msgid="8007686702282833600">"ក្រាហ្វិកមាននិន្នាការឡើង"</string> <string name="spoken_emoji_1F4C9" msgid="2271951411192893684">"ក្រាហ្វិកមាននិន្នាការចុះ"</string> @@ -573,11 +573,11 @@ <string name="spoken_emoji_1F4D3" msgid="5873386492793610808">"សៀវភៅ"</string> <string name="spoken_emoji_1F4D4" msgid="4754469936418776360">"សៀវភៅមានក្របពណ៌"</string> <string name="spoken_emoji_1F4D5" msgid="4642713351802778905">"សៀវភៅបិទ"</string> - <string name="spoken_emoji_1F4D6" msgid="6987347918381807186">"សៀវភៅបើក"</string> + <string name="spoken_emoji_1F4D6" msgid="6987347918381807186">"សៀវភៅបើក"</string> <string name="spoken_emoji_1F4D7" msgid="7813394163241379223">"សៀវភៅពណ៌បៃតង"</string> <string name="spoken_emoji_1F4D8" msgid="7189799718984979521">"សៀវភៅពណ៌ខៀវ"</string> <string name="spoken_emoji_1F4D9" msgid="3874664073186440225">"សៀវភៅពណ៌ទឹកក្រូច"</string> - <string name="spoken_emoji_1F4DA" msgid="872212072924287762">"សៀវភៅ"</string> + <string name="spoken_emoji_1F4DA" msgid="872212072924287762">"សៀវភៅ"</string> <string name="spoken_emoji_1F4DB" msgid="2015183603583392969">"ស្លាកឈ្មោះ"</string> <string name="spoken_emoji_1F4DC" msgid="5075845110932456783">"ក្រដាសរមូរ"</string> <string name="spoken_emoji_1F4DD" msgid="2494006707147586786">"កំណត់ចំណាំ"</string> @@ -589,7 +589,7 @@ <string name="spoken_emoji_1F4E3" msgid="5588916572878599224">"ឧបករណ៍បំពងសំឡេង"</string> <string name="spoken_emoji_1F4E4" msgid="2063561529097749707">"ថាសចេញ"</string> <string name="spoken_emoji_1F4E5" msgid="3232462702926143576">"ថាសចូល"</string> - <string name="spoken_emoji_1F4E6" msgid="3399454337197561635">"កញ្ចប់"</string> + <string name="spoken_emoji_1F4E6" msgid="3399454337197561635">"កញ្ចប់"</string> <string name="spoken_emoji_1F4E7" msgid="5557136988503873238">"និមិត្តសញ្ញាអ៊ីមែល"</string> <string name="spoken_emoji_1F4E8" msgid="30698793974124123">"ស្រោមសំបុត្រចូល"</string> <string name="spoken_emoji_1F4E9" msgid="5947550337678643166">"ស្រោមសំបុត្រមានសញ្ញាព្រួញពីលើ"</string> @@ -626,7 +626,7 @@ <string name="spoken_emoji_1F50C" msgid="7793219132036431680">"ដុយអគ្គិសនី"</string> <string name="spoken_emoji_1F50D" msgid="8140244710637926780">"កែវពង្រីកចង្អុលខាងឆ្វេង"</string> <string name="spoken_emoji_1F50E" msgid="4751821352839693365">"កែវពង្រីកចង្អុលខាងស្ដាំ"</string> - <string name="spoken_emoji_1F50F" msgid="915079280472199605">"ចាក់សោដោយប្រើប៊ិច"</string> + <string name="spoken_emoji_1F50F" msgid="915079280472199605">"ចាក់សោដោយប្រើប៊ិច"</string> <string name="spoken_emoji_1F510" msgid="7658381761691758318">"បិទសោដោយប្រើកូនសោ"</string> <string name="spoken_emoji_1F511" msgid="262319867774655688">"សោ"</string> <string name="spoken_emoji_1F512" msgid="5628688337255115175">"ចាក់សោ"</string> @@ -645,15 +645,15 @@ <string name="spoken_emoji_1F51F" msgid="8673370823728653973">"គ្រាប់ចុច ១០"</string> <string name="spoken_emoji_1F520" msgid="7335109890337048900">"និមិត្តសញ្ញាបញ្ចូលសម្រាប់អក្សរឡាតាំងធំ"</string> <string name="spoken_emoji_1F521" msgid="2693185864450925778">"និមិត្តសញ្ញាបញ្ចូលសម្រាប់អក្សរឡាតាំងតូច"</string> - <string name="spoken_emoji_1F522" msgid="8419130286280673347">"និមិត្តសញ្ញាបញ្ចូលសម្រាប់លេខ"</string> + <string name="spoken_emoji_1F522" msgid="8419130286280673347">"និមិត្តសញ្ញាបញ្ចូលសម្រាប់លេខ"</string> <string name="spoken_emoji_1F523" msgid="3318053476401719421">"ការបញ្ចូលនិមិត្តសញ្ញា"</string> <string name="spoken_emoji_1F524" msgid="1625073997522316331">"និមិត្តសញ្ញាបញ្ចូលសម្រាប់អក្សរឡាតាំង"</string> <string name="spoken_emoji_1F525" msgid="4083884189172963790">"ភ្លើង"</string> <string name="spoken_emoji_1F526" msgid="2035494936742643580">"ពិលអគ្គិសនី"</string> <string name="spoken_emoji_1F527" msgid="134257142354034271">"ម៉ាឡេត"</string> <string name="spoken_emoji_1F528" msgid="700627429570609375">"ញញួរ"</string> - <string name="spoken_emoji_1F529" msgid="7480548235904988573">"ឡោស៊ី"</string> - <string name="spoken_emoji_1F52A" msgid="7613580031502317893">"កាំបិត"</string> + <string name="spoken_emoji_1F529" msgid="7480548235904988573">"ឡោស៊ី"</string> + <string name="spoken_emoji_1F52A" msgid="7613580031502317893">"កាំបិត"</string> <string name="spoken_emoji_1F52B" msgid="4554906608328118613">"កាំភ្លើងខ្លី"</string> <string name="spoken_emoji_1F52C" msgid="1330294501371770790">"មីក្រូទស្សន៍"</string> <string name="spoken_emoji_1F52D" msgid="7549551775445177140">"កែវយឹត"</string> @@ -662,7 +662,7 @@ <string name="spoken_emoji_1F530" msgid="3572898444281774023">"និមិត្តសញ្ញាជប៉ុនសម្រាប់អ្នកចាប់ផ្ដើម"</string> <string name="spoken_emoji_1F531" msgid="5225633376450025396">"លំពែងមុខបី"</string> <string name="spoken_emoji_1F532" msgid="9169568490485180779">"ប៊ូតុងការេពណ៌ខ្មៅ"</string> - <string name="spoken_emoji_1F533" msgid="6554193837201918598">"ប៊ូតុងការ៉េពណ៌ស"</string> + <string name="spoken_emoji_1F533" msgid="6554193837201918598">"ប៊ូតុងការ៉េពណ៌ស"</string> <string name="spoken_emoji_1F534" msgid="8339298801331865340">"រង្វង់ពណ៌ក្រហមធំ"</string> <string name="spoken_emoji_1F535" msgid="1227403104835533512">"រង្វង់ពណ៌ខៀវធំ"</string> <string name="spoken_emoji_1F536" msgid="5477372445510469331">"ពេជ្រពណ៌ទឹកក្រូចធំ"</string> @@ -745,8 +745,8 @@ <string name="spoken_emoji_1F628" msgid="8875777401624904224">"មុខភ័យខ្លាច"</string> <string name="spoken_emoji_1F629" msgid="1411538490319190118">"មុខនឿយហត់"</string> <string name="spoken_emoji_1F62A" msgid="4726686726690289969">"មុខងងុយគេង"</string> - <string name="spoken_emoji_1F62B" msgid="3221980473921623613">"មុខអស់កម្លាំង"</string> - <string name="spoken_emoji_1F62C" msgid="4616356691941225182">"មុខក្រញេវក្រញូវ"</string> + <string name="spoken_emoji_1F62B" msgid="3221980473921623613">"មុខអស់កម្លាំង"</string> + <string name="spoken_emoji_1F62C" msgid="4616356691941225182">"មុខក្រញេវក្រញូវ"</string> <string name="spoken_emoji_1F62D" msgid="4283677508698812232">"មុខយំលឺៗ"</string> <string name="spoken_emoji_1F62E" msgid="726083405284353894">"មុខបើកមាត់"</string> <string name="spoken_emoji_1F62F" msgid="7746620088234710962">"មុខស្ងៀមស្ងាត់"</string> @@ -784,7 +784,7 @@ <string name="spoken_emoji_1F683" msgid="8772750354339223092">"ទូររថភ្លើង"</string> <string name="spoken_emoji_1F684" msgid="346396777356203608">"រថភ្លើងល្បឿនលឿន"</string> <string name="spoken_emoji_1F685" msgid="1237059817190832730">"រថភ្លើងល្បឿនលឿនមានច្រមុះ"</string> - <string name="spoken_emoji_1F686" msgid="3525197227223620343">"រថភ្លើង"</string> + <string name="spoken_emoji_1F686" msgid="3525197227223620343">"រថភ្លើង"</string> <string name="spoken_emoji_1F687" msgid="5110143437960392837">"មេត្រូ"</string> <string name="spoken_emoji_1F688" msgid="4702085029871797965">"រថភ្លើងប្រើពន្លឺ"</string> <string name="spoken_emoji_1F689" msgid="2375851019798817094">"ស្ថានីយ"</string> @@ -803,7 +803,7 @@ <string name="spoken_emoji_1F696" msgid="6391604457418285404">"តាក់ស៊ីខាងមុខ"</string> <string name="spoken_emoji_1F697" msgid="7978399334396733790">"រថយន្ត"</string> <string name="spoken_emoji_1F698" msgid="7006050861129732018">"រថយន្តខាងមុខ"</string> - <string name="spoken_emoji_1F699" msgid="630317052666590607">"រថយន្តសម្រាប់កម្សាន្ត"</string> + <string name="spoken_emoji_1F699" msgid="630317052666590607">"រថយន្តសម្រាប់កម្សាន្ត"</string> <string name="spoken_emoji_1F69A" msgid="4739797891735823577">"រថយន្តចែកចាយ"</string> <string name="spoken_emoji_1F69B" msgid="4715997280786620649">"ឡានកាមីយ៉ុង"</string> <string name="spoken_emoji_1F69C" msgid="5557395610750818161">"ត្រាក់ទ័រ"</string> @@ -819,7 +819,7 @@ <string name="spoken_emoji_1F6A6" msgid="485575967773793454">"ភ្លើងចរាចរណ៍បញ្ឈរ"</string> <string name="spoken_emoji_1F6A7" msgid="6411048933816976794">"សញ្ញាសំណង់"</string> <string name="spoken_emoji_1F6A8" msgid="6345717218374788364">"រថយន្តប៉ូលិសបើកសារ៉ែនវិល"</string> - <string name="spoken_emoji_1F6A9" msgid="6586380356807600412">"បង្គោលទង់ជាតិរាងត្រីកោណ"</string> + <string name="spoken_emoji_1F6A9" msgid="6586380356807600412">"បង្គោលទង់ជាតិរាងត្រីកោណ"</string> <string name="spoken_emoji_1F6AA" msgid="8954448167261738885">"ទ្វារ"</string> <string name="spoken_emoji_1F6AB" msgid="5313946262888343544">"សញ្ញាហាមចូល"</string> <string name="spoken_emoji_1F6AC" msgid="6946858177965948288">"សញ្ញាជក់បារី"</string> diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml index 91ba5b96f..2cf51d875 100644 --- a/java/res/values-km-rKH/strings.xml +++ b/java/res/values-km-rKH/strings.xml @@ -28,7 +28,7 @@ <string name="popup_on_keypress" msgid="123894815723512944">"លេចឡើងនៅពេលចុចគ្រាប់ចុច"</string> <string name="general_category" msgid="1859088467017573195">"ទូទៅ"</string> <string name="correction_category" msgid="2236750915056607613">"ការកែអត្ថបទ"</string> - <string name="gesture_typing_category" msgid="497263612130532630">"បញ្ចូលដោយប្រើកាយវិការ"</string> + <string name="gesture_typing_category" msgid="497263612130532630">"បញ្ចូលដោយប្រើកាយវិការ"</string> <string name="misc_category" msgid="6894192814868233453">"ជម្រើសផ្សេងទៀត"</string> <string name="advanced_settings" msgid="362895144495591463">"ការកំណត់កម្រិតខ្ពស់"</string> <string name="advanced_settings_summary" msgid="4487980456152830271">"ជម្រើសសម្រាប់អ្នកជំនាញ"</string> @@ -38,7 +38,7 @@ <string name="show_language_switch_key_summary" msgid="7343403647474265713">"បង្ហាញនៅពេលដែលបើកភាសាបញ្ចូលច្រើន"</string> <string name="sliding_key_input_preview" msgid="6604262359510068370">"បង្ហាញទ្រនិចបង្ហាញស្លាយ"</string> <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"បង្ហាញសញ្ញាមើលឃើញខណៈពេលដែលរុញពីឆ្វេង ឬគ្រាប់ចុចនិមិត្តសញ្ញា"</string> - <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"សោលេចឡើងបោះបង់ការពន្យារពេល"</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"សោលេចឡើងបោះបង់ការពន្យារពេល"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"គ្មានការពន្យារពេល"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"លំនាំដើម"</string> <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> មិល្លីវិនាទី"</string> @@ -50,7 +50,7 @@ <skip /> <string name="use_double_space_period" msgid="8781529969425082860">"រយៈពេលចុចដកឃ្លាពីរដង"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"ប៉ះដកឃ្លាពីរដងបញ្ចូលរយៈពេលដែលអនុវត្តតាមដកឃ្លា"</string> - <string name="auto_cap" msgid="1719746674854628252">"ការសរសេរជាអក្សរធំស្វ័យប្រវត្តិ"</string> + <string name="auto_cap" msgid="1719746674854628252">"ការសរសេរជាអក្សរធំស្វ័យប្រវត្តិ"</string> <string name="auto_cap_summary" msgid="7934452761022946874">"សរសេរពាក្យដំបូងជាអក្សរធំនៃប្រយោគនីមួយៗ"</string> <string name="edit_personal_dictionary" msgid="3996910038952940420">"វចនានុក្រមផ្ទាល់ខ្លួន"</string> <string name="configure_dictionaries_title" msgid="4238652338556902049">"ផ្នែកបន្ថែមវចនានុក្រម"</string> @@ -61,7 +61,7 @@ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"បង្ហាញនៅក្នុងរបៀបបញ្ឈរ"</string> <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"លាក់ជានិច្ច"</string> <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"ទប់ស្កាត់ពាក្យបំពាន"</string> - <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំស្នើឲ្យពាក្យបំពានមានសក្ដានុពល"</string> + <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំស្នើឲ្យពាក្យបំពានមានសក្ដានុពល"</string> <string name="auto_correction" msgid="7630720885194996950">"ការកែស្វ័យប្រវត្តិ"</string> <string name="auto_correction_summary" msgid="5625751551134658006">"ចន្លោះមិនឃើញ និងសញ្ញាវណ្ណយុត្តកែពាក្យដែលបានវាយខុសស្វ័យប្រវត្តិ"</string> <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"បិទ"</string> @@ -121,7 +121,7 @@ <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"ថិរវេលាញ័រពេលចុចគ្រាប់ចុច"</string> <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"កម្រិតសំឡេងពេលចុចគ្រាប់ចុច"</string> <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"អានឯកសារវចនានុក្រមខាងក្រៅ"</string> - <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មានឯកសារវចនានុក្រមនៅក្នុងថតទាញយក"</string> + <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មានឯកសារវចនានុក្រមនៅក្នុងថតទាញយក"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ជ្រើសឯកសារវចនានុក្រម ដើម្បីដំឡើង"</string> <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ពិតជាដំឡើងឯកសារនេះសម្រាប់ <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"មានកំហុស"</string> @@ -148,7 +148,7 @@ <string name="dictionary_provider_name" msgid="3027315045397363079">"កម្មវិធីផ្ដល់វចនានុក្រម"</string> <string name="dictionary_service_name" msgid="6237472350693511448">"សេវាកម្មវចនានុក្រម"</string> <string name="download_description" msgid="6014835283119198591">"ព័ត៌មានបច្ចុប្បន្នភាពវចនានុក្រម"</string> - <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែកបន្ថែមវចនានុក្រម"</string> + <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែកបន្ថែមវចនានុក្រម"</string> <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"វចនានុក្រមអាចប្រើបាន"</string> <string name="dictionary_settings_summary" msgid="5305694987799824349">"ការកំណត់សម្រាប់វចនានុក្រម"</string> <string name="user_dictionaries" msgid="3582332055892252845">"វចនានុក្រមអ្នកប្រើ"</string> @@ -164,10 +164,10 @@ <string name="message_updating" msgid="4457761393932375219">"ពិនិត្យមើលបច្ចុប្បន្នភាព"</string> <string name="message_loading" msgid="5638680861387748936">"កំពុងផ្ទុក..."</string> <string name="main_dict_description" msgid="3072821352793492143">"វចនានុក្រមចម្បង"</string> - <string name="cancel" msgid="6830980399865683324">"បោះបង់"</string> + <string name="cancel" msgid="6830980399865683324">"បោះបង់"</string> <string name="go_to_settings" msgid="3876892339342569259">"ការកំណត់"</string> <string name="install_dict" msgid="180852772562189365">"ដំឡើង"</string> - <string name="cancel_download_dict" msgid="7843340278507019303">"បោះបង់"</string> + <string name="cancel_download_dict" msgid="7843340278507019303">"បោះបង់"</string> <string name="delete_dict" msgid="756853268088330054">"លុប"</string> <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ភាសាដែលបានជ្រើសនៅលើឧបករណ៍ចល័តមានវចនានុក្រមអាចប្រើបាន។<br/> យើងផ្ដល់អនុសាសន៍ឲ្យ <b>ទាញយក</b> វចនានុក្រមភាសា <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ដើម្បីបង្កើនបទពិសោធន៍វាយបញ្ចូលរបស់អ្នក។<br/> <br/> ការទាញយកអាចចំណាយពេលប្រហែលពីរនាទីនៅតាម 3G។ ការគិតថ្លៃអាចអនុវត្តប្រសិនបើអ្នកមិនប្រើ <b>ផែនការទិន្នន័យគ្មានដែនកំណត់</b>.<br/> បើអ្នកមិនប្រាកដថាផែនការណាមួយដែលអ្នកមាន យើងផ្ដល់អនុសាសន៍ឲ្យភ្ជាប់វ៉ាយហ្វាយ ដើម្បីចាប់ផ្ដើមទាញយកដោយស្វ័យប្រវត្តិ។<br/> <br/> ជំនួយ៖ អ្នកអាចទាញយក និងលុបវចនានុក្រមដោយចូលទៅ <b>ភាសា & ការបញ្ចូល</b> នៅក្នុងម៉ឺនុយ <b>ការកំណត់</b> សម្រាប់ឧបករណ៍ចល័ត។"</string> <string name="download_over_metered" msgid="1643065851159409546">"ទាញយកឥឡូវនេះ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> មេកាបៃ)"</string> @@ -185,7 +185,7 @@ <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"ពាក្យ៖"</string> <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"ផ្លូវកាត់៖"</string> <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"ភាសា៖"</string> - <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយបញ្ចូលពាក្យ"</string> + <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយបញ្ចូលពាក្យ"</string> <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"ផ្លូវកាត់ជាជម្រើស"</string> <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"កែពាក្យ"</string> <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"កែ"</string> diff --git a/java/res/values-lo-rLA/strings-emoji-descriptions.xml b/java/res/values-lo-rLA/strings-emoji-descriptions.xml index 0747fa629..83a702e95 100644 --- a/java/res/values-lo-rLA/strings-emoji-descriptions.xml +++ b/java/res/values-lo-rLA/strings-emoji-descriptions.xml @@ -210,7 +210,7 @@ <string name="spoken_emoji_1F330" msgid="3115760035618051575">"ລູກເກົາລັດ"</string> <string name="spoken_emoji_1F331" msgid="5658888205290008691">"ກ້າໄມ້"</string> <string name="spoken_emoji_1F332" msgid="2935650450421165938">"ຕົ້ນໄມ້ບໍ່ຜັດໃບ"</string> - <string name="spoken_emoji_1F333" msgid="5898847427062482675">"ຕົ້ນໄມ້ຜັດໃບ"</string> + <string name="spoken_emoji_1F333" msgid="5898847427062482675">"ຕົ້ນໄມ້ຜັດໃບ"</string> <string name="spoken_emoji_1F334" msgid="6183375224678417894">"ຕົ້ນປາມ"</string> <string name="spoken_emoji_1F335" msgid="5352418412103584941">"ກະບອງເພັດ"</string> <string name="spoken_emoji_1F337" msgid="3839107352363566289">"ທິວລິບ"</string> @@ -450,7 +450,7 @@ <string name="spoken_emoji_1F458" msgid="5704243858031107692">"ກິໂມໂນ"</string> <string name="spoken_emoji_1F459" msgid="3553148747050035251">"ບິກີນີ"</string> <string name="spoken_emoji_1F45A" msgid="1389654639484716101">"ເສື້ອຜ້າຜູ່ຍິງ"</string> - <string name="spoken_emoji_1F45B" msgid="1113293170254222904">"ກະເປົາ"</string> + <string name="spoken_emoji_1F45B" msgid="1113293170254222904">"ກະເປົາ"</string> <string name="spoken_emoji_1F45C" msgid="3410257778598006936">"ກະເປົາ"</string> <string name="spoken_emoji_1F45D" msgid="812176504300064819">"ກະເປົາ"</string> <string name="spoken_emoji_1F45E" msgid="2901741399934723562">"ເກີບຜູ່ຊາຍ"</string> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index a1f478bd5..fcb919d0b 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -26,8 +26,6 @@ <attr name="keyboardViewStyle" format="reference" /> <!-- MainKeyboardView style --> <attr name="mainKeyboardViewStyle" format="reference" /> - <!-- Key preview text view style --> - <attr name="keyPreviewTextViewStyle" format="reference"/> <!-- EmojiPalettesView style --> <attr name="emojiPalettesViewStyle" format="reference" /> <!-- MoreKeysKeyboard style --> @@ -106,8 +104,8 @@ <attr name="longPressShiftLockTimeout" format="integer" /> <!-- Ignore special key timeout while typing in millisecond. --> <attr name="ignoreAltCodeKeyTimeout" format="integer" /> - <!-- Layout resource for key press feedback.--> - <attr name="keyPreviewLayout" format="reference" /> + <!-- Background resource for key press feedback.--> + <attr name="keyPreviewBackground" format="reference" /> <!-- Vertical offset of the key press feedback from the key. --> <attr name="keyPreviewOffset" format="dimension" /> <!-- Height of the key press feedback popup. --> diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml index 02a93ca82..2b2a80aed 100644 --- a/java/res/values/themes-common.xml +++ b/java/res/values/themes-common.xml @@ -75,7 +75,6 @@ <item name="keyRepeatInterval">@integer/config_key_repeat_interval</item> <item name="longPressShiftLockTimeout">@integer/config_longpress_shift_lock_timeout</item> <item name="ignoreAltCodeKeyTimeout">@integer/config_ignore_alt_code_key_timeout</item> - <item name="keyPreviewLayout">@layout/key_preview</item> <item name="keyPreviewHeight">@dimen/config_key_preview_height</item> <!-- TODO: consolidate key preview linger timeout with the key preview animation parameters. --> <item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item> @@ -106,7 +105,6 @@ <style name="MainKeyboardView" parent="KeyboardView" /> - <style name="KeyPreviewTextView" /> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style name="EmojiPalettesView" /> diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml index 319b4aeed..073ae90b9 100644 --- a/java/res/values/themes-ics.xml +++ b/java/res/values/themes-ics.xml @@ -23,7 +23,6 @@ <item name="keyboardStyle">@style/Keyboard.ICS</item> <item name="keyboardViewStyle">@style/KeyboardView.ICS</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item> - <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.ICS</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.ICS</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.ICS</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.ICS</item> @@ -66,6 +65,7 @@ name="MainKeyboardView.ICS" parent="KeyboardView.ICS" > + <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_ics</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_ics</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> @@ -75,12 +75,6 @@ <item name="languageOnSpacebarTextShadowRadius">1.0</item> <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> </style> - <style - name="KeyPreviewTextView.ICS" - parent="KeyPreviewTextView" - > - <item name="android:background">@drawable/keyboard_key_feedback_ics</item> - </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml index 208723dd3..f895de572 100644 --- a/java/res/values/themes-klp.xml +++ b/java/res/values/themes-klp.xml @@ -23,7 +23,6 @@ <item name="keyboardStyle">@style/Keyboard.KLP</item> <item name="keyboardViewStyle">@style/KeyboardView.KLP</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.KLP</item> - <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.KLP</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.KLP</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.KLP</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.KLP</item> @@ -66,6 +65,7 @@ name="MainKeyboardView.KLP" parent="KeyboardView.KLP" > + <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_klp</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_klp</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> @@ -75,12 +75,6 @@ <item name="languageOnSpacebarTextShadowRadius">1.0</item> <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> </style> - <style - name="KeyPreviewTextView.KLP" - parent="KeyPreviewTextView" - > - <item name="android:background">@drawable/keyboard_key_feedback_klp</item> - </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style diff --git a/java/res/values/themes-lxx-dark.xml b/java/res/values/themes-lxx-dark.xml index e9a295c67..1db8f428e 100644 --- a/java/res/values/themes-lxx-dark.xml +++ b/java/res/values/themes-lxx-dark.xml @@ -23,7 +23,6 @@ <item name="keyboardStyle">@style/Keyboard.LXX_Dark</item> <item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark</item> - <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.LXX_Dark</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Dark</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark</item> @@ -67,6 +66,7 @@ name="MainKeyboardView.LXX_Dark" parent="KeyboardView.LXX_Dark" > + <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_lxx_dark</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_lxx_dark</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_lxx_dark</item> @@ -76,12 +76,6 @@ <!-- A negative value to disable text shadow layer. --> <item name="languageOnSpacebarTextShadowRadius">-1.0</item> </style> - <style - name="KeyPreviewTextView.LXX_Dark" - parent="KeyPreviewTextView" - > - <item name="android:background">@drawable/keyboard_key_feedback_lxx_dark</item> - </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java index d67d9dc4b..3925fc652 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java +++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java @@ -305,7 +305,7 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> key.onPressed(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); - provider.sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER); + provider.onHoverEnterTo(key); provider.performActionForKey(key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS); } @@ -328,6 +328,6 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> key.onReleased(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); - provider.sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT); + provider.onHoverExitFrom(key); } } diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java index cb13483f2..61d066af5 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java +++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java @@ -65,6 +65,9 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC /** The virtual view identifier for the focused node. */ private int mAccessibilityFocusedView = UNDEFINED; + /** The virtual view identifier for the hovering node. */ + private int mHoveringNodeId = UNDEFINED; + /** The current keyboard view. */ private final KeyboardView mKeyboardView; @@ -76,7 +79,6 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance(); mAccessibilityUtils = AccessibilityUtils.getInstance(); mKeyboardView = keyboardView; - updateParentLocation(); // Since this class is constructed lazily, we might not get a subsequent // call to setKeyboard() and therefore need to call it now. @@ -141,6 +143,28 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC return event; } + public void onHoverEnterTo(final Key key) { + final int id = getVirtualViewIdOf(key); + if (id == View.NO_ID) { + return; + } + // Start hovering on the key. Because our accessibility model is lift-to-type, we should + // report the node info without click and long click actions to avoid unnecessary + // announcements. + mHoveringNodeId = id; + // Invalidate the node info of the key. + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED); + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER); + } + + public void onHoverExitFrom(final Key key) { + mHoveringNodeId = UNDEFINED; + // Invalidate the node info of the key to be able to revert the change we have done + // in {@link #onHoverEnterTo(Key)}. + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED); + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT); + } + /** * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or @@ -169,10 +193,23 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC } if (virtualViewId == View.NO_ID) { // We are requested to create an AccessibilityNodeInfo describing - // this View. Returning an empty info is sufficient for a keyboard. + // this View, i.e. the root of the virtual sub-tree. final AccessibilityNodeInfoCompat rootInfo = AccessibilityNodeInfoCompat.obtain(mKeyboardView); ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo); + updateParentLocation(); + + // Add the virtual children of the root View. + final List<Key> sortedKeys = mKeyboard.getSortedKeys(); + final int size = sortedKeys.size(); + for (int index = 0; index < size; index++) { + final Key key = sortedKeys.get(index); + if (key.isSpacer()) { + continue; + } + // Use an index of the sorted keys list as a virtual view id. + rootInfo.addChild(mKeyboardView, index); + } return rootInfo; } @@ -200,9 +237,16 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC info.setBoundsInScreen(boundsInScreen); info.setParent(mKeyboardView); info.setSource(mKeyboardView, virtualViewId); - info.setBoundsInScreen(boundsInScreen); - info.setEnabled(true); + info.setEnabled(key.isEnabled()); info.setVisibleToUser(true); + // Don't add ACTION_CLICK and ACTION_LONG_CLOCK actions while hovering on the key. + // See {@link #onHoverEnterTo(Key)} and {@link #onHoverExitFrom(Key)}. + if (virtualViewId != mHoveringNodeId) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK); + if (key.isLongPressEnabled()) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK); + } + } if (mAccessibilityFocusedView == virtualViewId) { info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS); @@ -241,6 +285,12 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC sendAccessibilityEventForKey( key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); return true; + case AccessibilityNodeInfoCompat.ACTION_CLICK: + sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_CLICKED); + return true; + case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK: + sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); + return true; default: return false; } diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 9a859bfdb..81825934f 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -35,7 +35,6 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodSubtype; -import android.widget.TextView; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.MainKeyboardAccessibilityDelegate; @@ -48,6 +47,7 @@ import com.android.inputmethod.keyboard.internal.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper; +import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; import com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview; import com.android.inputmethod.keyboard.internal.TimerHandler; @@ -236,16 +236,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); mGestureFloatingTextDrawingPreview = new GestureFloatingTextDrawingPreview( - mDrawingPreviewPlacerView, mainKeyboardViewAttr); - mDrawingPreviewPlacerView.addPreview(mGestureFloatingTextDrawingPreview); + mainKeyboardViewAttr); + mGestureFloatingTextDrawingPreview.setDrawingView(mDrawingPreviewPlacerView); - mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview( - mDrawingPreviewPlacerView, mainKeyboardViewAttr); - mDrawingPreviewPlacerView.addPreview(mGestureTrailsDrawingPreview); + mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview(mainKeyboardViewAttr); + mGestureTrailsDrawingPreview.setDrawingView(mDrawingPreviewPlacerView); - mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview( - mDrawingPreviewPlacerView, mainKeyboardViewAttr); - mDrawingPreviewPlacerView.addPreview(mSlidingKeyInputDrawingPreview); + mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview(mainKeyboardViewAttr); + mSlidingKeyInputDrawingPreview.setDrawingView(mDrawingPreviewPlacerView); mainKeyboardViewAttr.recycle(); mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) @@ -428,15 +426,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack windowContentView.addView(mDrawingPreviewPlacerView); } - /** - * Returns the enabled state of the key feedback preview - * @return whether or not the key feedback preview is enabled - * @see #setKeyPreviewPopupEnabled(boolean, int) - */ - public boolean isKeyPreviewPopupEnabled() { - return mKeyPreviewDrawParams.isPopupEnabled(); - } - // Implements {@link DrawingHandler.Callbacks} method. @Override public void dismissAllKeyPreviews() { @@ -461,12 +450,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } locatePreviewPlacerView(); - final TextView previewTextView = mKeyPreviewChoreographer.getKeyPreviewTextView( - key, mDrawingPreviewPlacerView); getLocationInWindow(mOriginCoords); - mKeyPreviewChoreographer.placeKeyPreview(key, previewTextView, keyboard.mIconsSet, - mKeyDrawParams, getWidth(), mOriginCoords); - mKeyPreviewChoreographer.showKeyPreview(key, previewTextView, isHardwareAccelerated()); + mKeyPreviewChoreographer.placeKeyPreviewAndShow(key, keyboard.mIconsSet, mKeyDrawParams, + getWidth(), mOriginCoords, mDrawingPreviewPlacerView, isHardwareAccelerated()); } // Implements {@link TimerHandler.Callbacks} method. @@ -557,13 +543,25 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) { - if (key.getMoreKeys() == null) { + final MoreKeySpec[] moreKeys = key.getMoreKeys(); + if (moreKeys == null) { return null; } Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key); if (moreKeysKeyboard == null) { - moreKeysKeyboard = new MoreKeysKeyboard.Builder( - context, key, this, mKeyPreviewDrawParams).build(); + // {@link KeyPreviewDrawParams#mPreviewVisibleWidth} should have been set at + // {@link KeyPreviewChoreographer#placeKeyPreview(Key,TextView,KeyboardIconsSet,KeyDrawParams,int,int[]}, + // though there may be some chances that the value is zero. <code>width == 0</code> + // will cause zero-division error at + // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}. + final boolean singleMoreKeyWithPreview = mKeyPreviewDrawParams.isPopupEnabled() + && !key.noKeyPreview() && moreKeys.length == 1 + && mKeyPreviewDrawParams.getVisibleWidth() > 0; + final MoreKeysKeyboard.Builder builder = new MoreKeysKeyboard.Builder( + context, key, getKeyboard(), singleMoreKeyWithPreview, + mKeyPreviewDrawParams.getVisibleWidth(), + mKeyPreviewDrawParams.getVisibleHeight(), newLabelPaint(key)); + moreKeysKeyboard = builder.build(); mMoreKeysKeyboardCache.put(key, moreKeysKeyboard); } @@ -619,7 +617,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int[] lastCoords = CoordinateUtils.newInstance(); tracker.getLastCoordinates(lastCoords); - final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !key.noKeyPreview(); + final boolean keyPreviewEnabled = mKeyPreviewDrawParams.isPopupEnabled() + && !key.noKeyPreview(); // The more keys keyboard is usually horizontally aligned with the center of the parent key. // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more // keys keyboard is placed at the touch point of the parent key. @@ -730,6 +729,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } public void onHideWindow() { + onDismissMoreKeysPanel(); final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate; if (accessibilityDelegate != null) { accessibilityDelegate.onHideWindow(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index a72f79137..353e07cf7 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -21,7 +21,6 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.KeyboardParams; @@ -260,32 +259,25 @@ public final class MoreKeysKeyboard extends Keyboard { /** * The builder of MoreKeysKeyboard. * @param context the context of {@link MoreKeysKeyboardView}. - * @param parentKey the {@link Key} that invokes more keys keyboard. - * @param parentKeyboardView the {@link KeyboardView} that contains the parentKey. + * @param key the {@link Key} that invokes more keys keyboard. + * @param keyboard the {@link Keyboard} that contains the parentKey. + * @param singleMoreKeyWithPreview true if the <code>key</code> has only one more key + * and key popup preview is enabled. * @param keyPreviewDrawParams the parameter to place key preview. + * @param paintToMeasure the {@link Paint} object to measure a more key width */ - public Builder(final Context context, final Key parentKey, - final MainKeyboardView parentKeyboardView, - final KeyPreviewDrawParams keyPreviewDrawParams) { + public Builder(final Context context, final Key key, final Keyboard keyboard, + final boolean singleMoreKeyWithPreview, final int keyPreviewVisibleWidth, + final int keyPreviewVisibleHeight, final Paint paintToMeasure) { super(context, new MoreKeysKeyboardParams()); - final Keyboard parentKeyboard = parentKeyboardView.getKeyboard(); - load(parentKeyboard.mMoreKeysTemplate, parentKeyboard.mId); + load(keyboard.mMoreKeysTemplate, keyboard.mId); // TODO: More keys keyboard's vertical gap is currently calculated heuristically. // Should revise the algorithm. - mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2; - mParentKey = parentKey; - - final MoreKeySpec[] moreKeys = parentKey.getMoreKeys(); - final int width, height; - // {@link KeyPreviewDrawParams#mPreviewVisibleWidth} should have been set at - // {@link MainKeyboardView#showKeyPreview(PointerTracker}, though there may be - // some chances that the value is zero. <code>width == 0</code> will cause - // zero-division error at - // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}. - final boolean singleMoreKeyWithPreview = parentKeyboardView.isKeyPreviewPopupEnabled() - && !parentKey.noKeyPreview() && moreKeys.length == 1 - && keyPreviewDrawParams.getVisibleWidth() > 0; + mParams.mVerticalGap = keyboard.mVerticalGap / 2; + mParentKey = key; + + final int keyWidth, rowHeight; if (singleMoreKeyWithPreview) { // Use pre-computed width and height if this more keys keyboard has only one key to // mitigate visual flicker between key preview and more keys keyboard. @@ -294,29 +286,28 @@ public final class MoreKeysKeyboard extends Keyboard { // left/right/top paddings. The bottom paddings of both backgrounds don't need to // be considered because the vertical positions of both backgrounds were already // adjusted with their bottom paddings deducted. - width = keyPreviewDrawParams.getVisibleWidth(); - height = keyPreviewDrawParams.getVisibleHeight() + mParams.mVerticalGap; + keyWidth = keyPreviewVisibleWidth; + rowHeight = keyPreviewVisibleHeight + mParams.mVerticalGap; } else { final float padding = context.getResources().getDimension( R.dimen.config_more_keys_keyboard_key_horizontal_padding) - + (parentKey.hasLabelsInMoreKeys() + + (key.hasLabelsInMoreKeys() ? mParams.mDefaultKeyWidth * LABEL_PADDING_RATIO : 0.0f); - width = getMaxKeyWidth(parentKey, mParams.mDefaultKeyWidth, padding, - parentKeyboardView.newLabelPaint(parentKey)); - height = parentKeyboard.mMostCommonKeyHeight; + keyWidth = getMaxKeyWidth(key, mParams.mDefaultKeyWidth, padding, paintToMeasure); + rowHeight = keyboard.mMostCommonKeyHeight; } final int dividerWidth; - if (parentKey.needsDividersInMoreKeys()) { + if (key.needsDividersInMoreKeys()) { mDivider = mResources.getDrawable(R.drawable.more_keys_divider); - dividerWidth = (int)(width * DIVIDER_RATIO); + dividerWidth = (int)(keyWidth * DIVIDER_RATIO); } else { mDivider = null; dividerWidth = 0; } - mParams.setParameters(moreKeys.length, parentKey.getMoreKeysColumn(), - width, height, parentKey.getX() + parentKey.getWidth() / 2, - parentKeyboard.mId.mWidth, parentKey.isFixedColumnOrderMoreKeys(), - dividerWidth); + final MoreKeySpec[] moreKeys = key.getMoreKeys(); + mParams.setParameters(moreKeys.length, key.getMoreKeysColumn(), keyWidth, rowHeight, + key.getX() + key.getWidth() / 2, keyboard.mId.mWidth, + key.isFixedColumnOrderMoreKeys(), dividerWidth); } private static int getMaxKeyWidth(final Key parentKey, final int minKeyWidth, diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java index a34dbef4b..8010a3e7e 100644 --- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java @@ -21,6 +21,7 @@ import android.os.Handler; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; +import android.view.accessibility.AccessibilityEvent; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.KeyboardAccessibilityDelegate; @@ -106,6 +107,12 @@ final class EmojiPageKeyboardView extends KeyboardView implements } } + @Override + public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) { + // Don't populate accessibility event with all Emoji keys. + return true; + } + /** * {@inheritDoc} */ diff --git a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java index 3a72aed0d..a194f3dfd 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java @@ -27,16 +27,19 @@ import com.android.inputmethod.keyboard.PointerTracker; * SlidingKeyInputDrawingPreview. */ public abstract class AbstractDrawingPreview { - private final View mDrawingView; + private View mDrawingView; private boolean mPreviewEnabled; private boolean mHasValidGeometry; - protected AbstractDrawingPreview(final View drawingView) { + public void setDrawingView(final DrawingPreviewPlacerView drawingView) { mDrawingView = drawingView; + drawingView.addPreview(this); } - protected final View getDrawingView() { - return mDrawingView; + protected void invalidateDrawingView() { + if (mDrawingView != null) { + mDrawingView.invalidate(); + } } protected final boolean isPreviewEnabled() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java index 3b4c43418..a5d47adb3 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java @@ -46,7 +46,9 @@ public final class DrawingPreviewPlacerView extends RelativeLayout { } public void addPreview(final AbstractDrawingPreview preview) { - mPreviews.add(preview); + if (mPreviews.indexOf(preview) < 0) { + mPreviews.add(preview); + } } public void setKeyboardViewGeometry(final int[] originCoords, final int width, diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java index 2fa703083..fd84856b7 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java @@ -23,7 +23,6 @@ import android.graphics.Paint.Align; import android.graphics.Rect; import android.graphics.RectF; import android.text.TextUtils; -import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; @@ -49,6 +48,7 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { public final float mGesturePreviewHorizontalPadding; public final float mGesturePreviewVerticalPadding; public final float mGesturePreviewRoundRadius; + public final int mDisplayWidth; private final int mGesturePreviewTextSize; private final int mGesturePreviewTextColor; @@ -72,6 +72,7 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { R.styleable.MainKeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); mGesturePreviewRoundRadius = mainKeyboardViewAttr.getDimension( R.styleable.MainKeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); + mDisplayWidth = mainKeyboardViewAttr.getResources().getDisplayMetrics().widthPixels; final Paint textPaint = getTextPaint(); final Rect textRect = new Rect(); @@ -100,9 +101,8 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; private final int[] mLastPointerCoords = CoordinateUtils.newInstance(); - public GestureFloatingTextDrawingPreview(final View drawingView, final TypedArray typedArray) { - super(drawingView); - mParams = new GesturePreviewTextParams(typedArray); + public GestureFloatingTextDrawingPreview(final TypedArray mainKeyboardViewAttr) { + mParams = new GesturePreviewTextParams(mainKeyboardViewAttr); } @Override @@ -149,7 +149,7 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { */ protected void updatePreviewPosition() { if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) { - getDrawingView().invalidate(); + invalidateDrawingView(); return; } final String text = mSuggestedWords.getWord(0); @@ -163,10 +163,9 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { final float rectWidth = textWidth + hPad * 2.0f; final float rectHeight = textHeight + vPad * 2.0f; - final int displayWidth = getDrawingView().getResources().getDisplayMetrics().widthPixels; final float rectX = Math.min( Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f), - displayWidth - rectWidth); + mParams.mDisplayWidth - rectWidth); final float rectY = CoordinateUtils.y(mLastPointerCoords) - mParams.mGesturePreviewTextOffset - rectHeight; rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight); @@ -174,6 +173,6 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { mPreviewTextX = (int)(rectX + hPad + textWidth / 2.0f); mPreviewTextY = (int)(rectY + vPad) + textHeight; // TODO: Should narrow the invalidate region. - getDrawingView().invalidate(); + invalidateDrawingView(); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java index 72628e38a..f7bd7efe0 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java @@ -24,17 +24,15 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.os.Message; +import android.os.Handler; import android.util.SparseArray; -import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; -import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; /** * Draw preview graphics of multiple gesture trails during gesture input. */ -public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { +public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview implements Runnable { private final SparseArray<GestureTrailDrawingPoints> mGestureTrails = new SparseArray<>(); private final GestureTrailDrawingParams mDrawingParams; private final Paint mGesturePaint; @@ -47,45 +45,10 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { private final Rect mDirtyRect = new Rect(); private final Rect mGestureTrailBoundsRect = new Rect(); // per trail - private final DrawingHandler mDrawingHandler; + private final Handler mDrawingHandler = new Handler(); - private static final class DrawingHandler - extends LeakGuardHandlerWrapper<GestureTrailsDrawingPreview> { - private static final int MSG_UPDATE_GESTURE_TRAIL = 0; - - private final GestureTrailDrawingParams mDrawingParams; - - public DrawingHandler(final GestureTrailsDrawingPreview ownerInstance, - final GestureTrailDrawingParams drawingParams) { - super(ownerInstance); - mDrawingParams = drawingParams; - } - - @Override - public void handleMessage(final Message msg) { - final GestureTrailsDrawingPreview preview = getOwnerInstance(); - if (preview == null) { - return; - } - switch (msg.what) { - case MSG_UPDATE_GESTURE_TRAIL: - preview.getDrawingView().invalidate(); - break; - } - } - - public void postUpdateGestureTrailPreview() { - removeMessages(MSG_UPDATE_GESTURE_TRAIL); - sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_TRAIL), - mDrawingParams.mUpdateInterval); - } - } - - public GestureTrailsDrawingPreview(final View drawingView, - final TypedArray mainKeyboardViewAttr) { - super(drawingView); + public GestureTrailsDrawingPreview(final TypedArray mainKeyboardViewAttr) { mDrawingParams = new GestureTrailDrawingParams(mainKeyboardViewAttr); - mDrawingHandler = new DrawingHandler(this, mDrawingParams); final Paint gesturePaint = new Paint(); gesturePaint.setAntiAlias(true); gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); @@ -153,6 +116,12 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { return needsUpdatingGestureTrail; } + @Override + public void run() { + // Update preview. + invalidateDrawingView(); + } + /** * Draws the preview * @param canvas The canvas where the preview is drawn. @@ -167,7 +136,8 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { final boolean needsUpdatingGestureTrail = drawGestureTrails( mOffscreenCanvas, mGesturePaint, mDirtyRect); if (needsUpdatingGestureTrail) { - mDrawingHandler.postUpdateGestureTrailPreview(); + mDrawingHandler.removeCallbacks(this); + mDrawingHandler.postDelayed(this, mDrawingParams.mUpdateInterval); } // Transfer offscreen buffer to screen. if (!mDirtyRect.isEmpty()) { @@ -199,6 +169,6 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { trail.addStroke(tracker.getGestureStrokeDrawingPoints(), tracker.getDownTime()); // TODO: Should narrow the invalidate region. - getDrawingView().invalidate(); + invalidateDrawingView(); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java index 605519b02..6fc300beb 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -21,17 +21,12 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; -import android.graphics.drawable.Drawable; -import android.util.TypedValue; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; -import android.widget.TextView; import com.android.inputmethod.keyboard.Key; -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.ViewLayoutUtils; @@ -46,10 +41,11 @@ import java.util.HashSet; * - how key previews should be shown and dismissed. */ public final class KeyPreviewChoreographer { - // Free {@link TextView} pool that can be used for key preview. - private final ArrayDeque<TextView> mFreeKeyPreviewTextViews = new ArrayDeque<>(); - // Map from {@link Key} to {@link TextView} that is currently being displayed as key preview. - private final HashMap<Key,TextView> mShowingKeyPreviewTextViews = new HashMap<>(); + // Free {@link KeyPreviewView} pool that can be used for key preview. + private final ArrayDeque<KeyPreviewView> mFreeKeyPreviewViews = new ArrayDeque<>(); + // Map from {@link Key} to {@link KeyPreviewView} that is currently being displayed as key + // preview. + private final HashMap<Key,KeyPreviewView> mShowingKeyPreviewViews = new HashMap<>(); private final KeyPreviewDrawParams mParams; @@ -57,32 +53,28 @@ public final class KeyPreviewChoreographer { mParams = params; } - public TextView getKeyPreviewTextView(final Key key, final ViewGroup placerView) { - TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); - if (previewTextView != null) { - return previewTextView; + public KeyPreviewView getKeyPreviewView(final Key key, final ViewGroup placerView) { + KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.remove(key); + if (keyPreviewView != null) { + return keyPreviewView; } - previewTextView = mFreeKeyPreviewTextViews.poll(); - if (previewTextView != null) { - return previewTextView; + keyPreviewView = mFreeKeyPreviewViews.poll(); + if (keyPreviewView != null) { + return keyPreviewView; } final Context context = placerView.getContext(); - if (mParams.mLayoutId != 0) { - previewTextView = (TextView)LayoutInflater.from(context) - .inflate(mParams.mLayoutId, null); - } else { - previewTextView = new TextView(context); - } - placerView.addView(previewTextView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0)); - return previewTextView; + keyPreviewView = new KeyPreviewView(context, null /* attrs */); + keyPreviewView.setBackgroundResource(mParams.mPreviewBackgroundResId); + placerView.addView(keyPreviewView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0)); + return keyPreviewView; } public boolean isShowingKeyPreview(final Key key) { - return mShowingKeyPreviewTextViews.containsKey(key); + return mShowingKeyPreviewViews.containsKey(key); } public void dismissAllKeyPreviews() { - for (final Key key : new HashSet<>(mShowingKeyPreviewTextViews.keySet())) { + for (final Key key : new HashSet<>(mShowingKeyPreviewViews.keySet())) { dismissKeyPreview(key, false /* withAnimation */); } } @@ -91,11 +83,11 @@ public final class KeyPreviewChoreographer { if (key == null) { return; } - final TextView previewTextView = mShowingKeyPreviewTextViews.get(key); - if (previewTextView == null) { + final KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.get(key); + if (keyPreviewView == null) { return; } - final Object tag = previewTextView.getTag(); + final Object tag = keyPreviewView.getTag(); if (withAnimation) { if (tag instanceof KeyPreviewAnimations) { final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; @@ -104,105 +96,76 @@ public final class KeyPreviewChoreographer { } } // Dismiss preview without animation. - mShowingKeyPreviewTextViews.remove(key); + mShowingKeyPreviewViews.remove(key); if (tag instanceof Animator) { ((Animator)tag).cancel(); } - previewTextView.setTag(null); - previewTextView.setVisibility(View.INVISIBLE); - mFreeKeyPreviewTextViews.add(previewTextView); + keyPreviewView.setTag(null); + keyPreviewView.setVisibility(View.INVISIBLE); + mFreeKeyPreviewViews.add(keyPreviewView); } - // Background state set - private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { - { // STATE_MIDDLE - {}, - { R.attr.state_has_morekeys } - }, - { // STATE_LEFT - { R.attr.state_left_edge }, - { R.attr.state_left_edge, R.attr.state_has_morekeys } - }, - { // STATE_RIGHT - { R.attr.state_right_edge }, - { R.attr.state_right_edge, R.attr.state_has_morekeys } - } - }; - private static final int STATE_MIDDLE = 0; - private static final int STATE_LEFT = 1; - private static final int STATE_RIGHT = 2; - private static final int STATE_NORMAL = 0; - private static final int STATE_HAS_MOREKEYS = 1; + public void placeKeyPreviewAndShow(final Key key, final KeyboardIconsSet iconsSet, + final KeyDrawParams drawParams, final int keyboardViewWidth, final int[] keyboardOrigin, + final ViewGroup placerView, final boolean withAnimation) { + final KeyPreviewView keyPreviewView = getKeyPreviewView(key, placerView); + placeKeyPreview( + key, keyPreviewView, iconsSet, drawParams, keyboardViewWidth, keyboardOrigin); + showKeyPreview(key, keyPreviewView, withAnimation); + } - public void placeKeyPreview(final Key key, final TextView previewTextView, + private void placeKeyPreview(final Key key, final KeyPreviewView keyPreviewView, final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams, final int keyboardViewWidth, final int[] originCoords) { - previewTextView.setTextColor(drawParams.mPreviewTextColor); - final Drawable background = previewTextView.getBackground(); - final String label = key.getPreviewLabel(); - // What we show as preview should match what we show on a key top in onDraw(). - if (label != null) { - // TODO Should take care of temporaryShiftLabel here. - previewTextView.setCompoundDrawables(null, null, null, null); - previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, - key.selectPreviewTextSize(drawParams)); - previewTextView.setTypeface(key.selectPreviewTypeface(drawParams)); - previewTextView.setText(label); - } else { - previewTextView.setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet)); - previewTextView.setText(null); - } - - previewTextView.measure( + keyPreviewView.setPreviewVisual(key, iconsSet, drawParams); + keyPreviewView.measure( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - mParams.setGeometry(previewTextView); - final int previewWidth = previewTextView.getMeasuredWidth(); + mParams.setGeometry(keyPreviewView); + final int previewWidth = keyPreviewView.getMeasuredWidth(); final int previewHeight = mParams.mPreviewHeight; final int keyDrawWidth = key.getDrawWidth(); // The key preview is horizontally aligned with the center of the visible part of the // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and // the left/right background is used if such background is specified. - final int statePosition; + final int keyPreviewPosition; int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 + CoordinateUtils.x(originCoords); if (previewX < 0) { previewX = 0; - statePosition = STATE_LEFT; + keyPreviewPosition = KeyPreviewView.POSITION_LEFT; } else if (previewX > keyboardViewWidth - previewWidth) { previewX = keyboardViewWidth - previewWidth; - statePosition = STATE_RIGHT; + keyPreviewPosition = KeyPreviewView.POSITION_RIGHT; } else { - statePosition = STATE_MIDDLE; + keyPreviewPosition = KeyPreviewView.POSITION_MIDDLE; } + final boolean hasMoreKeys = (key.getMoreKeys() != null); + keyPreviewView.setPreviewBackground(hasMoreKeys, keyPreviewPosition); // The key preview is placed vertically above the top edge of the parent key with an // arbitrary offset. final int previewY = key.getY() - previewHeight + mParams.mPreviewOffset + CoordinateUtils.y(originCoords); - if (background != null) { - final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; - background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); - } ViewLayoutUtils.placeViewAt( - previewTextView, previewX, previewY, previewWidth, previewHeight); - previewTextView.setPivotX(previewWidth / 2.0f); - previewTextView.setPivotY(previewHeight); + keyPreviewView, previewX, previewY, previewWidth, previewHeight); + keyPreviewView.setPivotX(previewWidth / 2.0f); + keyPreviewView.setPivotY(previewHeight); } - public void showKeyPreview(final Key key, final TextView previewTextView, + private void showKeyPreview(final Key key, final KeyPreviewView keyPreviewView, final boolean withAnimation) { if (!withAnimation) { - previewTextView.setVisibility(View.VISIBLE); - mShowingKeyPreviewTextViews.put(key, previewTextView); + keyPreviewView.setVisibility(View.VISIBLE); + mShowingKeyPreviewViews.put(key, keyPreviewView); return; } // Show preview with animation. - final Animator showUpAnimation = createShowUpAniation(key, previewTextView); - final Animator dismissAnimation = createDismissAnimation(key, previewTextView); + final Animator showUpAnimation = createShowUpAniation(key, keyPreviewView); + final Animator dismissAnimation = createDismissAnimation(key, keyPreviewView); final KeyPreviewAnimations animation = new KeyPreviewAnimations( showUpAnimation, dismissAnimation); - previewTextView.setTag(animation); + keyPreviewView.setTag(animation); animation.startShowUp(); } @@ -212,13 +175,13 @@ public final class KeyPreviewChoreographer { private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); - private Animator createShowUpAniation(final Key key, final TextView previewTextView) { + private Animator createShowUpAniation(final Key key, final KeyPreviewView keyPreviewView) { // TODO: Optimization for no scale animation and no duration. final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_X, mParams.getShowUpStartScale(), + keyPreviewView, View.SCALE_X, mParams.getShowUpStartScale(), KEY_PREVIEW_SHOW_UP_END_SCALE); final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_Y, mParams.getShowUpStartScale(), + keyPreviewView, View.SCALE_Y, mParams.getShowUpStartScale(), KEY_PREVIEW_SHOW_UP_END_SCALE); final AnimatorSet showUpAnimation = new AnimatorSet(); showUpAnimation.play(scaleXAnimation).with(scaleYAnimation); @@ -227,18 +190,18 @@ public final class KeyPreviewChoreographer { showUpAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(final Animator animation) { - showKeyPreview(key, previewTextView, false /* withAnimation */); + showKeyPreview(key, keyPreviewView, false /* withAnimation */); } }); return showUpAnimation; } - private Animator createDismissAnimation(final Key key, final TextView previewTextView) { + private Animator createDismissAnimation(final Key key, final KeyPreviewView keyPreviewView) { // TODO: Optimization for no scale animation and no duration. final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_X, mParams.getDismissEndScale()); + keyPreviewView, View.SCALE_X, mParams.getDismissEndScale()); final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_Y, mParams.getDismissEndScale()); + keyPreviewView, View.SCALE_Y, mParams.getDismissEndScale()); final AnimatorSet dismissAnimation = new AnimatorSet(); dismissAnimation.play(scaleXAnimation).with(scaleYAnimation); final int dismissDuration = Math.min( diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java index 37e5c889d..68c9831fa 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java @@ -23,9 +23,9 @@ import com.android.inputmethod.latin.R; public final class KeyPreviewDrawParams { // XML attributes of {@link MainKeyboardView}. - public final int mLayoutId; public final int mPreviewOffset; public final int mPreviewHeight; + public final int mPreviewBackgroundResId; private int mShowUpDuration; private int mDismissDuration; private float mShowUpStartScale; @@ -63,13 +63,10 @@ public final class KeyPreviewDrawParams { R.styleable.MainKeyboardView_keyPreviewOffset, 0); mPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( R.styleable.MainKeyboardView_keyPreviewHeight, 0); + mPreviewBackgroundResId = mainKeyboardViewAttr.getResourceId( + R.styleable.MainKeyboardView_keyPreviewBackground, 0); mLingerTimeout = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); - mLayoutId = mainKeyboardViewAttr.getResourceId( - R.styleable.MainKeyboardView_keyPreviewLayout, 0); - if (mLayoutId == 0) { - mShowPopup = false; - } } public void setVisibleOffset(final int previewVisibleOffset) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java new file mode 100644 index 000000000..360faf829 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 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. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.TextView; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.latin.R; + +/** + * The pop up key preview view. + */ +public class KeyPreviewView extends TextView { + public static final int POSITION_MIDDLE = 0; + public static final int POSITION_LEFT = 1; + public static final int POSITION_RIGHT = 2; + + public KeyPreviewView(final Context context, final AttributeSet attrs) { + this(context, attrs, 0); + } + + public KeyPreviewView(final Context context, final AttributeSet attrs, final int defStyleAttr) { + super(context, attrs, defStyleAttr); + setGravity(Gravity.CENTER); + } + + public void setPreviewVisual(final Key key, final KeyboardIconsSet iconsSet, + final KeyDrawParams drawParams) { + // What we show as preview should match what we show on a key top in onDraw(). + final int iconId = key.getIconId(); + if (iconId != KeyboardIconsSet.ICON_UNDEFINED) { + setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet)); + setText(null); + return; + } + + setCompoundDrawables(null, null, null, null); + setTextColor(drawParams.mPreviewTextColor); + setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams)); + setTypeface(key.selectPreviewTypeface(drawParams)); + // TODO Should take care of temporaryShiftLabel here. + setText(key.getPreviewLabel()); + } + + // Background state set + private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { + { // POSITION_MIDDLE + {}, + { R.attr.state_has_morekeys } + }, + { // POSITION_LEFT + { R.attr.state_left_edge }, + { R.attr.state_left_edge, R.attr.state_has_morekeys } + }, + { // POSITION_RIGHT + { R.attr.state_right_edge }, + { R.attr.state_right_edge, R.attr.state_has_morekeys } + } + }; + private static final int STATE_NORMAL = 0; + private static final int STATE_HAS_MOREKEYS = 1; + + public void setPreviewBackground(final boolean hasMoreKeys, final int position) { + final Drawable background = getBackground(); + if (background == null) { + return; + } + final int hasMoreKeysState = hasMoreKeys ? STATE_HAS_MOREKEYS : STATE_NORMAL; + background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[position][hasMoreKeysState]); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java index 76cb89160..ef4c74d61 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java @@ -20,7 +20,6 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; -import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; @@ -28,6 +27,11 @@ import com.android.inputmethod.latin.utils.CoordinateUtils; /** * Draw rubber band preview graphics during sliding key input. + * + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewColor + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewWidth + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewBodyRatio + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewShadowRatio */ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview { private final float mPreviewBodyRadius; @@ -40,9 +44,7 @@ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview private final RoundedLine mRoundedLine = new RoundedLine(); private final Paint mPaint = new Paint(); - public SlidingKeyInputDrawingPreview(final View drawingView, - final TypedArray mainKeyboardViewAttr) { - super(drawingView); + public SlidingKeyInputDrawingPreview(final TypedArray mainKeyboardViewAttr) { final int previewColor = mainKeyboardViewAttr.getColor( R.styleable.MainKeyboardView_slidingKeyInputPreviewColor, 0); final float previewRadius = mainKeyboardViewAttr.getDimension( @@ -69,7 +71,7 @@ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview public void dismissSlidingKeyInputPreview() { mShowsSlidingKeyInputPreview = false; - getDrawingView().invalidate(); + invalidateDrawingView(); } /** @@ -99,6 +101,6 @@ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview tracker.getDownCoordinates(mPreviewFrom); tracker.getLastCoordinates(mPreviewTo); mShowsSlidingKeyInputPreview = true; - getDrawingView().invalidate(); + invalidateDrawingView(); } } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 543f74fc4..42105e2c3 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -28,7 +28,6 @@ import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; -import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.JniUtils; @@ -49,10 +48,6 @@ import java.util.Map; public final class BinaryDictionary extends Dictionary { private static final String TAG = BinaryDictionary.class.getSimpleName(); - // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h - private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; - // Must be equal to MAX_RESULTS in native/jni/src/defines.h - private static final int MAX_RESULTS = 18; // The cutoff returned by native for auto-commit confidence. // Must be equal to CONFIDENCE_TO_AUTO_COMMIT in native/jni/src/defines.h private static final int CONFIDENCE_TO_AUTO_COMMIT = 1000000; @@ -88,21 +83,10 @@ public final class BinaryDictionary extends Dictionary { private final Locale mLocale; private final long mDictSize; private final String mDictFilePath; + private final boolean mUseFullEditDistance; private final boolean mIsUpdatable; private boolean mHasUpdated; - private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH]; - private final int[] mOutputSuggestionCount = new int[1]; - private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS]; - private final int[] mSpaceIndices = new int[MAX_RESULTS]; - private final int[] mOutputScores = new int[MAX_RESULTS]; - private final int[] mOutputTypes = new int[MAX_RESULTS]; - // Only one result is ever used - private final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; - private final float[] mInputOutputLanguageWeight = new float[1]; - - private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions(); - private final SparseArray<DicTraverseSession> mDicTraverseSessions = new SparseArray<>(); // TODO: There should be a way to remove used DicTraverseSession objects from @@ -136,7 +120,7 @@ public final class BinaryDictionary extends Dictionary { mDictFilePath = filename; mIsUpdatable = isUpdatable; mHasUpdated = false; - mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); + mUseFullEditDistance = useFullEditDistance; loadDictionary(filename, offset, length, isUpdatable); } @@ -148,7 +132,6 @@ public final class BinaryDictionary extends Dictionary { * @param formatVersion the format version of the dictionary * @param attributeMap the attributes of the dictionary */ - @UsedForTesting public BinaryDictionary(final String filename, final boolean useFullEditDistance, final Locale locale, final String dictType, final long formatVersion, final Map<String, String> attributeMap) { @@ -159,7 +142,7 @@ public final class BinaryDictionary extends Dictionary { // On memory dictionary is always updatable. mIsUpdatable = true; mHasUpdated = false; - mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); + mUseFullEditDistance = useFullEditDistance; final String[] keyArray = new String[attributeMap.size()]; final String[] valueArray = new String[attributeMap.size()]; int index = 0; @@ -274,8 +257,8 @@ public final class BinaryDictionary extends Dictionary { if (!isValidDictionary()) { return null; } - - Arrays.fill(mInputCodePoints, Constants.NOT_A_CODE); + final DicTraverseSession session = getTraverseSession(sessionId); + Arrays.fill(session.mInputCodePoints, Constants.NOT_A_CODE); // TODO: toLowerCase in the native code final int[] prevWordCodePointArray = (null == prevWordsInfo.mPrevWord) ? null : StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); @@ -284,47 +267,50 @@ public final class BinaryDictionary extends Dictionary { final int inputSize; if (!isGesture) { inputSize = composer.copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount( - mInputCodePoints); + session.mInputCodePoints); if (inputSize < 0) { return null; } } else { inputSize = inputPointers.getPointerSize(); } - - mNativeSuggestOptions.setIsGesture(isGesture); - mNativeSuggestOptions.setBlockOffensiveWords(blockOffensiveWords); - mNativeSuggestOptions.setAdditionalFeaturesOptions(additionalFeaturesOptions); + session.mNativeSuggestOptions.setUseFullEditDistance(mUseFullEditDistance); + session.mNativeSuggestOptions.setIsGesture(isGesture); + session.mNativeSuggestOptions.setBlockOffensiveWords(blockOffensiveWords); + session.mNativeSuggestOptions.setAdditionalFeaturesOptions(additionalFeaturesOptions); if (inOutLanguageWeight != null) { - mInputOutputLanguageWeight[0] = inOutLanguageWeight[0]; + session.mInputOutputLanguageWeight[0] = inOutLanguageWeight[0]; } else { - mInputOutputLanguageWeight[0] = Dictionary.NOT_A_LANGUAGE_WEIGHT; + session.mInputOutputLanguageWeight[0] = Dictionary.NOT_A_LANGUAGE_WEIGHT; } // proximityInfo and/or prevWordForBigrams may not be null. getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), getTraverseSession(sessionId).getSession(), inputPointers.getXCoordinates(), inputPointers.getYCoordinates(), inputPointers.getTimes(), - inputPointers.getPointerIds(), mInputCodePoints, inputSize, - mNativeSuggestOptions.getOptions(), prevWordCodePointArray, - prevWordsInfo.mIsBeginningOfSentence, mOutputSuggestionCount, - mOutputCodePoints, mOutputScores, mSpaceIndices, mOutputTypes, - mOutputAutoCommitFirstWordConfidence, mInputOutputLanguageWeight); + inputPointers.getPointerIds(), session.mInputCodePoints, inputSize, + session.mNativeSuggestOptions.getOptions(), prevWordCodePointArray, + prevWordsInfo.mIsBeginningOfSentence, session.mOutputSuggestionCount, + session.mOutputCodePoints, session.mOutputScores, session.mSpaceIndices, + session.mOutputTypes, session.mOutputAutoCommitFirstWordConfidence, + session.mInputOutputLanguageWeight); if (inOutLanguageWeight != null) { - inOutLanguageWeight[0] = mInputOutputLanguageWeight[0]; + inOutLanguageWeight[0] = session.mInputOutputLanguageWeight[0]; } - final int count = mOutputSuggestionCount[0]; + final int count = session.mOutputSuggestionCount[0]; final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>(); for (int j = 0; j < count; ++j) { - final int start = j * MAX_WORD_LENGTH; + final int start = j * Constants.DICTIONARY_MAX_WORD_LENGTH; int len = 0; - while (len < MAX_WORD_LENGTH && mOutputCodePoints[start + len] != 0) { + while (len < Constants.DICTIONARY_MAX_WORD_LENGTH + && session.mOutputCodePoints[start + len] != 0) { ++len; } if (len > 0) { - suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len), - mOutputScores[j], mOutputTypes[j], this /* sourceDict */, - mSpaceIndices[j] /* indexOfTouchPointOfSecondWord */, - mOutputAutoCommitFirstWordConfidence[0])); + suggestions.add(new SuggestedWordInfo( + new String(session.mOutputCodePoints, start, len), + session.mOutputScores[j], session.mOutputTypes[j], this /* sourceDict */, + session.mSpaceIndices[j] /* indexOfTouchPointOfSecondWord */, + session.mOutputAutoCommitFirstWordConfidence[0])); } } return suggestions; @@ -377,7 +363,7 @@ public final class BinaryDictionary extends Dictionary { return null; } final int[] codePoints = StringUtils.toCodePointArray(word); - final int[] outCodePoints = new int[MAX_WORD_LENGTH]; + final int[] outCodePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; final boolean[] outFlags = new boolean[FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT]; final int[] outProbabilityInfo = new int[FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT]; @@ -412,7 +398,7 @@ public final class BinaryDictionary extends Dictionary { * If token is 0, this method newly starts iterating the dictionary. */ public GetNextWordPropertyResult getNextWordProperty(final int token) { - final int[] codePoints = new int[MAX_WORD_LENGTH]; + final int[] codePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; final int nextToken = getNextWordNative(mNativeDict, token, codePoints); final String word = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints); return new GetNextWordPropertyResult(getWordProperty(word), nextToken); diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java index 8d295adee..8bbf426e5 100644 --- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java +++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.utils.JniUtils; import java.util.Locale; @@ -24,6 +25,20 @@ public final class DicTraverseSession { static { JniUtils.loadNativeLibrary(); } + // Must be equal to MAX_RESULTS in native/jni/src/defines.h + private static final int MAX_RESULTS = 18; + public final int[] mInputCodePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; + public final int[] mOutputSuggestionCount = new int[1]; + public final int[] mOutputCodePoints = + new int[Constants.DICTIONARY_MAX_WORD_LENGTH * MAX_RESULTS]; + public final int[] mSpaceIndices = new int[MAX_RESULTS]; + public final int[] mOutputScores = new int[MAX_RESULTS]; + public final int[] mOutputTypes = new int[MAX_RESULTS]; + // Only one result is ever used + public final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; + public final float[] mInputOutputLanguageWeight = new float[1]; + + public final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions(); private static native long setDicTraverseSessionNative(String locale, long dictSize); private static native void initDicTraverseSessionNative(long nativeDicTraverseSession, diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index 4a28a242a..8c4870d08 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -468,15 +468,19 @@ public class DictionaryFacilitator { isValid, timeStampInSeconds, mDistracterFilter); } - public void cancelAddingUserHistory(final PrevWordsInfo prevWordsInfo, - final String committedWord) { - final ExpandableBinaryDictionary userHistoryDictionary = - mDictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY); - if (userHistoryDictionary != null) { - userHistoryDictionary.removeNgramDynamically(prevWordsInfo, committedWord); + private void removeWord(final String dictName, final String word) { + final ExpandableBinaryDictionary dictionary = mDictionaries.getSubDict(dictName); + if (dictionary != null) { + dictionary.removeUnigramEntryDynamically(word); } } + public void removeWordFromPersonalizedDicts(final String word) { + removeWord(Dictionary.TYPE_USER_HISTORY, word); + removeWord(Dictionary.TYPE_PERSONALIZATION, word); + removeWord(Dictionary.TYPE_CONTEXTUAL, word); + } + // TODO: Revise the way to fusion suggestion results. public SuggestionResults getSuggestionResults(final WordComposer composer, final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo, diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index b1966bffc..6199c7dfe 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -311,6 +311,27 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } /** + * Dynamically remove the unigram entry from the dictionary. + */ + public void removeUnigramEntryDynamically(final String word) { + reloadDictionaryIfRequired(); + asyncExecuteTaskWithWriteLock(new Runnable() { + @Override + public void run() { + if (mBinaryDictionary == null) { + return; + } + runGCIfRequiredLocked(true /* mindsBlockByGC */); + if (!mBinaryDictionary.removeUnigramEntry(word)) { + if (DEBUG) { + Log.i(TAG, "Cannot remove unigram entry: " + word); + } + } + } + }); + } + + /** * Adds n-gram information of a word to the dictionary. May overwrite an existing entry. */ public void addNgramEntry(final PrevWordsInfo prevWordsInfo, final String word, @@ -341,6 +362,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { /** * Dynamically remove the n-gram entry in the dictionary. */ + @UsedForTesting public void removeNgramDynamically(final PrevWordsInfo prevWordsInfo, final String word) { reloadDictionaryIfRequired(); asyncExecuteTaskWithWriteLock(new Runnable() { diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index e1ae3dfe3..ebe436128 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -41,6 +41,7 @@ public final class InputAttributes { final public boolean mShouldShowSuggestions; final public boolean mApplicationSpecifiedCompletionOn; final public boolean mShouldInsertSpacesAutomatically; + final public boolean mShouldShowVoiceInputKey; final private int mInputType; final private EditorInfo mEditorInfo; final private String mPackageNameForPrivateImeOptions; @@ -74,6 +75,7 @@ public final class InputAttributes { mInputTypeNoAutoCorrect = false; mApplicationSpecifiedCompletionOn = false; mShouldInsertSpacesAutomatically = false; + mShouldShowVoiceInputKey = false; return; } // inputClass == InputType.TYPE_CLASS_TEXT @@ -99,6 +101,12 @@ public final class InputAttributes { mShouldInsertSpacesAutomatically = InputTypeUtils.isAutoSpaceFriendlyType(inputType); + final boolean noMicrophone = mIsPasswordField + || InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS == variation + || InputType.TYPE_TEXT_VARIATION_URI == variation + || hasNoMicrophoneKeyOption(); + mShouldShowVoiceInputKey = !noMicrophone; + // If it's a browser edit field and auto correct is not ON explicitly, then // disable auto correction, but keep suggestions on. // If NO_SUGGESTIONS is set, don't do prediction. @@ -119,7 +127,7 @@ public final class InputAttributes { return editorInfo.inputType == mInputType; } - public boolean hasNoMicrophoneKeyOption() { + private boolean hasNoMicrophoneKeyOption() { @SuppressWarnings("deprecation") final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions( null, NO_MICROPHONE_COMPAT, mEditorInfo); diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index de95b9787..9462c385d 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -884,6 +884,9 @@ public final class InputLogic { final String rejectedSuggestion = mWordComposer.getTypedWord(); mWordComposer.reset(); mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion); + if (!TextUtils.isEmpty(rejectedSuggestion)) { + mDictionaryFacilitator.removeWordFromPersonalizedDicts(rejectedSuggestion); + } } else { mWordComposer.processEvent(inputTransaction.mEvent); } @@ -1187,6 +1190,8 @@ public final class InputLogic { Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " + "requested!"); } + // Clear the suggestions strip. + mSuggestionStripViewAccessor.showSuggestionStrip(SuggestedWords.EMPTY); return; } @@ -1363,7 +1368,6 @@ public final class InputLogic { * @param inputTransaction The transaction in progress. */ private void revertCommit(final InputTransaction inputTransaction) { - final PrevWordsInfo prevWordsInfo = mLastComposedWord.mPrevWordsInfo; final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord; final CharSequence committedWord = mLastComposedWord.mCommittedWord; final String committedWordString = committedWord.toString(); @@ -1385,8 +1389,8 @@ public final class InputLogic { } } mConnection.deleteSurroundingText(deleteLength, 0); - if (!TextUtils.isEmpty(prevWordsInfo.mPrevWord) && !TextUtils.isEmpty(committedWord)) { - mDictionaryFacilitator.cancelAddingUserHistory(prevWordsInfo, committedWordString); + if (!TextUtils.isEmpty(committedWord)) { + mDictionaryFacilitator.removeWordFromPersonalizedDicts(committedWordString); } final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString; final SpannableString textToCommit = new SpannableString(stringToCommit); diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 44104019b..8de5fed07 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -125,8 +125,7 @@ public final class SettingsValues { mSlidingKeyInputPreviewEnabled = prefs.getBoolean( DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true); mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res) - && !mInputAttributes.mIsPasswordField - && !mInputAttributes.hasNoMicrophoneKeyOption() + && mInputAttributes.mShouldShowVoiceInputKey && SubtypeSwitcher.getInstance().isShortcutImeEnabled(); final String autoCorrectionThresholdRawValue = prefs.getString( Settings.PREF_AUTO_CORRECTION_THRESHOLD, diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 19b48f081..46f5cdee0 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -44,6 +44,7 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.PunctuationSuggestions; import com.android.inputmethod.latin.R; @@ -386,6 +387,12 @@ final class SuggestionStripLayoutHelper { final float scaleX = getTextScaleX(word, width, wordView.getPaint()); wordView.setText(text); // TextView.setText() resets text scale x to 1.0. wordView.setTextScaleX(Math.max(scaleX, MIN_TEXT_XSCALE)); + // A <code>wordView</code> should be disabled when <code>word</code> is empty in order to + // make it unclickable. + // With accessibility touch exploration on, <code>wordView</code> should be enabled even + // when it is empty to avoid announcing as "disabled". + wordView.setEnabled(!TextUtils.isEmpty(word) + || AccessibilityUtils.getInstance().isTouchExplorationEnabled()); return wordView; } diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 47b5c3344..72f8f87e4 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -92,3 +92,6 @@ include $(LOCAL_PATH)/CleanupNativeFileList.mk #################### Unit test on host environment include $(LOCAL_PATH)/HostUnitTests.mk + +#################### Unit test on target environment +include $(LOCAL_PATH)/TargetUnitTests.mk diff --git a/native/jni/TargetUnitTests.mk b/native/jni/TargetUnitTests.mk new file mode 100644 index 000000000..12aae44ea --- /dev/null +++ b/native/jni/TargetUnitTests.mk @@ -0,0 +1,55 @@ +# Copyright (C) 2014 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. + +LOCAL_PATH := $(call my-dir) + +###################################### +include $(CLEAR_VARS) + +include $(LOCAL_PATH)/NativeFileList.mk + +#################### Target library for unit test +LATIN_IME_SRC_DIR := src +LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function +LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) +LOCAL_MODULE := liblatinime_target_static_for_unittests +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := $(addprefix $(LATIN_IME_SRC_DIR)/, $(LATIN_IME_CORE_SRC_FILES)) +# Here intentionally use libc++_shared rather than libc++_static because +# $(BUILD_NATIVE_TEST) has not yet supported libc++_static. +LOCAL_SDK_VERSION := 14 +LOCAL_NDK_STL_VARIANT := c++_shared +include $(BUILD_STATIC_LIBRARY) + +#################### Target native tests +include $(CLEAR_VARS) +LATIN_IME_TEST_SRC_DIR := tests +LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function +LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) +LOCAL_MODULE := liblatinime_target_unittests +LOCAL_MODULE_TAGS := tests +LOCAL_SRC_FILES := \ + $(addprefix $(LATIN_IME_TEST_SRC_DIR)/, $(LATIN_IME_CORE_TEST_FILES)) +LOCAL_STATIC_LIBRARIES += liblatinime_target_static_for_unittests +# Here intentionally include external/libcxx/libcxx.mk rather because +# $(BUILD_NATIVE_TEST) fails when LOCAL_NDK_STL_VARIANT is specified. +include external/libcxx/libcxx.mk +include $(BUILD_NATIVE_TEST) + +#################### Clean up the tmp vars +LATIN_IME_SRC_DIR := +LATIN_IME_TEST_SRC_DIR := +include $(LOCAL_PATH)/CleanupNativeFileList.mk diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 6e2219d87..c2cd2addd 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -304,17 +304,18 @@ static jint latinime_BinaryDictionary_getNextWord(JNIEnv *env, jclass clazz, jlong dict, jint token, jintArray outCodePoints) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); if (!dictionary) return 0; - const jsize outCodePointsLength = env->GetArrayLength(outCodePoints); - if (outCodePointsLength != MAX_WORD_LENGTH) { - AKLOGE("Invalid outCodePointsLength: %d", outCodePointsLength); + const jsize codePointBufSize = env->GetArrayLength(outCodePoints); + if (codePointBufSize != MAX_WORD_LENGTH) { + AKLOGE("Invalid outCodePointsLength: %d", codePointBufSize); ASSERT(false); return 0; } - int wordCodePoints[outCodePointsLength]; - memset(wordCodePoints, 0, sizeof(wordCodePoints)); - const int nextToken = dictionary->getNextWordAndNextToken(token, wordCodePoints); + int wordCodePoints[codePointBufSize]; + int wordCodePointCount = 0; + const int nextToken = dictionary->getNextWordAndNextToken(token, wordCodePoints, + &wordCodePointCount); JniDataUtils::outputCodePoints(env, outCodePoints, 0 /* start */, - MAX_WORD_LENGTH /* maxLength */, wordCodePoints, outCodePointsLength, + MAX_WORD_LENGTH /* maxLength */, wordCodePoints, wordCodePointCount, false /* needsNullTermination */); return nextToken; } @@ -555,12 +556,13 @@ static bool latinime_BinaryDictionary_migrateNative(JNIEnv *env, jclass clazz, j // TODO: Migrate historical information. int wordCodePoints[MAX_WORD_LENGTH]; + int wordCodePointCount = 0; int token = 0; // Add unigrams. do { - token = dictionary->getNextWordAndNextToken(token, wordCodePoints); - const int wordLength = CharUtils::getCodePointCount(MAX_WORD_LENGTH, wordCodePoints); - const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, wordLength); + token = dictionary->getNextWordAndNextToken(token, wordCodePoints, &wordCodePointCount); + const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, + wordCodePointCount); if (dictionaryStructureWithBufferPolicy->needsToRunGC(true /* mindsBlockByGC */)) { dictionaryStructureWithBufferPolicy = runGCAndGetNewStructurePolicy( std::move(dictionaryStructureWithBufferPolicy), dictFilePathChars); @@ -569,8 +571,8 @@ static bool latinime_BinaryDictionary_migrateNative(JNIEnv *env, jclass clazz, j return false; } } - if (!dictionaryStructureWithBufferPolicy->addUnigramEntry(wordCodePoints, wordLength, - wordProperty.getUnigramProperty())) { + if (!dictionaryStructureWithBufferPolicy->addUnigramEntry(wordCodePoints, + wordCodePointCount, wordProperty.getUnigramProperty())) { LogUtils::logToJava(env, "Cannot add unigram to the new dict."); return false; } @@ -578,9 +580,9 @@ static bool latinime_BinaryDictionary_migrateNative(JNIEnv *env, jclass clazz, j // Add bigrams. do { - token = dictionary->getNextWordAndNextToken(token, wordCodePoints); - const int wordLength = CharUtils::getCodePointCount(MAX_WORD_LENGTH, wordCodePoints); - const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, wordLength); + token = dictionary->getNextWordAndNextToken(token, wordCodePoints, &wordCodePointCount); + const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, + wordCodePointCount); if (dictionaryStructureWithBufferPolicy->needsToRunGC(true /* mindsBlockByGC */)) { dictionaryStructureWithBufferPolicy = runGCAndGetNewStructurePolicy( std::move(dictionaryStructureWithBufferPolicy), dictFilePathChars); @@ -589,8 +591,8 @@ static bool latinime_BinaryDictionary_migrateNative(JNIEnv *env, jclass clazz, j return false; } } - const PrevWordsInfo prevWordsInfo(wordCodePoints, wordLength, - false /* isStartOfSentence */); + const PrevWordsInfo prevWordsInfo(wordCodePoints, wordCodePointCount, + false /* isBeginningOfSentence */); for (const BigramProperty &bigramProperty : *wordProperty.getBigramProperties()) { if (!dictionaryStructureWithBufferPolicy->addNgramEntry(&prevWordsInfo, &bigramProperty)) { diff --git a/native/jni/run-tests.sh b/native/jni/run-tests.sh index 5b60e0d65..3da45270d 100755 --- a/native/jni/run-tests.sh +++ b/native/jni/run-tests.sh @@ -13,17 +13,56 @@ # See the License for the specific language governing permissions and # limitations under the License. +function usage() { + echo "usage: source run-tests.sh [--host] [--target] [-h] [--help]" 1>&2 + echo " --host: run test on the host environment" 1>&2 + echo " --no-host: skip host test" 1>&2 + echo " --target: run test on the target environment" 1>&2 + echo " --no-target: skip target device test" 1>&2 +} + +# check script arguments if [[ $(type -t mmm) != function ]]; then -echo "Usage:" 1>&2 -echo " source $0" 1>&2 -echo " or" 1>&2 -echo " . $0" 1>&2 +usage if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi fi +show_usage=no +enable_host_test=yes +enable_target_device_test=no +while [ "$1" != "" ] + do + case "$1" in + "-h") show_usage=yes;; + "--help") show_usage=yes;; + "--target") enable_target_device_test=yes;; + "--no-target") enable_target_device_test=no;; + "--host") enable_host_test=yes;; + "--no-host") enable_host_test=no;; + esac + shift +done + +if [[ $show_usage == yes ]]; then + usage + if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi +fi + +target_test_name=liblatinime_target_unittests +host_test_name=liblatinime_host_unittests + pushd $PWD > /dev/null cd $(gettop) mmm -j16 packages/inputmethods/LatinIME/native/jni || \ - make -j16 liblatinime_host_unittests -${ANDROID_HOST_OUT}/bin/liblatinime_host_unittests -popd > /dev/null
\ No newline at end of file + make -j16 adb $target_test_name $host_test_name +if [[ $enable_host_test == yes ]]; then + $ANDROID_HOST_OUT/bin/$host_test_name +fi +if [[ $enable_target_device_test == yes ]]; then + target_test_local=$ANDROID_PRODUCT_OUT/data/nativetest/$target_test_name/$target_test_name + target_test_device=/data/nativetest/$target_test_name/$target_test_name + adb push $target_test_local $target_test_device + adb shell $target_test_device + adb shell rm -rf $target_test_device +fi +popd > /dev/null diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp index 0bcde2294..228260216 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp @@ -145,10 +145,11 @@ const WordProperty Dictionary::getWordProperty(const int *const codePoints, codePoints, codePointCount); } -int Dictionary::getNextWordAndNextToken(const int token, int *const outCodePoints) { +int Dictionary::getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount) { TimeKeeper::setCurrentTime(); return mDictionaryStructureWithBufferPolicy->getNextWordAndNextToken( - token, outCodePoints); + token, outCodePoints, outCodePointCount); } void Dictionary::logDictionaryInfo(JNIEnv *const env) const { diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h index 542ba7291..247ee2421 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.h +++ b/native/jni/src/suggest/core/dictionary/dictionary.h @@ -103,7 +103,8 @@ class Dictionary { // Method to iterate all words in the dictionary. // The returned token has to be used to get the next word. If token is 0, this method newly // starts iterating the dictionary. - int getNextWordAndNextToken(const int token, int *const outCodePoints); + int getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount); const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const { return mDictionaryStructureWithBufferPolicy.get(); diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h index e2771f97c..b72601109 100644 --- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h +++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h @@ -104,7 +104,8 @@ class DictionaryStructureWithBufferPolicy { // Method to iterate all words in the dictionary. // The returned token has to be used to get the next word. If token is 0, this method newly // starts iterating the dictionary. - virtual int getNextWordAndNextToken(const int token, int *const outCodePoints) = 0; + virtual int getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount) = 0; virtual bool isCorrupted() const = 0; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h index 4032a67fa..1999a51a6 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h @@ -58,7 +58,7 @@ class Ver4PatriciaTrieNodeReader : public PtNodeReader { ~Ver4PatriciaTrieNodeReader() {} - virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const { + virtual const PtNodeParams fetchPtNodeParamsInBufferFromPtNodePos(const int ptNodePos) const { return fetchPtNodeInfoFromBufferAndProcessMovedPtNode(ptNodePos, NOT_A_DICT_POS /* siblingNodePos */); } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp index 805820b05..9780ae048 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp @@ -135,7 +135,7 @@ int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) c if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_PROBABILITY; } - const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos)); if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) { return NOT_A_PROBABILITY; } @@ -146,7 +146,7 @@ int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) con if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos)); if (ptNodeParams.isDeleted()) { return NOT_A_DICT_POS; } @@ -158,7 +158,7 @@ int Ver4PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) cons if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos)); if (ptNodeParams.isDeleted()) { return NOT_A_DICT_POS; } @@ -410,7 +410,7 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const code AKLOGE("getWordProperty is called for invalid word."); return WordProperty(); } - const PtNodeParams ptNodeParams = mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); std::vector<int> codePointVector(ptNodeParams.getCodePoints(), ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); const ProbabilityEntry probabilityEntry = @@ -478,10 +478,9 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const code return WordProperty(&codePointVector, &unigramProperty, &bigrams); } -int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints) { - // TODO: Return code point count like other methods. - // Null termination. - outCodePoints[0] = 0; +int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount) { + *outCodePointCount = 0; if (token == 0) { mTerminalPtNodePositionsForIteratingWords.clear(); DynamicPtReadingHelper::TraversePolicyToGetAllTerminalPtNodePositions traversePolicy( @@ -498,13 +497,8 @@ int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const } const int terminalPtNodePos = mTerminalPtNodePositionsForIteratingWords[token]; int unigramProbability = NOT_A_PROBABILITY; - const int codePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( + *outCodePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( terminalPtNodePos, MAX_WORD_LENGTH, outCodePoints, &unigramProbability); - if (codePointCount < MAX_WORD_LENGTH) { - // Null termination. outCodePoints have to be null terminated or contain MAX_WORD_LENGTH - // code points. - outCodePoints[codePointCount] = 0; - } const int nextToken = token + 1; if (nextToken >= terminalPtNodePositionsVectorSize) { // All words have been iterated. diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h index 2e948ac4a..16b1bd2c1 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h @@ -134,7 +134,8 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { const WordProperty getWordProperty(const int *const codePoints, const int codePointCount) const; - int getNextWordAndNextToken(const int token, int *const outCodePoints); + int getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount); bool isCorrupted() const { return mIsCorrupted; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp index 99eed0f67..3fb4caa08 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp @@ -224,7 +224,7 @@ bool Ver4PatriciaTrieWritingHelper::truncateUnigrams( const int ptNodePos = priorityQueue.top().getDictPos(); priorityQueue.pop(); const PtNodeParams ptNodeParams = - ptNodeReader->fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + ptNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); if (ptNodeParams.representsNonWordInfo()) { continue; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp index 1f00fc6ab..db1a802d0 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp @@ -65,7 +65,7 @@ bool DynamicPtGcEventListeners bool DynamicPtGcEventListeners::TraversePolicyToUpdateBigramProbability ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) { - if (!ptNodeParams->isDeleted() && ptNodeParams->hasBigrams()) { + if (!ptNodeParams->isDeleted()) { int bigramEntryCount = 0; if (!mPtNodeWriter->updateAllBigramEntriesAndDeleteUselessEntries(ptNodeParams, &bigramEntryCount)) { diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h index cc7b5ff70..2e05bf397 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h @@ -126,7 +126,7 @@ class DynamicPtReadingHelper { if (isEnd()) { return PtNodeParams(); } - return mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(mReadingState.mPos); + return mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(mReadingState.mPos); } AK_FORCE_INLINE bool isValidTerminalNode(const PtNodeParams &ptNodeParams) const { diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp index 9e575858a..f31c914d2 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp @@ -87,9 +87,9 @@ bool DynamicPtUpdatingHelper::addUnigramWord( bool DynamicPtUpdatingHelper::addBigramWords(const int word0Pos, const int word1Pos, const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) { const PtNodeParams sourcePtNodeParams( - mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word0Pos)); + mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word0Pos)); const PtNodeParams targetPtNodeParams( - mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word1Pos)); + mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word1Pos)); return mPtNodeWriter->addNewBigramEntry(&sourcePtNodeParams, &targetPtNodeParams, bigramProperty, outAddedNewBigram); } @@ -97,16 +97,16 @@ bool DynamicPtUpdatingHelper::addBigramWords(const int word0Pos, const int word1 // Remove a bigram relation from word0Pos to word1Pos. bool DynamicPtUpdatingHelper::removeBigramWords(const int word0Pos, const int word1Pos) { const PtNodeParams sourcePtNodeParams( - mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word0Pos)); + mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word0Pos)); const PtNodeParams targetPtNodeParams( - mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word1Pos)); + mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word1Pos)); return mPtNodeWriter->removeBigramEntry(&sourcePtNodeParams, &targetPtNodeParams); } bool DynamicPtUpdatingHelper::addShortcutTarget(const int wordPos, const int *const targetCodePoints, const int targetCodePointCount, const int shortcutProbability) { - const PtNodeParams ptNodeParams(mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(wordPos)); + const PtNodeParams ptNodeParams(mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(wordPos)); return mPtNodeWriter->addShortcutTarget(&ptNodeParams, targetCodePoints, targetCodePointCount, shortcutProbability); } @@ -125,7 +125,7 @@ bool DynamicPtUpdatingHelper::createAndInsertNodeIntoPtNodeArray(const int paren bool DynamicPtUpdatingHelper::setPtNodeProbability(const PtNodeParams *const originalPtNodeParams, const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram) { - if (originalPtNodeParams->isTerminal()) { + if (originalPtNodeParams->isTerminal() && !originalPtNodeParams->isDeleted()) { // Overwrites the probability. *outAddedNewUnigram = false; return mPtNodeWriter->updatePtNodeUnigramProperty(originalPtNodeParams, unigramProperty); @@ -260,7 +260,7 @@ bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes( } // Load node info. Information of the 1st part will be fetched. const PtNodeParams ptNodeParams( - mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(firstPartOfReallocatedPtNodePos)); + mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(firstPartOfReallocatedPtNodePos)); // Update children position. return mPtNodeWriter->updateChildrenPosition(&ptNodeParams, actualChildrenPos); } @@ -270,8 +270,8 @@ const PtNodeParams DynamicPtUpdatingHelper::getUpdatedPtNodeParams( const bool isNotAWord, const bool isBlacklisted, const bool isTerminal, const int parentPos, const int codePointCount, const int *const codePoints, const int probability) const { const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::createAndGetFlags( - isBlacklisted, isNotAWord, isTerminal, originalPtNodeParams->hasShortcutTargets(), - originalPtNodeParams->hasBigrams(), codePointCount > 1 /* hasMultipleChars */, + isBlacklisted, isNotAWord, isTerminal, false /* hasShortcutTargets */, + false /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */, CHILDREN_POSITION_FIELD_SIZE); return PtNodeParams(originalPtNodeParams, flags, parentPos, codePointCount, codePoints, probability); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h index c6b2a8bed..31299a707 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h @@ -27,7 +27,8 @@ namespace latinime { class PtNodeReader { public: virtual ~PtNodeReader() {} - virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const = 0; + virtual const PtNodeParams fetchPtNodeParamsInBufferFromPtNodePos( + const int ptNodePos) const = 0; protected: PtNodeReader() {}; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp index a6a470c4e..5c62b9caf 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp @@ -282,7 +282,8 @@ int PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_PROBABILITY; } - const PtNodeParams ptNodeParams = mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + const PtNodeParams ptNodeParams = + mPtNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); if (ptNodeParams.isNotAWord() || ptNodeParams.isBlacklisted()) { // If this is not a word, or if it's a blacklisted entry, it should behave as // having no probability outside of the suggestion process (where it should be used @@ -296,14 +297,14 @@ int PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const { if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - return mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos).getShortcutPos(); + return mPtNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos).getShortcutPos(); } int PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const { if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - return mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos).getBigramsPos(); + return mPtNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos).getBigramsPos(); } int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNode, @@ -339,7 +340,8 @@ const WordProperty PatriciaTriePolicy::getWordProperty(const int *const codePoin AKLOGE("getWordProperty was called for invalid word."); return WordProperty(); } - const PtNodeParams ptNodeParams = mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + const PtNodeParams ptNodeParams = + mPtNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); std::vector<int> codePointVector(ptNodeParams.getCodePoints(), ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); // Fetch bigram information. @@ -389,7 +391,9 @@ const WordProperty PatriciaTriePolicy::getWordProperty(const int *const codePoin return WordProperty(&codePointVector, &unigramProperty, &bigrams); } -int PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints) { +int PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount) { + *outCodePointCount = 0; if (token == 0) { // Start iterating the dictionary. mTerminalPtNodePositionsForIteratingWords.clear(); @@ -407,8 +411,8 @@ int PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outC } const int terminalPtNodePos = mTerminalPtNodePositionsForIteratingWords[token]; int unigramProbability = NOT_A_PROBABILITY; - getCodePointsAndProbabilityAndReturnCodePointCount(terminalPtNodePos, MAX_WORD_LENGTH, - outCodePoints, &unigramProbability); + *outCodePointCount = getCodePointsAndProbabilityAndReturnCodePointCount(terminalPtNodePos, + MAX_WORD_LENGTH, outCodePoints, &unigramProbability); const int nextToken = token + 1; if (nextToken >= terminalPtNodePositionsVectorSize) { // All words have been iterated. diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h index dce94363a..ec8407408 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h @@ -137,7 +137,8 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { const WordProperty getWordProperty(const int *const codePoints, const int codePointCount) const; - int getNextWordAndNextToken(const int token, int *const outCodePoints); + int getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount); bool isCorrupted() const { return mIsCorrupted; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp index 0c8de0df2..c1e938710 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp @@ -20,7 +20,7 @@ namespace latinime { -const PtNodeParams Ver2ParticiaTrieNodeReader::fetchNodeInfoInBufferFromPtNodePos( +const PtNodeParams Ver2ParticiaTrieNodeReader::fetchPtNodeParamsInBufferFromPtNodePos( const int ptNodePos) const { if (ptNodePos < 0 || ptNodePos >= mDictSize) { // Reading invalid position because of bug or broken dictionary. diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h index 86fc89c5e..f0725b66d 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h @@ -36,7 +36,7 @@ class Ver2ParticiaTrieNodeReader : public PtNodeReader { : mDictBuffer(dictBuffer), mDictSize(dictSize), mBigramPolicy(bigramPolicy), mShortuctPolicy(shortcutPolicy) {} - virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const; + virtual const PtNodeParams fetchPtNodeParamsInBufferFromPtNodePos(const int ptNodePos) const; private: DISALLOW_IMPLICIT_CONSTRUCTORS(Ver2ParticiaTrieNodeReader); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h index f24307e7b..22ed4a6c0 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h @@ -41,7 +41,7 @@ class Ver4PatriciaTrieNodeReader : public PtNodeReader { ~Ver4PatriciaTrieNodeReader() {} - virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const { + virtual const PtNodeParams fetchPtNodeParamsInBufferFromPtNodePos(const int ptNodePos) const { return fetchPtNodeInfoFromBufferAndProcessMovedPtNode(ptNodePos, NOT_A_DICT_POS /* siblingNodePos */); } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp index f89d3d7a0..3d8da9173 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp @@ -231,14 +231,6 @@ bool Ver4PatriciaTrieNodeWriter::addNewBigramEntry( sourcePtNodeParams->getTerminalId(), targetPtNodeParam->getTerminalId()); return false; } - if (!sourcePtNodeParams->hasBigrams()) { - // Update has bigrams flag. - return updatePtNodeFlags(sourcePtNodeParams->getHeadPos(), - sourcePtNodeParams->isBlacklisted(), sourcePtNodeParams->isNotAWord(), - sourcePtNodeParams->isTerminal(), sourcePtNodeParams->hasShortcutTargets(), - true /* hasBigrams */, - sourcePtNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); - } return true; } @@ -303,28 +295,9 @@ bool Ver4PatriciaTrieNodeWriter::addShortcutTarget(const PtNodeParams *const ptN AKLOGE("Cannot add new shortuct entry. terminalId: %d", ptNodeParams->getTerminalId()); return false; } - if (!ptNodeParams->hasShortcutTargets()) { - // Update has shortcut targets flag. - return updatePtNodeFlags(ptNodeParams->getHeadPos(), - ptNodeParams->isBlacklisted(), ptNodeParams->isNotAWord(), - ptNodeParams->isTerminal(), true /* hasShortcutTargets */, - ptNodeParams->hasBigrams(), - ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); - } return true; } -bool Ver4PatriciaTrieNodeWriter::updatePtNodeHasBigramsAndShortcutTargetsFlags( - const PtNodeParams *const ptNodeParams) { - const bool hasBigrams = mBuffers->getBigramDictContent()->getBigramListHeadPos( - ptNodeParams->getTerminalId()) != NOT_A_DICT_POS; - const bool hasShortcutTargets = mBuffers->getShortcutDictContent()->getShortcutListHeadPos( - ptNodeParams->getTerminalId()) != NOT_A_DICT_POS; - return updatePtNodeFlags(ptNodeParams->getHeadPos(), ptNodeParams->isBlacklisted(), - ptNodeParams->isNotAWord(), ptNodeParams->isTerminal(), hasShortcutTargets, - hasBigrams, ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); -} - bool Ver4PatriciaTrieNodeWriter::writePtNodeAndGetTerminalIdAndAdvancePosition( const PtNodeParams *const ptNodeParams, int *const outTerminalId, int *const ptNodeWritingPos) { @@ -377,8 +350,7 @@ bool Ver4PatriciaTrieNodeWriter::writePtNodeAndGetTerminalIdAndAdvancePosition( return false; } return updatePtNodeFlags(nodePos, ptNodeParams->isBlacklisted(), ptNodeParams->isNotAWord(), - isTerminal, ptNodeParams->hasShortcutTargets(), ptNodeParams->hasBigrams(), - ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); + isTerminal, ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); } const ProbabilityEntry Ver4PatriciaTrieNodeWriter::createUpdatedEntryFrom( @@ -402,11 +374,11 @@ const ProbabilityEntry Ver4PatriciaTrieNodeWriter::createUpdatedEntryFrom( bool Ver4PatriciaTrieNodeWriter::updatePtNodeFlags(const int ptNodePos, const bool isBlacklisted, const bool isNotAWord, const bool isTerminal, - const bool hasShortcutTargets, const bool hasBigrams, const bool hasMultipleChars) { + const bool hasMultipleChars) { // Create node flags and write them. PatriciaTrieReadingUtils::NodeFlags nodeFlags = PatriciaTrieReadingUtils::createAndGetFlags(isBlacklisted, isNotAWord, isTerminal, - hasShortcutTargets, hasBigrams, hasMultipleChars, + false /* hasShortcutTargets */, false /* hasBigrams */, hasMultipleChars, CHILDREN_POSITION_FIELD_SIZE); if (!DynamicPtWritingUtils::writeFlags(mTrieBuffer, nodeFlags, ptNodePos)) { AKLOGE("Cannot write PtNode flags. flags: %x, pos: %d", nodeFlags, ptNodePos); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h index e90bc44c0..162dc9b1d 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h @@ -93,8 +93,6 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter { const int *const targetCodePoints, const int targetCodePointCount, const int shortcutProbability); - bool updatePtNodeHasBigramsAndShortcutTargetsFlags(const PtNodeParams *const ptNodeParams); - private: DISALLOW_COPY_AND_ASSIGN(Ver4PatriciaTrieNodeWriter); @@ -110,8 +108,7 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter { const UnigramProperty *const unigramProperty) const; bool updatePtNodeFlags(const int ptNodePos, const bool isBlacklisted, const bool isNotAWord, - const bool isTerminal, const bool hasShortcutTargets, const bool hasBigrams, - const bool hasMultipleChars); + const bool isTerminal, const bool hasMultipleChars); static const int CHILDREN_POSITION_FIELD_SIZE; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp index aec3b8ea3..46107d92a 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp @@ -125,7 +125,7 @@ int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) c if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_PROBABILITY; } - const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos)); if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) { return NOT_A_PROBABILITY; } @@ -136,7 +136,7 @@ int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) con if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos)); if (ptNodeParams.isDeleted()) { return NOT_A_DICT_POS; } @@ -148,7 +148,7 @@ int Ver4PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) cons if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos)); if (ptNodeParams.isDeleted()) { return NOT_A_DICT_POS; } @@ -222,8 +222,24 @@ bool Ver4PatriciaTriePolicy::addUnigramEntry(const int *const word, const int le } bool Ver4PatriciaTriePolicy::removeUnigramEntry(const int *const word, const int length) { - // TODO: Implement. - return false; + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: removeUnigramEntry() is called for non-updatable dictionary."); + return false; + } + const int ptNodePos = getTerminalPtNodePositionOfWord(word, length, + false /* forceLowerCaseSearch */); + if (ptNodePos == NOT_A_DICT_POS) { + return false; + } + const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); + if (!mNodeWriter.markPtNodeAsDeleted(&ptNodeParams)) { + AKLOGE("Cannot remove unigram. ptNodePos: %d", ptNodePos); + return false; + } + if (!ptNodeParams.representsNonWordInfo()) { + mUnigramCount--; + } + return true; } bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsInfo, @@ -405,7 +421,7 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const code AKLOGE("getWordProperty is called for invalid word."); return WordProperty(); } - const PtNodeParams ptNodeParams = mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); std::vector<int> codePointVector(ptNodeParams.getCodePoints(), ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); const ProbabilityEntry probabilityEntry = @@ -473,10 +489,9 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const code return WordProperty(&codePointVector, &unigramProperty, &bigrams); } -int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints) { - // TODO: Return code point count like other methods. - // Null termination. - outCodePoints[0] = 0; +int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount) { + *outCodePointCount = 0; if (token == 0) { mTerminalPtNodePositionsForIteratingWords.clear(); DynamicPtReadingHelper::TraversePolicyToGetAllTerminalPtNodePositions traversePolicy( @@ -493,13 +508,8 @@ int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const } const int terminalPtNodePos = mTerminalPtNodePositionsForIteratingWords[token]; int unigramProbability = NOT_A_PROBABILITY; - const int codePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( + *outCodePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( terminalPtNodePos, MAX_WORD_LENGTH, outCodePoints, &unigramProbability); - if (codePointCount < MAX_WORD_LENGTH) { - // Null termination. outCodePoints have to be null terminated or contain MAX_WORD_LENGTH - // code points. - outCodePoints[codePointCount] = 0; - } const int nextToken = token + 1; if (nextToken >= terminalPtNodePositionsVectorSize) { // All words have been iterated. diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h index 0a20965f3..5d66a2cce 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h @@ -113,7 +113,8 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { const WordProperty getWordProperty(const int *const codePoints, const int codePointCount) const; - int getNextWordAndNextToken(const int token, int *const outCodePoints); + int getNextWordAndNextToken(const int token, int *const outCodePoints, + int *const outCodePointCount); bool isCorrupted() const { return mIsCorrupted; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp index e868ddf6f..40fdfa068 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp @@ -215,7 +215,7 @@ bool Ver4PatriciaTrieWritingHelper::truncateUnigrams( const int ptNodePos = priorityQueue.top().getDictPos(); priorityQueue.pop(); const PtNodeParams ptNodeParams = - ptNodeReader->fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + ptNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); if (ptNodeParams.representsNonWordInfo()) { continue; } @@ -286,8 +286,9 @@ bool Ver4PatriciaTrieWritingHelper::TraversePolicyToUpdateAllPtNodeFlagsAndTermi } if (!mPtNodeWriter->updateTerminalId(ptNodeParams, it->second)) { AKLOGE("Cannot update terminal id. %d -> %d", it->first, it->second); + return false; } - return mPtNodeWriter->updatePtNodeHasBigramsAndShortcutTargetsFlags(ptNodeParams); + return true; } } // namespace latinime diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java index 2cbc04154..3ef03f4bd 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java @@ -26,11 +26,13 @@ import org.xml.sax.SAXException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; @@ -51,14 +53,17 @@ public final class BinaryDictOffdeviceUtils { public final static String ENCRYPTION = "encrypted"; private final static int MAX_DECODE_DEPTH = 8; + private final static int COPY_BUFFER_SIZE = 8192; public static class DecoderChainSpec { ArrayList<String> mDecoderSpec = new ArrayList<>(); File mFile; + public DecoderChainSpec addStep(final String stepDescription) { mDecoderSpec.add(stepDescription); return this; } + public String describeChain() { final StringBuilder s = new StringBuilder("raw"); for (final String step : mDecoderSpec) { @@ -70,13 +75,10 @@ public final class BinaryDictOffdeviceUtils { } public static void copy(final InputStream input, final OutputStream output) throws IOException { - final byte[] buffer = new byte[1000]; - final BufferedInputStream in = new BufferedInputStream(input); - final BufferedOutputStream out = new BufferedOutputStream(output); - for (int readBytes = in.read(buffer); readBytes >= 0; readBytes = in.read(buffer)) + final byte[] buffer = new byte[COPY_BUFFER_SIZE]; + for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer)) { output.write(buffer, 0, readBytes); - in.close(); - out.close(); + } } /** @@ -131,11 +133,15 @@ public final class BinaryDictOffdeviceUtils { try { final File dst = File.createTempFile(PREFIX, SUFFIX); dst.deleteOnExit(); - final FileOutputStream dstStream = new FileOutputStream(dst); - copy(Compress.getUncompressedStream(new BufferedInputStream(new FileInputStream(src))), - new BufferedOutputStream(dstStream)); // #copy() closes the streams - return dst; - } catch (IOException e) { + try ( + final InputStream input = Compress.getUncompressedStream( + new BufferedInputStream(new FileInputStream(src))); + final OutputStream output = new BufferedOutputStream(new FileOutputStream(dst)) + ) { + copy(input, output); + return dst; + } + } catch (final IOException e) { // Could not uncompress the file: presumably the file is simply not a compressed file return null; } @@ -150,20 +156,20 @@ public final class BinaryDictOffdeviceUtils { try { final File dst = File.createTempFile(PREFIX, SUFFIX); dst.deleteOnExit(); - final FileOutputStream dstStream = new FileOutputStream(dst); - copy(Crypt.getDecryptedStream(new BufferedInputStream(new FileInputStream(src))), - dstStream); // #copy() closes the streams - return dst; - } catch (IOException e) { + try ( + final InputStream input = Crypt.getDecryptedStream( + new BufferedInputStream(new FileInputStream(src))); + final OutputStream output = new BufferedOutputStream(new FileOutputStream(dst)) + ) { + copy(input, output); + return dst; + } + } catch (final IOException e) { // Could not decrypt the file: presumably the file is simply not a crypted file return null; } } - static void crash(final String filename, final Exception e) { - throw new RuntimeException("Can't read file " + filename, e); - } - static FusionDictionary getDictionary(final String filename, final boolean report) { final File file = new File(filename); if (report) { @@ -172,45 +178,40 @@ public final class BinaryDictOffdeviceUtils { } try { if (XmlDictInputOutput.isXmlUnigramDictionary(filename)) { - if (report) System.out.println("Format : XML unigram list"); + if (report) { + System.out.println("Format : XML unigram list"); + } return XmlDictInputOutput.readDictionaryXml( new BufferedInputStream(new FileInputStream(file)), null /* shortcuts */, null /* bigrams */); - } else { - final DecoderChainSpec decodedSpec = getRawDictionaryOrNull(file); - if (null == decodedSpec) { - crash(filename, new RuntimeException( - filename + " does not seem to be a dictionary file")); - } else if (CombinedInputOutput.isCombinedDictionary( - decodedSpec.mFile.getAbsolutePath())){ - if (report) { - System.out.println("Format : Combined format"); - System.out.println("Packaging : " + decodedSpec.describeChain()); - System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); - } - return CombinedInputOutput.readDictionaryCombined( - new BufferedInputStream(new FileInputStream(decodedSpec.mFile))); - } else { - final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder( - decodedSpec.mFile, 0, decodedSpec.mFile.length(), - DictDecoder.USE_BYTEARRAY); - if (report) { - System.out.println("Format : Binary dictionary format"); - System.out.println("Packaging : " + decodedSpec.describeChain()); - System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); - } - return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); + } + final DecoderChainSpec decodedSpec = getRawDictionaryOrNull(file); + if (null == decodedSpec) { + throw new RuntimeException("Does not seem to be a dictionary file " + filename); + } + if (CombinedInputOutput.isCombinedDictionary(decodedSpec.mFile.getAbsolutePath())) { + if (report) { + System.out.println("Format : Combined format"); + System.out.println("Packaging : " + decodedSpec.describeChain()); + System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); } + try (final BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(decodedSpec.mFile), "UTF-8"))) { + return CombinedInputOutput.readDictionaryCombined(reader); + } + } + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder( + decodedSpec.mFile, 0, decodedSpec.mFile.length(), + DictDecoder.USE_BYTEARRAY); + if (report) { + System.out.println("Format : Binary dictionary format"); + System.out.println("Packaging : " + decodedSpec.describeChain()); + System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); } - } catch (IOException e) { - crash(filename, e); - } catch (SAXException e) { - crash(filename, e); - } catch (ParserConfigurationException e) { - crash(filename, e); - } catch (UnsupportedFormatException e) { - crash(filename, e); + return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); + } catch (final IOException | SAXException | ParserConfigurationException | + UnsupportedFormatException e) { + throw new RuntimeException("Can't read file " + filename, e); } - return null; } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java index 6a0e1b7f0..23cbee81c 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java @@ -26,13 +26,9 @@ import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.utils.CombinedFormatUtils; import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; +import java.io.BufferedWriter; import java.io.FileReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.TreeSet; @@ -57,27 +53,15 @@ public class CombinedInputOutput { * @return true if the file is in the combined format, false otherwise */ public static boolean isCombinedDictionary(final String filename) { - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(new File(filename))); + try (final BufferedReader reader = new BufferedReader(new FileReader(filename))) { String firstLine = reader.readLine(); while (firstLine.startsWith(COMMENT_LINE_STARTER)) { firstLine = reader.readLine(); } return firstLine.matches( "^" + CombinedFormatUtils.DICTIONARY_TAG + "=[^:]+(:[^=]+=[^:]+)*"); - } catch (FileNotFoundException e) { + } catch (final IOException e) { return false; - } catch (IOException e) { - return false; - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - // do nothing - } - } } } @@ -87,12 +71,11 @@ public class CombinedInputOutput { * This is the public method that will read a combined file and return the corresponding memory * representation. * - * @param source the file to read the data from. + * @param reader the buffered reader to read the data from. * @return the in-memory representation of the dictionary. */ - public static FusionDictionary readDictionaryCombined(final InputStream source) + public static FusionDictionary readDictionaryCombined(final BufferedReader reader) throws IOException { - final BufferedReader reader = new BufferedReader(new InputStreamReader(source, "UTF-8")); String headerLine = reader.readLine(); while (headerLine.startsWith(COMMENT_LINE_STARTER)) { headerLine = reader.readLine(); @@ -218,11 +201,11 @@ public class CombinedInputOutput { /** * Writes a dictionary to a combined file. * - * @param destination a destination stream to write to. + * @param destination a destination writer. * @param dict the dictionary to write. */ - public static void writeDictionaryCombined( - final Writer destination, final FusionDictionary dict) throws IOException { + public static void writeDictionaryCombined(final BufferedWriter destination, + final FusionDictionary dict) throws IOException { final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<>(); for (final WordProperty wordProperty : dict) { // This for ordering by frequency, then by asciibetic order @@ -232,6 +215,5 @@ public class CombinedInputOutput { for (final WordProperty wordProperty : wordPropertiesInDict) { destination.write(CombinedFormatUtils.formatWordProperty(wordProperty)); } - destination.close(); } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java index b7f48b522..728a159a0 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java @@ -16,11 +16,6 @@ package com.android.inputmethod.latin.dicttool; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -32,8 +27,7 @@ public class Compress { // This container class is not publicly instantiable. } - public static OutputStream getCompressedStream(final OutputStream out) - throws java.io.IOException { + public static OutputStream getCompressedStream(final OutputStream out) throws IOException { return new GZIPOutputStream(out); } @@ -43,7 +37,6 @@ public class Compress { static public class Compressor extends Dicttool.Command { public static final String COMMAND = "compress"; - public static final String STDIN_OR_STDOUT = "-"; public Compressor() { } @@ -61,17 +54,18 @@ public class Compress { } final String inFilename = mArgs.length >= 1 ? mArgs[0] : STDIN_OR_STDOUT; final String outFilename = mArgs.length >= 2 ? mArgs[1] : STDIN_OR_STDOUT; - final InputStream input = inFilename.equals(STDIN_OR_STDOUT) ? System.in - : new BufferedInputStream(new FileInputStream(new File(inFilename))); - final OutputStream output = outFilename.equals(STDIN_OR_STDOUT) ? System.out - : new BufferedOutputStream(new FileOutputStream(new File(outFilename))); - BinaryDictOffdeviceUtils.copy(input, new GZIPOutputStream(output)); + try ( + final InputStream input = getFileInputStreamOrStdIn(inFilename); + final OutputStream compressedOutput = getCompressedStream( + getFileOutputStreamOrStdOut(outFilename)) + ) { + BinaryDictOffdeviceUtils.copy(input, compressedOutput); + } } } static public class Uncompressor extends Dicttool.Command { public static final String COMMAND = "uncompress"; - public static final String STDIN_OR_STDOUT = "-"; public Uncompressor() { } @@ -89,11 +83,13 @@ public class Compress { } final String inFilename = mArgs.length >= 1 ? mArgs[0] : STDIN_OR_STDOUT; final String outFilename = mArgs.length >= 2 ? mArgs[1] : STDIN_OR_STDOUT; - final InputStream input = inFilename.equals(STDIN_OR_STDOUT) ? System.in - : new BufferedInputStream(new FileInputStream(new File(inFilename))); - final OutputStream output = outFilename.equals(STDIN_OR_STDOUT) ? System.out - : new BufferedOutputStream(new FileOutputStream(new File(outFilename))); - BinaryDictOffdeviceUtils.copy(new GZIPInputStream(input), output); + try ( + final InputStream uncompressedInput = getUncompressedStream( + getFileInputStreamOrStdIn(inFilename)); + final OutputStream output = getFileOutputStreamOrStdOut(outFilename) + ) { + BinaryDictOffdeviceUtils.copy(uncompressedInput, output); + } } } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java index 37c8d4184..3d0557b5c 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java @@ -27,19 +27,23 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import com.android.inputmethod.latin.makedict.Ver4DictEncoder; +import org.xml.sax.SAXException; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.Arrays; import java.util.LinkedList; import javax.xml.parsers.ParserConfigurationException; -import org.xml.sax.SAXException; - /** * Main class/method for DictionaryMaker. */ @@ -279,22 +283,21 @@ public class DictionaryMaker { */ private static FusionDictionary readCombinedFile(final String combinedFilename) throws FileNotFoundException, IOException { - FileInputStream inStream = null; - try { - final File file = new File(combinedFilename); - inStream = new FileInputStream(file); - return CombinedInputOutput.readDictionaryCombined(inStream); - } finally { - if (null != inStream) { - try { - inStream.close(); - } catch (IOException e) { - // do nothing - } - } + try (final BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(combinedFilename), "UTF-8")) + ) { + return CombinedInputOutput.readDictionaryCombined(reader); } } + private static BufferedInputStream getBufferedFileInputStream(final String filename) + throws FileNotFoundException { + if (filename == null) { + return null; + } + return new BufferedInputStream(new FileInputStream(filename)); + } + /** * Read a dictionary from a unigram XML file, and optionally a bigram XML file. * @@ -310,12 +313,13 @@ public class DictionaryMaker { private static FusionDictionary readXmlFile(final String unigramXmlFilename, final String shortcutXmlFilename, final String bigramXmlFilename) throws FileNotFoundException, SAXException, IOException, ParserConfigurationException { - final FileInputStream unigrams = new FileInputStream(new File(unigramXmlFilename)); - final FileInputStream shortcuts = null == shortcutXmlFilename ? null : - new FileInputStream(new File(shortcutXmlFilename)); - final FileInputStream bigrams = null == bigramXmlFilename ? null : - new FileInputStream(new File(bigramXmlFilename)); - return XmlDictInputOutput.readDictionaryXml(unigrams, shortcuts, bigrams); + try ( + final BufferedInputStream unigrams = getBufferedFileInputStream(unigramXmlFilename); + final BufferedInputStream shortcuts = getBufferedFileInputStream(shortcutXmlFilename); + final BufferedInputStream bigrams = getBufferedFileInputStream(bigramXmlFilename); + ) { + return XmlDictInputOutput.readDictionaryXml(unigrams, shortcuts, bigrams); + } } /** @@ -374,8 +378,9 @@ public class DictionaryMaker { */ private static void writeXmlDictionary(final String outputFilename, final FusionDictionary dict) throws FileNotFoundException, IOException { - XmlDictInputOutput.writeDictionaryXml(new BufferedWriter(new FileWriter(outputFilename)), - dict); + try (final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilename))) { + XmlDictInputOutput.writeDictionaryXml(writer, dict); + } } /** @@ -388,7 +393,8 @@ public class DictionaryMaker { */ private static void writeCombinedDictionary(final String outputFilename, final FusionDictionary dict) throws FileNotFoundException, IOException { - CombinedInputOutput.writeDictionaryCombined( - new BufferedWriter(new FileWriter(outputFilename)), dict); + try (final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilename))) { + CombinedInputOutput.writeDictionaryCombined(writer, dict); + } } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java index 8ae035f64..e49b35084 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java @@ -16,23 +16,63 @@ package com.android.inputmethod.latin.dicttool; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Arrays; import java.util.HashMap; public class Dicttool { public static abstract class Command { + public static final String STDIN_OR_STDOUT = "-"; protected String[] mArgs; + public void setArgs(String[] args) throws IllegalArgumentException { mArgs = args; } + + protected static InputStream getFileInputStreamOrStdIn(final String inFilename) + throws FileNotFoundException { + if (STDIN_OR_STDOUT.equals(inFilename)) { + return System.in; + } + return getFileInputStream(new File(inFilename)); + } + + protected static InputStream getFileInputStream(final File inFile) + throws FileNotFoundException { + return new BufferedInputStream(new FileInputStream(inFile)); + } + + protected static OutputStream getFileOutputStreamOrStdOut(final String outFilename) + throws FileNotFoundException { + if (STDIN_OR_STDOUT.equals(outFilename)) { + return System.out; + } + return getFileOutputStream(new File(outFilename)); + } + + protected static OutputStream getFileOutputStream(final File outFile) + throws FileNotFoundException { + return new BufferedOutputStream(new FileOutputStream(outFile)); + } + abstract public String getHelp(); abstract public void run() throws Exception; } + static HashMap<String, Class<? extends Command>> sCommands = new HashMap<>(); + static { CommandList.populate(); } + public static void addCommand(final String commandName, final Class<? extends Command> cls) { sCommands.put(commandName, cls); } @@ -60,7 +100,7 @@ public class Dicttool { return sCommands.containsKey(commandName); } - private Command getCommand(final String[] arguments) { + private static Command getCommand(final String[] arguments) { final String commandName = arguments[0]; if (!isCommand(commandName)) { throw new RuntimeException("Unknown command : " + commandName); @@ -76,7 +116,7 @@ public class Dicttool { * @param arguments the arguments passed to dicttool. * @return 0 for success, an error code otherwise (always 1 at the moment) */ - private int execute(final String[] arguments) { + private static int execute(final String[] arguments) { final Command command = getCommand(arguments); try { command.run(); @@ -95,6 +135,6 @@ public class Dicttool { return; } // Exit with the success/error code from #execute() as status. - System.exit(new Dicttool().execute(arguments)); + System.exit(execute(arguments)); } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java index dff3387be..1f6798269 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java @@ -21,8 +21,9 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; public class Package { private Package() { @@ -86,9 +87,13 @@ public class Package { } System.out.println("Packaging : " + decodedSpec.describeChain()); System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); - final FileOutputStream dstStream = new FileOutputStream(new File(mArgs[1])); - BinaryDictOffdeviceUtils.copy(new BufferedInputStream( - new FileInputStream(decodedSpec.mFile)), new BufferedOutputStream(dstStream)); + try ( + final InputStream input = getFileInputStream(decodedSpec.mFile); + final OutputStream output = new BufferedOutputStream( + getFileOutputStreamOrStdOut(mArgs[1])) + ) { + BinaryDictOffdeviceUtils.copy(input, output); + } } } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java index 7435fa7d6..bdec44761 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java @@ -23,13 +23,16 @@ import com.android.inputmethod.latin.makedict.ProbabilityInfo; import com.android.inputmethod.latin.makedict.WeightedString; import com.android.inputmethod.latin.makedict.WordProperty; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import java.io.BufferedInputStream; import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; +import java.io.BufferedWriter; +import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.Writer; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.TreeSet; @@ -38,10 +41,6 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - /** * Reads and writes XML files for a FusionDictionary. * @@ -57,8 +56,6 @@ public class XmlDictInputOutput { private static final String WORD_ATTR = "word"; private static final String NOT_A_WORD_ATTR = "not_a_word"; - private static final String OPTIONS_KEY = "options"; - /** * SAX handler for a unigram XML file. */ @@ -120,7 +117,6 @@ public class XmlDictInputOutput { final String attrName = attrs.getLocalName(attrIndex); attributes.put(attrName, attrs.getValue(attrIndex)); } - final String optionsString = attributes.get(OPTIONS_KEY); mDictionary = new FusionDictionary(new PtNodeArray(), new DictionaryOptions(attributes)); } else { @@ -244,14 +240,13 @@ public class XmlDictInputOutput { protected int getValueFromFreqString(final String freqString) { if (WHITELIST_MARKER.equals(freqString)) { return WHITELIST_FREQ_VALUE; - } else { - final int intValue = super.getValueFromFreqString(freqString); - if (intValue < MIN_FREQ || intValue > MAX_FREQ) { - throw new RuntimeException("Shortcut freq out of range. Accepted range is " - + MIN_FREQ + ".." + MAX_FREQ); - } - return intValue; } + final int intValue = super.getValueFromFreqString(freqString); + if (intValue < MIN_FREQ || intValue > MAX_FREQ) { + throw new RuntimeException("Shortcut freq out of range. Accepted range is " + + MIN_FREQ + ".." + MAX_FREQ); + } + return intValue; } // As per getAssocMap(), this never returns null. @@ -269,23 +264,12 @@ public class XmlDictInputOutput { * @return true if the file is in the unigram XML format, false otherwise */ public static boolean isXmlUnigramDictionary(final String filename) { - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(new File(filename))); + try (final BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(filename), "UTF-8"))) { final String firstLine = reader.readLine(); return firstLine.matches("^\\s*<wordlist .*>\\s*$"); - } catch (FileNotFoundException e) { + } catch (final IOException e) { return false; - } catch (IOException e) { - return false; - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - // do nothing - } - } } } @@ -300,8 +284,8 @@ public class XmlDictInputOutput { * @param bigrams the file to read the bigrams from, or null. * @return the in-memory representation of the dictionary. */ - public static FusionDictionary readDictionaryXml(final InputStream unigrams, - final InputStream shortcuts, final InputStream bigrams) + public static FusionDictionary readDictionaryXml(final BufferedInputStream unigrams, + final BufferedInputStream shortcuts, final BufferedInputStream bigrams) throws SAXException, IOException, ParserConfigurationException { final SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); @@ -350,8 +334,8 @@ public class XmlDictInputOutput { * @param destination a destination stream to write to. * @param dict the dictionary to write. */ - public static void writeDictionaryXml(Writer destination, FusionDictionary dict) - throws IOException { + public static void writeDictionaryXml(final BufferedWriter destination, + final FusionDictionary dict) throws IOException { final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<>(); for (WordProperty wordProperty : dict) { wordPropertiesInDict.add(wordProperty); diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java index fccb654b0..0236a446d 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java @@ -62,13 +62,13 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { final File dst = File.createTempFile("testGetRawDict", ".tmp"); dst.deleteOnExit(); - - final OutputStream out = Compress.getCompressedStream( + try (final OutputStream out = Compress.getCompressedStream( Compress.getCompressedStream( Compress.getCompressedStream( - new BufferedOutputStream(new FileOutputStream(dst))))); - final DictEncoder dictEncoder = new Ver2DictEncoder(out); - dictEncoder.writeDictionary(dict, new FormatOptions(2, false)); + new BufferedOutputStream(new FileOutputStream(dst)))))) { + final DictEncoder dictEncoder = new Ver2DictEncoder(out); + dictEncoder.writeDictionary(dict, new FormatOptions(2, false)); + } // Test for an actually compressed dictionary and its contents final BinaryDictOffdeviceUtils.DecoderChainSpec decodeSpec = @@ -96,11 +96,11 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { // Randomly create some 4k file containing garbage final File dst = File.createTempFile("testGetRawDict", ".tmp"); dst.deleteOnExit(); - final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst)); - for (int i = 0; i < 1024; ++i) { - out.write(0x12345678); + try (final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst))) { + for (int i = 0; i < 1024; ++i) { + out.write(0x12345678); + } } - out.close(); // Test that a random data file actually fails assertNull("Wrongly identified data file", @@ -108,12 +108,12 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { final File gzDst = File.createTempFile("testGetRawDict", ".tmp"); gzDst.deleteOnExit(); - final OutputStream gzOut = - Compress.getCompressedStream(new BufferedOutputStream(new FileOutputStream(gzDst))); - for (int i = 0; i < 1024; ++i) { - gzOut.write(0x12345678); + try (final OutputStream gzOut = Compress.getCompressedStream( + new BufferedOutputStream(new FileOutputStream(gzDst)))) { + for (int i = 0; i < 1024; ++i) { + gzOut.write(0x12345678); + } } - gzOut.close(); // Test that a compressed random data file actually fails assertNull("Wrongly identified data file", |