aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/AndroidManifest.xml9
-rw-r--r--java/res/values-kk-rKZ/strings.xml16
-rw-r--r--java/res/values-km-rKH/strings-emoji-descriptions.xml44
-rw-r--r--java/res/values-km-rKH/strings-letter-descriptions.xml358
-rw-r--r--java/res/values-ur-rPK/strings.xml2
-rw-r--r--java/res/values-uz-rUZ/strings.xml38
-rw-r--r--java/res/values/donottranslate-config-important-notice.xml30
-rw-r--r--java/res/values/important_notice_strings.xml21
-rw-r--r--java/res/values/strings-config-important-notice.xml1
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java1
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java7
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsContentObserver.java28
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java8
-rw-r--r--java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java78
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java18
-rw-r--r--java/src/com/android/inputmethod/latin/permissions/PermissionsActivity.java97
-rw-r--r--java/src/com/android/inputmethod/latin/permissions/PermissionsManager.java91
-rw-r--r--java/src/com/android/inputmethod/latin/permissions/PermissionsUtil.java93
-rw-r--r--java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java42
-rw-r--r--java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java50
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsActivity.java10
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java2
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java12
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java54
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java4
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java107
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java149
28 files changed, 788 insertions, 584 deletions
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index f58c401c7..8882cdea5 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -18,7 +18,7 @@
coreApp="true"
package="com.android.inputmethod.latin">
- <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
+ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
@@ -77,6 +77,13 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".permissions.PermissionsActivity"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="false"
+ android:taskAffinity="" >
+ </activity>
+
<activity android:name=".setup.SetupWizardActivity"
android:theme="@style/platformActivityTheme"
android:label="@string/english_ime_name"
diff --git a/java/res/values-kk-rKZ/strings.xml b/java/res/values-kk-rKZ/strings.xml
index c72816311..16b270e4a 100644
--- a/java/res/values-kk-rKZ/strings.xml
+++ b/java/res/values-kk-rKZ/strings.xml
@@ -25,7 +25,7 @@
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Емлені тексеру құралы контактілер тізімінің жазбаларын пайдаланады"</string>
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Пернені басқан кездегі діріл"</string>
<string name="sound_on_keypress" msgid="6093592297198243644">"Пернені басу кезіндегі дыбыс"</string>
- <string name="popup_on_keypress" msgid="123894815723512944">"Пернені басқан кездегі ашылмалы мәзір"</string>
+ <string name="popup_on_keypress" msgid="123894815723512944">"Басылған пернені үлкейтіп көрсету"</string>
<string name="settings_screen_preferences" msgid="2696713156722014624">"Қалауларыңыз"</string>
<string name="settings_screen_accounts" msgid="2786418968536696670">"Есептік жазбалар және құпиялық"</string>
<string name="settings_screen_appearance" msgid="7358046399111611615">"Сыртқы түр және орналасулар"</string>
@@ -50,7 +50,7 @@
<string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Тілді ауыстыру пернесі басқа енгізу әдістерін де қамтиды"</string>
<string name="show_language_switch_key" msgid="5915478828318774384">"Тілді ауыстыру пернесі"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Бірнеше енгізу тілдері қосылған кезде көрсету"</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>
@@ -59,8 +59,8 @@
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Ұсыныстар мен түзетулер үшін контакт аттарын пайдалану"</string>
<string name="use_personalized_dicts" msgid="5167396352105467626">"Жекелендірілген ұсыныстар"</string>
<string name="enable_metrics_logging" msgid="5506372337118822837">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> жақсарту"</string>
- <string name="use_double_space_period" msgid="8781529969425082860">"Қос бос орын кезеңі"</string>
- <string name="use_double_space_period_summary" msgid="6532892187247952799">"Бос орынға екі рет түрту бос орыннан кейінгі кезеңді енгізеді"</string>
+ <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_summary" msgid="7934452761022946874">"Әрбір сөйлемнің бірінші әріпін бас әріпке түрлендіру"</string>
<string name="edit_personal_dictionary" msgid="3996910038952940420">"Жеке сөздік"</string>
@@ -68,7 +68,7 @@
<string name="main_dictionary" msgid="4798763781818361168">"Негізгі сөздік"</string>
<string name="prefs_show_suggestions" msgid="8026799663445531637">"Түзету ұсыныстарын көрсету"</string>
<string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Теру кезінде ұсынылған сөздерді көрсету"</string>
- <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Қорлаушы сөздерді құлыптамау"</string>
+ <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Қорлаушы сөздерді тыю"</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>
@@ -77,7 +77,7 @@
<string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Белсенді"</string>
<string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Өте белсенді"</string>
<string name="bigram_prediction" msgid="1084449187723948550">"Келесі сөз ұсыныстары"</string>
- <string name="bigram_prediction_summary" msgid="3896362682751109677">"Ұсыныстар жасауда бастапқы сөзді пайдалану"</string>
+ <string name="bigram_prediction_summary" msgid="3896362682751109677">"Ұсыныстар жасауда алдыңғы сөзді пайдалану"</string>
<string name="gesture_input" msgid="826951152254563827">"Қимылмен теруді қосу"</string>
<string name="gesture_input_summary" msgid="9180350639305731231">"Әріптерді жанап өту арқылы сөзді енгізу"</string>
<string name="gesture_preview_trail" msgid="3802333369335722221">"Қимыл қадамын көрсету"</string>
@@ -126,10 +126,10 @@
<string name="custom_input_styles_title" msgid="8429952441821251512">"Реттелетін енгізу стильдері"</string>
<string name="add_style" msgid="6163126614514489951">"Стиль қосу"</string>
<string name="add" msgid="8299699805688017798">"Қосу"</string>
- <string name="remove" msgid="4486081658752944606">"Аластау"</string>
+ <string name="remove" msgid="4486081658752944606">"Өшіру"</string>
<string name="save" msgid="7646738597196767214">"Сақтау"</string>
<string name="subtype_locale" msgid="8576443440738143764">"Тіл"</string>
- <string name="keyboard_layout_set" msgid="4309233698194565609">"Пішім"</string>
+ <string name="keyboard_layout_set" msgid="4309233698194565609">"Орналасу"</string>
<string name="custom_input_style_note_message" msgid="8826731320846363423">"Реттелетін енгізу стилі пайдалануды бастамас бұрын қосылуы қажет. Оны қазір қосу қажет пе?"</string>
<string name="enable" msgid="5031294444630523247">"Қосу"</string>
<string name="not_now" msgid="6172462888202790482">"Қазір емес"</string>
diff --git a/java/res/values-km-rKH/strings-emoji-descriptions.xml b/java/res/values-km-rKH/strings-emoji-descriptions.xml
index aca04fc4d..532e04226 100644
--- a/java/res/values-km-rKH/strings-emoji-descriptions.xml
+++ b/java/res/values-km-rKH/strings-emoji-descriptions.xml
@@ -92,7 +92,7 @@
<string name="spoken_emoji_26BE" msgid="8959760533076498209">"បាល់បោះ"</string>
<string name="spoken_emoji_26C4" msgid="3045791757044255626">"អ្នកលេង​ព្រិល​ដោយ​គ្មាន​ព្រិល"</string>
<string name="spoken_emoji_26C5" msgid="5580129409712578639">"ព្រះអាទិត្យ​នៅ​​ក្រោយ​ពពក"</string>
- <string name="spoken_emoji_26CE" msgid="8963656417276062998">"សញ្ញា (⛎)"</string>
+ <string name="spoken_emoji_26CE" msgid="8963656417276062998">"សញ្ញាអាព្យូឈូស"</string>
<string name="spoken_emoji_26D4" msgid="2231451988209604130">"ហាមចូល"</string>
<string name="spoken_emoji_26EA" msgid="7513319636103804907">"វិហារ​សាសនា"</string>
<string name="spoken_emoji_26F2" msgid="7134115206158891037">"បាញ់​ទឹក"</string>
@@ -114,7 +114,7 @@
<string name="spoken_emoji_2728" msgid="5650330815808691881">"បញ្ចេញ​ពន្លឺ"</string>
<string name="spoken_emoji_2733" msgid="8915809595141157327">"ផ្កាយ​ប្រាំ​បី​ជ្រុង"</string>
<string name="spoken_emoji_2734" msgid="4846583547980754332">"ផ្កាយ​ប្រាំ​បី​ជ្រុង​ដិត"</string>
- <string name="spoken_emoji_2744" msgid="4350636647760161042">"សញ្ញា (❄)"</string>
+ <string name="spoken_emoji_2744" msgid="4350636647760161042">"ផ្កាព្រិល"</string>
<string name="spoken_emoji_2747" msgid="3718282973916474455">"បញ្ចេញ​ពន្លឺ"</string>
<string name="spoken_emoji_274C" msgid="2752145886733295314">"សញ្ញា​​ខ្វែង"</string>
<string name="spoken_emoji_274E" msgid="4262918689871098338">"សញ្ញា​ខ្វែង​ក្នុង​ប្រអប់"</string>
@@ -139,11 +139,11 @@
<string name="spoken_emoji_2B50" msgid="3850845519526950524">"​ផ្កាយ​​មធ្យម​ពណ៌ស"</string>
<string name="spoken_emoji_2B55" msgid="9137882158811541824">"រង្វង់​ធំ​​ដិត"</string>
<string name="spoken_emoji_3030" msgid="4609172241893565639">"សញ្ញា​​រលក​ដិត"</string>
- <string name="spoken_emoji_303D" msgid="2545833934975907505">"សញ្ញា (〽)"</string>
- <string name="spoken_emoji_3297" msgid="928912923628973800">"សញ្ញា (㊗)"</string>
- <string name="spoken_emoji_3299" msgid="3930347573693668426">"សញ្ញា (㊙)"</string>
- <string name="spoken_emoji_1F004" msgid="1705216181345894600">"សញ្ញា (🀄)"</string>
- <string name="spoken_emoji_1F0CF" msgid="7601493592085987866">"សញ្ញា (🃏)"</string>
+ <string name="spoken_emoji_303D" msgid="2545833934975907505">"សញ្ញាចាប់ផ្តើមចម្រៀង"</string>
+ <string name="spoken_emoji_3297" msgid="928912923628973800">"សញ្ញាអបអរសាទរមូល"</string>
+ <string name="spoken_emoji_3299" msgid="3930347573693668426">"សញ្ញាសម្ងាត់មូល"</string>
+ <string name="spoken_emoji_1F004" msgid="1705216181345894600">"សញ្ញានាគក្រហមម៉ាចុង"</string>
+ <string name="spoken_emoji_1F0CF" msgid="7601493592085987866">"រូបតុក្កតាបៀពណ៌ខ្មៅ"</string>
<string name="spoken_emoji_1F170" msgid="3817698686602826773">"ឈាម​ប្រភេទ A"</string>
<string name="spoken_emoji_1F171" msgid="3684218589626650242">"ឈាម​ប្រភេទ B"</string>
<string name="spoken_emoji_1F17E" msgid="2978809190364779029">"ឈាម​ប្រភេទ O"</string>
@@ -159,21 +159,21 @@
<string name="spoken_emoji_1F198" msgid="7020298909426960622">"ប្រអប់ SOS"</string>
<string name="spoken_emoji_1F199" msgid="5971252667136235630">"ប្រអប់ up!"</string>
<string name="spoken_emoji_1F19A" msgid="4557270135899843959">"ប្រអប់ vs"</string>
- <string name="spoken_emoji_1F201" msgid="7000490044681139002">"សញ្ញា (🈁)"</string>
- <string name="spoken_emoji_1F202" msgid="8560906958695043947">"សញ្ញា (🈂)"</string>
- <string name="spoken_emoji_1F21A" msgid="1496435317324514033">"សញ្ញា (🈚)"</string>
- <string name="spoken_emoji_1F22F" msgid="609797148862445402">"សញ្ញា (🈯)"</string>
- <string name="spoken_emoji_1F232" msgid="8125716331632035820">"សញ្ញា (🈲)"</string>
- <string name="spoken_emoji_1F233" msgid="8749401090457355028">"សញ្ញា (🈳)"</string>
- <string name="spoken_emoji_1F234" msgid="3546951604285970768">"សញ្ញា (🈴)"</string>
- <string name="spoken_emoji_1F235" msgid="5320186982841793711">"សញ្ញា (🈵)"</string>
- <string name="spoken_emoji_1F236" msgid="879755752069393034">"សញ្ញា (🈶)"</string>
- <string name="spoken_emoji_1F237" msgid="6741807001205851437">"សញ្ញា (🈷)"</string>
- <string name="spoken_emoji_1F238" msgid="5504414186438196912">"សញ្ញា (🈸)"</string>
- <string name="spoken_emoji_1F239" msgid="1634067311597618959">"សញ្ញា (🈹)"</string>
- <string name="spoken_emoji_1F23A" msgid="3107862957630169536">"សញ្ញា (🈺)"</string>
- <string name="spoken_emoji_1F250" msgid="6586943922806727907">"សញ្ញា (🉐)"</string>
- <string name="spoken_emoji_1F251" msgid="9099032855993346948">"សញ្ញា (🉑)"</string>
+ <string name="spoken_emoji_1F201" msgid="7000490044681139002">"សញ្ញានៅទីនេះកាតាកាណាជ្រុង"</string>
+ <string name="spoken_emoji_1F202" msgid="8560906958695043947">"សញ្ញាសេវាកម្មកាតាកាណាជ្រុង"</string>
+ <string name="spoken_emoji_1F21A" msgid="1496435317324514033">"សញ្ញាឥតគិតថ្លៃជ្រុង"</string>
+ <string name="spoken_emoji_1F22F" msgid="609797148862445402">"សញ្ញាកន្លែងកក់រួចជ្រុង"</string>
+ <string name="spoken_emoji_1F232" msgid="8125716331632035820">"សញ្ញាហាមឃាត់ជ្រុង"</string>
+ <string name="spoken_emoji_1F233" msgid="8749401090457355028">"សញ្ញាកន្លែងទំនេរជ្រុង"</string>
+ <string name="spoken_emoji_1F234" msgid="3546951604285970768">"សញ្ញាព្រមទទួលជ្រុង"</string>
+ <string name="spoken_emoji_1F235" msgid="5320186982841793711">"សញ្ញាជួលពេញជ្រុង"</string>
+ <string name="spoken_emoji_1F236" msgid="879755752069393034">"សញ្ញាមានផ្តល់ជូនជ្រុង"</string>
+ <string name="spoken_emoji_1F237" msgid="6741807001205851437">"សញ្ញាប្រចាំខែជ្រុង"</string>
+ <string name="spoken_emoji_1F238" msgid="5504414186438196912">"សញ្ញាកម្មវិធីជ្រុង"</string>
+ <string name="spoken_emoji_1F239" msgid="1634067311597618959">"សញ្ញាបញ្ចុះតម្លៃជ្រុង"</string>
+ <string name="spoken_emoji_1F23A" msgid="3107862957630169536">"សញ្ញាដំណើរការអាជីវកម្មជ្រុង"</string>
+ <string name="spoken_emoji_1F250" msgid="6586943922806727907">"សញ្ញាអត្ថប្រយោជន៍មូល"</string>
+ <string name="spoken_emoji_1F251" msgid="9099032855993346948">"សញ្ញាយល់ព្រមមូល"</string>
<string name="spoken_emoji_1F300" msgid="4720098285295840383">"ស៊ីក្លូន"</string>
<string name="spoken_emoji_1F301" msgid="3601962477653752974">"អ័ភ្រ"</string>
<string name="spoken_emoji_1F302" msgid="3404357123421753593">"ឆត្រ​បិទ"</string>
diff --git a/java/res/values-km-rKH/strings-letter-descriptions.xml b/java/res/values-km-rKH/strings-letter-descriptions.xml
index f58eff4d1..b33d5d1d6 100644
--- a/java/res/values-km-rKH/strings-letter-descriptions.xml
+++ b/java/res/values-km-rKH/strings-letter-descriptions.xml
@@ -26,183 +26,183 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="spoken_accented_letter_00AA" msgid="4374325261868451570">"សញ្ញា ª"</string>
- <string name="spoken_accented_letter_00B5" msgid="9031387673828823891">"សញ្ញា µ"</string>
- <string name="spoken_accented_letter_00BA" msgid="5045198452071207437">"សញ្ញា º"</string>
- <string name="spoken_accented_letter_00DF" msgid="2260098367028134281">"សញ្ញា ß"</string>
- <string name="spoken_accented_letter_00E0" msgid="2234515772182387086">"សញ្ញា à"</string>
- <string name="spoken_accented_letter_00E1" msgid="7780174500802535063">"សញ្ញា á"</string>
- <string name="spoken_accented_letter_00E2" msgid="7054108480488102631">"សញ្ញា â"</string>
- <string name="spoken_accented_letter_00E3" msgid="8252569677935693343">"សញ្ញា ã"</string>
- <string name="spoken_accented_letter_00E4" msgid="6610118430986969466">"សញ្ញា ä"</string>
- <string name="spoken_accented_letter_00E5" msgid="7630449270070348394">"សញ្ញា å"</string>
- <string name="spoken_accented_letter_00E6" msgid="701838036007000032">"សញ្ញា æ"</string>
- <string name="spoken_accented_letter_00E7" msgid="2991289211702135310">"សញ្ញា ç"</string>
- <string name="spoken_accented_letter_00E8" msgid="2080035251848179782">"សញ្ញា è"</string>
- <string name="spoken_accented_letter_00E9" msgid="2708473976407506968">"សញ្ញា é"</string>
- <string name="spoken_accented_letter_00EA" msgid="1898848081635119449">"សញ្ញា ê"</string>
- <string name="spoken_accented_letter_00EB" msgid="8318942663983499634">"សញ្ញា ë"</string>
- <string name="spoken_accented_letter_00EC" msgid="7643810590358306098">"សញ្ញា ì"</string>
- <string name="spoken_accented_letter_00ED" msgid="8288035355103120759">"សញ្ញា í"</string>
- <string name="spoken_accented_letter_00EE" msgid="1137417730211688894">"សញ្ញា î"</string>
- <string name="spoken_accented_letter_00EF" msgid="8993714322731956785">"សញ្ញា ï"</string>
- <string name="spoken_accented_letter_00F0" msgid="3427567511221967857">"សញ្ញា ð"</string>
- <string name="spoken_accented_letter_00F1" msgid="6983294908255378605">"សញ្ញា ñ"</string>
- <string name="spoken_accented_letter_00F2" msgid="2623804069332183695">"សញ្ញា ò"</string>
- <string name="spoken_accented_letter_00F3" msgid="8945987631729216917">"សញ្ញា ó"</string>
- <string name="spoken_accented_letter_00F4" msgid="2415494299699717276">"សញ្ញា ô"</string>
- <string name="spoken_accented_letter_00F5" msgid="7320512716652765243">"សញ្ញា õ"</string>
- <string name="spoken_accented_letter_00F6" msgid="9101179351242478555">"សញ្ញា ö"</string>
- <string name="spoken_accented_letter_00F8" msgid="1488324280918884122">"សញ្ញា ø"</string>
- <string name="spoken_accented_letter_00F9" msgid="2823570256527173278">"សញ្ញា ù"</string>
- <string name="spoken_accented_letter_00FA" msgid="6883092085077298608">"សញ្ញា ú"</string>
- <string name="spoken_accented_letter_00FB" msgid="4948239400399514418">"សញ្ញា û"</string>
- <string name="spoken_accented_letter_00FC" msgid="2496066211694000442">"សញ្ញា ü"</string>
- <string name="spoken_accented_letter_00FD" msgid="2400529610834233890">"សញ្ញា ý"</string>
- <string name="spoken_accented_letter_00FE" msgid="8788160115017853040">"សញ្ញា þ"</string>
- <string name="spoken_accented_letter_00FF" msgid="5225610161025124830">"សញ្ញា ÿ"</string>
- <string name="spoken_accented_letter_0101" msgid="5573209280917268157">"សញ្ញា ā"</string>
- <string name="spoken_accented_letter_0103" msgid="2469151120095164730">"សញ្ញា ă"</string>
- <string name="spoken_accented_letter_0105" msgid="8312689789855786427">"សញ្ញា ą"</string>
- <string name="spoken_accented_letter_0107" msgid="5708507895287798642">"សញ្ញា ć"</string>
- <string name="spoken_accented_letter_0109" msgid="7008112603489583335">"សញ្ញា ĉ"</string>
- <string name="spoken_accented_letter_010B" msgid="5641359473019753216">"សញ្ញា ċ"</string>
- <string name="spoken_accented_letter_010D" msgid="1048661826408437168">"សញ្ញា č"</string>
- <string name="spoken_accented_letter_010F" msgid="603374318657992205">"សញ្ញា ď"</string>
- <string name="spoken_accented_letter_0111" msgid="5517997642285938260">"សញ្ញា đ"</string>
- <string name="spoken_accented_letter_0113" msgid="2326009009311798997">"សញ្ញា ē"</string>
- <string name="spoken_accented_letter_0115" msgid="3964545407091037747">"សញ្ញា ĕ"</string>
- <string name="spoken_accented_letter_0117" msgid="8799753183781089777">"សញ្ញា ė"</string>
- <string name="spoken_accented_letter_0119" msgid="3772451226935709136">"សញ្ញា ę"</string>
- <string name="spoken_accented_letter_011B" msgid="7663481332351461288">"សញ្ញា ě"</string>
- <string name="spoken_accented_letter_011D" msgid="1181326600595482369">"សញ្ញា ĝ"</string>
- <string name="spoken_accented_letter_011F" msgid="6843415389823096647">"សញ្ញា ğ"</string>
- <string name="spoken_accented_letter_0121" msgid="6205288708713306903">"សញ្ញា ġ"</string>
- <string name="spoken_accented_letter_0123" msgid="2394277128105386261">"សញ្ញា ģ"</string>
- <string name="spoken_accented_letter_0125" msgid="6575866461277751345">"សញ្ញា ĥ"</string>
- <string name="spoken_accented_letter_0127" msgid="1316971762214091641">"សញ្ញា ħ"</string>
- <string name="spoken_accented_letter_0129" msgid="7824912405885325754">"សញ្ញា ĩ"</string>
- <string name="spoken_accented_letter_012B" msgid="6772690258769905270">"សញ្ញា ī"</string>
- <string name="spoken_accented_letter_012D" msgid="2933871131556503448">"សញ្ញា ĭ"</string>
- <string name="spoken_accented_letter_012F" msgid="1340511254985181663">"សញ្ញា į"</string>
- <string name="spoken_accented_letter_0131" msgid="5635600720566083969">"សញ្ញា ı"</string>
- <string name="spoken_accented_letter_0133" msgid="7593704176516791941">"សញ្ញា ij"</string>
- <string name="spoken_accented_letter_0135" msgid="4521109674238248436">"សញ្ញា ĵ"</string>
- <string name="spoken_accented_letter_0137" msgid="5886444641003852175">"សញ្ញា ķ"</string>
- <string name="spoken_accented_letter_0138" msgid="4200294389170924853">"សញ្ញា ĸ"</string>
- <string name="spoken_accented_letter_013A" msgid="3558015385412543517">"សញ្ញា ĺ"</string>
- <string name="spoken_accented_letter_013C" msgid="1853639924813858734">"សញ្ញា ļ"</string>
- <string name="spoken_accented_letter_013E" msgid="7489345561739421886">"សញ្ញា ľ"</string>
- <string name="spoken_accented_letter_0140" msgid="7946718707268270589">"សញ្ញា ŀ"</string>
- <string name="spoken_accented_letter_0142" msgid="752931798111122240">"សញ្ញា ł"</string>
- <string name="spoken_accented_letter_0144" msgid="201843550323875352">"សញ្ញា ń"</string>
- <string name="spoken_accented_letter_0146" msgid="3403847152606051818">"សញ្ញា ņ"</string>
- <string name="spoken_accented_letter_0148" msgid="9215300786722209338">"សញ្ញា ň"</string>
- <string name="spoken_accented_letter_0149" msgid="3191850286630154063">"សញ្ញា ʼn"</string>
- <string name="spoken_accented_letter_014B" msgid="8503022408522837410">"សញ្ញា ŋ"</string>
- <string name="spoken_accented_letter_014D" msgid="4452323602550610641">"សញ្ញា ō"</string>
- <string name="spoken_accented_letter_014F" msgid="2795957717094385336">"សញ្ញា ŏ"</string>
- <string name="spoken_accented_letter_0151" msgid="8013704745216410244">"សញ្ញា ő"</string>
- <string name="spoken_accented_letter_0153" msgid="8410582495993285221">"សញ្ញា œ"</string>
- <string name="spoken_accented_letter_0155" msgid="7601517174689798560">"សញ្ញា ŕ"</string>
- <string name="spoken_accented_letter_0157" msgid="9071455715455643810">"សញ្ញា ŗ"</string>
- <string name="spoken_accented_letter_0159" msgid="7726911392381543439">"សញ្ញា ř"</string>
- <string name="spoken_accented_letter_015B" msgid="1854129531164494117">"សញ្ញា ś"</string>
- <string name="spoken_accented_letter_015D" msgid="4743571603550582530">"សញ្ញា ŝ"</string>
- <string name="spoken_accented_letter_015F" msgid="1519945638631588761">"សញ្ញា ş"</string>
- <string name="spoken_accented_letter_0161" msgid="7493478552029144246">"សញ្ញា š"</string>
- <string name="spoken_accented_letter_0163" msgid="9103547637928833069">"សញ្ញា ţ"</string>
- <string name="spoken_accented_letter_0165" msgid="7306159398214872062">"សញ្ញា ť"</string>
- <string name="spoken_accented_letter_0167" msgid="5578767705098672443">"សញ្ញា ŧ"</string>
- <string name="spoken_accented_letter_0169" msgid="413046581387735371">"សញ្ញា ũ"</string>
- <string name="spoken_accented_letter_016B" msgid="3209778874978859441">"សញ្ញា ū"</string>
- <string name="spoken_accented_letter_016D" msgid="2983326533258602840">"សញ្ញា ŭ"</string>
- <string name="spoken_accented_letter_016F" msgid="4416532499516387231">"សញ្ញា ů"</string>
- <string name="spoken_accented_letter_0171" msgid="3435171971353200807">"សញ្ញា ű"</string>
- <string name="spoken_accented_letter_0173" msgid="4494154432483553480">"សញ្ញា ų"</string>
- <string name="spoken_accented_letter_0175" msgid="2154545579611918513">"សញ្ញា ŵ"</string>
- <string name="spoken_accented_letter_0177" msgid="4034463827306904781">"សញ្ញា ŷ"</string>
- <string name="spoken_accented_letter_017A" msgid="3368292232292925369">"សញ្ញា ź"</string>
- <string name="spoken_accented_letter_017C" msgid="2834484584505860430">"សញ្ញា ż"</string>
- <string name="spoken_accented_letter_017E" msgid="1209240442434887098">"សញ្ញា ž"</string>
- <string name="spoken_accented_letter_017F" msgid="317501463253362415">"សញ្ញា ſ"</string>
- <string name="spoken_accented_letter_01A1" msgid="630186564859044196">"សញ្ញា ơ"</string>
- <string name="spoken_accented_letter_01B0" msgid="8544012177684640443">"សញ្ញា ư"</string>
- <string name="spoken_accented_letter_0219" msgid="1960371842020076066">"សញ្ញា ș"</string>
- <string name="spoken_accented_letter_021B" msgid="1398418662032919032">"សញ្ញា ț"</string>
- <string name="spoken_accented_letter_0259" msgid="2464085263158415898">"សញ្ញា ə"</string>
- <string name="spoken_accented_letter_1EA1" msgid="688124877202887630">"សញ្ញា ạ"</string>
- <string name="spoken_accented_letter_1EA3" msgid="327960130366386256">"សញ្ញា ả"</string>
- <string name="spoken_accented_letter_1EA5" msgid="637406363453769610">"សញ្ញា ấ"</string>
- <string name="spoken_accented_letter_1EA7" msgid="1419591804181615409">"សញ្ញា ầ"</string>
- <string name="spoken_accented_letter_1EA9" msgid="6068887382734896756">"សញ្ញា ẩ"</string>
- <string name="spoken_accented_letter_1EAB" msgid="7236523151662538333">"សញ្ញា ẫ"</string>
- <string name="spoken_accented_letter_1EAD" msgid="2363364864106332076">"សញ្ញា ậ"</string>
- <string name="spoken_accented_letter_1EAF" msgid="1576329511464272935">"សញ្ញា ắ"</string>
- <string name="spoken_accented_letter_1EB1" msgid="4634735072816076592">"សញ្ញា ằ"</string>
- <string name="spoken_accented_letter_1EB3" msgid="2325245849038771534">"សញ្ញា ẳ"</string>
- <string name="spoken_accented_letter_1EB5" msgid="3720427596242746295">"សញ្ញា ẵ"</string>
- <string name="spoken_accented_letter_1EB7" msgid="700415535653646695">"សញ្ញា ặ"</string>
- <string name="spoken_accented_letter_1EB9" msgid="3901338692305890487">"សញ្ញា ẹ"</string>
- <string name="spoken_accented_letter_1EBB" msgid="4028688699415417302">"សញ្ញា ẻ"</string>
- <string name="spoken_accented_letter_1EBD" msgid="181253633045931897">"សញ្ញា ẽ"</string>
- <string name="spoken_accented_letter_1EBF" msgid="3309618845007944963">"សញ្ញា ế"</string>
- <string name="spoken_accented_letter_1EC1" msgid="8139046749226332542">"សញ្ញា ề"</string>
- <string name="spoken_accented_letter_1EC3" msgid="3239674223053133383">"សញ្ញា ể"</string>
- <string name="spoken_accented_letter_1EC5" msgid="2216559244705714587">"សញ្ញា ễ"</string>
- <string name="spoken_accented_letter_1EC7" msgid="9012731468253986792">"សញ្ញា ệ"</string>
- <string name="spoken_accented_letter_1EC9" msgid="2901917620195717034">"សញ្ញា ỉ"</string>
- <string name="spoken_accented_letter_1ECB" msgid="5470387489820034621">"សញ្ញា ị"</string>
- <string name="spoken_accented_letter_1ECD" msgid="1340122876914839806">"សញ្ញា ọ"</string>
- <string name="spoken_accented_letter_1ECF" msgid="2326921263882559755">"សញ្ញា ỏ"</string>
- <string name="spoken_accented_letter_1ED1" msgid="2885683296042774958">"សញ្ញា ố"</string>
- <string name="spoken_accented_letter_1ED3" msgid="6857664926477376178">"សញ្ញា ồ"</string>
- <string name="spoken_accented_letter_1ED5" msgid="2015209467290624062">"សញ្ញា ổ"</string>
- <string name="spoken_accented_letter_1ED7" msgid="7924481354960306389">"សញ្ញា ỗ"</string>
- <string name="spoken_accented_letter_1ED9" msgid="7023315590332365554">"សញ្ញា ộ"</string>
- <string name="spoken_accented_letter_1EDB" msgid="2379438944917634496">"សញ្ញា ớ"</string>
- <string name="spoken_accented_letter_1EDD" msgid="8107077534204404085">"សញ្ញា ờ"</string>
- <string name="spoken_accented_letter_1EDF" msgid="1846880105528347966">"សញ្ញា ở"</string>
- <string name="spoken_accented_letter_1EE1" msgid="1520037313389776718">"សញ្ញា ỡ"</string>
- <string name="spoken_accented_letter_1EE3" msgid="907964027171008963">"សញ្ញា ợ"</string>
- <string name="spoken_accented_letter_1EE5" msgid="1522024630360038700">"សញ្ញា ụ"</string>
- <string name="spoken_accented_letter_1EE7" msgid="7815412228302952637">"សញ្ញា ủ"</string>
- <string name="spoken_accented_letter_1EE9" msgid="4219119671251485651">"សញ្ញា ứ"</string>
- <string name="spoken_accented_letter_1EEB" msgid="4086009841269002231">"សញ្ញា ừ"</string>
- <string name="spoken_accented_letter_1EED" msgid="3528151733528719847">"សញ្ញា ử"</string>
- <string name="spoken_accented_letter_1EEF" msgid="3508548229409072119">"សញ្ញា ữ"</string>
- <string name="spoken_accented_letter_1EF1" msgid="1912816350401931115">"សញ្ញា ự"</string>
- <string name="spoken_accented_letter_1EF3" msgid="7211760439435946494">"សញ្ញា ỳ"</string>
- <string name="spoken_accented_letter_1EF5" msgid="8998864482764007384">"សញ្ញា ỵ"</string>
- <string name="spoken_accented_letter_1EF7" msgid="922043627252869200">"សញ្ញា ỷ"</string>
- <string name="spoken_accented_letter_1EF9" msgid="6213977100552260366">"សញ្ញា ỹ"</string>
- <string name="spoken_symbol_00A1" msgid="4281758332905123408">"សញ្ញា ¡"</string>
- <string name="spoken_symbol_00AB" msgid="4093069643313064892">"សញ្ញា «"</string>
- <string name="spoken_symbol_00B7" msgid="2447718728927874920">"សញ្ញា ·"</string>
- <string name="spoken_symbol_00B9" msgid="8026257165451461231">"សញ្ញា ¹"</string>
- <string name="spoken_symbol_00BB" msgid="1102740075655373928">"សញ្ញា »"</string>
- <string name="spoken_symbol_00BF" msgid="6233794752573788098">"សញ្ញា ¿"</string>
- <string name="spoken_symbol_2018" msgid="4886476295598930225">"សញ្ញា ‘"</string>
- <string name="spoken_symbol_2019" msgid="8892530161598134083">"សញ្ញា ’"</string>
- <string name="spoken_symbol_201A" msgid="2072987157683446644">"សញ្ញា ‚"</string>
- <string name="spoken_symbol_201C" msgid="4588048378803665427">"សញ្ញា “"</string>
- <string name="spoken_symbol_201D" msgid="1642776849495925895">"សញ្ញា ”"</string>
- <string name="spoken_symbol_2020" msgid="9084628638189344431">"សញ្ញា †"</string>
- <string name="spoken_symbol_2021" msgid="5081396468559426475">"សញ្ញា ‡"</string>
- <string name="spoken_symbol_2030" msgid="9068837172419431755">"សញ្ញា ‰"</string>
- <string name="spoken_symbol_2032" msgid="3014506329156664396">"សញ្ញា ′"</string>
- <string name="spoken_symbol_2033" msgid="1251022699713475088">"សញ្ញា ″"</string>
- <string name="spoken_symbol_2039" msgid="6989616457213775957">"សញ្ញា ‹"</string>
- <string name="spoken_symbol_203A" msgid="31245095449823701">"សញ្ញា ›"</string>
- <string name="spoken_symbol_2074" msgid="2116717717093306894">"សញ្ញា ⁴"</string>
- <string name="spoken_symbol_207F" msgid="1706731172134246659">"សញ្ញា ⁿ"</string>
- <string name="spoken_symbol_20B1" msgid="2159994270622444689">"សញ្ញា ₱"</string>
- <string name="spoken_symbol_2105" msgid="7289404939366976829">"សញ្ញា ℅"</string>
- <string name="spoken_symbol_2192" msgid="827804523596125414">"សញ្ញា →"</string>
- <string name="spoken_symbol_2193" msgid="2659541693445985717">"សញ្ញា ↓"</string>
- <string name="spoken_symbol_2205" msgid="4457188084269117343">"សញ្ញា ∅"</string>
- <string name="spoken_symbol_2206" msgid="4856786565708380687">"សញ្ញា ∆"</string>
- <string name="spoken_symbol_2264" msgid="5092061257745123554">"សញ្ញា ≤"</string>
- <string name="spoken_symbol_2265" msgid="1907966479878036357">"សញ្ញា ≥"</string>
- <string name="spoken_symbol_2605" msgid="5202920479405857753">"សញ្ញា ★"</string>
+ <string name="spoken_accented_letter_00AA" msgid="4374325261868451570">"សញ្ញាលេខលំដាប់បញ្ជាក់ភេទស្រី"</string>
+ <string name="spoken_accented_letter_00B5" msgid="9031387673828823891">"សញ្ញាម៉ុយ"</string>
+ <string name="spoken_accented_letter_00BA" msgid="5045198452071207437">"សញ្ញាលេខលំដាប់ភេទបញ្ជាក់ប្រុស"</string>
+ <string name="spoken_accented_letter_00DF" msgid="2260098367028134281">"S ស្រួច"</string>
+ <string name="spoken_accented_letter_00E0" msgid="2234515772182387086">"A បន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_00E1" msgid="7780174500802535063">"A បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_00E2" msgid="7054108480488102631">"A សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_00E3" msgid="8252569677935693343">"A សក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_00E4" msgid="6610118430986969466">"A សក់ចុចពីរ"</string>
+ <string name="spoken_accented_letter_00E5" msgid="7630449270070348394">"A រង្វង់ពីលើ"</string>
+ <string name="spoken_accented_letter_00E6" msgid="701838036007000032">"សញ្ញា A និង E ជាប់គ្នា"</string>
+ <string name="spoken_accented_letter_00E7" msgid="2991289211702135310">"C ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_00E8" msgid="2080035251848179782">"E បន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_00E9" msgid="2708473976407506968">"E បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_00EA" msgid="1898848081635119449">"E សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_00EB" msgid="8318942663983499634">"E សក់ចុចពីរ"</string>
+ <string name="spoken_accented_letter_00EC" msgid="7643810590358306098">"I បន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_00ED" msgid="8288035355103120759">"I បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_00EE" msgid="1137417730211688894">"I សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_00EF" msgid="8993714322731956785">"I សក់ចុចពីរ"</string>
+ <string name="spoken_accented_letter_00F0" msgid="3427567511221967857">"សញ្ញាអ៊េដ"</string>
+ <string name="spoken_accented_letter_00F1" msgid="6983294908255378605">"N សក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_00F2" msgid="2623804069332183695">"O បន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_00F3" msgid="8945987631729216917">"O បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_00F4" msgid="2415494299699717276">"O សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_00F5" msgid="7320512716652765243">"O សក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_00F6" msgid="9101179351242478555">"O សក់ចុចពីរ"</string>
+ <string name="spoken_accented_letter_00F8" msgid="1488324280918884122">"O ឆូត"</string>
+ <string name="spoken_accented_letter_00F9" msgid="2823570256527173278">"U បន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_00FA" msgid="6883092085077298608">"U បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_00FB" msgid="4948239400399514418">"U សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_00FC" msgid="2496066211694000442">"U សក់ចុចពីរ"</string>
+ <string name="spoken_accented_letter_00FD" msgid="2400529610834233890">"Y បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_00FE" msgid="8788160115017853040">"សញ្ញាសន"</string>
+ <string name="spoken_accented_letter_00FF" msgid="5225610161025124830">"Y សក់ចុចពីរ"</string>
+ <string name="spoken_accented_letter_0101" msgid="5573209280917268157">"A សក់ឆូត"</string>
+ <string name="spoken_accented_letter_0103" msgid="2469151120095164730">"A សក់អក្សរយូ"</string>
+ <string name="spoken_accented_letter_0105" msgid="8312689789855786427">"A ជើងកណ្តៀវ"</string>
+ <string name="spoken_accented_letter_0107" msgid="5708507895287798642">"C បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_0109" msgid="7008112603489583335">"C សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_010B" msgid="5641359473019753216">"C ចុចពីលើ"</string>
+ <string name="spoken_accented_letter_010D" msgid="1048661826408437168">"C សក់អក្សរវី"</string>
+ <string name="spoken_accented_letter_010F" msgid="603374318657992205">"D មានវណ្ណយុត្តិ"</string>
+ <string name="spoken_accented_letter_0111" msgid="5517997642285938260">"D ឆូត"</string>
+ <string name="spoken_accented_letter_0113" msgid="2326009009311798997">"E សក់ឆូត"</string>
+ <string name="spoken_accented_letter_0115" msgid="3964545407091037747">"E សក់អក្សរយូ"</string>
+ <string name="spoken_accented_letter_0117" msgid="8799753183781089777">"E ចុចពីលើ"</string>
+ <string name="spoken_accented_letter_0119" msgid="3772451226935709136">"E ជើងកណ្តៀវ"</string>
+ <string name="spoken_accented_letter_011B" msgid="7663481332351461288">"E សក់អក្សរវី"</string>
+ <string name="spoken_accented_letter_011D" msgid="1181326600595482369">"G សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_011F" msgid="6843415389823096647">"G សក់អក្សរយូ"</string>
+ <string name="spoken_accented_letter_0121" msgid="6205288708713306903">"G ចុចពីលើ"</string>
+ <string name="spoken_accented_letter_0123" msgid="2394277128105386261">"G ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_0125" msgid="6575866461277751345">"H សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_0127" msgid="1316971762214091641">"H ឆូត"</string>
+ <string name="spoken_accented_letter_0129" msgid="7824912405885325754">"I សក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_012B" msgid="6772690258769905270">"I សក់ឆូត"</string>
+ <string name="spoken_accented_letter_012D" msgid="2933871131556503448">"I សក់អក្សរយូ"</string>
+ <string name="spoken_accented_letter_012F" msgid="1340511254985181663">"I ជើងកណ្តៀវ"</string>
+ <string name="spoken_accented_letter_0131" msgid="5635600720566083969">"I អត់ចុចពីលើ"</string>
+ <string name="spoken_accented_letter_0133" msgid="7593704176516791941">"សញ្ញា IJ"</string>
+ <string name="spoken_accented_letter_0135" msgid="4521109674238248436">"J សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_0137" msgid="5886444641003852175">"K ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_0138" msgid="4200294389170924853">"អក្សរក្រា"</string>
+ <string name="spoken_accented_letter_013A" msgid="3558015385412543517">"L បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_013C" msgid="1853639924813858734">"L ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_013E" msgid="7489345561739421886">"L មានវណ្ណយុត្តិ"</string>
+ <string name="spoken_accented_letter_0140" msgid="7946718707268270589">"L ចុចកណ្តាល"</string>
+ <string name="spoken_accented_letter_0142" msgid="752931798111122240">"L ឆូត"</string>
+ <string name="spoken_accented_letter_0144" msgid="201843550323875352">"N បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_0146" msgid="3403847152606051818">"N ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_0148" msgid="9215300786722209338">"N សក់អក្សរវី"</string>
+ <string name="spoken_accented_letter_0149" msgid="3191850286630154063">"N មានសញ្ញាវណ្ណយុត្តិនៅខាងមុខ"</string>
+ <string name="spoken_accented_letter_014B" msgid="8503022408522837410">"សញ្ញាអ៊ីង"</string>
+ <string name="spoken_accented_letter_014D" msgid="4452323602550610641">"O សក់ឆូត"</string>
+ <string name="spoken_accented_letter_014F" msgid="2795957717094385336">"O សក់អក្សរយូ"</string>
+ <string name="spoken_accented_letter_0151" msgid="8013704745216410244">"O បន្តក់បញ្ឆិតស្តាំទ្វេ"</string>
+ <string name="spoken_accented_letter_0153" msgid="8410582495993285221">"សញ្ញា O និង E ជាប់គ្នា"</string>
+ <string name="spoken_accented_letter_0155" msgid="7601517174689798560">"R បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_0157" msgid="9071455715455643810">"R ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_0159" msgid="7726911392381543439">"R សក់អក្សរវី"</string>
+ <string name="spoken_accented_letter_015B" msgid="1854129531164494117">"S បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_015D" msgid="4743571603550582530">"S សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_015F" msgid="1519945638631588761">"S ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_0161" msgid="7493478552029144246">"S សក់អក្សរវី"</string>
+ <string name="spoken_accented_letter_0163" msgid="9103547637928833069">"T ស៊ីឌីឡា"</string>
+ <string name="spoken_accented_letter_0165" msgid="7306159398214872062">"T មានវណ្ណយុត្តិ"</string>
+ <string name="spoken_accented_letter_0167" msgid="5578767705098672443">"T ឆូត"</string>
+ <string name="spoken_accented_letter_0169" msgid="413046581387735371">"U សក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_016B" msgid="3209778874978859441">"U សក់ឆូត"</string>
+ <string name="spoken_accented_letter_016D" msgid="2983326533258602840">"U សក់អក្សរយូ"</string>
+ <string name="spoken_accented_letter_016F" msgid="4416532499516387231">"U រង្វង់ពីលើ"</string>
+ <string name="spoken_accented_letter_0171" msgid="3435171971353200807">"U បន្តក់បញ្ឆិតស្តាំទ្វេ"</string>
+ <string name="spoken_accented_letter_0173" msgid="4494154432483553480">"U ជើងកណ្តៀវ"</string>
+ <string name="spoken_accented_letter_0175" msgid="2154545579611918513">"W សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_0177" msgid="4034463827306904781">"Y សក់ព្រួញ"</string>
+ <string name="spoken_accented_letter_017A" msgid="3368292232292925369">"Z បន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_017C" msgid="2834484584505860430">"Z ចុចពីលើ"</string>
+ <string name="spoken_accented_letter_017E" msgid="1209240442434887098">"Z សក់អក្សរវី"</string>
+ <string name="spoken_accented_letter_017F" msgid="317501463253362415">"S វែង"</string>
+ <string name="spoken_accented_letter_01A1" msgid="630186564859044196">"O មានស្នែង"</string>
+ <string name="spoken_accented_letter_01B0" msgid="8544012177684640443">"U មានស្នែង"</string>
+ <string name="spoken_accented_letter_0219" msgid="1960371842020076066">"S មានក្បៀសខាងក្រោម"</string>
+ <string name="spoken_accented_letter_021B" msgid="1398418662032919032">"T មានក្បៀសខាងក្រោម"</string>
+ <string name="spoken_accented_letter_0259" msgid="2464085263158415898">"អក្សរអ៊ីបញ្ច្រាស"</string>
+ <string name="spoken_accented_letter_1EA1" msgid="688124877202887630">"A ចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EA3" msgid="327960130366386256">"A ទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EA5" msgid="637406363453769610">"A សក់ព្រួញ និងបន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_1EA7" msgid="1419591804181615409">"A សក់ព្រួញ និងបន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_1EA9" msgid="6068887382734896756">"A សក់ព្រួញ និងទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EAB" msgid="7236523151662538333">"A សក់ព្រួញ និងទឹករលក"</string>
+ <string name="spoken_accented_letter_1EAD" msgid="2363364864106332076">"A សក់ព្រួញ និងចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EAF" msgid="1576329511464272935">"A សក់អក្សរយូ និងបន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_1EB1" msgid="4634735072816076592">"A សក់អក្សរយូ និងបន្តប់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_1EB3" msgid="2325245849038771534">"A សក់អក្សរយូរ និងទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EB5" msgid="3720427596242746295">"A សក់អក្សរយូរ និងទឹករលក"</string>
+ <string name="spoken_accented_letter_1EB7" msgid="700415535653646695">"A សក់អក្សរយូ និងចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EB9" msgid="3901338692305890487">"E ចុចពីក្រោម"</string>
+ <string name="spoken_accented_letter_1EBB" msgid="4028688699415417302">"E ទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EBD" msgid="181253633045931897">"E សក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_1EBF" msgid="3309618845007944963">"E សក់ព្រួញ និងបន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_1EC1" msgid="8139046749226332542">"E សក់ព្រួញ និងបន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_1EC3" msgid="3239674223053133383">"E សក់ព្រួញ និងទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EC5" msgid="2216559244705714587">"E សក់ព្រួញ និងទឹករលក"</string>
+ <string name="spoken_accented_letter_1EC7" msgid="9012731468253986792">"E សក់ព្រួញ និងចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EC9" msgid="2901917620195717034">"I ទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1ECB" msgid="5470387489820034621">"I ចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1ECD" msgid="1340122876914839806">"O ចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1ECF" msgid="2326921263882559755">"O ទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1ED1" msgid="2885683296042774958">"O សក់ព្រួញ និងបន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_1ED3" msgid="6857664926477376178">"O សក់ព្រួញ និងបន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_1ED5" msgid="2015209467290624062">"O សក់ព្រួញ និងទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1ED7" msgid="7924481354960306389">"O សក់ព្រួញ និងទឹករលក"</string>
+ <string name="spoken_accented_letter_1ED9" msgid="7023315590332365554">"O សក់ព្រួញ និងចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EDB" msgid="2379438944917634496">"O មានស្នែង និងបន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_1EDD" msgid="8107077534204404085">"O មានស្នែង និងបន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_1EDF" msgid="1846880105528347966">"O មានស្នែង និងទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EE1" msgid="1520037313389776718">"O មានស្នែង និងសក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_1EE3" msgid="907964027171008963">"O មានស្នែង និងចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EE5" msgid="1522024630360038700">"U ចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EE7" msgid="7815412228302952637">"U ទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EE9" msgid="4219119671251485651">"U មានស្នែង និងបន្តក់បញ្ឆិតស្តាំ"</string>
+ <string name="spoken_accented_letter_1EEB" msgid="4086009841269002231">"U មានស្នែង និងបន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_1EED" msgid="3528151733528719847">"U មានស្នែង និងទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EEF" msgid="3508548229409072119">"U មានស្នែង និងសក់ទឹករលក"</string>
+ <string name="spoken_accented_letter_1EF1" msgid="1912816350401931115">"U មានស្នែង និងចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EF3" msgid="7211760439435946494">"Y បន្តក់បញ្ឆិតឆ្វេង"</string>
+ <string name="spoken_accented_letter_1EF5" msgid="8998864482764007384">"Y ចុចខាងក្រោម"</string>
+ <string name="spoken_accented_letter_1EF7" msgid="922043627252869200">"Y ទំពក់ពីលើ"</string>
+ <string name="spoken_accented_letter_1EF9" msgid="6213977100552260366">"Y សក់ទឹករលក"</string>
+ <string name="spoken_symbol_00A1" msgid="4281758332905123408">"សញ្ញាឧទានបញ្ច្រាស"</string>
+ <string name="spoken_symbol_00AB" msgid="4093069643313064892">"សញ្ញាសម្រង់ទ្វេចង្អុលមកឆ្វេង"</string>
+ <string name="spoken_symbol_00B7" msgid="2447718728927874920">"ចំណុចកណ្តាល"</string>
+ <string name="spoken_symbol_00B9" msgid="8026257165451461231">"ស្វ័យគុណមួយ"</string>
+ <string name="spoken_symbol_00BB" msgid="1102740075655373928">"សញ្ញាសម្រង់ទ្វេចង្អុលមកស្តាំ"</string>
+ <string name="spoken_symbol_00BF" msgid="6233794752573788098">"សញ្ញាសួរបញ្ច្រាស"</string>
+ <string name="spoken_symbol_2018" msgid="4886476295598930225">"សញ្ញាសម្រង់ទោលខាងឆ្វេង"</string>
+ <string name="spoken_symbol_2019" msgid="8892530161598134083">"សញ្ញាសម្រង់ទោលខាងស្តាំ"</string>
+ <string name="spoken_symbol_201A" msgid="2072987157683446644">"សញ្ញាសម្រង់ខាងក្រោមទោល"</string>
+ <string name="spoken_symbol_201C" msgid="4588048378803665427">"សញ្ញាសម្រង់ទ្វេខាងឆ្វេង"</string>
+ <string name="spoken_symbol_201D" msgid="1642776849495925895">"សញ្ញាសម្រង់ទ្វេខាងស្តាំ"</string>
+ <string name="spoken_symbol_2020" msgid="9084628638189344431">"ឈើឆ្កាង"</string>
+ <string name="spoken_symbol_2021" msgid="5081396468559426475">"ឈើឆ្កាងទ្វេ"</string>
+ <string name="spoken_symbol_2030" msgid="9068837172419431755">"សញ្ញាក្នុងមួយម៉ាយ៍"</string>
+ <string name="spoken_symbol_2032" msgid="3014506329156664396">"បន្តក់រង្វាស់"</string>
+ <string name="spoken_symbol_2033" msgid="1251022699713475088">"បន្តក់រង្វាស់ទ្វេ"</string>
+ <string name="spoken_symbol_2039" msgid="6989616457213775957">"សញ្ញាសម្រង់ទោលចង្អុលមកឆ្វេង"</string>
+ <string name="spoken_symbol_203A" msgid="31245095449823701">"សញ្ញាសម្រង់ទោលចង្អុលមកស្តាំ"</string>
+ <string name="spoken_symbol_2074" msgid="2116717717093306894">"ស្វ័យគុណបួន"</string>
+ <string name="spoken_symbol_207F" msgid="1706731172134246659">"ស្វ័យគុណ n"</string>
+ <string name="spoken_symbol_20B1" msgid="2159994270622444689">"សញ្ញាប៉េសូ"</string>
+ <string name="spoken_symbol_2105" msgid="7289404939366976829">"សញ្ញា Care of"</string>
+ <string name="spoken_symbol_2192" msgid="827804523596125414">"ព្រួញទៅស្តាំ"</string>
+ <string name="spoken_symbol_2193" msgid="2659541693445985717">"ព្រួញចុះក្រោម"</string>
+ <string name="spoken_symbol_2205" msgid="4457188084269117343">"សំណុំទទេ"</string>
+ <string name="spoken_symbol_2206" msgid="4856786565708380687">"បន្ថែម"</string>
+ <string name="spoken_symbol_2264" msgid="5092061257745123554">"តូចជាង ឬស្មើ"</string>
+ <string name="spoken_symbol_2265" msgid="1907966479878036357">"ធំជាង ឬស្មើ"</string>
+ <string name="spoken_symbol_2605" msgid="5202920479405857753">"ផ្កាយខ្មៅ"</string>
</resources>
diff --git a/java/res/values-ur-rPK/strings.xml b/java/res/values-ur-rPK/strings.xml
index 2aeac89cc..be1181298 100644
--- a/java/res/values-ur-rPK/strings.xml
+++ b/java/res/values-ur-rPK/strings.xml
@@ -71,7 +71,7 @@
<string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"ناگوار الفاظ مسدود کریں"</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_summary" msgid="5625751551134658006">"اسپیس بار اور رموز اوقاف غلط ٹائپ کردہ الفاظ کی اصلاح کرتے ہیں"</string>
<string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"آف"</string>
<string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"معتدل"</string>
<string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"پر جوش"</string>
diff --git a/java/res/values-uz-rUZ/strings.xml b/java/res/values-uz-rUZ/strings.xml
index 4303152b2..87e2831d7 100644
--- a/java/res/values-uz-rUZ/strings.xml
+++ b/java/res/values-uz-rUZ/strings.xml
@@ -22,24 +22,24 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="english_ime_input_options" msgid="3909945612939668554">"Sozlamalar"</string>
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktlarni qidirish"</string>
- <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Imlo tekshirgich kontaktlaringizdagi qaydlardan foydalanadi"</string>
+ <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Imloni tekshirishda kontaktlar ro‘yxatiga murojaat qilish"</string>
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Tugma bosilganda tebranish"</string>
<string name="sound_on_keypress" msgid="6093592297198243644">"Tugma bosilganda ovoz"</string>
- <string name="popup_on_keypress" msgid="123894815723512944">"Tugma bosilganda qalqib chiqish"</string>
- <string name="settings_screen_preferences" msgid="2696713156722014624">"Shaxsiy sozlamalar"</string>
+ <string name="popup_on_keypress" msgid="123894815723512944">"Tugma bosilganda qalqish"</string>
+ <string name="settings_screen_preferences" msgid="2696713156722014624">"Sozlamalar"</string>
<string name="settings_screen_accounts" msgid="2786418968536696670">"Hisoblar va maxfiylik"</string>
- <string name="settings_screen_appearance" msgid="7358046399111611615">"Tashqi ko‘rinishi va joylashuvi"</string>
- <string name="settings_screen_gesture" msgid="8826372746901183556">"Imo-ishoralar bilan yozish"</string>
+ <string name="settings_screen_appearance" msgid="7358046399111611615">"Ko‘rinish va sxema"</string>
+ <string name="settings_screen_gesture" msgid="8826372746901183556">"Qo‘l uzmasdan yozish"</string>
<string name="settings_screen_correction" msgid="1616818407747682955">"Matnni tuzatish"</string>
<string name="settings_screen_advanced" msgid="7472408607625972994">"Qo‘shimcha"</string>
<string name="settings_screen_theme" msgid="2137262503543943871">"Mavzu"</string>
<string name="enable_split_keyboard" msgid="4177264923999493614">"Ikkiga ajratiladigan klaviaturani yoqish"</string>
- <string name="cloud_sync_title" msgid="8579271074443847055">"Google klaviaturasini sinx-sh"</string>
+ <string name="cloud_sync_title" msgid="8579271074443847055">"Klaviaturani sinxronlash"</string>
<string name="cloud_sync_summary" msgid="7684887161145650857">"Sinxronlash yoqildi"</string>
<string name="cloud_sync_summary_disabled" msgid="4553338970382825796">"Shaxsiy lug‘atingizni qurilmalar bo‘ylab sinxronlang"</string>
<string name="sync_now_title" msgid="3088838136743277721">"Sinxronlash"</string>
<string name="clear_sync_data_title" msgid="8582001557037069154">"Bulutdagi ma’lumotlarni o‘chirish"</string>
- <string name="clear_sync_data_summary" msgid="993477139012576584">"Google xizmatlaridagi sinxronlangan ma’lumotlaringizni o‘chirib tashlaydi"</string>
+ <string name="clear_sync_data_summary" msgid="993477139012576584">"Sinxronlangan ma’lumotlarni Google serveridan o‘chirib tashlash"</string>
<string name="clear_sync_data_confirmation" msgid="2811931135574727678">"Sinxronlangan ma’lumotlaringiz o‘chib ketadi. Davom etsinmi?"</string>
<string name="clear_sync_data_ok" msgid="613104067705915132">"O‘chirish"</string>
<string name="cloud_sync_cancel" msgid="5877481252150919037">"Bekor qilish"</string>
@@ -50,8 +50,8 @@
<string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tilni o‘zgartirish tugmasi matn kiritish usulini ham o‘zgartiradi"</string>
<string name="show_language_switch_key" msgid="5915478828318774384">"Tilni o‘zgartirish tugmasi"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Bir nechta matn kiritish tili mavjud bo‘lganda ko‘rsatilsin"</string>
- <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Yopilish uchun to‘xtalish"</string>
- <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"To‘xtalishlarsiz"</string>
+ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Yopilish vaqti"</string>
+ <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Kechikishsiz"</string>
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standart"</string>
<string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
<string name="settings_system_default" msgid="6268225104743331821">"Tizim standarti"</string>
@@ -70,15 +70,15 @@
<string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Matn kiritishda so‘z variantlari taklif qilinsin"</string>
<string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Haqorat so‘zlarini bloklash"</string>
<string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Haqoratomuz so‘zlar taklif qilinmasin"</string>
- <string name="auto_correction" msgid="7630720885194996950">"Avtomatik to‘g‘rilash"</string>
- <string name="auto_correction_summary" msgid="5625751551134658006">"Bo‘sh joy yoki tinish belgisi xato yoz-n so‘z-ni avto. to‘g‘ri-di"</string>
+ <string name="auto_correction" msgid="7630720885194996950">"Avtomatik tuzatish"</string>
+ <string name="auto_correction_summary" msgid="5625751551134658006">"Tinish belgisi kiritilsa yoki bo‘sh joy qoldirilsa, xato so‘z avtomatik tuzatiladi"</string>
<string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"O‘chirish"</string>
<string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"O‘rtacha"</string>
<string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Juda faol"</string>
<string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Juda faol"</string>
<string name="bigram_prediction" msgid="1084449187723948550">"Keyingi so‘zni taklif qilish"</string>
- <string name="bigram_prediction_summary" msgid="3896362682751109677">"So‘zlarni taklif qilishda avval yozilgan so‘zga asoslanish"</string>
- <string name="gesture_input" msgid="826951152254563827">"Imo-ishoralar bilan yozish"</string>
+ <string name="bigram_prediction_summary" msgid="3896362682751109677">"Avvalgi so‘zlar asosida keyingi so‘zni taklif qilish"</string>
+ <string name="gesture_input" msgid="826951152254563827">"Qo‘l uzmasdan yozish"</string>
<string name="gesture_input_summary" msgid="9180350639305731231">"So‘zlarni barmog‘ingizni klaviaturadan uzmasdan yozing"</string>
<string name="gesture_preview_trail" msgid="3802333369335722221">"Barmoq yo‘lini chizish"</string>
<string name="gesture_floating_preview_text" msgid="4443240334739381053">"Takliflarni ko‘rsatish"</string>
@@ -123,13 +123,13 @@
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Lotin (shaxsiy kompyuter)"</string>
<string name="subtype_emoji" msgid="7483586578074549196">"Kulgichlar"</string>
<string name="keyboard_theme" msgid="4909551808526178852">"Klaviatura mavzusi"</string>
- <string name="custom_input_styles_title" msgid="8429952441821251512">"Moslashtirilgan usullar"</string>
- <string name="add_style" msgid="6163126614514489951">"Uslub qo‘shish"</string>
+ <string name="custom_input_styles_title" msgid="8429952441821251512">"Maxsus usullar"</string>
+ <string name="add_style" msgid="6163126614514489951">"Usul qo‘shish"</string>
<string name="add" msgid="8299699805688017798">"Qo‘shish"</string>
<string name="remove" msgid="4486081658752944606">"O‘chirish"</string>
<string name="save" msgid="7646738597196767214">"Saqlash"</string>
<string name="subtype_locale" msgid="8576443440738143764">"Til"</string>
- <string name="keyboard_layout_set" msgid="4309233698194565609">"Joylashuv"</string>
+ <string name="keyboard_layout_set" msgid="4309233698194565609">"Sxema"</string>
<string name="custom_input_style_note_message" msgid="8826731320846363423">"Moslashtirilgan matn kiritish usulini yoqish lozim. Uni hozir yoqmoqchimisiz?"</string>
<string name="enable" msgid="5031294444630523247">"Yoqish"</string>
<string name="not_now" msgid="6172462888202790482">"Hozir emas"</string>
@@ -141,7 +141,7 @@
<string name="prefs_enable_emoji_alt_physical_key_summary" msgid="5259484820941627827">"Tashqi klaviaturadagi Alt tugmasi kulgichlar ro‘yxatini ko‘rsatadi"</string>
<string name="button_default" msgid="3988017840431881491">"Standart"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ilovasiga xush kelibsiz!"</string>
- <string name="setup_welcome_additional_description" msgid="8150252008545768953">"Imo-ishoralar bilan yozish"</string>
+ <string name="setup_welcome_additional_description" msgid="8150252008545768953">"qo‘l uzmasdan yozish"</string>
<string name="setup_start_action" msgid="8936036460897347708">"Boshladik"</string>
<string name="setup_next_action" msgid="371821437915144603">"Keyingi qadam"</string>
<string name="setup_steps_title" msgid="6400373034871816182">"Sozlash: <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
@@ -189,7 +189,7 @@
<string name="dict_available_notification_title" msgid="4583842811218581658">"Lug‘at mavjud: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string>
<string name="dict_available_notification_description" msgid="1075194169443163487">"Ko‘rib chiqish va yuklab olish uchun bosing"</string>
<string name="toast_downloading_suggestions" msgid="6128155879830851739">"Yuklab olinmoqda: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> tili uchun so‘zlarni taklif qilish xususiyati tez orada tayyor bo‘ladi."</string>
- <string name="version_text" msgid="2715354215568469385">"<xliff:g id="VERSION_NUMBER">%1$s</xliff:g> versiyasi"</string>
+ <string name="version_text" msgid="2715354215568469385">"<xliff:g id="VERSION_NUMBER">%1$s</xliff:g> versiya"</string>
<string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Qo‘shish"</string>
<string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Lug‘atga qo‘shish"</string>
<string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"Ibora"</string>
@@ -200,7 +200,7 @@
<string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Tezkor tugmalar:"</string>
<string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Til:"</string>
<string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"So‘zni kiriting"</string>
- <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Ibora uchun yorliq (ixtiyoriy)"</string>
+ <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Tezkor tugma (ixtiyoriy)"</string>
<string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"So‘zni tahrirlash"</string>
<string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Tahrirlash"</string>
<string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"O‘chirish"</string>
diff --git a/java/res/values/donottranslate-config-important-notice.xml b/java/res/values/donottranslate-config-important-notice.xml
deleted file mode 100644
index 7c6527c28..000000000
--- a/java/res/values/donottranslate-config-important-notice.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<resources>
- <!-- The array of the text of the important notices displayed on the suggestion strip. -->
- <string-array name="important_notice_title_array" translatable="false">
- <!-- empty -->
- </string-array>
- <!-- The array of the contents of the important notices. -->
- <string-array name="important_notice_contents_array" translatable="false">
- <!-- empty -->
- </string-array>
-</resources>
diff --git a/java/res/values/important_notice_strings.xml b/java/res/values/important_notice_strings.xml
new file mode 100644
index 000000000..b1f3fc137
--- /dev/null
+++ b/java/res/values/important_notice_strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+
+<resources>
+ <!-- The text shown on the suggestion bar to request the contacts permission info. -->
+ <string name="important_notice_suggest_contact_names">Suggest contact names? Touch for info.</string>
+</resources> \ No newline at end of file
diff --git a/java/res/values/strings-config-important-notice.xml b/java/res/values/strings-config-important-notice.xml
index aa3cd109c..de8d6fc5e 100644
--- a/java/res/values/strings-config-important-notice.xml
+++ b/java/res/values/strings-config-important-notice.xml
@@ -19,7 +19,6 @@
-->
<resources>
- <integer name="config_important_notice_version">0</integer>
<!-- Description for option enabling the use by the keyboards of sent/received messages, e-mail and typing history to improve suggestion accuracy [CHAR LIMIT=68] -->
<string name="use_personalized_dicts_summary">Learn from your communications and typed data to improve suggestions</string>
</resources>
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index adab136c5..1fe0a4cce 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -27,7 +27,6 @@ import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
-import com.android.inputmethod.latin.common.FileUtils;
import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
import com.android.inputmethod.dictionarypack.MD5Calculator;
import com.android.inputmethod.dictionarypack.UpdateHandler;
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 15a14e5af..dbd639fe8 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import android.Manifest;
import android.content.Context;
import android.net.Uri;
import android.provider.ContactsContract;
@@ -25,6 +26,7 @@ import android.util.Log;
import com.android.inputmethod.annotations.ExternallyReferenced;
import com.android.inputmethod.latin.ContactsManager.ContactsChangedListener;
import com.android.inputmethod.latin.common.StringUtils;
+import com.android.inputmethod.latin.permissions.PermissionsUtil;
import com.android.inputmethod.latin.personalization.AccountUtils;
import java.io.File;
@@ -108,6 +110,11 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
* Loads data within content providers to the dictionary.
*/
private void loadDictionaryForUriLocked(final Uri uri) {
+ if (!PermissionsUtil.checkAllPermissionsGranted(
+ mContext, Manifest.permission.READ_CONTACTS)) {
+ Log.i(TAG, "No permission to read contacts. Not loading the Dictionary.");
+ }
+
final ArrayList<String> validNames = mContactsManager.getValidNames(uri);
for (final String name : validNames) {
addNameLocked(name);
diff --git a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
index 872e4c8fc..6103a8296 100644
--- a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
+++ b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import android.Manifest;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -25,6 +26,7 @@ import android.util.Log;
import com.android.inputmethod.latin.ContactsManager.ContactsChangedListener;
import com.android.inputmethod.latin.define.DebugFlags;
+import com.android.inputmethod.latin.permissions.PermissionsUtil;
import com.android.inputmethod.latin.utils.ExecutorUtils;
import java.util.ArrayList;
@@ -35,10 +37,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
public class ContactsContentObserver implements Runnable {
private static final String TAG = "ContactsContentObserver";
- private static AtomicBoolean sRunning = new AtomicBoolean(false);
private final Context mContext;
private final ContactsManager mManager;
+ private final AtomicBoolean mRunning = new AtomicBoolean(false);
private ContentObserver mContentObserver;
private ContactsChangedListener mContactsChangedListener;
@@ -49,6 +51,13 @@ public class ContactsContentObserver implements Runnable {
}
public void registerObserver(final ContactsChangedListener listener) {
+ if (!PermissionsUtil.checkAllPermissionsGranted(
+ mContext, Manifest.permission.READ_CONTACTS)) {
+ Log.i(TAG, "No permission to read contacts. Not registering the observer.");
+ // do nothing if we do not have the permission to read contacts.
+ return;
+ }
+
if (DebugFlags.DEBUG_ENABLED) {
Log.d(TAG, "registerObserver()");
}
@@ -66,7 +75,14 @@ public class ContactsContentObserver implements Runnable {
@Override
public void run() {
- if (!sRunning.compareAndSet(false /* expect */, true /* update */)) {
+ if (!PermissionsUtil.checkAllPermissionsGranted(
+ mContext, Manifest.permission.READ_CONTACTS)) {
+ Log.i(TAG, "No permission to read contacts. Not updating the contacts.");
+ unregister();
+ return;
+ }
+
+ if (!mRunning.compareAndSet(false /* expect */, true /* update */)) {
if (DebugFlags.DEBUG_ENABLED) {
Log.d(TAG, "run() : Already running. Don't waste time checking again.");
}
@@ -78,10 +94,16 @@ public class ContactsContentObserver implements Runnable {
}
mContactsChangedListener.onContactsChange();
}
- sRunning.set(false);
+ mRunning.set(false);
}
boolean haveContentsChanged() {
+ if (!PermissionsUtil.checkAllPermissionsGranted(
+ mContext, Manifest.permission.READ_CONTACTS)) {
+ Log.i(TAG, "No permission to read contacts. Marking contacts as not changed.");
+ return false;
+ }
+
final long startTime = SystemClock.uptimeMillis();
final int contactCount = mManager.getContactCount();
if (contactCount > ContactsDictionaryConstants.MAX_CONTACTS_PROVIDER_QUERY_LIMIT) {
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
index c7115c9d9..b435de867 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import android.Manifest;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
@@ -28,6 +29,7 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.common.ComposedData;
import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.StringUtils;
+import com.android.inputmethod.latin.permissions.PermissionsUtil;
import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.utils.ExecutorUtils;
@@ -287,7 +289,11 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
// TODO: Make subDictTypesToUse configurable by resource or a static final list.
final HashSet<String> subDictTypesToUse = new HashSet<>();
subDictTypesToUse.add(Dictionary.TYPE_USER);
- if (useContactsDict) {
+
+ // Do not use contacts dictionary if we do not have permissions to read contacts.
+ final boolean contactsPermissionGranted = PermissionsUtil.checkAllPermissionsGranted(
+ context, Manifest.permission.READ_CONTACTS);
+ if (useContactsDict && contactsPermissionGranted) {
subDictTypesToUse.add(Dictionary.TYPE_CONTACTS);
}
if (usePersonalizedDicts) {
diff --git a/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java
deleted file mode 100644
index 567087c81..000000000
--- a/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.latin;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-
-import com.android.inputmethod.latin.utils.DialogUtils;
-import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
-
-/**
- * The dialog box that shows the important notice contents.
- */
-public final class ImportantNoticeDialog extends AlertDialog implements OnClickListener {
- public interface ImportantNoticeDialogListener {
- public void onUserAcknowledgmentOfImportantNoticeDialog(final int nextVersion);
- public void onClickSettingsOfImportantNoticeDialog(final int nextVersion);
- }
-
- private final ImportantNoticeDialogListener mListener;
- private final int mNextImportantNoticeVersion;
-
- public ImportantNoticeDialog(
- final Context context, final ImportantNoticeDialogListener listener) {
- super(DialogUtils.getPlatformDialogThemeContext(context));
- mListener = listener;
- mNextImportantNoticeVersion = ImportantNoticeUtils.getNextImportantNoticeVersion(context);
- setMessage(ImportantNoticeUtils.getNextImportantNoticeContents(context));
- // Create buttons and set listeners.
- setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), this);
- if (shouldHaveSettingsButton()) {
- setButton(BUTTON_NEGATIVE, context.getString(R.string.go_to_settings), this);
- }
- // This dialog is cancelable by pressing back key. See {@link #onBackPress()}.
- setCancelable(true /* cancelable */);
- setCanceledOnTouchOutside(false /* cancelable */);
- }
-
- private boolean shouldHaveSettingsButton() {
- return mNextImportantNoticeVersion
- == ImportantNoticeUtils.VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS;
- }
-
- private void userAcknowledged() {
- ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext());
- mListener.onUserAcknowledgmentOfImportantNoticeDialog(mNextImportantNoticeVersion);
- }
-
- @Override
- public void onClick(final DialogInterface dialog, final int which) {
- if (shouldHaveSettingsButton() && which == BUTTON_NEGATIVE) {
- mListener.onClickSettingsOfImportantNoticeDialog(mNextImportantNoticeVersion);
- }
- userAcknowledged();
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- userAcknowledged();
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 089670ebf..1f2b6f25d 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -20,6 +20,7 @@ import static com.android.inputmethod.latin.common.Constants.ImeOption.FORCE_ASC
import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
+import android.Manifest.permission;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -73,6 +74,7 @@ import com.android.inputmethod.latin.common.InputPointers;
import com.android.inputmethod.latin.define.DebugFlags;
import com.android.inputmethod.latin.define.ProductionFlags;
import com.android.inputmethod.latin.inputlogic.InputLogic;
+import com.android.inputmethod.latin.permissions.PermissionsManager;
import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.settings.SettingsActivity;
@@ -106,7 +108,7 @@ import javax.annotation.Nonnull;
public class LatinIME extends InputMethodService implements KeyboardActionListener,
SuggestionStripView.Listener, SuggestionStripViewAccessor,
DictionaryFacilitator.DictionaryInitializationListener,
- ImportantNoticeDialog.ImportantNoticeDialogListener {
+ PermissionsManager.PermissionsResultCallback {
static final String TAG = LatinIME.class.getSimpleName();
private static final boolean TRACE = false;
@@ -1251,18 +1253,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// pressed.
@Override
public void showImportantNoticeContents() {
- showOptionDialog(new ImportantNoticeDialog(this /* context */, this /* listener */));
+ PermissionsManager.get(this).requestPermissions(
+ this /* PermissionsResultCallback */,
+ null /* activity */, permission.READ_CONTACTS);
}
- // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener}
@Override
- public void onClickSettingsOfImportantNoticeDialog(final int nextVersion) {
- launchSettings(SettingsActivity.EXTRA_ENTRY_VALUE_NOTICE_DIALOG);
- }
-
- // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener}
- @Override
- public void onUserAcknowledgmentOfImportantNoticeDialog(final int nextVersion) {
+ public void onRequestPermissionsResult(boolean allGranted) {
+ ImportantNoticeUtils.updateContactsNoticeShown(this /* context */);
setNeutralSuggestionStrip();
}
diff --git a/java/src/com/android/inputmethod/latin/permissions/PermissionsActivity.java b/java/src/com/android/inputmethod/latin/permissions/PermissionsActivity.java
new file mode 100644
index 000000000..bdd63fa00
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/permissions/PermissionsActivity.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 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.latin.permissions;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+
+/**
+ * An activity to help request permissions. It's used when no other activity is available, e.g. in
+ * InputMethodService. This activity assumes that all permissions are not granted yet.
+ */
+public final class PermissionsActivity
+ extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback {
+
+ /**
+ * Key to retrieve requested permissions from the intent.
+ */
+ public static final String EXTRA_PERMISSION_REQUESTED_PERMISSIONS = "requested_permissions";
+
+ /**
+ * Key to retrieve request code from the intent.
+ */
+ public static final String EXTRA_PERMISSION_REQUEST_CODE = "request_code";
+
+ private static final int INVALID_REQUEST_CODE = -1;
+
+ private int mPendingRequestCode = INVALID_REQUEST_CODE;
+
+ /**
+ * Starts a PermissionsActivity and checks/requests supplied permissions.
+ */
+ public static void run(
+ @NonNull Context context, int requestCode, @NonNull String... permissionStrings) {
+ Intent intent = new Intent(context.getApplicationContext(), PermissionsActivity.class);
+ intent.putExtra(EXTRA_PERMISSION_REQUESTED_PERMISSIONS, permissionStrings);
+ intent.putExtra(EXTRA_PERMISSION_REQUEST_CODE, requestCode);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ context.startActivity(intent);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mPendingRequestCode = (savedInstanceState != null)
+ ? savedInstanceState.getInt(EXTRA_PERMISSION_REQUEST_CODE, INVALID_REQUEST_CODE)
+ : INVALID_REQUEST_CODE;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(EXTRA_PERMISSION_REQUEST_CODE, mPendingRequestCode);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // Only do request when there is no pending request to avoid duplicated requests.
+ if (mPendingRequestCode == INVALID_REQUEST_CODE) {
+ final Bundle extras = getIntent().getExtras();
+ final String[] permissionsToRequest =
+ extras.getStringArray(EXTRA_PERMISSION_REQUESTED_PERMISSIONS);
+ mPendingRequestCode = extras.getInt(EXTRA_PERMISSION_REQUEST_CODE);
+ // Assuming that all supplied permissions are not granted yet, so that we don't need to
+ // check them again.
+ PermissionsUtil.requestPermissions(this, mPendingRequestCode, permissionsToRequest);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ mPendingRequestCode = INVALID_REQUEST_CODE;
+ PermissionsManager.get(this).onRequestPermissionsResult(
+ requestCode, permissions, grantResults);
+ finish();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/permissions/PermissionsManager.java b/java/src/com/android/inputmethod/latin/permissions/PermissionsManager.java
new file mode 100644
index 000000000..08c623ab5
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/permissions/PermissionsManager.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 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.latin.permissions;
+
+import android.app.Activity;
+import android.content.Context;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Manager to perform permission related tasks. Always call on the UI thread.
+ */
+public class PermissionsManager {
+
+ public interface PermissionsResultCallback {
+ void onRequestPermissionsResult(boolean allGranted);
+ }
+
+ private int mRequestCodeId;
+
+ private final Context mContext;
+ private final Map<Integer, PermissionsResultCallback> mRequestIdToCallback = new HashMap<>();
+
+ private static PermissionsManager sInstance;
+
+ public PermissionsManager(Context context) {
+ mContext = context;
+ }
+
+ @Nonnull
+ public static synchronized PermissionsManager get(@Nonnull Context context) {
+ if (sInstance == null) {
+ sInstance = new PermissionsManager(context);
+ }
+ return sInstance;
+ }
+
+ private synchronized int getNextRequestId() {
+ return ++mRequestCodeId;
+ }
+
+
+ public synchronized void requestPermissions(@Nonnull PermissionsResultCallback callback,
+ @Nullable Activity activity,
+ String... permissionsToRequest) {
+ List<String> deniedPermissions = PermissionsUtil.getDeniedPermissions(
+ mContext, permissionsToRequest);
+ if (deniedPermissions.isEmpty()) {
+ return;
+ }
+ // otherwise request the permissions.
+ int requestId = getNextRequestId();
+ String[] permissionsArray = deniedPermissions.toArray(
+ new String[deniedPermissions.size()]);
+
+ mRequestIdToCallback.put(requestId, callback);
+ if (activity != null) {
+ PermissionsUtil.requestPermissions(activity, requestId, permissionsArray);
+ } else {
+ PermissionsActivity.run(mContext, requestId, permissionsArray);
+ }
+ }
+
+ public synchronized void onRequestPermissionsResult(
+ int requestCode, String[] permissions, int[] grantResults) {
+ PermissionsResultCallback permissionsResultCallback = mRequestIdToCallback.get(requestCode);
+ mRequestIdToCallback.remove(requestCode);
+
+ boolean allGranted = PermissionsUtil.allGranted(grantResults);
+ permissionsResultCallback.onRequestPermissionsResult(allGranted);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/permissions/PermissionsUtil.java b/java/src/com/android/inputmethod/latin/permissions/PermissionsUtil.java
new file mode 100644
index 000000000..747f64f24
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/permissions/PermissionsUtil.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.latin.permissions;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class for permissions.
+ */
+public class PermissionsUtil {
+
+ /**
+ * Returns the list of permissions not granted from the given list of permissions.
+ * @param context Context
+ * @param permissions list of permissions to check.
+ * @return the list of permissions that do not have permission to use.
+ */
+ public static List<String> getDeniedPermissions(Context context,
+ String... permissions) {
+ final List<String> deniedPermissions = new ArrayList<>();
+ for (String permission : permissions) {
+ if (ContextCompat.checkSelfPermission(context, permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ deniedPermissions.add(permission);
+ }
+ }
+ return deniedPermissions;
+ }
+
+ /**
+ * Uses the given activity and requests the user for permissions.
+ * @param activity activity to use.
+ * @param requestCode request code/id to use.
+ * @param permissions String array of permissions that needs to be requested.
+ */
+ public static void requestPermissions(Activity activity, int requestCode,
+ String[] permissions) {
+ ActivityCompat.requestPermissions(activity, permissions, requestCode);
+ }
+
+ /**
+ * Checks if all the permissions are granted.
+ */
+ public static boolean allGranted(@NonNull int[] grantResults) {
+ for (int result : grantResults) {
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Queries if al the permissions are granted for the given permission strings.
+ */
+ public static boolean checkAllPermissionsGranted(Context context, String... permissions) {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ // For all pre-M devices, we should have all the premissions granted on install.
+ return true;
+ }
+
+ for (String permission : permissions) {
+ if (ContextCompat.checkSelfPermission(context, permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
index cb2097826..b39e6b477 100644
--- a/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.latin.settings;
import static com.android.inputmethod.latin.settings.LocalSettingsConstants.PREF_ACCOUNT_NAME;
import static com.android.inputmethod.latin.settings.LocalSettingsConstants.PREF_ENABLE_CLOUD_SYNC;
+import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -40,6 +41,7 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.accounts.AccountStateChangedListener;
import com.android.inputmethod.latin.accounts.LoginAccountUtils;
import com.android.inputmethod.latin.define.ProductionFlags;
+import com.android.inputmethod.latin.permissions.PermissionsUtil;
import com.android.inputmethod.latin.utils.ManagedProfileUtils;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -254,11 +256,14 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
if (!ProductionFlags.ENABLE_USER_HISTORY_DICTIONARY_SYNC) {
return;
}
- final String[] accountsForLogin =
- LoginAccountUtils.getAccountsForLogin(getActivity());
- final String currentAccount = getSignedInAccountName();
+ boolean hasAccountsPermission = PermissionsUtil.checkAllPermissionsGranted(
+ getActivity(), Manifest.permission.READ_CONTACTS);
- if (!mManagedProfileBeingDetected.get() &&
+ final String[] accountsForLogin = hasAccountsPermission ?
+ LoginAccountUtils.getAccountsForLogin(getActivity()) : new String[0];
+ final String currentAccount = hasAccountsPermission ? getSignedInAccountName() : null;
+
+ if (hasAccountsPermission && !mManagedProfileBeingDetected.get() &&
!mHasManagedProfile.get() && accountsForLogin.length > 0) {
// Sync can be used by user; enable all preferences.
enableSyncPreferences(accountsForLogin, currentAccount);
@@ -266,26 +271,35 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
// Sync cannot be used by user; disable all preferences.
disableSyncPreferences();
}
- refreshSyncSettingsMessaging(mManagedProfileBeingDetected.get(),
+ refreshSyncSettingsMessaging(hasAccountsPermission, mManagedProfileBeingDetected.get(),
mHasManagedProfile.get(), accountsForLogin.length > 0,
currentAccount);
}
/**
+ * @param hasAccountsPermission whether the app has the permission to read accounts.
* @param managedProfileBeingDetected whether we are in process of determining work profile.
* @param hasManagedProfile whether the device has work profile.
* @param hasAccountsForLogin whether the device has enough accounts for login.
* @param currentAccount the account currently selected in the application.
*/
- private void refreshSyncSettingsMessaging(boolean managedProfileBeingDetected,
- boolean hasManagedProfile, boolean hasAccountsForLogin, String currentAccount) {
+ private void refreshSyncSettingsMessaging(boolean hasAccountsPermission,
+ boolean managedProfileBeingDetected,
+ boolean hasManagedProfile,
+ boolean hasAccountsForLogin,
+ String currentAccount) {
if (!ProductionFlags.ENABLE_USER_HISTORY_DICTIONARY_SYNC) {
return;
}
- // If we are determining eligiblity, we show empty summaries.
- // Once we have some deterministic result, we set summaries based on different results.
- if (managedProfileBeingDetected) {
+ if (!hasAccountsPermission) {
+ mEnableSyncPreference.setChecked(false);
+ mEnableSyncPreference.setSummary(getString(R.string.cloud_sync_summary_disabled));
+ mAccountSwitcher.setSummary("");
+ return;
+ } else if (managedProfileBeingDetected) {
+ // If we are determining eligiblity, we show empty summaries.
+ // Once we have some deterministic result, we set summaries based on different results.
mEnableSyncPreference.setSummary("");
mAccountSwitcher.setSummary("");
} else if (hasManagedProfile) {
@@ -462,7 +476,7 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog,
- final int which) {
+ final int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
final Context context = getActivity();
final String[] accountsForLogin =
@@ -473,9 +487,9 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
.show();
}
}
- })
- .setNegativeButton(R.string.cloud_sync_cancel, null)
- .create();
+ })
+ .setNegativeButton(R.string.cloud_sync_cancel, null)
+ .create();
optInDialog.setOnShowListener(this);
optInDialog.show();
}
diff --git a/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
index d28e703fe..dfe899ece 100644
--- a/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
@@ -16,17 +16,23 @@
package com.android.inputmethod.latin.settings;
+import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.preference.Preference;
+import android.preference.SwitchPreference;
+import android.text.TextUtils;
import com.android.inputmethod.dictionarypack.DictionarySettingsActivity;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.permissions.PermissionsManager;
+import com.android.inputmethod.latin.permissions.PermissionsUtil;
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
@@ -45,12 +51,17 @@ import java.util.TreeSet;
* - Suggest Contact names
* - Next-word suggestions
*/
-public final class CorrectionSettingsFragment extends SubScreenFragment {
+public final class CorrectionSettingsFragment extends SubScreenFragment
+ implements SharedPreferences.OnSharedPreferenceChangeListener,
+ PermissionsManager.PermissionsResultCallback {
+
private static final boolean DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS = false;
private static final boolean USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS =
DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS
|| Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2;
+ private SwitchPreference mUseContactsPreference;
+
@Override
public void onCreate(final Bundle icicle) {
super.onCreate(icicle);
@@ -76,6 +87,9 @@ public final class CorrectionSettingsFragment extends SubScreenFragment {
if (ri == null) {
overwriteUserDictionaryPreference(editPersonalDictionary);
}
+
+ mUseContactsPreference = (SwitchPreference) findPreference(Settings.PREF_KEY_USE_CONTACTS_DICT);
+ turnOffUseContactsIfNoPermission();
}
private void overwriteUserDictionaryPreference(final Preference userDictionaryPreference) {
@@ -101,4 +115,38 @@ public final class CorrectionSettingsFragment extends SubScreenFragment {
userDictionaryPreference.setFragment(UserDictionaryList.class.getName());
}
}
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
+ if (!TextUtils.equals(key, Settings.PREF_KEY_USE_CONTACTS_DICT)) {
+ return;
+ }
+ if (!sharedPreferences.getBoolean(key, false)) {
+ // don't care if the preference is turned off.
+ return;
+ }
+
+ // Check for permissions.
+ if (PermissionsUtil.checkAllPermissionsGranted(
+ getActivity() /* context */, Manifest.permission.READ_CONTACTS)) {
+ return; // all permissions granted, no need to request permissions.
+ }
+
+ PermissionsManager.get(getActivity() /* context */).requestPermissions(
+ this /* PermissionsResultCallback */,
+ getActivity() /* activity */,
+ Manifest.permission.READ_CONTACTS);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(boolean allGranted) {
+ turnOffUseContactsIfNoPermission();
+ }
+
+ private void turnOffUseContactsIfNoPermission() {
+ if (!PermissionsUtil.checkAllPermissionsGranted(
+ getActivity(), Manifest.permission.READ_CONTACTS)) {
+ mUseContactsPreference.setChecked(false);
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
index 9975277e4..a7d157a6b 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin.settings;
+import com.android.inputmethod.latin.permissions.PermissionsManager;
import com.android.inputmethod.latin.utils.FragmentUtils;
import com.android.inputmethod.latin.utils.StatsUtils;
import com.android.inputmethod.latin.utils.StatsUtilsManager;
@@ -24,9 +25,11 @@ import android.app.ActionBar;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceActivity;
+import android.support.v4.app.ActivityCompat;
import android.view.MenuItem;
-public final class SettingsActivity extends PreferenceActivity {
+public final class SettingsActivity extends PreferenceActivity
+ implements ActivityCompat.OnRequestPermissionsResultCallback {
private static final String DEFAULT_FRAGMENT = SettingsFragment.class.getName();
public static final String EXTRA_SHOW_HOME_AS_UP = "show_home_as_up";
@@ -77,4 +80,9 @@ public final class SettingsActivity extends PreferenceActivity {
public boolean isValidFragment(final String fragmentName) {
return FragmentUtils.isValidFragment(fragmentName);
}
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ PermissionsManager.get(this).onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java b/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
index 240f8f89b..5994a76df 100644
--- a/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
@@ -32,7 +32,7 @@ import android.util.Log;
* A base abstract class for a {@link PreferenceFragment} that implements a nested
* {@link PreferenceScreen} of the main preference screen.
*/
-abstract class SubScreenFragment extends PreferenceFragment
+public abstract class SubScreenFragment extends PreferenceFragment
implements OnSharedPreferenceChangeListener {
private OnSharedPreferenceChangeListener mSharedPreferenceChangeListener;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
index 294666b8b..356d9d021 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin.spellcheck;
+import com.android.inputmethod.latin.permissions.PermissionsManager;
import com.android.inputmethod.latin.utils.FragmentUtils;
import android.annotation.TargetApi;
@@ -23,11 +24,13 @@ import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
+import android.support.v4.app.ActivityCompat;
/**
* Spell checker preference screen.
*/
-public final class SpellCheckerSettingsActivity extends PreferenceActivity {
+public final class SpellCheckerSettingsActivity extends PreferenceActivity
+ implements ActivityCompat.OnRequestPermissionsResultCallback {
private static final String DEFAULT_FRAGMENT = SpellCheckerSettingsFragment.class.getName();
@Override
@@ -48,4 +51,11 @@ public final class SpellCheckerSettingsActivity extends PreferenceActivity {
public boolean isValidFragment(String fragmentName) {
return FragmentUtils.isValidFragment(fragmentName);
}
+
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, String[] permissions, int[] grantResults) {
+ PermissionsManager.get(this).onRequestPermissionsResult(
+ requestCode, permissions, grantResults);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
index 6850e9b58..12005c25e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
@@ -16,18 +16,31 @@
package com.android.inputmethod.latin.spellcheck;
+import android.Manifest;
+import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.text.TextUtils;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.permissions.PermissionsManager;
+import com.android.inputmethod.latin.permissions.PermissionsUtil;
+import com.android.inputmethod.latin.settings.SubScreenFragment;
import com.android.inputmethod.latin.settings.TwoStatePreferenceHelper;
import com.android.inputmethod.latin.utils.ApplicationUtils;
+import static com.android.inputmethod.latin.permissions.PermissionsManager.get;
+
/**
* Preference screen.
*/
-public final class SpellCheckerSettingsFragment extends PreferenceFragment {
+public final class SpellCheckerSettingsFragment extends SubScreenFragment
+ implements SharedPreferences.OnSharedPreferenceChangeListener,
+ PermissionsManager.PermissionsResultCallback {
+
+ private SwitchPreference mLookupContactsPreference;
+
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -36,5 +49,42 @@ public final class SpellCheckerSettingsFragment extends PreferenceFragment {
preferenceScreen.setTitle(ApplicationUtils.getActivityTitleResId(
getActivity(), SpellCheckerSettingsActivity.class));
TwoStatePreferenceHelper.replaceCheckBoxPreferencesBySwitchPreferences(preferenceScreen);
+
+ mLookupContactsPreference = (SwitchPreference) findPreference(
+ AndroidSpellCheckerService.PREF_USE_CONTACTS_KEY);
+ turnOffLookupContactsIfNoPermission();
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (!TextUtils.equals(key, AndroidSpellCheckerService.PREF_USE_CONTACTS_KEY)) {
+ return;
+ }
+
+ if (!sharedPreferences.getBoolean(key, false)) {
+ // don't care if the preference is turned off.
+ return;
+ }
+
+ // Check for permissions.
+ if (PermissionsUtil.checkAllPermissionsGranted(
+ getActivity() /* context */, Manifest.permission.READ_CONTACTS)) {
+ return; // all permissions granted, no need to request permissions.
+ }
+
+ get(getActivity() /* context */).requestPermissions(this /* PermissionsResultCallback */,
+ getActivity() /* activity */, Manifest.permission.READ_CONTACTS);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(boolean allGranted) {
+ turnOffLookupContactsIfNoPermission();
+ }
+
+ private void turnOffLookupContactsIfNoPermission() {
+ if (!PermissionsUtil.checkAllPermissionsGranted(
+ getActivity(), Manifest.permission.READ_CONTACTS)) {
+ mLookupContactsPreference.setChecked(false);
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index d8926ffba..9577d0913 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -191,7 +191,9 @@ final class SuggestionStripLayoutHelper {
final Bitmap buffer = Bitmap.createBitmap(width, (height * 3 / 2), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(buffer);
canvas.drawText(MORE_SUGGESTIONS_HINT, width / 2, height, paint);
- return new BitmapDrawable(res, buffer);
+ BitmapDrawable bitmapDrawable = new BitmapDrawable(res, buffer);
+ bitmapDrawable.setTargetDensity(canvas);
+ return bitmapDrawable;
}
private CharSequence getStyledSuggestedWord(final SuggestedWords suggestedWords,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 7dd0f03df..c1d1fad68 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -220,7 +220,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
if (getWidth() <= 0) {
return false;
}
- final String importantNoticeTitle = ImportantNoticeUtils.getNextImportantNoticeTitle(
+ final String importantNoticeTitle = ImportantNoticeUtils.getSuggestContactsNoticeTitle(
getContext());
if (TextUtils.isEmpty(importantNoticeTitle)) {
return false;
diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
index df0cd8437..cea263b3b 100644
--- a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin.utils;
+import android.Manifest;
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings;
@@ -25,6 +26,7 @@ import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.permissions.PermissionsUtil;
import com.android.inputmethod.latin.settings.SettingsValues;
import java.util.concurrent.TimeUnit;
@@ -35,14 +37,14 @@ public final class ImportantNoticeUtils {
// {@link SharedPreferences} name to save the last important notice version that has been
// displayed to users.
private static final String PREFERENCE_NAME = "important_notice_pref";
+
+ private static final String KEY_SUGGEST_CONTACTS_NOTICE = "important_notice_suggest_contacts";
+
@UsedForTesting
- static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version";
- @UsedForTesting
- static final String KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE =
- "timestamp_of_first_important_notice";
+ static final String KEY_TIMESTAMP_OF_CONTACTS_NOTICE = "timestamp_of_suggest_contacts_notice";
+
@UsedForTesting
static final long TIMEOUT_OF_IMPORTANT_NOTICE = TimeUnit.HOURS.toMillis(23);
- public static final int VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS = 1;
// Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key.
// The value is zero until each multiuser completes system setup wizard.
@@ -73,87 +75,66 @@ public final class ImportantNoticeUtils {
}
@UsedForTesting
- static int getCurrentImportantNoticeVersion(final Context context) {
- return context.getResources().getInteger(R.integer.config_important_notice_version);
- }
-
- @UsedForTesting
- static int getLastImportantNoticeVersion(final Context context) {
- return getImportantNoticePreferences(context).getInt(KEY_IMPORTANT_NOTICE_VERSION, 0);
- }
-
- public static int getNextImportantNoticeVersion(final Context context) {
- return getLastImportantNoticeVersion(context) + 1;
- }
-
- @UsedForTesting
- static boolean hasNewImportantNotice(final Context context) {
- final int lastVersion = getLastImportantNoticeVersion(context);
- return getCurrentImportantNoticeVersion(context) > lastVersion;
- }
-
- @UsedForTesting
- static boolean hasTimeoutPassed(final Context context, final long currentTimeInMillis) {
- final SharedPreferences prefs = getImportantNoticePreferences(context);
- if (!prefs.contains(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)) {
- prefs.edit()
- .putLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis)
- .apply();
- }
- final long firstDisplayTimeInMillis = prefs.getLong(
- KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis);
- final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis;
- return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE;
+ static boolean hasContactsNoticeShown(final Context context) {
+ return getImportantNoticePreferences(context).getBoolean(
+ KEY_SUGGEST_CONTACTS_NOTICE, false);
}
public static boolean shouldShowImportantNotice(final Context context,
final SettingsValues settingsValues) {
- // Check to see whether personalization is enabled by the user.
- if (!settingsValues.isPersonalizationEnabled()) {
+ // Check to see whether "Use Contacts" is enabled by the user.
+ if (!settingsValues.mUseContactsDict) {
return false;
}
- if (!hasNewImportantNotice(context)) {
+
+ if (hasContactsNoticeShown(context)) {
+ return false;
+ }
+
+ // Don't show the dialog if we have all the permissions.
+ if (PermissionsUtil.checkAllPermissionsGranted(
+ context, Manifest.permission.READ_CONTACTS)) {
return false;
}
- final String importantNoticeTitle = getNextImportantNoticeTitle(context);
+
+ final String importantNoticeTitle = getSuggestContactsNoticeTitle(context);
if (TextUtils.isEmpty(importantNoticeTitle)) {
return false;
}
if (isInSystemSetupWizard(context)) {
return false;
}
- if (hasTimeoutPassed(context, System.currentTimeMillis())) {
- updateLastImportantNoticeVersion(context);
+ if (hasContactsNoticeTimeoutPassed(context, System.currentTimeMillis())) {
+ updateContactsNoticeShown(context);
return false;
}
return true;
}
- public static void updateLastImportantNoticeVersion(final Context context) {
- getImportantNoticePreferences(context)
- .edit()
- .putInt(KEY_IMPORTANT_NOTICE_VERSION, getNextImportantNoticeVersion(context))
- .remove(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)
- .apply();
+ public static String getSuggestContactsNoticeTitle(final Context context) {
+ return context.getResources().getString(R.string.important_notice_suggest_contact_names);
}
- public static String getNextImportantNoticeTitle(final Context context) {
- final int nextVersion = getNextImportantNoticeVersion(context);
- final String[] importantNoticeTitleArray = context.getResources().getStringArray(
- R.array.important_notice_title_array);
- if (nextVersion > 0 && nextVersion < importantNoticeTitleArray.length) {
- return importantNoticeTitleArray[nextVersion];
+ @UsedForTesting
+ static boolean hasContactsNoticeTimeoutPassed(
+ final Context context, final long currentTimeInMillis) {
+ final SharedPreferences prefs = getImportantNoticePreferences(context);
+ if (!prefs.contains(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)) {
+ prefs.edit()
+ .putLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis)
+ .apply();
}
- return null;
+ final long firstDisplayTimeInMillis = prefs.getLong(
+ KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis);
+ final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis;
+ return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE;
}
- public static String getNextImportantNoticeContents(final Context context) {
- final int nextVersion = getNextImportantNoticeVersion(context);
- final String[] importantNoticeContentsArray = context.getResources().getStringArray(
- R.array.important_notice_contents_array);
- if (nextVersion > 0 && nextVersion < importantNoticeContentsArray.length) {
- return importantNoticeContentsArray[nextVersion];
- }
- return null;
+ public static void updateContactsNoticeShown(final Context context) {
+ getImportantNoticePreferences(context)
+ .edit()
+ .putBoolean(KEY_SUGGEST_CONTACTS_NOTICE, true)
+ .remove(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)
+ .apply();
}
}
diff --git a/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
index e361c7704..df0180729 100644
--- a/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
@@ -16,8 +16,7 @@
package com.android.inputmethod.latin.utils;
-import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_IMPORTANT_NOTICE_VERSION;
-import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE;
+import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_TIMESTAMP_OF_CONTACTS_NOTICE;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -35,8 +34,6 @@ import java.util.concurrent.TimeUnit;
@MediumTest
public class ImportantNoticeUtilsTests extends AndroidTestCase {
- // This should be aligned with R.integer.config_important_notice_version.
- private static final int CURRENT_IMPORTANT_NOTICE_VERSION = 1;
private ImportantNoticePreferences mImportantNoticePreferences;
@@ -87,18 +84,15 @@ public class ImportantNoticeUtilsTests extends AndroidTestCase {
}
public void save() {
- mVersion = getInt(KEY_IMPORTANT_NOTICE_VERSION);
- mLastTime = getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE);
+ mLastTime = getLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE);
}
public void restore() {
- putInt(KEY_IMPORTANT_NOTICE_VERSION, mVersion);
- putLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, mLastTime);
+ putLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE, mLastTime);
}
public void clear() {
- removePreference(KEY_IMPORTANT_NOTICE_VERSION);
- removePreference(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE);
+ removePreference(KEY_TIMESTAMP_OF_CONTACTS_NOTICE);
}
}
@@ -117,141 +111,6 @@ public class ImportantNoticeUtilsTests extends AndroidTestCase {
mImportantNoticePreferences.restore();
}
- public void testCurrentVersion() {
- assertEquals("Current version", CURRENT_IMPORTANT_NOTICE_VERSION,
- ImportantNoticeUtils.getCurrentImportantNoticeVersion(getContext()));
- }
-
- public void testStateAfterFreshInstall() {
- mImportantNoticePreferences.clear();
-
- // Check internal state of {@link ImportantNoticeUtils.shouldShowImportantNotice(Context)}
- // after fresh install.
- assertEquals("Has new important notice after fresh install", true,
- ImportantNoticeUtils.hasNewImportantNotice(getContext()));
- assertEquals("Next important notice title after fresh install", false, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
- assertEquals("Is in system setup wizard after fresh install", false,
- ImportantNoticeUtils.isInSystemSetupWizard(getContext()));
- final long currentTimeMillis = System.currentTimeMillis();
- assertEquals("Has timeout passed after fresh install", false,
- ImportantNoticeUtils.hasTimeoutPassed(getContext(), currentTimeMillis));
- assertEquals("Timestamp of first important notice after fresh install",
- (Long)currentTimeMillis,
- mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
-
- assertEquals("Current boolean before update", true,
- ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
- }
-
- public void testUpdateVersion() {
- mImportantNoticePreferences.clear();
-
- assertEquals("Current boolean before update", true,
- ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
- assertEquals("Last version before update", 0,
- ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
- assertEquals("Next version before update ", 1,
- ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
- assertEquals("Current title before update", false, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
- assertEquals("Current contents before update", false, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
-
- ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext());
-
- assertEquals("Current boolean after update", false,
- ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
- assertEquals("Last version after update", 1,
- ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
- assertEquals("Next version after update", 2,
- ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
- assertEquals("Current title after update", true, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
- assertEquals("Current contents after update", true, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
- }
-
- private static void sleep(final long millseconds) {
- try { Thread.sleep(millseconds); } catch (final Exception e) { /* ignore */ }
- }
-
- public void testTimeout() {
- final long lastTime = System.currentTimeMillis()
- - ImportantNoticeUtils.TIMEOUT_OF_IMPORTANT_NOTICE
- + TimeUnit.MILLISECONDS.toMillis(1000);
- mImportantNoticePreferences.clear();
- assertEquals("Before set last time", null,
- mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
- assertEquals("Set last time", false,
- ImportantNoticeUtils.hasTimeoutPassed(getContext(), lastTime));
- assertEquals("After set last time", (Long)lastTime,
- mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
-
- // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} before timeout.
- assertEquals("Current boolean before timeout 1", true,
- ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
- assertEquals("Last version before timeout 1", 0,
- ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
- assertEquals("Next version before timeout 1", 1,
- ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
- assertEquals("Timestamp of first important notice before timeout 1", (Long)lastTime,
- mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
- assertEquals("Current title before timeout 1", false, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
- assertEquals("Current contents before timeout 1", false, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
-
- sleep(TimeUnit.MILLISECONDS.toMillis(600));
-
- // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} before timeout
- // again.
- assertEquals("Current boolean before timeout 2", true,
- ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
- assertEquals("Last version before timeout 2", 0,
- ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
- assertEquals("Next version before timeout 2", 1,
- ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
- assertEquals("Timestamp of first important notice before timeout 2", (Long)lastTime,
- mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
- assertEquals("Current title before timeout 2", false, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
- assertEquals("Current contents before timeout 2", false, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
-
- sleep(TimeUnit.MILLISECONDS.toMillis(600));
-
- // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} after timeout.
- assertEquals("Current boolean after timeout 1", false,
- ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
- assertEquals("Last version after timeout 1", 1,
- ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
- assertEquals("Next version after timeout 1", 2,
- ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
- assertEquals("Timestamp of first important notice after timeout 1", null,
- mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
- assertEquals("Current title after timeout 1", true, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
- assertEquals("Current contents after timeout 1", true, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
-
- sleep(TimeUnit.MILLISECONDS.toMillis(600));
-
- // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} after timeout again.
- assertEquals("Current boolean after timeout 2", false,
- ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
- assertEquals("Last version after timeout 2", 1,
- ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
- assertEquals("Next version after timeout 2", 2,
- ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
- assertEquals("Timestamp of first important notice after timeout 2", null,
- mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
- assertEquals("Current title after timeout 2", true, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
- assertEquals("Current contents after timeout 2", true, TextUtils.isEmpty(
- ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
- }
-
public void testPersonalizationSetting() {
mImportantNoticePreferences.clear();