diff options
68 files changed, 1057 insertions, 832 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/AndroidManifest.xml b/java/AndroidManifest.xml index 6f4e602ce..5d8ef43f5 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -86,7 +86,7 @@ </receiver> <activity android:name=".settings.SettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/english_ime_settings" android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> @@ -95,7 +95,7 @@ </activity> <activity android:name=".spellcheck.SpellCheckerSettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/android_spell_checker_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -103,7 +103,7 @@ </activity> <activity android:name=".settings.DebugSettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/english_ime_debug_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -150,7 +150,7 @@ </receiver> <activity android:name="com.android.inputmethod.dictionarypack.DictionarySettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/dictionary_settings_title" android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> 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-v20/platform-theme.xml b/java/res/values-v21/platform-theme.xml index 52e7f3521..a49e36459 100644 --- a/java/res/values-v20/platform-theme.xml +++ b/java/res/values-v21/platform-theme.xml @@ -18,9 +18,21 @@ */ --> -<!-- TODO: This file is temporarily placed under values-v20. --> -<!-- TODO: It might be moved under values-v21. --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="platformActivityTheme" parent="@android:style/Theme.Material.Light" /> + <!-- From packages/apps/Settings --> + <style name="platformSettingsTheme" parent="@android:style/Theme.Material.Settings"> + <item name="android:actionBarStyle">@android:style/Widget.Material.Light.ActionBar.Solid</item> + <item name="android:alertDialogTheme">@style/Theme.AlertDialog</item> + </style> + <!-- From packages/apps/Settings --> + <style name="Theme.AlertDialog" parent="@*android:style/Theme.Material.Light.Dialog.Alert"> + <!-- Used by the ActionBar: @color/theme_primary --> + <item name="android:colorPrimary">#ff263238</item> + <!-- Used by the StatusBar: @color/theme_primary_dark --> + <item name="android:colorPrimaryDark">#ff21272b</item> + <!-- Used by controls, e.g. CheckBox, ProgressBar, etc.: @color/theme_accent --> + <item name="android:colorAccent">#ff009688</item> + </style> <style name="platformDialogTheme" parent="@android:style/Theme.Material.Light.Dialog" /> </resources> 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/keyboard-themes.xml b/java/res/values/keyboard-themes.xml index a06082c6e..28a34c315 100644 --- a/java/res/values/keyboard-themes.xml +++ b/java/res/values/keyboard-themes.xml @@ -20,13 +20,14 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- For keyboard color scheme option dialog. --> <string-array name="keyboard_theme_names" translatable="false"> - <!-- TODO: Make this item as translatable string resource. --> - <item>Material</item> - <item>@string/keyboard_color_scheme_white</item> - <item>@string/keyboard_color_scheme_blue</item> + <!-- TODO: Implement Material Light theme. --> + <item>@string/keyboard_theme_material_dark</item> + <item>@string/keyboard_theme_holo_white</item> + <item>@string/keyboard_theme_holo_blue</item> </string-array> <!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. --> <string-array name="keyboard_theme_ids" translatable="false"> + <!-- TODO: Implement Material Light theme. --> <item>3</item> <item>2</item> <item>0</item> diff --git a/java/res/values/platform-theme.xml b/java/res/values/platform-theme.xml index 8e131a2b0..e68859712 100644 --- a/java/res/values/platform-theme.xml +++ b/java/res/values/platform-theme.xml @@ -20,5 +20,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="platformActivityTheme" parent="@android:style/Theme.Holo" /> + <style name="platformSettingsTheme" parent="@android:style/Theme.Holo" /> <style name="platformDialogTheme" parent="@android:style/Theme.Holo.Dialog" /> </resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 884911565..9ec3f469c 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -36,22 +36,18 @@ <!-- Option to control whether or not to show a popup with a larger font on each key press. --> <string name="popup_on_keypress">Popup on keypress</string> - <!-- Category title for general settings for Android keyboard --> - <string name="general_category">General</string> - - <!-- Category title for text prediction --> - <string name="correction_category">Text correction</string> - - <!-- Category title for gesture typing --> - <string name="gesture_typing_category">Gesture typing</string> - - <!-- Category title for misc options --> - <string name="misc_category">Other options</string> - - <!-- Option name for advanced settings screen [CHAR LIMIT=25] --> - <string name="advanced_settings">Advanced settings</string> - <!-- Option summary for advanced settings screen [CHAR LIMIT=65 (two lines) or 30 (fits on one line, preferable)] --> - <string name="advanced_settings_summary">Options for experts</string> + <!-- Settings screen title for input preferences [CHAR LIMIT=25]--> + <string name="settings_screen_input">Input preferences</string> + <!-- Settings screen title for appearance preferences [CHAR LIMIT=25] --> + <string name="settings_screen_appearances">Appearance</string> + <!-- Settings screen title for multi lingual options [CHAR_LIMIT=25] --> + <string name="settings_screen_multi_lingual">Multi lingual options</string> + <!-- Settings screen title for gesture typing preferences [CHAR_LIMIT=25] --> + <string name="settings_screen_gesture">Gesture typing preferences</string> + <!-- Settings screen title for text correction options [CHAR_LIMIT=25] --> + <string name="settings_screen_correction">Text correction</string> + <!-- Settings screen title for advanced settings [CHAR LIMIT=25] --> + <string name="settings_screen_advanced">Advanced</string> <!-- Option name for including other IMEs in the language switch list [CHAR LIMIT=30] --> <string name="include_other_imes_in_language_switch_list">Switch to other input methods</string> @@ -295,12 +291,16 @@ mobile devices. [CHAR LIMIT=25] --> <!-- Description for Emoji keyboard subtype [CHAR LIMIT=25] --> <string name="subtype_emoji">Emoji</string> - <!-- Title of the preference settings for switching keyboard color scheme [CHAR LIMIT=35] --> - <string name="keyboard_color_scheme">Color scheme</string> - <!-- The keyboard color scheme name, White [CHAR LIMIT=16] --> - <string name="keyboard_color_scheme_white">White</string> - <!-- The keyboard color scheme name, Blue [CHAR LIMIT=16] --> - <string name="keyboard_color_scheme_blue">Blue</string> + <!-- Title of the preference settings for switching keyboard theme [CHAR LIMIT=35] --> + <string name="keyboard_theme">Keyboard theme</string> + <!-- The keyboard theme name, Holo White [CHAR LIMIT=25] --> + <string name="keyboard_theme_holo_white">Holo White</string> + <!-- The keyboard theme name, Holo Blue [CHAR LIMIT=25] --> + <string name="keyboard_theme_holo_blue">Holo Blue</string> + <!-- The keyboard theme name, Material Dark [CHAR LIMIT=25] --> + <string name="keyboard_theme_material_dark">Material Dark</string> + <!-- The keyboard theme name, Material Light [CHAR LIMIT=25] --> + <string name="keyboard_theme_material_light">Material Light</string> <!-- Title of the preference settings for custom input styles (language and keyboard layout pairs) [CHAR LIMIT=35]--> <string name="custom_input_styles_title">Custom input styles</string> 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/res/xml/prefs.xml b/java/res/xml/prefs.xml index 0e9c16190..cb951d264 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -18,39 +18,117 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" android:key="english_ime_settings"> - <PreferenceCategory - android:title="@string/general_category" - android:key="general_settings"> - <CheckBoxPreference + <PreferenceScreen + android:title="@string/settings_screen_input" + android:key="screen_input"> + <SwitchPreference android:key="auto_cap" android:title="@string/auto_cap" android:summary="@string/auto_cap_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - <CheckBoxPreference + <SwitchPreference + android:key="pref_key_use_double_space_period" + android:title="@string/use_double_space_period" + android:summary="@string/use_double_space_period_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference android:key="vibrate_on" android:title="@string/vibrate_on_keypress" - android:defaultValue="@bool/config_default_vibration_enabled" - android:persistent="true" /> - <CheckBoxPreference + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="@bool/config_default_vibration_enabled" /> + <SwitchPreference android:key="sound_on" android:title="@string/sound_on_keypress" - android:defaultValue="@bool/config_default_sound_enabled" - android:persistent="true" /> - <CheckBoxPreference + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="@bool/config_default_sound_enabled" /> + <SwitchPreference android:key="popup_on" android:title="@string/popup_on_keypress" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="@bool/config_default_key_preview_popup" /> - <CheckBoxPreference + <SwitchPreference android:key="pref_voice_input_key" android:title="@string/voice_input" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - </PreferenceCategory> - <PreferenceCategory - android:title="@string/correction_category" - android:key="correction_settings"> + </PreferenceScreen> + <ListPreference + android:key="pref_keyboard_theme" + android:title="@string/keyboard_theme" + android:persistent="true" + android:entryValues="@array/keyboard_theme_ids" + android:entries="@array/keyboard_theme_names" /> + <PreferenceScreen + android:title="@string/settings_screen_multi_lingual" + android:key="screen_multi_lingual"> + <SwitchPreference + android:key="pref_show_language_switch_key" + android:title="@string/show_language_switch_key" + android:summary="@string/show_language_switch_key_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference + android:key="pref_include_other_imes_in_language_switch_list" + android:dependency="pref_show_language_switch_key" + android:title="@string/include_other_imes_in_language_switch_list" + android:summary="@string/include_other_imes_in_language_switch_list_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="false" /> + <PreferenceScreen + android:fragment="com.android.inputmethod.latin.settings.AdditionalSubtypeSettings" + android:key="custom_input_styles" + android:title="@string/custom_input_styles_title" /> + </PreferenceScreen> + <PreferenceScreen + android:title="@string/settings_screen_gesture" + android:key="screen_gesture"> + <SwitchPreference + android:key="gesture_input" + android:title="@string/gesture_input" + android:summary="@string/gesture_input_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference + android:key="pref_gesture_floating_preview_text" + android:dependency="gesture_input" + android:title="@string/gesture_floating_preview_text" + android:summary="@string/gesture_floating_preview_text_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference + android:key="pref_gesture_preview_trail" + android:dependency="gesture_input" + android:title="@string/gesture_preview_trail" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + </PreferenceScreen> + <PreferenceScreen + android:title="@string/settings_screen_correction" + android:key="screen_correction"> <PreferenceScreen android:key="edit_personal_dictionary" android:title="@string/edit_personal_dictionary"> @@ -67,10 +145,12 @@ android:value="@string/dictionary_pack_client_id" /> </intent> </PreferenceScreen> - <CheckBoxPreference + <SwitchPreference android:key="pref_key_block_potentially_offensive" android:title="@string/prefs_block_potentially_offensive_title" android:summary="@string/prefs_block_potentially_offensive_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="@bool/config_block_potentially_offensive" /> <ListPreference @@ -89,119 +169,66 @@ android:entryValues="@array/prefs_suggestion_visibility_values" android:entries="@array/prefs_suggestion_visibilities" android:defaultValue="@string/prefs_suggestion_visibility_default_value" /> - <CheckBoxPreference + <SwitchPreference android:key="pref_key_use_personalized_dicts" android:title="@string/use_personalized_dicts" android:summary="@string/use_personalized_dicts_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - <!-- title will be set programmatically to embed application name --> - <CheckBoxPreference - android:key="pref_enable_metrics_logging" - android:summary="@string/enable_metrics_logging_summary" - android:persistent="true" - android:defaultValue="true" /> - </PreferenceCategory> - <PreferenceCategory - android:title="@string/gesture_typing_category" - android:key="gesture_typing_settings"> - <CheckBoxPreference - android:key="gesture_input" - android:title="@string/gesture_input" - android:summary="@string/gesture_input_summary" - android:persistent="true" - android:defaultValue="true" /> - <!-- TODO: Move these two options to the advanced settings. --> - <CheckBoxPreference - android:key="pref_gesture_floating_preview_text" - android:dependency="gesture_input" - android:title="@string/gesture_floating_preview_text" - android:summary="@string/gesture_floating_preview_text_summary" + <SwitchPreference + android:key="pref_key_use_contacts_dict" + android:title="@string/use_contacts_dict" + android:summary="@string/use_contacts_dict_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_gesture_preview_trail" - android:dependency="gesture_input" - android:title="@string/gesture_preview_trail" - android:persistent="true" - android:defaultValue="true" /> - </PreferenceCategory> - <PreferenceCategory - android:title="@string/misc_category" - android:key="misc_settings"> - <CheckBoxPreference + <SwitchPreference android:key="next_word_prediction" android:title="@string/bigram_prediction" android:summary="@string/bigram_prediction_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + </PreferenceScreen> + <PreferenceScreen + android:title="@string/settings_screen_advanced" + android:key="screen_advanced"> + <!-- TODO: consolidate key preview dismiss delay with the key preview animation parameters. --> + <ListPreference + android:key="pref_key_preview_popup_dismiss_delay" + android:title="@string/key_preview_popup_dismiss_delay" /> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_vibration_duration_settings" + android:title="@string/prefs_keypress_vibration_duration_settings" + latin:maxValue="@integer/config_max_vibration_duration" /> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_keypress_sound_volume" + android:title="@string/prefs_keypress_sound_volume_settings" + latin:maxValue="100" /> <!-- percent --> + <!-- The settigs for showing setup wizard application icon shouldn't be persistent and + the default value is added programmatically. --> + <SwitchPreference + android:key="pref_show_setup_wizard_icon" + android:title="@string/show_setup_wizard_icon" + android:summary="@string/show_setup_wizard_icon_summary" + android:switchTextOn="" + android:switchTextOff="" /> + <!-- title will be set programmatically to embed application name --> + <SwitchPreference + android:key="pref_enable_metrics_logging" + android:summary="@string/enable_metrics_logging_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> <PreferenceScreen - android:key="pref_advanced_settings" - android:title="@string/advanced_settings" - android:summary="@string/advanced_settings_summary"> - <CheckBoxPreference - android:key="pref_key_use_contacts_dict" - android:title="@string/use_contacts_dict" - android:summary="@string/use_contacts_dict_summary" - android:persistent="true" - android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_key_use_double_space_period" - android:title="@string/use_double_space_period" - android:summary="@string/use_double_space_period_summary" - android:persistent="true" - android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_show_language_switch_key" - android:title="@string/show_language_switch_key" - android:summary="@string/show_language_switch_key_summary" - android:persistent="true" - android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_include_other_imes_in_language_switch_list" - android:dependency="pref_show_language_switch_key" - android:title="@string/include_other_imes_in_language_switch_list" - android:summary="@string/include_other_imes_in_language_switch_list_summary" - android:persistent="true" - android:defaultValue="false" /> - <ListPreference - android:key="pref_keyboard_theme" - android:title="@string/keyboard_color_scheme" - android:persistent="true" - android:entryValues="@array/keyboard_theme_ids" - android:entries="@array/keyboard_theme_names" /> - <PreferenceScreen - android:fragment="com.android.inputmethod.latin.settings.AdditionalSubtypeSettings" - android:key="custom_input_styles" - android:title="@string/custom_input_styles_title" /> - <!-- TODO: consolidate key preview dismiss delay with the key preview animation parameters. --> - <ListPreference - android:key="pref_key_preview_popup_dismiss_delay" - android:title="@string/key_preview_popup_dismiss_delay" /> - <com.android.inputmethod.latin.settings.SeekBarDialogPreference - android:key="pref_vibration_duration_settings" - android:title="@string/prefs_keypress_vibration_duration_settings" - latin:maxValue="@integer/config_max_vibration_duration" /> - <com.android.inputmethod.latin.settings.SeekBarDialogPreference - android:key="pref_keypress_sound_volume" - android:title="@string/prefs_keypress_sound_volume_settings" - latin:maxValue="100" /> <!-- percent --> - <!-- The settigs for showing setup wizard application icon shouldn't be persistent and - the default value is added programmatically. --> - <CheckBoxPreference - android:key="pref_show_setup_wizard_icon" - android:title="@string/show_setup_wizard_icon" - android:summary="@string/show_setup_wizard_icon_summary" /> - </PreferenceScreen> - <PreferenceScreen - android:key="send_feedback" - android:title="@string/send_feedback" /> - <PreferenceScreen - android:key="about_keyboard" /> - <PreferenceScreen - android:key="debug_settings" + android:key="screen_debug" android:title="Debug settings" android:persistent="true" android:defaultValue="false" /> - </PreferenceCategory> + </PreferenceScreen> </PreferenceScreen> diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml index 0bcc5cbe4..be4c8b3e1 100644 --- a/java/res/xml/prefs_for_debug.xml +++ b/java/res/xml/prefs_for_debug.xml @@ -20,20 +20,26 @@ android:title="@string/prefs_debug_mode" android:key="english_ime_debug_settings" > - <CheckBoxPreference + <SwitchPreference android:key="debug_mode" android:title="@string/prefs_debug_mode" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="false" /> - <CheckBoxPreference + <SwitchPreference android:key="force_non_distinct_multitouch" android:title="@string/prefs_force_non_distinct_multitouch" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="false" /> - <CheckBoxPreference + <SwitchPreference android:key="pref_sliding_key_input_preview" android:title="@string/sliding_key_input_preview" android:summary="@string/sliding_key_input_preview_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> <com.android.inputmethod.latin.settings.SeekBarDialogPreference diff --git a/java/res/xml/spell_checker_settings.xml b/java/res/xml/spell_checker_settings.xml index de67e7f81..e3db4850b 100644 --- a/java/res/xml/spell_checker_settings.xml +++ b/java/res/xml/spell_checker_settings.xml @@ -15,11 +15,14 @@ --> <PreferenceScreen - xmlns:android="http://schemas.android.com/apk/res/android"> - <CheckBoxPreference - android:key="pref_spellcheck_use_contacts" - android:title="@string/use_contacts_for_spellchecking_option_title" - android:summary="@string/use_contacts_for_spellchecking_option_summary" - android:persistent="true" - android:defaultValue="true" /> + xmlns:android="http://schemas.android.com/apk/res/android" +> + <SwitchPreference + android:key="pref_spellcheck_use_contacts" + android:title="@string/use_contacts_for_spellchecking_option_title" + android:summary="@string/use_contacts_for_spellchecking_option_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> </PreferenceScreen> 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/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/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index 845ddb377..c17e86892 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -21,14 +21,13 @@ import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.os.Process; -import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.preference.TwoStatePreference; -import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.DictionaryDumpBroadcastReceiver; import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.R; @@ -57,7 +56,7 @@ public final class DebugSettings extends PreferenceFragment public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout"; private boolean mServiceNeedsRestart = false; - private CheckBoxPreference mDebugMode; + private TwoStatePreference mDebugMode; @Override public void onCreate(Bundle icicle) { @@ -107,7 +106,7 @@ public final class DebugSettings extends PreferenceFragment res, R.fraction.config_key_preview_dismiss_end_scale)); mServiceNeedsRestart = false; - mDebugMode = (CheckBoxPreference) findPreference(PREF_DEBUG_MODE); + mDebugMode = (TwoStatePreference) findPreference(PREF_DEBUG_MODE); updateDebugMode(); } diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index 235847799..fb1a210bb 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -39,8 +39,14 @@ import java.util.concurrent.locks.ReentrantLock; public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = Settings.class.getSimpleName(); + // Settings screens + public static final String SCREEN_INPUT = "screen_input"; + public static final String SCREEN_MULTI_LINGUAL = "screen_multi_lingual"; + public static final String SCREEN_GESTURE = "screen_gesture"; + public static final String SCREEN_CORRECTION = "screen_correction"; + public static final String SCREEN_ADVANCED = "screen_advanced"; + public static final String SCREEN_DEBUG = "screen_debug"; // In the same order as xml/prefs.xml - public static final String PREF_GENERAL_SETTINGS = "general_settings"; public static final String PREF_AUTO_CAP = "auto_cap"; public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_SOUND_ON = "sound_on"; @@ -48,13 +54,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang // PREF_VOICE_MODE_OBSOLETE is obsolete. Use PREF_VOICE_INPUT_KEY instead. public static final String PREF_VOICE_MODE_OBSOLETE = "voice_mode"; public static final String PREF_VOICE_INPUT_KEY = "pref_voice_input_key"; - public static final String PREF_CORRECTION_SETTINGS = "correction_settings"; public static final String PREF_EDIT_PERSONAL_DICTIONARY = "edit_personal_dictionary"; public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key"; public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold"; public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting"; - public static final String PREF_MISC_SETTINGS = "misc_settings"; - public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; public static final String PREF_KEY_USE_PERSONALIZED_DICTS = "pref_key_use_personalized_dicts"; public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = @@ -75,7 +78,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction"; - public static final String PREF_GESTURE_SETTINGS = "gesture_typing_settings"; public static final String PREF_GESTURE_INPUT = "gesture_input"; public static final String PREF_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; @@ -89,7 +91,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_INPUT_LANGUAGE = "input_language"; public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; - public static final String PREF_DEBUG_SETTINGS = "debug_settings"; public static final String PREF_KEY_IS_INTERNAL = "pref_key_is_internal"; public static final String PREF_ENABLE_METRICS_LOGGING = "pref_enable_metrics_logging"; @@ -105,8 +106,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang "pref_last_used_personalization_dict_wiped_time"; private static final String PREF_CORPUS_HANDLES_FOR_PERSONALIZATION = "pref_corpus_handles_for_personalization"; - public static final String PREF_SEND_FEEDBACK = "send_feedback"; - public static final String PREF_ABOUT_KEYBOARD = "about_keyboard"; // Emoji public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys"; diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java index 5eb0377c7..9d824121c 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java @@ -27,13 +27,15 @@ import android.content.res.Resources; import android.media.AudioManager; import android.os.Build; import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.preference.TwoStatePreference; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.dictionarypack.DictionarySettingsActivity; @@ -61,6 +63,10 @@ public final class SettingsFragment extends InputMethodSettingsFragment DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS || Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2; + private static final int NO_MENU_GROUP = Menu.NONE; // We don't care about menu grouping. + private static final int MENU_FEEDBACK = Menu.FIRST; // The first menu item id and order. + private static final int MENU_ABOUT = Menu.FIRST + 1; // The second menu item id and order. + private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { final Preference preference = findPreference(preferenceKey); if (preference != null) { @@ -93,6 +99,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment @Override public void onCreate(final Bundle icicle) { super.onCreate(icicle); + setHasOptionsMenu(true); setInputMethodSettingsCategoryTitle(R.string.language_selection_title); setSubtypeEnablerTitle(R.string.select_language); addPreferencesFromResource(R.xml.prefs); @@ -117,66 +124,42 @@ public final class SettingsFragment extends InputMethodSettingsFragment ensureConsistencyOfAutoCorrectionSettings(); - final PreferenceGroup generalSettings = - (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS); - final PreferenceGroup miscSettings = - (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS); - - final Preference debugSettings = findPreference(Settings.PREF_DEBUG_SETTINGS); - if (debugSettings != null) { - if (Settings.isInternal(prefs)) { - final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); - debugSettingsIntent.setClassName( - context.getPackageName(), DebugSettingsActivity.class.getName()); - debugSettings.setIntent(debugSettingsIntent); - } else { - miscSettings.removePreference(debugSettings); - } - } - - final Preference feedbackSettings = findPreference(Settings.PREF_SEND_FEEDBACK); - final Preference aboutSettings = findPreference(Settings.PREF_ABOUT_KEYBOARD); - if (feedbackSettings != null) { - if (FeedbackUtils.isFeedbackFormSupported()) { - feedbackSettings.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(final Preference pref) { - FeedbackUtils.showFeedbackForm(getActivity()); - return true; - } - }); - aboutSettings.setTitle(FeedbackUtils.getAboutKeyboardTitleResId()); - aboutSettings.setIntent(FeedbackUtils.getAboutKeyboardIntent(getActivity())); - } else { - miscSettings.removePreference(feedbackSettings); - miscSettings.removePreference(aboutSettings); - } + final PreferenceScreen inputScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_INPUT); + final PreferenceScreen advancedScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_ADVANCED); + final Preference debugScreen = findPreference(Settings.SCREEN_DEBUG); + if (Settings.isInternal(prefs)) { + final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); + debugSettingsIntent.setClassName( + context.getPackageName(), DebugSettingsActivity.class.getName()); + debugScreen.setIntent(debugSettingsIntent); + } else { + advancedScreen.removePreference(debugScreen); } final boolean showVoiceKeyOption = res.getBoolean( R.bool.config_enable_show_voice_key_option); if (!showVoiceKeyOption) { - removePreference(Settings.PREF_VOICE_INPUT_KEY, generalSettings); + removePreference(Settings.PREF_VOICE_INPUT_KEY, inputScreen); } - final PreferenceGroup advancedSettings = - (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS); if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { - removePreference(Settings.PREF_VIBRATE_ON, generalSettings); - removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedSettings); + removePreference(Settings.PREF_VIBRATE_ON, inputScreen); + removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedScreen); } if (!Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS) { + final PreferenceScreen multiLingualScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_MULTI_LINGUAL); + removePreference(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, multiLingualScreen); removePreference( - Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, advancedSettings); - removePreference( - Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, advancedSettings); + Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, multiLingualScreen); } - // TODO: consolidate key preview dismiss delay with the key preview animation parameters. if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) { - removePreference(Settings.PREF_POPUP_ON, generalSettings); - removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedSettings); + removePreference(Settings.PREF_POPUP_ON, inputScreen); + removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedScreen); } else { // TODO: Cleanup this setup. final ListPreference keyPreviewPopupDismissDelay = @@ -199,18 +182,18 @@ public final class SettingsFragment extends InputMethodSettingsFragment } if (!res.getBoolean(R.bool.config_setup_wizard_available)) { - removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedSettings); + removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedScreen); } - final PreferenceGroup textCorrectionGroup = - (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); + final PreferenceScreen correctionScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_CORRECTION); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); final Intent intent = dictionaryLink.getIntent(); intent.setClassName(context.getPackageName(), DictionarySettingsActivity.class.getName()); final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); if (0 >= number) { - textCorrectionGroup.removePreference(dictionaryLink); + correctionScreen.removePreference(dictionaryLink); } if (ProductionFlag.IS_METRICS_LOGGING_SUPPORTED) { @@ -224,7 +207,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment enableMetricsLogging.setTitle(enableMetricsLoggingTitle); } } else { - removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, textCorrectionGroup); + removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, advancedScreen); } final Preference editPersonalDictionary = @@ -238,7 +221,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment } if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) { - removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen()); + removePreference(Settings.SCREEN_GESTURE, getPreferenceScreen()); } AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this); @@ -261,8 +244,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment voiceInputKeyOption.setSummary(isShortcutImeEnabled ? null : res.getText(R.string.voice_input_disabled_summary)); } - final CheckBoxPreference showSetupWizardIcon = - (CheckBoxPreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); + final TwoStatePreference showSetupWizardIcon = + (TwoStatePreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); if (showSetupWizardIcon != null) { showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity())); } @@ -476,4 +459,29 @@ public final class SettingsFragment extends InputMethodSettingsFragment userDictionaryPreference.setFragment(UserDictionaryList.class.getName()); } } + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + if (!FeedbackUtils.isFeedbackFormSupported()) { + return; + } + menu.add(NO_MENU_GROUP, MENU_FEEDBACK /* itemId */, MENU_FEEDBACK /* order */, + R.string.send_feedback); + menu.add(NO_MENU_GROUP, MENU_ABOUT /* itemId */, MENU_ABOUT /* order */, + FeedbackUtils.getAboutKeyboardTitleResId()); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + final int itemId = item.getItemId(); + if (itemId == MENU_FEEDBACK) { + FeedbackUtils.showFeedbackForm(getActivity()); + return true; + } + if (itemId == MENU_ABOUT) { + startActivity(FeedbackUtils.getAboutKeyboardIntent(getActivity())); + return true; + } + return super.onOptionsItemSelected(item); + } } 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/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/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..4ac0f406e 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 = 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..7e1f3b233 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. 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..f7f2a32b4 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 = 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", |